Bake textures into vertex colors
Written by Jesper Tingvall, Product Expert, Simplygon
Disclaimer: The code in this post is written using version 9.2.7000.0 of Simplygon and Unity 2021.3.0f1. If you encounter this post at a later stage, some of the API calls might have changed. However, the core concepts should still remain valid.
Introduction
In this post we are going to bake textures into vertex colors. This is useful for LODs which are really far away, where we just want some color. In order to do this, we need to disable sRBG on all texture nodes in the scene. So we'll cover how to traverse shader network as well.
We are going to use this brightly colored container asset for this post.
Prerequisites
This example will use the Simplygon integration in Unity, but the same concepts can be applied to all other integrations of the Simplygon API.
Problem to solve
We want a LOD that uses vertex colors for coloring. Reason for this can be that we want to avoid loading any texture into memory and can skip texture sampling in our shader.
To bake data from textures into vertex colors we can use a Vertex color caster. We can do a first try via the user interface and use the settings below.
After processing we discover a problem however. The colors are a wrong. Reason is that we have sampled the color texture with sRGB flag on.
Solution
The solution is to not read the textures as sRBG. To do this we need to manipulate the shading network on our exported scene. To do this we need to perform the LOD generation through scripting.
Find all texture nodes in a shading network
First we are going to create a helper function for finding all texture nodes.
We can detect if the node is a spShadingTextureNode
by doing a SafeCast
to it. After casting we can see if it was successfully casted by checking IsNull
. It will be false if it was casted correctly.
If we are not in a texture node we check if we are in a spShadingFilterNode
. This is the parent class to all nodes which can have other nodes as input. We can use GetParameterCount
to find how many inputs it has and GetParameterIsInputable
to detect if a specific input can be other nodes. Then we can get the next nodes to traverse via GetInput
.
Disable sRGB flags
When we have found every texture node in our material we can disable sRGB using SetUseSRGB
.
Remeshing pipeline
To process our LOD we are going to use a RemeshingPipeline
. To this we add a VertexColorCaster
with Unity specific casting settings.
Since the corners of our asset is sharp we set SetHardEdgeAngles
to 45 to ensure those are kept. This means any angle above 45 will be counted as a hard edge, below it will be a smooth edge.
Before running the scene we disable sRGB on all materials using the helper functions we created above.
After processing and importing the model looks like this. It is optimized enough, but lacks color.
Vertex color shader
Unity's standard shader does not use display vertex colors. To achieve this we are going to write a simple shader that showcase them.
With the shader in place the optimized mesh looks like this. The colors are displayed correctly.
Fixing smeared vertex colors
While the colors are displayed correctly we get lots of smearing between them. Using SetColorSpaceEdgeThreshold
we can control when we should get a hard or smooth color edge. This is similar to how SetHardEdgeAngle
which we covered above works. A color difference above treshold will give us a hard color edge, below will give us smooth colors.
The lowest value of 0.0 gives noticable hard color edges at places we do not want. A value of 0.025 is suitable for our purpose. Our script is thus updated with following setting.
Result
Up close it is easy to see the difference between the optimized model and original. However from far away it is hard. Can you see any difference in image below?