Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Why does CommandBuffer.DrawMesh draw all meshes with the same color when different colors are set?

Discussion in 'Shaders' started by Spankenstein, Aug 30, 2016.

  1. Spankenstein

    Spankenstein

    Joined:
    Jan 9, 2014
    Posts:
    25
    I am using the following code to create a draw two meshes on the screen with two different colors.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Rendering;
    3.  
    4. public class DebugMeshColour : MonoBehaviour
    5. {
    6.     CommandBuffer commandBuffer;
    7.     Material meshMaterial;
    8.     Camera cameraUsedToRender;
    9.     RenderTexture debugRT;
    10.  
    11.     void Awake()
    12.     {
    13.         meshMaterial = Resources.Load<Material>("Materials/MeshRender");
    14.  
    15.         cameraUsedToRender = Camera.main;
    16.         cameraUsedToRender.orthographicSize = 10f;
    17.  
    18.         // Create debug render texture to render to using our camera
    19.         debugRT = new RenderTexture(cameraUsedToRender.pixelWidth, cameraUsedToRender.pixelHeight, 16);
    20.         debugRT.Create();
    21.  
    22.         // Create command buffer
    23.         commandBuffer = new CommandBuffer();
    24.         commandBuffer.name = "Debug Alpha Blending";
    25.     }
    26.  
    27.     void OnRenderObject()
    28.     {
    29.         cameraUsedToRender.RemoveAllCommandBuffers();
    30.  
    31.         commandBuffer.SetRenderTarget(debugRT);
    32.  
    33.         // Clear the render target
    34.         commandBuffer.ClearRenderTarget(false, true, Color.black);
    35.  
    36.         var colours = new [] { Color.white, Color.red };
    37.  
    38.         for (int i = 0; i < 2; ++i)
    39.         {
    40.             // Generate the mesh
    41.             var mesh = GenerateMesh(Vector3.zero + new Vector3(i * 6, i * 6, 0f), Vector3.one * 2f);
    42.  
    43.             // Set the colour of the mesh
    44.             meshMaterial.SetColor("_Color", colours[i]);
    45.  
    46.             // Draw the mesh
    47.             commandBuffer.DrawMesh(mesh, Matrix4x4.identity, meshMaterial);
    48.         }
    49.  
    50.         // Release the render target
    51.         commandBuffer.SetRenderTarget(null as RenderTexture);
    52.  
    53.         cameraUsedToRender.AddCommandBuffer(CameraEvent.AfterEverything, commandBuffer);
    54.     }
    55.  
    56.     void OnGUI()
    57.     {
    58.         GUI.DrawTexture(new Rect(0f, 0f, Screen.width, Screen.height), debugRT);
    59.     }
    60.  
    61.     Mesh GenerateMesh(Vector3 position, Vector3 extents)
    62.     {
    63.         var mesh = new Mesh();
    64.  
    65.         var indices = new[] { 0, 1, 2, 2, 1, 3 };
    66.  
    67.         var normals = new[]
    68.         {
    69.             Vector3.back,
    70.             Vector3.back,
    71.             Vector3.back,
    72.             Vector3.back
    73.         };
    74.  
    75.         var vertices = new[]
    76.         {
    77.             new Vector3(position.x - extents.x, position.y + extents.y, 0f),    // ul
    78.             new Vector3(position.x + extents.x, position.y + extents.y, 0f),    // ur
    79.             new Vector3(position.x - extents.x, position.y - extents.y, 0f),    // ll
    80.             new Vector3(position.x + extents.x, position.y - extents.y, 0f)     // lr
    81.         };
    82.  
    83.         var uvs = new[]
    84.         {
    85.             new Vector2(0, 1),    // ul
    86.             new Vector2(1, 1),    // ur
    87.             new Vector2(0, 0),    // ll
    88.             new Vector2(1, 0)     // lr        
    89.         };
    90.  
    91.         mesh.vertices = vertices;
    92.         mesh.normals = normals;
    93.         mesh.triangles = indices;
    94.         mesh.uv = uvs;
    95.  
    96.         return mesh;
    97.     }
    98. }
    The problem is that even though I explicitly set the color of each mesh before calling DrawMesh the two meshes are always drawn with the last color set.

    upload_2016-8-30_21-34-46.png

    The shader code returns the color that has been set

    Code (CSharp):
    1. Shader "Custom/MeshRender"
    2. {
    3.     Properties
    4.     {
    5.         _Color("Color", Color) = (0.0, 0.0, 0.0, 0.0)      
    6.     }
    7.     SubShader
    8.     {
    9.         Pass
    10.         {      
    11.             CGPROGRAM
    12.  
    13.             #pragma vertex vert
    14.             #pragma fragment frag
    15.             #include "UnityCG.cginc"
    16.  
    17.             uniform float4 _Color;
    18.  
    19.             struct VertexShaderOutput
    20.             {
    21.                 float4 position                        : SV_POSITION;
    22.                 float4 uv                            : TEXCOORD0;
    23.                 float4 worldSpacePosition            : TEXCOORD1;
    24.             };
    25.  
    26.             VertexShaderOutput vert(appdata_base vertIn)
    27.             {
    28.                 VertexShaderOutput o;
    29.  
    30.                 o.position = mul(UNITY_MATRIX_MVP, vertIn.vertex);
    31.                 o.worldSpacePosition = mul(unity_ObjectToWorld, vertIn.vertex);
    32.                 o.uv = vertIn.texcoord;
    33.  
    34.                 return o;
    35.             }
    36.  
    37.             float4 frag(VertexShaderOutput i) : COLOR // SV_Target0
    38.             {                      
    39.                 return _Color;
    40.             }
    41.  
    42.             ENDCG
    43.  
    44.             //Blend SrcAlpha OneMinusSrcAlpha         // Additive blending
    45.             //Blend One One                            // Simple additive blending
    46.             Blend Off
    47.             Fog{ Mode Off }
    48.             Lighting Off
    49.             ZWrite Off
    50.             ZTest Always                              // Deactivate depth test
    51.         }
    52.     }
    53. }
    The OnRenderObject method is where the colors are being set.

    Why can't I set two different colors?
     
    almaione-sdn likes this.
  2. Spankenstein

    Spankenstein

    Joined:
    Jan 9, 2014
    Posts:
    25
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,242
    Yes, passing a material property block with the DrawMesh is the correct way of doing this. The reason why it wasn't working is you're constructing a command buffer, which is a set of instructions to run at a later time, not something that happens immediately. However changing the material color does happen immediately. So you're setting the color, then adding a DrawMesh command to the command buffer, then changing the color again and adding another DrawMesh command, and then much later once everything else has been rendered it renders those two meshes using the material as it is at that later time.
     
  4. Spankenstein

    Spankenstein

    Joined:
    Jan 9, 2014
    Posts:
    25
    That makes a lot of sense. It might explain why my shadows from the shadow map are jiggling when combined with my scene?

    Further investigation is required there but my current line of thinking is that the shadows are always a frame behind.

    The scene is copied using CameraEvent.BeforeImageEffects on one CommandBuffer and combined with the final CameraEvent.AfterEverything on another CommandBuffer attached to the same camera.