stbova I assume that's because it's skipping the pass that applies the lighting?
No, there is only one lit pass used at this shader. The problem is that unfortunately lighting data is not automatically forwarded to CommandBuffer.DrawMesh
: "Note that the rendered mesh will not have any lighting related shader data (light colors, directions, shadows, light and reflection probes etc.) set up. If the shader used by the material uses any lighting related variables, the results are undefined."
In this regard, the CommandBuffer
API is unfortunately very limited.
So unfortunately it seems that some vertex-lit Spine shaders are unlucky in this regard (Spine/Skeleton Lit
and Spine/Sprite/Vertex Lit
) while the pixel-lit shader Spine/Sprite/Pixel Lit
luckily receives lighting data accordingly, which might not be reliable though.
A safe way should theoretically be to manually set the lighting data as parameters. Unfortunately we could not get this to work using the MaterialPropertyBlock
even when setting params shown in the Frame Debugger. The following code did not work as desired, sharing in case anyone knows a solution to this:
protected virtual void SetupLightingData () {
if (lights == null || lights.Length == 0) return;
commandBuffer.SetGlobalVector("_WorldSpaceCameraPos", Camera.main.transform.position);
Light mainLight = lights[0];
commandBuffer.SetGlobalVector("_WorldSpaceLightPos0", mainLight.transform.forward * -1.0f);
commandBuffer.SetGlobalVector("_LightColor0", mainLight.transform.forward * -1.0f);
for (int i = 0; i < Mathf.Min(4, lights.Length); i++) {
Light light = lights[i];
bool isDirectional = light.type == LightType.Directional;
Vector3 lightPos = isDirectional ? light.transform.forward * -1.0f : light.transform.position;
lightPositions[i] = new Vector4(lightPos.x, lightPos.y, lightPos.z, isDirectional ? 0.0f : 1.0f);
lightColor[i] = light.color * light.intensity;
}
commandBuffer.SetGlobalVectorArray("unity_LightPosition0", lightPositions);
commandBuffer.SetGlobalVectorArray("unity_LightColor0", lightColor);
commandBuffer.SetGlobalVector("unity_VertexLightParams", new Vector4(1f, 0f, 1f, 0f));
}
Another way could be to replace Graphics.ExecuteCommandBuffer(commandBuffer);
with adding the CommandBuffer
into the render-queue at a different location:
void OnEnable () {
Camera.main.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, commandBuffer);
...
}
void OnDisable () {
Camera.main.RemoveCommandBuffer(CameraEvent.BeforeForwardOpaque, commandBuffer);
...
}
Note that this is still using undefined behaviour, so not really a safe solution. It works to some extent, but if you pause the game in play-mode you will see some incorrect rendering happening.
The safest solutions for lit skeletons would be:
- a) Use an unlit shader at the skeleton and then use a pixel-lit shader as RenderQuad material. This way you receive lighting at the later stage, but it would be correct and reliable.
- b) To create a separate Camera which renders to a RenderTexture instead of using the
SkeletonRenderTexture
component. This should apply lighting as desired, but you lose any layout and pixel-perfect benefits.