Surface Shader with StructuredBuffer Error [SOLVED]

Hi,

How can I use Surface Shader with StructuredBuffer input?

Shader "Custom/DirectX 11 Diffuse Mapping" {
   Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
     SubShader {
         Tags {"LightMode" = "ForwardBase" }
            
              
         Pass {
         CGPROGRAM
         #include "UnityCG.cginc"
         #pragma target 5.0
         #pragma vertex vertex_shader
         #pragma surface surf Lambert vertex:vert
    
         sampler2D _MainTex;
         float4 _MainTex_ST;
         uniform fixed4 _LightColor0;
            
         struct Point{
             float3         vertex;
             float3         normal;
             float4         tangent;
             float2 uv;
         };   
         StructuredBuffer<Point> points;

         struct v2f {
            float4 pos : SV_POSITION;
            float4 col : COLOR;
            float2 uv : TEXCOORD0;
         };
         v2f vertex_shader (uint id : SV_VertexID, uint inst : SV_InstanceID) {
            float4 vertex_position =  float4(points[id].vertex,1.0f);
            float4 vertex_normal = float4(points[id].normal, 1.0f);         
            v2f o;
            // . . .
            return o;
         }
   
         struct Input {
            float4 color : COLOR;
         };
         void surf (Input IN, inout SurfaceOutput o) {
             o.Albedo = 1; // 1 = (1,1,1,1) = white
         }

         ENDCG
     }
     }
}

When I’m trying to get vertices in vertex shader and then use surface shader - it doesn’t work.
Its saying

Shader error in '...': Unexpected identifier "StructuredBuffer". Expected one of: typedef const void inline uniform nointerpolation extern shared static volatile row_major column_major struct or a user-defined type at line 31

Ok, I fixed this error (found a solution here) but still can’t make StructuredBuffer work with SurfaceShader

Here’s new code. I added SHADER_API_D3D11 to fix the problem

Shader "Custom/kek" {

   Properties {
      _MainTex ("Texture", 2D) = "white" {}
   }

   SubShader {

      Tags { "RenderType" = "Opaque" }            
           

      CGPROGRAM

      // #include "UnityCG.cginc"
      #pragma target 5.0
      #pragma vertex vert
      #pragma surface surf Lambert
 
      sampler2D _MainTex;
      float4 _MainTex_ST;
         
      struct Point{
         float3 vertex;
         float3 normal;
         float4 tangent;
         float2 uv;
      };   


      #ifdef SHADER_API_D3D11
         StructuredBuffer<Point> points;
      #endif

      struct v2f {
         float4 pos : SV_POSITION;
         float4 col : COLOR;
         float2 uv : TEXCOORD0;
      };

      v2f vert (uint id : SV_VertexID) { //, uint inst : SV_InstanceID

         float4 vertex_position =  float4(points[id].vertex,1.0f);
         float4 vertex_normal = float4(points[id].normal, 1.0f);      
         v2f o;
         //....
         return o;
      }

      struct Input {
          float4 color : COLOR;
      };
      void surf (Input IN, inout SurfaceOutput o) {
         o.Albedo = fixed4(1f,0f,0f,1f);
      }

      ENDCG

   }
}

The problem now is that StructuredBuffer needs
uint id : SV_VertexID as vertex shader input
but SurfaceShader needs
inout appdata_full v as vertex shader input

So I have this conflict and error message

Shader error in '...': Surface shader vertex function 'vert' #0 parameter has wrong modifier; has no modifier but needs 'inout' at 'uint id' at line 12

How can I solve it ?

appdata_full is just one of the helper input structs. You can define your own.

ok, but how can i combine uint id : SV_VertexID with appdata_custom?
what’s the right way to define vertex shader params? that I have SV_VertexID as an input and appdata_custom as an output?

Well, you can combine it by making that uint part of the struct. I honestly don’t know whether it will work, but that would be the first thing to try. The input and output of a vertex and fragment shader is commonly a combination of values combined into a struct. So, just add the uint to the input struct.

Just tried it. Didn’t work

Shader "Custom/kek"{ //StructuredBuffer+SurfaceShader

   // Properties {}
   SubShader {

         CGPROGRAM
  
         #include "UnityCG.cginc"
         #pragma target 5.0
         #pragma surface surf Lambert vertex:vert

         struct Point{
            float3 vertex;
            float3 normal;
            float4 tangent;
            float2 uv;
         };     

         #ifdef SHADER_API_D3D11
            StructuredBuffer<Point> points;
         #endif


         struct appdata{
            float4 vertex : SV_POSITION;
            float3 normal : NORMAL;
            float4 texcoord : TEXCOORD0;

            uint id : SV_VertexID;
            uint inst : SV_InstanceID;
         };

         struct Input {
            float4 color : COLOR;
         };

         void vert (inout appdata v) {

            v.vertex =  float4(points[id].vertex,1.0f);
            v.normal =  float4(normalize(points[id].normal), 1.0f);
            v.texcoord = points[id].uv;

         }


         void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = fixed4(1f,0f,0f,1f);
         }

         ENDCG

   }
}

Now it’s giving me this error

Shader error in '...': undeclared identifier 'id' at line 39 (on d3d11)

So, obviously id isn’t set. Please, unity people, help!

Because it’s part of the appdata struct, which is being passed to the vert function via the v variable.

points[v.id]

4 Likes

yeah! now it works.
dude u always appear out of nowhere and fix stuff. unity wizard. thank you.

1 Like