Top down/side batchable shader billboards
Hello guys,
I'm trying to create a shader billboard where I can see vegetation from top down and side view too. I managed to do it, but for my first attempt I had to disable batching so I could see them. According to unity docs it says that happens because when unity batch them the shader loses the reference to the vertex positions, so the calculations inside the shader become wrong.
As a second attempt, I stored the vertex positions in the UV2 of my model, then I was able to recover the values from it, I removed the DisableBatching tag, my billboard was displaying fine, but it still wasn't batching.
Then I've downloaded the built in shaders from Unity and looked at how speedtree manages to do the vertex displacement + batching. Speedtree doesn't really touch the "VertexOutput positions", so I tried doing the same flow as they do, but my final results are sad. I couldn't get the vertex displacement to work.
So my first question is, does anyone knows why my second attempt doesn't batch? Second question is, does anyone knows the secret behind speedtree batching?
Best regards
Here is my vertex shader for the second attempt ( With DisableBatching tag removed ). It uses an Albedo as a sprite of 8x8 images for yaw and pitch rotation.;
v2f vert(appdata_full v) { v2f o; o.texcoord = TRANSFOR$$anonymous$$TEX(v.texcoord, $$anonymous$$ainTex);
o.vertex = mul(UNITY_$$anonymous$$ATRIX_P, mul(UNITY_$$anonymous$$ATRIX_$$anonymous$$V, float4(0.0, 0.0, 0.0, 1.0)) - float4(-v.texcoord1.x, -v.texcoord1.y, 0.0, 0.0));
float3 dir = normalize(_WorldSpaceCameraPos.xyz - mul(_Object2World, float4(0.0, 0.0, 0.0, 1.0)).xyz);
float d = saturate(dot(dir, fixed3(0, 1, 0)));
float tile = 1.0 / 8;
o.texcoord.xy /= 8;
o.texcoord.y -= tile;
int row = (int)(d * 8);
o.texcoord.y -= tile * row;
float3 billboardTangent = normalize(float3(-dir.z, 0, dir.x));
float3 billboardNormal = float3(billboardTangent.z, 0, -billboardTangent.x);
float3 angle = atan2(billboardNormal.z, billboardNormal.x);
int col = fmod(angle, 8);
o.texcoord.x += tile * (col - row * 8);
return o;
}
And here is my shader that only rotates in yaw, but it batches.
v2f vert(appdata_full v) { v2f o; o.texcoord = TRANSFOR$$anonymous$$TEX(v.texcoord, $$anonymous$$ainTex);
float position_NotBatched_X = v.texcoord1.x / 1.0;
float2 centerOfQuad_XZ = v.vertex.xz * _Object2World[0].x - float2(position_NotBatched_X, 0.0);
float2 zVector_XZ = normalize(_WorldSpaceCameraPos.xz + _World2Object[3].xz - centerOfQuad_XZ);
position_NotBatched_X /= _Object2World[0].x;
float4 position_Object = v.vertex;
position_Object.x += zVector_XZ[1] * position_NotBatched_X - position_NotBatched_X;
position_Object.z -= zVector_XZ.x * position_NotBatched_X;
o.vertex = mul(UNITY_$$anonymous$$ATRIX_$$anonymous$$VP,position_Object);
float3 dir = normalize(_WorldSpaceCameraPos.xyz - mul(_Object2World, float4(0.0, 0.0, 0.0, 1.0)).xyz);
float d = saturate(dot(dir, fixed3(0, 1, 0)));
float tile = 1.0 / 8;
o.texcoord.xy /= 8;
o.texcoord.y -= tile;
int row = (int)(d * 8);
o.texcoord.y -= tile * row;
float3 billboardTangent = normalize(float3(-dir.z, 0, dir.x));
float3 billboardNormal = float3(billboardTangent.z, 0, -billboardTangent.x);
float3 angle = atan2(billboardNormal.z, billboardNormal.x);
int col = fmod(angle, 8);
o.texcoord.x += tile * (col - row * 8);
return o;
}
The difference between the two of them is that I split the matrix multiplication in the first case. That seems to break the batch apparently. Does anyone know why?
Your answer
Follow this Question
Related Questions
Billboard Trees White Dots Everywhere... 0 Answers
Can I render billboards in forward render? 1 Answer
Unable to save generated/rendered Texture2D to use for billboard 3 Answers
Billboard trees on terrain don't work on URP,Billboard trees on the landscape don't work on URP 1 Answer
Terrain trees appear as billboards, 0 Answers