Menu Close

Author: changsooeun

3dsMax tips #5 – Make SkinWrap faster

Often the riggers skin a low res character and use it to drive hires version of character with SkinWrap modifier.

When you use SkinWrap, your driver object need to be Mesh object. If it is not, it will convert to poly under the hood. The mesh <> poly conversion price is very high.When I tested this originally in 3dsMax 2014. The test result was 9.75fps vs 17.89fps. I retested other file in 2021.3. The difference was 10.8fps vs 13.1 fps. So, I guess there has been some progress. It is still taxing 30%.

Skin modifier doesn’t care about poly or mesh. Therefore, if your base object is Editable Poly, just apply Mesh Select before Skin. You will get performance boost.

3dsMax 2021.3 Retopology Modifier Quick Start – Part.2

OK. Part.2! In this post, we will focus on object with hard edges like booleaned model or CAD data.

Booleand Model

Booleaned model is usually pretty easy. Applying Retopology modifier, set the target number and pressing Compute is enough.  But, again it might fail sometime, and you simply want to get better result. So, here is some tips for booleaned model.

Tips

  • Utilize Boolean Seams for very low angle sharp edges
  • Regularize option can help to get more even quad distribution and prevent spiral loops.
  • Adding Subdivide modifier can help a lot to solve and get better result.
  • Having some support edges helps to get better edge flow. Especially for flat circular shapes.

Example

Here is an example. I just apply Retopology modifier, set target to 3000 and just pressed Compute. Auto Edge was on with Smoothing group by default. We got something . But, the topology doesn’t look that great, especially the center circle.

So, I went back to the center boolean operand and give some Cap segments. You can see it makes better edge flow on the big one circular ngon.

Or, you can just add Subdivide modifier. I usually use “Adaptive” option with default. You can see the edge flow is a lot better for both center circular area and front flat face.

Let6’s see one more example. For this kinds of source object, you must Subdivide.

The Retopology result looks good. But, it has an issue. It created the infamous spirals.  I fixed with by increasing Regularize to 1.0. Again this option doesn’t guarantee to remove all spirals. But, certainly worth to try.

CAD Data

Source Preparation

I guess I don’t need to explain how bad models from CAD can be. You all already know. The new algorithms in Subdivide modifier certainly does great jobs for making more Reform friendly faces. But, the mesh has split edges and inverted normal and overlapped double faces what not. Reform nor Subdivide will fail. Until we have T-1000 to retopo, you still gotta do what you gotta do. Here are some notes on mesh preparation.

  • Weld split edges and unwelded vertex. Reform would now know if that’s real edge boundary you want to keep or just bad meshed. The easiest way to check this is applying Relax or TurboSmooth. You will be able to see split edge easily. Then, you could apply Vertex Weld modifier with Threshold 0.001 to fix it.
  • 3dsMax 2021.3 provide Mesh Cleaner modifier. Try that. It also fix some issues.
  • Check if normal is flipped between neighboring faces. Unify option in Normal modifier could help.
  • Delete very small random elements with only few polygons especially for scanned data.
  • Sometimes Quadrify modifier fixes bad topology since it rebuilds meshes. You can also try TurboSmooth with iteration 0.

Tips

  • If it is small part, you can just treat like booleaned model, But, if it has complicated shape, evaluate how much minimum target is needed with Auto Edge OFF.
    If the target is too low, Reform often cause “IPOPT maximum iterations exceeded” error” which means basically Reform saying “I can’t solve this.”. By turning off Auto Edge, you can quickly check how much target is needed.
  • When you Auto Edge, you need enough information within the auto edge boundaries. If you don’t have enough information, again you will meet “IPOPT maximum iterations exceeded” error”. To increase the information, there are 2 options.  1) Subdivide more 2) Remove auto edge condition. For example, if you use UV seams, you could stitch unnecessary seams. If you use Smoothing group, you can smooth some minor edges.
  • Check if your hard edge is coming from the smoothing group or explicit normal. If you only have explicit normals for hard edges and turning on only smoothing group means you don’t get any hard edges. If you are lazy like me,. you can just use Angle option instead of Smoothing Group or Specified Nornal option.
  • Sometimes model could have bad smoothing group and that prevent Subdivide modifier to work properly. Use Smooth modifier to clean up smoothing group.
  • Since Retopology doesn’t preserve mesh data yet. It will look all smooth after it solves. Apply Smooth or Weighted Normal to check hard edges.
  • Often CAD data has nice UV seams, utilize it.

Example

This is a part from Fusion 360 sample scene. It had a unique problem. So, I thought that it was good example to show how I processed the model. You don’t have to go through like this for every model!

This is the source model.
The First attempt with Specified Normal. I got solve. but, I don’t like the edge flow.
I applied Subdivide modifier and set to Adaptive. OK.. something is wrong. I still see a lot of thin edges. This is because there are many smoothing groups there.
I cleaned smoothing group. Subdivide look better.
Retopoed again. Better edge flow. But, I want to improve.
Subdivided more and set Regularize to 1.0.

Then, I was thinking how about go lower res model and TurboSmooth?

This is 2000 target.
Chamfer and TurboSmooth!

OK, I shared all things I have learned during beta testing. If you think it is helpful. Please visit renderStacks!

Also don’t forget to check Autodesk Learning Channel Retopology Tutorial.

https://www.youtube.com/watch?v=sKEu2Gs3G_U
https://www.youtube.com/watch?v=HhUMdy-0kSI
https://www.youtube.com/watch?v=AUikqN_lVPc

 

3dsMax 2021.3 Retopology Modifier Quick Start – Part.1

The new Reform algorithm in the new Retopology modifier in 3dsMax 2021.3 is a definitely one of the best automatic retopology tech on the market. But, this is not driven by crazy AI nor a silver bullet to solve everything with a click. You need a different approach for a different case to get the best result in short amount of time. This is a collected notes from my beta testing period. I hope you find it useful.

Scanned Data

OK. This is easy one. For any organic models, just 2 things.

  • Turn off Auto Edge. This is for preserving sharp edges for hard surface model.
  • Decimate with ProOptimizer A LOT. I mean really a lot. Usually the rule of thumb is matching ProOptimizer verts count to Target count gives you best result in the shortest amount of time.So, if you want to get 40,000 poly mesh, ProOptimized to 40,000 verts first the Compute. Think this way. if your target is 30,000 poly from 2 million poly source. You will not get all the details of 2 million in anyway. There is no reason to feed all those noise data to Reform.
  • If you want to retopologize to really high poly count to reserve all scanned details and Retopology doesn’t solve with that mesh, try InstantMesh mode as a pre-process instead of ProOptimizer. You can’t decimate as much as ProOptimizer with it. But, it generates more Reform friendly mesh. Therefore, it will give you a higher chance to get result.

Tips

  • If you want to process even faster? Then, apply Relax modifier before ProOptimize. You could get faster result in exchange of the loss of details.
  • After ProOptimize if you have very big flat polygon. Remove it or subdivide a little. This kinds of big single polygon can make Deform fail. I’ll show you in the following example.

Example

This is scanned model from Konrad O?óg, www.aunar3d.com. Thanks for the model. It has 1.95 million verts and 3.9 million tris. Look at that beautiful wireframe on right. If you just apply Retopology on this and press Compute. It will takes days.

I applied ProOptimizer and went down to 2%, 39012 verts. As you can see from the shaded view. ProOptimizer does great job for reducing poly count while keeping shape intact.

Then, I had a hiccup. This big lowres place at the bottom was throwing a wrench. I could subdivide this. But, I simply delete it. You don’t see anyway. Also I can recap later.

I turn off Auto Edge and set Target Face Count to 40,000. After 100 second. I got this with 43,000 poly.

The following images are high resolution retopology example using InstantMesh as a pre-process. I pre-processed to 500,000 poly with Instant Mesh and Reformed it to 150,000. It took 20 min on Ryzen 2700X.

Original scan – 1.95 million verts / 3.9 million tri
InstantMesh – 475k verts / 494k quad
Reform – 163k verts(1/11 of original) / 162k quad

Do you want to make your render life 1000% easier! Click here!

Also don’t forget to check Autodesk Learning Channel Retopology Tutorial.

https://www.youtube.com/watch?v=sKEu2Gs3G_U
https://www.youtube.com/watch?v=HhUMdy-0kSI
https://www.youtube.com/watch?v=AUikqN_lVPc

3dsMax 2021.3 Retopology Tutorials Video Collection

Max’s New Remesher is INSANE!

Simple Trick for Perfect Retopology in Max

Introduction to Retopology Tools for 3ds Max®: Retopologizing CAD datal

Introduction to Retopology Tools for 3ds Max®: Retopologizing a Booleaned Model

Introduction to Retopology Tools for 3ds Max®: Retopologizing a Scanned Mesh

Retopology in 3ds Max. Tips & Tricks

3ds Max Retopology

3ds Max Retopology from Jose M. Elizardo

Boolean Mesh Retopoly pitfalls

Miro Retopo

Gladiator Hulk Retopo

3D Studio MAX 2021 Retopology Tools – Adán Martín

Now time to check renderStacks!

3dsMax 2021.3 New Retopology Modifier Test Gallery

3dsMax 2021.3 has been released. The biggest addition of this update is the brand new Retopology modifier. I’ll have another post for the collection of showcase and tutorial videos.

It comes with 3 algorithms to choose, Reform, InstantMesh and QuadriFlow. Reform is the internally developed Autodesk’s own retopology engine.

I have had a chance to beta test while is was developed. This post is the collection of images that I have created while beta testing. I tried my best to test many different types of sources includes 3D scanned model, ZBrush sculpting, CAD import, booleaned meshes and more. Enjoy!

Make sure click image to see big to see wireframe better. Under the image I also tried to post the original source of model as much as remember.

ZBrush Sculpt

296k , 408k

201,881 Poly
Original model 1.2 million poly
Close up
60k, 210k, 2.8mil

732k / 86k / 32k / 20k / 8.6k vets

Do you like new Retopology modifier? renderStacks is as good as this for rendering! Click here to learn!

Scanned Model

https://sketchfab.com/3d-models/lowe-von-asparn-57a57a99ce1f4e45adee5ae37a91f51b
100mil / 300k/ 100k verts
857k / 513k / 116f faces

 

1.5 mil vs 220k https://www.artec3d.com/

CAD Import

Boolean

Up Resolution

One more chance!  Click here to learn about renderStacks. It will change your rendering life!

 

52,464 / 106,302 / 246,787 / 394,237 https://gumroad.com/l/xAQxj

OSL mini tutorial #3 – utilizing scene data and some Math

Welcome to my 3rd OSL tutorial! In this tutorial, we well learn how to query scene/object data and utilize it with MATH! Yes, you heard it right. MATH! I know you always have been regretted that you didn’t pay attention to the math class when you were in middle school. But, never late than never. Re-learning some simple math will make your life easier. WE CAN DO IT TOGETHER!

Like always, we will not write a single line of code in this tutorial. We will use SlateME as our OSL editor. Let me say it again, YOU DON’T NEED TO KNOW HOW TO CODE TO USE OSL IN 3dsMax.

I’ll use MeetMat2 for this tutorial. You can download from Substance website.

First, let’s see how we can query the position of pixel in the scene and utilize. For example, we can make a transition of 2 maps between certain heights from the ground.

You can use “Named Coord Space” map to get a position of a coordinate space.Let’s make one and s some basic setup for the tutorial.

  • Make “Named Coord Space” map and a Standard material.
  • Make Self-Illumination 100.
  • Connect UVW of “Named Coord Space” to the Diffuse Color of Standard material.
  • Make sure to turn on Show Realistic Material in Viewport.
  • Select “High Quality” mode in the viewport.
  • Apply the Standard material to Mat.

3dsMax OSL has an amazing OSL > HLSL auto conversion features as I posted before. You can see OSL map exactly same as render in viewport for most cases. All OSL map has a indicator at the bottom to show if this map could be displayed in viewport. To utilize this feature, your material must set to Show Realistic Material in Viewport, and your viewport must set to Advanced Rendering mode which High Quality preset has.

Your viewport should like this if you follow me correctly. What you are seeing is the World coordinate position as color. If you know what is World coordinate and Object coordinate, you can jump to the next section.

World position is the position from the world origin. Since we plug X, Y, Z, into R, G, B. You can see more Red color along X. Green along Y, Blue along Z. Color can only display from 0-1, that’s why you can only see a little gradient around an axis. Mat’s size is 8.2×1.0x9.4. If value is less than 0, it will be all black. If you rotate the model, you can see the color is not moving with object. Because the coordinate is fixed in world.

Another coordinate you might use is “Object” which is based on each object’s local coordinate. The origin will be at object’s pivot point. The axis will use object’s local axis. This means when the object is moving or rotating, the value will move with objects. If you need to make a map that is stick to the object, this is coordinate you need to use.

Now you know what World/Object position is and how to get the value with “Named Coord Space” map. Let’s utilize the value we got. We will try to blend 2 check map along the height(Z-axis)

  • Make a Maps > OSL > Math Vector > Component (Vector ).
  • Connect UVW of Named Coord Space to Input of Component (Vector)
  • Make a Maps > OSL > Math Float> Range/Remapper.
  • Connect Z of Named Coord Space to Input Value of Range/Remapper
  • Connect Out of Range/Remapper to Diffuse Color of the Standard material.

This should be what it looks like. BTW, I turned off AO. What’s happening here. We took only Z axis value with Component (Vector) map. This map is you can separate each channel from a vector or assemble a vector from 3 floats. Then, we fed the Z value to Range/Remapper which doesn’t do anything with default values. You can see the gradient goes from 0 to height 1. Again, as a color we can only visualize 0-1. I put 1 unit height box as reference.

Now we need to manipulate this value so the value can go from 0.0 – 1.0 between height 1.5 – 3.5. That’s what Range/Remapper  does. Click the map and set Input Range Start to 1.5, Input Range End to 3.5. Now this map takes World Z position as Input Value. You can see “M” button shows that the value is coming from the connection, Then, map the input value 1.5 – 3.5 as 0.0 – 1.0 as output.  You can visually see the gradient is moved up and 2x wider.

We can utilize this value as the Mix value for Mix map.Mix map is a map that Mix 2 color. Surprise! I could use Composite Map, too. But, this map is simpler. Also this is a tutorial. You gotta something new.

  • Make a Maps > OSL > Math Color > Mix(Color) map.
  • Make 2 OSL checker map with different colors and Size 0.05.
  • Connect each Checker map as A and B of Mix(Color) map.
  • Connect Out of Range/Remapper to Mix of Mix(Color) map.

Now let’s make it a little bit more complicated. What if I want to have blue check only top of Mat’s head like snow on his head. We can utilize normal for that.

You can get the normal data with Normal map. Duh. It is under Scene Attribute. It has one option, Coordspace. It should be “World”. Normal is “normal is an object such as a line, ray, or vector that is perpendicular to a given object.” according to Wiki. You can thin think as an arrow that coming out of a face. OK, that’s cool. But, so what? How can it help me?

Usually you need two sidekicks to utilize the Normal data, “Dot product” and another vector. Wha… WTH is “Dot poduct”? My head is already hurting!!! If you really want to know what it is. You can suffer from reading this. Butm I have a good news for ya. You don’t actually need to know what it is. We just need to know how to use this.

  • Make a Maps > OSL > Math Vector > Dot product (vector).
  • Make a Maps > OSL > Values > Vector Value.
    Put 1.0 as Z value. Make sure X, Y are 0.0
  • Make a Maps > OSL > Scene Attribute > Normal.
  • Connect Out of Normal to A of Dot product (vector).
  • Connect Out of Vector Value to B of Dot product (vector).
  • Connect Out of  Dot product (vector) to the Diffuse Color of Standard material.

What did we just do? It looks like face becomes whiter if it face more to the top. When you dot product 3 vectors, Normal and [0, 0, 1] for us. The more 2 vectors look the same direction, The result becomes closer to 1.0. If two vectors are aligned exactly and toward same( direction. the dot product becomes 1.0. If two vectors are at right angle(90 degree), the dot product becomes 0.0. If two vectors are looking at the exact opposite direction. the dot product becomes -1.0. That’s all you need to know. This is how Falloff map works under the hood.

just for the test’s sake, change the vector Z value to -1.0. As you expected, it gets whiter as the point more face down.

How about X = 1.0 and Y, X =0.0?

Got it? Then, Let’s set back to [0, 0, 1].

Now we need some house cleaning. When you dealing with normals and dot product. It is always a good idea to normalize the incoming vectors like this. this makes the incoming vector as a unit vector. If you don’t want to know what/why. just memorize and do it. It is good for you. Normal map is at Maps > OSL > Math Vector > Normalize (vector).

Another item for house cleaning is Clamp. As I mentioned above, dot product generates value from -1.0 to 1.0. You can not see the negative value in render or viewport since both only shows between 0.0 – 1.0. But, if you use negative value for other operation, it could cause issues, therefore. it is always a good idea to cut negative values with Clamp map. Clamp map limits any value outside of Min and Max value as Min and Max value. The default is 0.0 and 1.0. So, any value less than 0.0 will become 0.0. Any value bigger than 1.0 will become 1.0. The map is in Maps > OSL > Math Float > Clamp.

OK. Now we have 2 map trees. One for blending by height. Another one for the direction. We want to combine both so we can have blue check only at the top of Mat’s head. For this kinds of case, we can simply multiply two masks.

  • Select Range/Remapper. Set Input Range Start to 3.0, Input Range End to 4.0.
    This should move mas above Mat’s head.
  • Make a Maps > OSL > Math Float > Multiply map
  • Connect Out of Range/Remapper to A of Multiply.
  • Connect Out of Clamp to B of Multiply.

I know… after all those node, what you got is not that cool. But, this is how you learn.

In this tutorial…

  • we learned how to get position and normal information from the scene
  • how to utilize normal with dot product
  • many of frequently used important math maps such as Range/Remapper, Clamp, Normalize, Multiply. Component.

BUT! Yes, there is always BUT!

The portion that we used to make a mask by face normal exist as one map, Falloff map. This map is basically same as the map tree we set up with a bunch of maps. It take cares Normalize and Clamp, it also have option to map ti the different range. It also allow to define each end as color which is same as Remapping the result with Gradient.

In Falloff map, you have coordinate to choose just like Normal map. You have Face and Away color for each end. Face means the color when dot product is 1.o. Away is the color when dot product is 0 because Type is Perpendicular/Parallel. If you switch to Toward/Away. The Color will map between dot product 1.0 to -1.0.

Thanks!

Do you like my OSL mini tutorial series? Then click here and check out renderStacks, too!

3dsMax tips #4 – My rig is stuck at the previous animation range!

This post is from the recent discussion on Stack Facebook group

The original question was…

has someone experienced that a rotation script controller gets broken/stops calculating properly when it was created with the timerange set e.g. 0-100f and afterwards timeline gets extended to let’s say 0-500f and you start animating with autokey the affected objects, which have the script controller?

I had the experience, too. This could happen in all procedural controllers like Script, Noise controller or Expression controller. What is the solution? One of the most Sr. 3dsMax developer Larry Minton chimed in and gave the answer.

When max creates procedural controllers, by default the controller range is set to be ignored. The setting on whether this is done is controlled by the following 3dsmax.ini setting:

[AnimationPreferences]
IgnoreControllerRange = 1

This setting is exposed to maxscript via: maxops.overrideControllerRangeDefault

And is in the Preferences dialog in the Animation tab in the Controller Defaults group.

Apparently when these controllers were created this option was off. Or this is an extremely old file, this option went into max back in 2005.

You can turn this override back on for these controllers by saying:
c = getclassinstances rotation_script
enableORTs c false

This is the settiing. It is on by default and should be ON.

If you want to make this to be on. You can run this code as a startup script.

maxops.overrideControllerRangeDefault = true

If you already have finished the rig and even animated it. Then, you can use this code to fix for a class of controller. This code is for rotation script controller. If you want to reset all Noise position controller. Swap rotation_script to noise_position.

c = getclassinstances rotation_script
enableORTs c false

You can also change from TrackView for each controller. Set to Ignore Animation Range. Here is 3dsMax help file link.

 

OSL mini tutorial #2 Random map per tile for SimpleTiles map

Using only 1 map.

Welcome to my second OSL tutorial. Again, we will not write a single line of code in this tutorial. We will use SlateME as our OSL editor. Let me say it again, YOU DON’T NEED TO KNOW HOW TO CODE TO USE OSL IN 3dsMax.

I don’t want to spoil the ending. But, you should read til the end. 🙂

One of the advantage(or could be disadvantage for some users) of using OSL in 3dsMax is that it brings more granular and lower level of control which provide a greater flexibility. But, it also means that user need to learn and understand a new way of thinking(or workflow). Again it doesn’t mean you need to learn to code. But, you need to understand how and what kinds of data is flowing between lower level maps and how to control them. So, please try pay more attention to the explanation of “why” I’m connect port A to port B instead of memorizing map tree. 🙂

Today’s goal is randomizing textures in the tiles of Simple Tiles OSL shader so we can get infinite random tile texture from a few texture files.

    1. Open SlateME.
    2. Make a Simple Tiles map. Maps > OSL > Textures > Simple Tiles.
      This is an equivalent of Tiles legacy map. You can make a various tile or brick patterns.
    3. Double click the thumbnail so we can have a bugger thumbnail.
    4. Change Tiling Mode to Twist Box.

As you can see, OSL can output not only color information but also various data information. For this tutorial, we will mainly utilize Index data which is a integer index number for individual tiles. Let’s see that it means visually.

    1. Make 2 OSL > Math Float > Random by Index.
    2. Connect Index port of Simple Tiles to Idx of both Random by Index map.

So, what’s happening here?

Random by Index map generates a random float number between Min and Max and drives the randomization with the Idx and Seed parameters.

Since Idx of Random by Index is provided by the Index value of Simple Tiles, all pixels in the same tile will get the same random value.You can see that well from the thumbnail, each tile has a different shade of gray.

But, you can see both map has exactly same pattern and color. That’s because both map has same Seed number by default. What is the Seed number? This is from the Wikipedia. “A random seed (or seed state, or just seed) is a number (or vector) used to initialize a pseudorandom number generator.”, which brings another important concept, pseudorandom.

In CG, we can not use true random number, if a number is truly random. That means every time when you render or even open file again. You will have a different number and different pattern! Therefore, all random number in CG is pseudorandom driven by Seed number. If Seed number is same you get the same ransom number just like the above image.

  1. Select the bottom Random by Index map
  2. Set Seed to “77”, You should get this.

OK. let’s make a bunch more maps and actually do something with these 2 random maps.

  1. Make the following maps
    OSL > Math Vector > Component (Vector)
    OSL > UVWCoordinates > UVW Transform
    OSL > BitmapLookUp
  2. Choose “C:\Program Files\Autodesk\3ds Max 2021\maps\uvwunwrap\uv_checker.png” for BitmapLookUp
    This is a new 4k UV template which is added in 2021.
  3. Connect Out of the top Random by Index > X of Component (Vector)
  4. Connect Out of the bottom Random by Index > Y of Component (Vector)
  5. Connect Out of the Component (Vector) > Offset of UVW Transform
    Do not connect anything to BitmapLookUp yet.

The 2 Random by Index we made were for the random Offset value of UVW, and it is a vector value. How do I know? If you see in UI, you can ses that it is made out of 3 values. The, it is a vector value.

So, we can not directly plug 2 float values into the Offset port. We need to assemble a vector data and plug into Offset. Component (Vector) map allow to compose or decompose a vector from/to 3 floats. Since we need to use only X and Y value. you don’t have to plug anything into Z. If no map is connected to the property, OSL map will use the value in the UI which was 0.

What we got so far? As you see in the thumbnail of UVW Transform, we randomly offset UV per tile. If you see more red, that means the pixel is offset more along U. If you see more green, that means the pixel is offset more along V. Remember Slate can only show any value range from 0-1 because it is made for color. Fortunately this case out data range is also 0-1. So, we could see what’s going on as image. But, it would be be the case all the time.

  1. Now Connect UVW of the UVW Transform > UV Coordinates of BitmapLookUp
    Tada! you can see your texture randomly offset by Tile ID.

Cool. Now how can I control the scale of texture? Yes, you change the Scale value of UVW Transform.

How can I control the size of tiles? Scale in Simple Tiles.

Let’s see what it looks like with a real texture. Remember this technique only works with seamless tileable texture. This is with the TexturesCom_RockSmooth0172_1_seamless_S.jpg from here. https://www.textures.com/. I use scale to 5.0 for UV.

How about some mid tone variation? We can use Tweak/Levels OSL map for this. We will also need another Random by Index map driven by Index.

  1. Select one of Random by Index map and SHIFT+drag to make a copy.
  2. Set Min as 0.75, Max as 1.25. Seed as 131.
  3. Add a OSL > Tweak/Levels map.
  4. Connect Out of the new Random by Index map to MidTones of Tweak/Levels.
  5. Connect Out(RGB) of BitmapLookUp map to the Input of Tweak/Levels.

OK, I hope you get the hang of how to wrangle data to drive values at this point. Next, let’s put the gaps in. There are unlimited ways to how to handle gaps. But, I’ll just go easiest way since the main purpose of this post is tutorial. The Bump output of Simple Tiles map already give you a black gaps and white tiles. I’ll use that output to composite with Multiply mode.

  1. Make OSL > Compositing > Composite map.
  2. Connect Out of the Tweak/Levels > Bottom layer RGB of Composite
  3. Connect Bump of the Simple Tiles  > Top layer RGB of Composite
  4. Set Top layer Alpha as 0.7, BlendMode as Multiply.

OK, it is getting there. Let’s add one more randomization, the rotation. By now, you should already know what to do.Yes, you need to have another Random by Index (Float) with range 0.1 – 360 and feed into Rotate of UVW Transform. BUT, since it is a tutorial, let’s make things more complicate to learn. What if we want to rotate only at right angle like 90, 180, 270 degree?

Our goal is get only one of the 0, 90, 180. 270 per tile. How we do that? Right, we can get a random value between 0 – 3 and multiply 90.0. But, Random by Index (Float) generates float number, and we don’t have Random by Index (Integer) map. Well, don’t worry. Here comes Float-to-Int map to the rescue!

  1. Copy one of Random by Index (Float).
  2. Set Min as 0.0, Max as 3.99. Seed as 666.
  3. Make OSL > Math Float > Float-to-Int map
  4. Set Mode as floor.
  5. Make OSL > Math Float > Multiply map
  6. Set B as 90.0
  7. Connect Out of the new Random by Index map to Input of Float-to-Int.
  8. Connect Out of the Float-to-Int map to A of Multiply
  9. Connect Out of the Multiply map to Rotate of UVW Transform.
    You may wonder why 3.99 instead of 3.00, and what the heck is “floor”? Floor is a way to convert a float value to integer value by returning the largest whole number (integer) that is less than or equal to the number. if you had 1.24, you would get 1.o. So, it is a floor of the range 1.0-2.0. There is also “ceil” which is kinda opposite. The ceil of 1.24 would be 2.0. By setting range as 0.0-3.99 and mode as floor, we are trying to make sure all 4 numbers are getting even chance. 0.0-1;0 > 0.0. 1.0-1.99 > 1, 2.0-2.99 > 2.0. 3.0-3.99 > 3.0.
    Left is without the rotation randomization. Right is with the rotation randomization.

As you can see, you can randomize any parameters you want. You just need to know when to stop. Should we stop now then? No, not yet. So far, we have used only one map file and looks like getting a good result. But, what if we can use multiple map files and randomly use per file?

Here is a great news. One of the new feature of 3dsMax 2021.2 is 1-of-N(Filename) map. If we don’t have this map, we have to setup a small tree with multiple BitmapLookup , 1-of-N Switcher and Random by Index map. Now we just need 2 maps.

  1. Add a OSL > Switchers > 1-of-N(Filename) map.
  2. Choose all 5 maps.
  3. Add a OSL > Switchers > Random Index by Number/Color map. BTW, such a great map, I wonder who made this? 🙂
  4. Connect Index of the Simple Tiles map to Input Number of Random Index by Number/Color.
  5. Connect Out of the Random Index by Number/Color to Filename of BitmapLookUp.

OK… This is the full tree. I guess we end up with not-so-mini-tutorial.

BUT! Yes, there is always. “BUT”.

We went through all these to learn how to work with OSL maps to build own randomization. Now I have to tell you this. Sorry, we didn’t need to go through all these if you wanted to just use it. Why? Because Zap made the awesome Bitmap Random Tiling for 3dsMax 2021.2.

This is what it looks like if you use Bitmap Random Tiling. Youjust need to plug Index into Seed. Make sure to turn off Randomize by UV position.

You can even randomize color, too.

If you want to use multiple map file? Then, re-use the 1-of-N(Filename). Another 2021.2 feature.

I guess it is worth to upgrade??? 🙂

If you are really lazy, here is the max file. It has the full setup and simple 2021.2 setup. I can not include texture file. So, you probably need to download some seamless tileable maps. Here is another good news. Because ,max file actually embed the source OSL code in the scene file, you can even open this file in 2019. You will see the new 2021.2 OSL shader there. Save the OSL map in a material library. Then, you can even use the new map in 2019 or 2020.  Another nice thing about 3dsMax OSL implementation!

Click to download .max file of this tutorial (2019 version)

Since you follow me all the way down here, you need to check renderStacks. Click here!

A teaser for the future article! What is the difference between the following 4 images?

The answer is… they all rendered in a different renderer. From the left, Corona, VRay, VRayGPU, Arnold. Yes, all different renderer. You can have exactly same map tree across different renderer even CPU/GPU. I can say this is the first time I ever see this is possible in CG history. I’ll have a blog post with more examples in the future.

3dsMax tips #3 How to make imported tree animation 15 times faster

UPDATE! Fully multi-threaded explicit normal calculation has been implemented in 3dsMax 2022.1. Now, the explicit normal version of model is deforming at 2.8fps( was 0.6 fps). That’s almost 450% improvement. BUT, please remember still the best way to make the deformation faster is not having 11 million extra normals. converting explicit normal as smoothing group will give you 17fps.

The models I have been dealing with in 3dsMax have been mostly internally made or purchased as .max file, which means I usually do not have explicit normals on my model. If you make a model in 3dsMax, you usually smoothing group instead of explicit normal.

But, most other DCCs are using explicit normal. Which means when you import fbx, obj or alembic. You will be likely to have a lot of explicit normals. I mean a lot. All this explicit normal also need to be recalculated when your object is deforming, which means it can have a great impact on your animation playback performance.

Recently I have learned the impact of normal calculation is HUGE. I mean really HUGE. Another reason why this issue surfaces more recently is that 3dsMax dev have beenputting a lot of effort to preverve explicit normal in various modifier. In the past, many modifiers had destroyed on the stack, now more explicit normals have preserved and causing slow down.

I downloaded a MaxTree sample file from https://maxtree.org/products/plant-models-vol-16/ 
They have the original max file and fbx file.Perfect.

I chose the biggest one, MT_PM_Albizia_saman_01_01_H, and applied animated Bend modifier.It has 4,4mil verts and 3.8mil tris. This is what it looks like in my Ryzen 2700X(kinda old… I know). I turned off real time playback.

The native max mesh from .max file plays at around 14fps. Not bad for 4.4 million verts animation.
Now I imported the fbx version of same tree. I got 0.6fps.
In other wards, max mesh took less than 2 second to play 24 frames. fbx mesh took 36 second to play 24 frames. That’s almost 20 times slower! When I check the amount of explicit normal, there were 11.399 million normals! File size also jumped from 294M to 645M! This mesh has total 11,399,301 normals. 11 million! Essentially you mesh becomes almost 16 million verts instead of 4.4 million.

3dsMax native mesh
Mesh from fbx with explicit normal

 

 

 

 

 

 

 

 

 

 

 

How to solve this issue

First of all, this is why it is always better if you stay in 3dsMax all the time. The native data is always the best. But, if you have to get data from outside of 3dsMax. The ultimate fix issue would be converting to smoothing group and remove all explicit normals. Unfortunately, I have not found a good way to do this for 4.4 million verts model.

So, I took a little bit of time to find a solution, and here is two work arounds.

Apply Mesh Select for Editable Poly, Smooth for Editable Mesh and set to “Off in render”

Some may think “why not Edit Normal modifier?” because it turns out that Edit Normals can not completely remove normal interface.  So far the only way to completely wipe out explicit normal is applying Mesh Select modifier on Editable Poly or Smooth modifier on Editable MeshThen, by setting this to Off in render, you wipe out explicit normals only for viewport and get correct smoothing while rendering.

So, by doing this, I got around 9fps. That’s a lot better than 0.6fps. That’s 15 times faster.

Do not turn on Auto Smooth on 4.4 million verts model. You don’t need to smooth anything. Just applying Smooth modifier on Editable Mesh will wipe out all normals. Same for Mesh Select, just apply it and change to “Off in Render”.

Conclusion

  • Use always the native mesh if you can. The native mesh is always the best.
  • Use always Smoothing group instead of explicit normal if you can.
  • “Smooth” to wipe out explicit normal in Editable Mesh.
    “Mesh Select” to wipe out explicit normal in Editable Poly.
    Edit Normals modifier can not do this.
  • After the model is imported, always try this if the model has animation.
  • As you can read the below paragraph, having any explicit normal will make 3dsMax calculate something all the time. Even tho you have an explicit normal per vetex(Usually it is a lot more), it is essentially same as having one more mesh. in the above case, it had 11.4 million explicit normals, which means it is same as having 4 trees than 1 tree.  On top of that, this would happen for each modifier after animated modifier. So, this tip will be always valid i n the future.
  • Don’t just assume 3dsMax would be slow for deforming hires mesh. If you for really low fps, always try something. It would be always case by case But, generally speaking, 3dsMax should not havce problem playing more than miilion verts around 10fps.

Technical details

One of the main 3dsMax developer, Peter Watje, game some insight about this issue. I’m sharing the full text. It is must read for any 3dsMax users who want to know the technical details. Thanks, Peter!

Mesh Normal Interface is really the correct name but basically it is an object that is attached to the mesh when you want to override the smoothing groups. It lets you describe normals by smoothing group, or by which faces they are attached to or by the user explicitly setting the value changing the normal direction. It carries around a lot of data even if you don’t have any explicit normals. So for instance if you Box and you put an Edit Normals all the normals start out as Unspecified Normals and are colored blue which means the normals are generated by smoothing groups. Then there are Specified Normals in which case the normal is still computed but the faces that are used are determined by the user. For instance if you Unify some normals they become a Specified Normals(cyan) and the normal is computed by all the faces the original normals where attached to, Finally there are Explicit Normals(green) which the changes the direction of the normal and that normal is no longer computed in anyway. All that data needs to be stored in the Mesh Normal Interface.

Reset Normals sets all the normals back to Unspecified. The Mesh Normal Interface is still there it just uses the smoothing groups to compute the normals but there is still alot of data there.

When it comes to performance it breaks down to were the normals are computed and how much data is copied to create them. With no Mesh Normal Interface the normals are created when the mesh is displayed and is actually done by a shader that takes the mesh and the smoothing groups and generates the normals directly on the display mesh. It is really fast which is why in some cases when you put certain modifiers on the stack that strip out the Mesh Normal Interface it becomes faster.

The other way performance path is thru the Mesh Normal Interface. Since it is data on an object that flows up the stack that means it may need to be copied which is a heavy weight operation. It also means that any geometry changing modifiers need to also deform the explicit normals in addition to the vertices. So when you come to the display all Specified and Unspecified Normals need to be computed if they were not already and merged with the Explicit Normals and then attached to the display geometry. So you performance is determined mainly by how heavy weight your stack was. Previously the stack was super conservative dealing with normal. It did extra copies and the deforming of normals on a single thread. We are looking at making it less conservative to get better performance but that might bring up other unforeseen issues.

A Tip in a tip

How to set modifier to work only in viewport? Right click menu of the modifier. You can set a modifier to on/off or on/off only in render or viewport.

How about making your workflow 15 times faster? Meet renderStacks!

3dsMax tips #2 Custom Viewport Tooltip

When your cursor is hovering over an object in the viewport, you can see that a tooltip pops up and shows object name. 3dsMax 2017+ allow you to customize the viewport tooltip of the active viewport. You can not only show any data you want but also have a custom style using a subset of html tags.

This is a template code for a custom viewport tooltip.

global genTooltip
fn genTooltip = (
local obj = callbacks.notificationParam() -- Getting the objects under cursor from callback
local nodeName = obj.name
local mtlName = (if obj.material == undefined then ("undefined") else (obj.material.name))
local faceNum = try(obj.mesh.numfaces as string)catch("0")
local vertsNum = try(obj.mesh.verts.count as string)catch("0")
local tooltipText = "<u><b><font color=blue size=6>" + nodeName + "</b></font></u><br>"
tooltipText += "<font  size=4>Layer : "+ obj.layer.name + "</font><br>"
tooltipText += "<font  size=4>Material : "+ mtlName + "</font><br>"
tooltipText += "Verts Count: " + vertsNum + "<br>"
tooltipText += "Face Count: " + faceNum + ""
viewport.appendtooltip tooltipText
)
callbacks.removeScripts id:#MXSVIewportTooltip
callbacks.addScript #preViewportTooltip "genTooltip()" id:#MXSVIewportTooltip

Let’s see what’s happening here.

First, we made a global function, genTooltip , to assemble the tooltip text and add to viewport.
The first line local obj = callbacks.notificationParam() is how you get the the objects under cursor from callback. It is what it is. Don’t touch it. 🙂

Then we build the text for the tooltip, As you can see, you can use a subset of html tags. The devloper mentioned to check this document. http://doc.qt.io/qt-4.8/richtext-html-subset.html

The above code will make a bold(<b></b>) big blue(<font color=blue size=6></font>) object name with underline(<u></u>).
Adding <br> is like adding enter to make a new line.
Then, the size 4 layer name and the material name will be added.
Then, normal size verts count and face count will be added.

After you build the text to display,viewport.appendtooltip tooltipText will resister the text as tooltip.

Lastly, we call this genTooltip  function as #preViewportTooltip callback.
That’s the lase 2 line. If copy/paste the above code into Maxscript Editor and run this once with CTRL+E, it will last for the session.

If you are lazy like me, you can copy/paste the above code into notepad.
Then, save as “customViewportTooltip.ms” in the user startup script folder.
C:\Users\[username]\AppData\Local\Autodesk\3dsMax\2020 – 64bit\ENU\scripts\startup

OK. if you are lazy again, type this in the listener and press num pad Enter.
getdir #userstartupscripts

Now every time when you start max, the script will run automatically for you.

Bonus tip!

If you have a looooooooooooot of objects(I mean really a lot), the hit testing to detect which object is under cursor might take a little bit of time. If you want to save a few milisecond. You can turn off viewport tooltip from here.

If you like this post, you will like renderStacks, too! Let’s click here and check it out!