Open sharyu opened 4 years ago
Yes. You need to use a texture array and even if you just want to use pure colors I still recommend using different textures as color palettes and then you sample the texture in the shader to get the different colors. It's much more performant than sending a whole bunch of colors to the meshes.
first create a script which will create and apply the texture array to the materials. The different textures need to have the same dimensions, for example a 8x8 color palette. And the textures need to be in the same format, for example RGB 24bit .
public class TextureArray : MonoBehaviour
{
public Texture2D[] textures;
public Material[] materials;
public bool applyOnStart = true;
private string TexArrayStringName = "_TextureArray";
private int texArrayHashId;
private Texture2DArray textureArray;
public void Start()
{
texArrayHashId = Shader.PropertyToID(TexArrayStringName);
if (applyOnStart)
{
SetTextures();
}
}
public void SetTextures()
{
int textureWidth = textures[0].width;
int textureHeight = textures[0].height;
var format = textures[0].format;
textureArray =
new Texture2DArray(textureWidth, textureHeight, textures.Length, format, false);
for (int i = 0; i < textures.Length; i++)
{
Graphics.CopyTexture(textures[i], 0, 0, textureArray, i, 0); // i is the index of the texture
}
for (int i = 0; i < materials.Length; i++)
{
SetTexArray(materials[i]);
}
}
public void SetTexArray(Material mat)
{
mat.SetTexture(texArrayHashId, textureArray);
}
}
In AnimationInstancing.cs add a new variable. This is where you change the texture index for each character.
public class AnimationInstancing : MonoBehaviour
{
public int texturArrIndex;
...
In AnimationInstancingMgr.cs add these things (every line under "//Add this " comment):
public class AnimationInstancingMgr : Singleton<AnimationInstancingMgr>
{
// array[index base on texture][package index][instance index]
public struct InstanceData
{
...
//Add this
public List<float[]>[] texureArrayIndex;
}
//Add this
private static readonly int TexArrIndexHash = Shader.PropertyToID("_TextureIndex");
...
private void Render()
{
foreach (var obj in vertexCachePool)
{
VertexCache vertexCache = obj.Value;
foreach (var block in vertexCache.instanceBlockList)
{
List<InstancingPackage>[] packageList =
block.Value.packageList;
for (int k = 0; k != packageList.Length; ++k)
{
for (int i = 0; i != packageList[k].Count; ++i)
{
InstancingPackage package = packageList[k][i];
if (package.instancingCount == 0)
continue;
for (int j = 0; j != package.subMeshCount; ++j)
{
InstanceData data = block.Value.instanceData;
if (useInstancing)
{
#if UNITY_EDITOR
PreparePackageMaterial(package, vertexCache, k);
#endif
//Add this
package.propertyBlock.SetFloatArray(TexArrIndexHash , data.texureArrayIndex[k][i]);
....
}
else
{
...
}
}
...
}
...
}
}
}
}
void ApplyBoneMatrix()
{
...
for (int i = 0; i != aniInstancingList.Count; ++i)
{
AnimationInstancing instance = aniInstancingList[i];
...
for (int j = 0; j != lod.vertexCacheList.Length; ++j)
{
...
else
++package.instancingCount;
{
...
if (count >= 0)
{
...
data.transitionProgress[aniTextureIndex][index][count] = transition;
//Add this
data.texureArrayIndex[aniTextureIndex][index][count]= instance.texturArrIndex;
}
}
}
...
}
...
}
...
public InstancingPackage CreatePackage(InstanceData data, Mesh mesh,
Material[] originalMaterial, int animationIndex)
{
...
//Add this
data.texureArrayIndex[animationIndex].Add(new float[instancingPackageSize]);
return package;
}
...
InstanceData CreateInstanceData(int packageCount)
{
...
//Add this
data.texureArrayIndex = new List<float[]>[packageCount];
for (int i = 0; i != packageCount; ++i)
{
//Add this
data.texureArrayIndex[i] = new List<float[]>();
}
return data;
}
}
in your shader you need to add this
UNITY_DECLARE_TEX2DARRAY(_TextureArray);
UNITY_INSTANCING_BUFFER_START(Props)
UNITY_DEFINE_INSTANCED_PROP(float, _TextureIndex)
#define _TexureIndex_arr Props
UNITY_INSTANCING_BUFFER_END(Props)
and to sample the texture in the fragment shader
int index = UNITY_ACCESS_INSTANCED_PROP(_TexureIndex_arr , _TextureIndex);
float4 color = UNITY_SAMPLE_TEX2DARRAY(_TextureArray, half3(IN.uv, index));
if you use the texture as a palette where each pixel is a different color and you want to sample one color you could use a function like this
float4 GetPalletteColor( int x, int y, int texDimension)
{
int index = UNITY_ACCESS_INSTANCED_PROP(_TexureIndex_arr , _TextureIndex);
float pixelSize = 1/texDimension;
float halfPixSize = pixelSize * 0.5;
return UNITY_SAMPLE_TEX2DARRAY(_TextureArray, half3(halfPixSize + x * pixelSize, halfPixSize + y * pixelSize, index));
}
this is useful if you use an RGB mask, so if the mask is black you sample pixel (0,0) if it's red pixel(0,1) etc.
Hi, I want to use same model and animation, but different colors. Is it possible?