I made a tutorial on how to bake perfect normal maps in Substance painter.
Forum thread here:
I made a tutorial on how to bake perfect normal maps in Substance painter.
Forum thread here:
The funny thing is that there are thousands of references available on how a light affects an object. But the amount of references available on how the light itself looks you can count on one hand. I once found a scientific paper, but that’s about it. Perhaps that is why very few people get it right. Often you see an emissive sphere with a flare sprite slapped on top of it. But that is a far cry from a physically based approach, which I will describe here.
Most lights have a lens, which makes them either highly directional like a flashlight, or horizontally directional, the result of a cylindrical Fresnel lens. This directional behavior is simulated with a phase function which shows nicely on a polar graph. Here you can see two common light radiation patterns:
The blue graph has the function 1 + cos(theta*2) where theta is the angle between the light normal and the vector from the light to the camera. The output of the function is the irradiance. Adding this to the shader gives the lights a nice angular effect.
Next is the attenuation. Contrary to popular belief, focused lights (in the extreme case, lasers) still attenuate with the inverse square law, as described here:
But contrary to even popular scientific belief, lights themselves don’t behave in quite the same way, or at least not perceptually. The inverse square law states that the intensity is inversely proportional to the square of the distance. Because of this:
You see this reference all over, for example here:
Yet the light itself is brighter than bar number 4, which is about at the same distance as the light to the camera. The light itself doesn’t seem to attenuate with the inverse square law. So why is this? Turns out that in order to model high gain light sources (such as directional lights), you need to place the source location far behind the actual source location. Then you can apply the inverse square law like this:
Note that highly directional lights have a very flat attenuation curve, which can be approximated with a linear function if needed in order to save GPU cycles.
Some more reading about the subject here (chapter Validity of the Inverse Square Law):
One other problem is that the light will disappear if it gets too far from the camera. This is the result of the light being smaller than one pixel. That is fine for normal objects but not for lights because even extremely distant or small lights are easily visible in real life, for example a star. It would be nice if we would have a programmable rasterizer, but so far no luck. Instead, I scale the lights up when they are smaller than one pixel, so they remain the same screen size. Together with the attenuation, this gives a very realistic effect. And all of this is done in the shader so it is very fast, about 0.4 ms for 10.000 lights on a 780ti.
Since I made this system for a flight simulator, I included some specific lights you find in aviation, like walking strobe lights (also done entirely in the shader):
And PAPI lights, which are a bit of a corner case. They radiate light in a split pattern like this (used by pilots to see if they are high or low on the approach):
Simulated here, also entirely in the shader.
Normally there are only 4 of these lights in a row, but here are 10.000, just for the fun of it. They have a small transition where the colors are blended (just like in reality), which you won’t find in any simulator product, even multi million dollar professional simulators. That’s a simple lerp() by the way.
I should also note that the shaders don’t use any conditional if-else statements but use lerp, clamp, and scaling trickery instead. So it plays nice even on low-end hardware.
Released for free, but with limited support:
Controls: same as in the editor.
Speed up/slow down: 1 and 2 (not numpad)
Bloom is SE natural bloom.
It looks best in fullscreen.
Note that the frame rate is much higher in a standalone build.
Previously, adding a hole in on a complex curved surface was not easy to do in Inventor. With the new Curve On Face feature in Inventor 2017, this has been made much easier. This is how it’s done:
-Start a 3D sketch.
-Select “Curve On Face”.
-Draw a 3 point spline on the surface, with the 4th connecting to the first one to close the loop.
-Finish the 3D sketch.
-Create a plane out of 3 points, using the 3 points from the spline.
-Create a 2D sketch on the plane.
-Add a circle on the 2D sketch and place it in the center of the spline points. The circle will be used to extrude the hole.
-Finish the 2D sketch.
-Create an axis by selecting “Normal to Plane through Point” and select the mid point and the work plane. This axis can be used later to align a screw.
-Hide the 3D sketch and the work plane, leaving only the hole, work point, and the work axis behind.
Here are some screenshots of the finished A320 cockpit CAD model. The CAD model is available for purchase. Please use the contact form at www.airlinetools.com for inquiries.
Experimental texturing of monitor in Substance painter:
Test of leather material in Substance Painter.
Test of leather material (armrest) in Substance Painter:
Throttle unit. The text is embossed into the geometry:
Some more screenshots:
When editing imported CAD data, there are several things to be aware of. CAD data uses explicit (custom) normals. Smoothing groups are not used at all. It is important that all implicit normals are maintained when editing the mesh, otherwise you are likely to get nasty shading errors.
There are three ways to check for shading errors:
-Check the normals.
-Check the shading look.
-Check for any back facing triangles using Views->xView->Face Orientation (shown in green).
The only way to view explicit normals is to add an “Edit Normals” modifier to the top of the stack, then adjust the Display Length (length of the vectors). The explicit normals are shown in green. Blue lines are unspecified normals which are calculated using averaging and you do not want to see those in a CAD model.
Unfortunately 3ds Max is very buggy maintaining explicit normals and not very helpful displaying any resulting shading errors. The main problems are:
-The way the default viewport shading works makes incorrect normals not very apparent.
-Some operations dump the explicit normals and replace it with unspecified normals.
-Some operations maintain the explicit normals but rotate them in some random direction.
-Some operations create double triangles (back facing and forward facing), which go undetected unless you view the vertex/triangle count.
-Importing an Inventor model as a body object will create flipped faces on mirrored features and in some cases even removes faces completely.
-Flipped triangles go undetected unless you use xView.
I wrote a script called CADtoSP (CAD to Substance Painter) which fixes all of these issues. It is still in Beta but will be released in the near future for free. Send me an email if you want to receive a preview. Until that time, here are some things to keep in mind.
Some surfaces appear to be watertight but are actually separate surfaces. To fix this, you need to weld the vertices of all objects. This is done in order to reduce vertex count and to make sure the derived projection cage is correct, in order to prevent texture baking errors. There are several ways to merge vertices, but all of them destroy explicit normals, except this method:
-Convert the object to an Editable_Mesh.
-Add a ProOptimizer modifier with the following settings:
*Keep Normals = on
*Protect Normals = on
*Merge Vertices = on
*Threshold = 0.0
-Press Calculate on the ProOptimizer modifier.
-Collapse the stack. Note that this is important because if there are a lot of objects and you do the above steps in a script loop, PropOptimizer WILL fail without warning.
If Inventor objects (and possibly other CAD files) are imported into 3ds Max as a body object, some mirrored features will have back facing triangles. The only reliable way to fix flipped faces is to re-import the Inventor model as a mesh instead of a body object. But this will trigger another bug in 3ds Max. The wireframe can’t be made visible. To work around this, add a ProOptimizer modifier to the object and configure the settings as above. Then press Calculate and the wireframe will be visible if enabled.
When the CAD file is exported to an FBX file, all objects will have a transform which is not set at zero. Unity imports this correctly, but unfortunately Substance Painter do not and it is unlikely they will fix this. A workaround is to use a script called “reset_Xform_on_selected.ms”, available here:
In order to reduce draw calls, static objects need to be fused into a single object wherever practical. There are several ways to do this, but all of them destroy explicit normals, except this method:
-Execute the script “reset_Xform_on_selected.ms” on each which is to be fused. This prevents the explicit normals from pointing in the wrong direction after the mesh is fused.
-Convert all objects which need to be fused to an Editable_Poly. This prevents the explicit normals to be converted into unspecified normals.
-Select the first object which need to be fused.
-On the Editable Poly modifier, on the Edit Geometry rollout, select the little icon next to the Attach button (Attach List). Or click on the Attach button and then click on a second object you want to attach.
Imported Inventor files contain materials which are incompatible with the FBX file format, and possibly other export file formats. This results in the loss of all materials. In order to fix this, you need to convert all materials to a standard material.
If you detach a surface, the normals will point the wrong direction after you fuse the new object with another object. In order to prevent this from happening, you need to add an Edit Normals modifier to the detached object and make the normals explicit, then collapse the stack. Now you can fuse the detached object with another object.
Due to a bug in 3ds Max, sometimes the mesh is not stitched water tight at some location. Adjust the mesh resolution slider to a higher resolution, or re-import the model as a mesh instead of a body object.
The 3d model of the cockpit I was working on is now complete and I want to list some do’s and don’ts which may come in handy if you have a similar project. I will write another blog about the complete high res – low res workflow some time later.
First off, if you have access to a high resolution 3d scanner, use that to make a scan of each individual part. Use the scan as an overlay (reference) to model the parts in 3ds Max (or any other non-parametric modeller). Make another overview scan at a lower resolution which is just used to position the parts relative to each other. This process will be quicker than measuring everything by hand and re-modelling it in Inventor like I did. The downside is that these scanners are incredibly expensive, ranging from 30k to 150k USD.
That being said, here are some things to keep in mind when you do need to reverse engineer something in Inventor.
-Use a variety of measuring tools. You will need at least a:
-Take photos of the object, print them out, and take notes on that, instead of making manual sketches.
-Make sure you have unrestricted access to the object you are working on, as you are likely need to re-measure things which don’t add up. If you have only one day, you have no choice but to use a 3d scanner.
-Don’t measure everything first and then start to model afterwards. Instead, measure some parts, model it, assemble them together, and then repeat this process. This is because some measurements are inevitably wrong or forgotten. You don’t want a small change affect the entire part because even if the design is parametric, changing something often causes errors.
-You cannot see the mesh model (triangles) in Inventor, so when modelling, think about what geometry will be created. You can import the ipt or iam file into 3ds Max at any time to see what it looks like once triangulated.
For example, if you model a cylinder on top of a square shape, you generally do not want to extrude the cylinder out of the square surface. This is because the square surface will receive additional polygons wrapping around the cylinder. Instead, create the square and cylinder as separate parts and assemble them together. Or model them in a single part but insert a Split feature at the base.
Note that if you use the split feature, it will create multiple solid bodies or surfaces. These will be imported into 3ds Max as separate objects/nodes. If you want to save draw calls in a real time renderer, you need to attach those separate objects together so they are a single object again.
Also note that if you split an object in Inventor, it creates additional surfaces at the split. Some of them will be out of view and you need to delete those surfaces using the Delete Face feature in Inventor.
Here is an example of the workflow to reduce polygons by splitting an object in Inventor. Let’s have a look at this object:
It looks fine, but if it is imported into 3ds Max and the wireframe view is turned on, it looks like this. Note the additional polygons at the square base.
Back in Inventor, split the part at the base:
Now it looks like this in 3ds Max. There are still unnecessary polygons at the base of the cylinder.
In Inventor, delete the face at the bottom of the cylinder. Note that you can select a face hidden behind other geometry by hovering the mouse over the hidden face for a while. This will give you a dropdown list where you can select the hidden face. After deleting this face, it looks like this in Inventor. It basically looks the same.
But if the part is imported into 3ds Max, it looks like this. Note that the redundant polygons at the base of the cylinder are removed:
Now the square and the cylinder can be attached together to make it a single part again.
-Think about the level of detail you want to model right from the start. You can model all surface details in the geometry as most of that can be baked into textures, but adding these details afterwards can be a source of trouble.
Here is an example of a part with all surface detail modelled in.
The wireframe looks like this. Note the excessive amount of triangles:
However, all surface detail can be removed in Inventor by simply deleting those features (using a duplicate project). Now the wireframe looks like this:
The high detail mesh can be baked into a normal map, which looks like this:
When the normal map is applied to the low poly object, it looks nearly identical to the original, but it is much faster to render.
-If you want to model all surface details, make sure you model it in such a way that it can be easily removed from the hierarchy. For example, bending a part using the Bend feature is a bad idea because this will create geometry at the rounded sides which cannot be removed. Instead, make a straight angle and add fillets to “simulate” the bend. The fillets can be removed from the hierarchy, allowing you to create a high and a low res model, which is required for baking into a texture. Also, avoid putting fillets in a sketch as it is easier to delete a fillet feature from the hierarchy then it is to modify it in a sketch.
Here is part with a Bend feature:
This is the same part but now the bend is modelled using fillets, which can be easily deleted and replaced with a normal map:
-If you are making the model for realtime rendering then don’t model geometry you can’t see.
-Cumulative measurement errors are an issue. If you have 10 objects stacked together, measure the total distance to crosscheck any individual part measurements.
-Related to cumulative errors, don’t measure any angles unless the distance it effects is no longer then 20 or 30 cm. Never use compounded angles as this makes it even worse. A small angle error will cause a large displacement of geometry if the distance is large. If you do need to work with angles, measure distances instead and derive the angles from that.
-Assemble individual parts together from the top down. Assembling a large amount of parts using parent-child constrains are unlikely to fit together with a tight tolerance. Again, cumulative errors are the issue here.
-Organic shapes are very hard or impossible to measure and/or to model in Inventor. You can use the freeform modeller but this requires a skill on its own. You can use photogrammetry (Agisoft PhotoScan) as a reference if you don’t have access to a 3d scanner, but the results will vary.
-If an object needs to be animated, think about where the pivot point should be. The pivot point is the part origin (center point).
-Delete faces on the low poly model in Inventor, not in 3ds Max, because it can be done much faster in Inventor (and easily undone since it is feature based).
-Use G2 fillets where possible, as these have smoother shading than G1 fillets.
-Do not use the default material on everything. Give each part its appropriate material because this makes the texturing process much easier. If you have 2 materials which are the same color but should have a different normal detail map (such as a leather surface and a smooth surface with the same color), give them each a slightly different color. This is done so that the different materials can be easily identified during the texturing process.
-Do not be shy of using multiple materials on a single part. These can be easily baked into an ID map which can be used to reconstruct complex materials in 3ds Max or any other modelling program.
-Model text on surfaces by using the Emboss feature with a very small depth. Do this only for non-flat surfaces, as you have to apply a material for each letter individually. It is faster to add text or other decals as a regular texture in 3ds Max.
That’s pretty much it. Let me know in the comments if you have any other suggestions.
Modern graphics cards can easily render millions of polygons at a high framerate. Usually other things will be a limiting factor such as draw calls, fillrate, complex shaders, etc. However, CAD models can produce excessive amounts of polygons and this needs to be reduced.
There are several techniques to reduce polygons from CAD models. I will go through each of them.
CAD models in general are vector based. So if you convert from CAD to non-CAD, you have to ask yourself how many polygons you want to create rather than how many polygons you want to remove.
A good program which can convert CAD vector files from Inventor (ipt and iam files) into polygons (fbx for example) is 3ds Max. At the import dialog you can choose how many polygons should be generated, called the “mesh resolution” slider.
I found that a value between 0 and -2 is adequate for real time rendering. Large curved surfaces might need a higher setting though.
Another great way of reducing polygons is to remove all surface detail and replace it with a texture. To do this, first copy your entire CAD project folder and rename it to something like “LOW RES”. Don’t remove the surface detail form the main CAD source as it can be a lot of work to undo the changes.
To remove the surface detail, click on all surface features such as small chamfers, fillets, extrudes, etc. and delete them. Below is an example of a model how it looks originally. You can see that it has a lot of surface detail which will convert to a lot of polygons. Without modification, this model will generate 2814 polygons with a mesh resolution setting of -2.
The screenshot below shows what the CAD model looks after removing all the surface details.
This model generates only 170 polygons with a mesh resolution setting of -2. That is a 16x reduction, just be removing the surface detail! The details can be replaced by a texture, making it much faster to render.
Not all surface details can be removed by simply deleting features, for example in the case of this coil.
Unless the coil shape is made by engraving a shape out of the edge of a cylinder, it can not be deleted. In this case we need to replace the coil by inserting a cylinder just below the coil feature. In order to do this, move the End Of Part icon to just below the coil feature. Then create a cylinder which matches the coil and move the End Of Part icon to the bottom again. Inventor should apply the bend to the cylinder automatically and you can delete the entire coil feature, leaving only the cylinder, as shown below.
In this case the amount of polygons are reduced from 10.596 to 394 (mesh resolution -2), as shown below.
This is a 1 minute tweak which results in a 27x reduction of polygons!
You can also remove polygons which will never be visible. This might not be worth the effort though as it requires a lot of manual work. Even if you managed to remove 100.000 polygons by hand (which is a lot of work!) then there will be no noticeable increase in frame rate unless you run it on a mobile device.
As an example, the bottom of our CAD model will never be visible, so these polygons can be removed. Here is the bottom of the model before.
Pictured below is the bottom of the model after manual polygon removal.
The amount of polygons is now reduced from 170 to 148. Again, this might not be worth the trouble. Either way, you most certainly don’t want to texture map invisible areas as that wastes texture space.
Now that we have our low res model, let’s make a high res model which will be used for baking textures. This is easy. Just import the original CAD file which includes all surface detail and set the mesh resolution to the highest available.
This is our CAD model imported with the highest mesh resolution.
Now the model has 51.698 polygons. This is not suitable for real time rendering (or at least not if the entire model has this resolution), but it is great for texture baking.
How to bake a texture from a high res model is different for each 3d modelling package so I won’t go into details. The basic idea is to project the high res model onto a texture to generate at the very least a normal map. Other maps such as occlusion and curvature maps can be used to further enhance the model. If this is done right, the low res model with a texture applied can look nearly identical to the high res model, under the right conditions.
I sometimes get asked the question why I use Autodesk Inventor for 3d modelling rather than something which is more suitable for game design such as 3ds Max. The answer is simple. Precision.
The A320 cockpit I am modelling will be used in a professional PC based flight simulator. The program will support Virtual Reality once the resolution is high enough to read the instruments. In order to support VR, all dimensions must be correct.
If you have spent thousands of hours in the cockpit of an airplane, you will notice straight away if a panel or switch position or orientation is slightly off. On top of that, people have muscle memory. You don’t consciously think where to place your finger to push a button, it is done automatically, like typing on a keyboard. If a button is not exactly in the right position, you will miss it. This is assuming accurate hand and finger tracking is available for VR but it is only a matter of time before that becomes available at a consumer level.
In order for the dimensions of the 3d model to be correct, the data source must be correct. I measure everything down to the millimetre using a variety of tools.
Getting those through security each day is the subject of another blog post.
Because air time is limited (our longest sector is only two hours), I make a quick sketch of the item to be measured and note down the dimensions. The actual modelling is done back home.
Another way of doing this is with the use of a 3d scanner. The data a 3d scanner produces isn’t suitable for realtime rendering because of quality and quantity issues but it can be used to scan once and measure later. The scanned data can be used as a background reference for direct modeling also. Unfortunately a good 3d scanner costs north of $30k, which is beyond my budget. Photogrammetry tools such as Photoscan cannot be used because most surfaces in the cockpit don’t have much surface detail and are glossy, producing a noisy result.
But I digress. So why use Inventor instead of 3ds Max to do the modelling. Because 3ds Max or any other non-CAD modelling program, doesn’t support constraint based parametric design. The position of a button on a panel needs to be exact, not eyeballed. And if I change one feature of a button, all related features must be updated. You just can’t do that with a program which doesn’t support CAD specific features, or at least not efficiently without the use of high quality 3d scanned data as a reference.
On top of that, the workflow of Inventor (or any CAD program for that matter) is to create a sketch and use that to model the geometry. These sketches look exactly the same as the notes I make while measuring, so turning that into a 3d model is a breeze. Still a lot of work though.
There is one major drawback to using a CAD program for game design though. It doesn’t support UV coordinates, so you can’t do proper texturing. This means you have to do the UV mapping in a game/movie modelling program. But if you make a change in the source model and convert it to an FBX again, all UV information is lost. So you have to make sure the model is correct before you start to unwrap the UV coordinates. And if you do want to make a change to the model, you will have to do it on the imported model.
Another issue with using CAD for game design is that you cannot edit the vertex normals on the source model. So things like smoothing groups have to be done on the imported model.
One way to mitigate this workflow which basically renders your CAD source useless, is to only re-import the part of the model you want to change. You will still lose all UV and normal data, but at least the damage is contained. Inventor and Max work nicely together and all ipt files are imported as a single object. This is not good for realtime performance (unless you use DX12, Vulcan, etc), but it is great for fixing design errors.
Here is a screenshot of some work in progress.
The 3ds Max Inventor importer has a fantastic LOD feature where you can increase the amount of polygons of curved surfaces while flat surfaces always have the smallest amount of polygons possible.
One last note. At some point you want to merge all static individual objects into a single mesh. This reduces the amount of batches to render and is better for performance. But once you do that, you can’t use the CAD source model anymore to change the design. This is the very last step in the modelling process though, and as long as you keep the source of pre-merged UV mapped model, it shouldn’t be a problem.
Bit Barrel Media specializes in aviation training software. We have over 11 years of hands on experience in the aviation industry, ranging from maintenance, general aviation, and commercial aviation. Our specialty is A320 cockpit model design and systems simulation.
Programming (C#, Unity, VR)
CAD design (Autodesk Inventor)
3D Cockpit design
bitbarrelmedia *at* gmail (dot) com
For Jetstar Pacific Airlines crew only.