- Home /
URP Height Map Shader Problem,URP Custom Shader: Cannot access the UVs of the object
Hello, I am trying to add a height map to a grass shader. Unfortunately I can't access the Uvs of the object to get the coordinate at the texture. What could be the reason for this? Unfortunately I am still quite new to shaders. Thanks for your help
Here the Shader:
 Shader "Unlit/GeoGrass" {
         Properties {
             _Color("Colour", Color) = (1,1,1,1)
             _Color2("Colour2", Color) = (1,1,1,1)
             _Width("Width", Float) = 1
             _RandomWidth("Random Width", Float) = 1
             _Height("Height", Float) = 1
             _RandomHeight("Random Height", Float) = 1
             _WindStrength("Wind Strength", Float) = 0.1
             [Space]
             _TessellationUniform("Tessellation Uniform", Range(1, 64)) = 1
             _GrassMap("GrassVisibilityMap", 2D) = "white" {}
             _GrassThreshold("Grass Visibility Threshold", Range(-0.1, 1)) = 0.5
         }
 
         SubShader {
             Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
             LOD 300
 
             Cull Off
 
             Pass {
                 Name "ForwardLit"
                 Tags {"LightMode" = "UniversalForward"}
 
                 HLSLPROGRAM
                 // Required to compile gles 2.0 with standard srp library
                 #pragma prefer_hlslcc gles
                 #pragma exclude_renderers d3d11_9x gles
                 #pragma target 4.5
 
                 #pragma require geometry
 
                 #pragma vertex vert
                 #pragma geometry geom
                 #pragma fragment frag
                 #pragma hull hull
                 #pragma domain domain
 
                 #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
                 #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
                 #pragma multi_compile _ _SHADOWS_SOFT
 
                 // Defines
 
                 #define BLADE_SEGMENTS 1
 
                 // Includes
 
                 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
                 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
                 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
                 #include "grass_structs.hlsl"
                 #include "CustomTessellation.hlsl"
                 #include "grass.hlsl"
 
                 // Fragment
 
                 float4 frag(GeometryOutput input) : SV_Target {
                     #if SHADOWS_SCREEN
                         float4 clipPos = TransformWorldToHClip(input.positionWS);
                         float4 shadowCoord = ComputeScreenPos(clipPos);
                     #else
                         float4 shadowCoord = TransformWorldToShadowCoord(input.positionWS);
                     #endif
 
                     Light mainLight = GetMainLight(shadowCoord);
 
                     return lerp(_Color, _Color2, input.uv.y) * mainLight.shadowAttenuation;
                 }
 
                 ENDHLSL
             }
         }
 }
And here are the other classes:
grass.hlsl
 float rand(float3 seed) {
     return frac(sin(dot(seed.xyz, float3(12.9898, 78.233, 53.539))) * 43758.5453);
 }
 
 // https://gist.github.com/keijiro/ee439d5e7388f3aafc5296005c8c3f33
 float3x3 AngleAxis3x3(float angle, float3 axis) {
     float c, s;
     sincos(angle, s, c);
 
     float t = 1 - c;
     float x = axis.x;
     float y = axis.y;
     float z = axis.z;
 
     return float3x3(
         t * x * x + c, t * x * y - s * z, t * x * z + s * y,
         t * x * y + s * z, t * y * y + c, t * y * z - s * x,
         t * x * z - s * y, t * y * z + s * x, t * z * z + c
     );
 }
 
 float3 _LightDirection;
 
 float4 GetShadowPositionHClip(float3 positionWS, float3 normalWS) {
     float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, _LightDirection));
 
 #if UNITY_REVERSED_Z
     positionCS.z = min(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE);
 #else
     positionCS.z = max(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE);
 #endif
 
     return positionCS;
 }
 
 float4 WorldToHClip(float3 positionWS, float3 normalWS) {
 #ifdef SHADOW
     return GetShadowPositionHClip(positionWS, normalWS);
 #else
     return TransformWorldToHClip(positionWS);
 #endif
 }
 
 // Variables
 CBUFFER_START(UnityPerMaterial) // Required to be compatible with SRP Batcher
 float4 _Color;
 float4 _Color2;
 float _Width;
 float _RandomWidth;
 float _WindStrength;
 float _Height;
 float _RandomHeight;
 
 sampler2D _GrassMap;
 float4 _GrassMap_ST;
 float  _GrassThreshold;
 CBUFFER_END
 
 // Vertex, Geometry & Fragment Shaders
 
 Varyings vert(Attributes input) {
     Varyings output = (Varyings)0;
 
     VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
     // Seems like GetVertexPositionInputs doesn't work with SRP Batcher inside geom function?
     // Had to move it here, in order to obtain positionWS and pass it through the Varyings output.
 
     output.positionOS = input.positionOS; //vertexInput.positionCS; //
     output.positionWS = vertexInput.positionWS;
     output.normal = input.normal;
     output.tangent = input.tangent;
     return output;
 }
 
 [maxvertexcount(BLADE_SEGMENTS * 2 + 1)]
 void geom(uint primitiveID : SV_PrimitiveID, triangle Varyings input[3], inout TriangleStream<GeometryOutput> triStream) {
     GeometryOutput output = (GeometryOutput)0;
 
     float grassVisibility = tex2Dlod(_GrassMap, float4(input[0].uv, 0, 0)).r;
 
     if(grassVisibility >= _GrassThreshold) {
         // Construct World -> Tangent Matrix (for aligning grass with mesh normals)
         float3 normal = input[0].normal;
         float4 tangent = input[0].tangent;
         float3 binormal = cross(normal, tangent) * tangent.w;
 
         float3x3 tangentToLocal = float3x3(
             tangent.x, binormal.x, normal.x,
             tangent.y, binormal.y, normal.y,
             tangent.z, binormal.z, normal.z
             );
 
         float3 positionWS = input[0].positionWS;
 
         float r = rand(positionWS.xyz);
         float3x3 randRotation = AngleAxis3x3(r * TWO_PI, float3(0, 0, 1));
 
         // Wind (based on sin / cos, aka a circular motion, but strength of 0.1 * sine)
         float2 wind = float2(sin(_Time.y + positionWS.x * 0.5), cos(_Time.y + positionWS.z * 0.5)) * _WindStrength * sin(_Time.y + r);
         float3x3 windMatrix = AngleAxis3x3((wind * PI).y, normalize(float3(wind.x, wind.y, 0)));
 
         float3x3 transformMatrix = mul(tangentToLocal, randRotation);
         float3x3 transformMatrixWithWind = mul(mul(tangentToLocal, windMatrix), randRotation);
 
         float bend = rand(positionWS.xyz) - 0.5;
         float width = _Width + _RandomWidth * (rand(positionWS.zyx) - 0.5);
         float height = _Height + _RandomHeight * (rand(positionWS.yxz) - 0.5);
 
         float3 normalWS = mul(transformMatrix, float3(0, 1, 0)); //?
 
         // Handle Geometry
 
         // Base 2 vertices
         output.positionWS = positionWS + mul(transformMatrix, float3(width, 0, 0));
         output.positionCS = WorldToHClip(output.positionWS, normalWS);
         output.uv = float2(0, 0);
         triStream.Append(output);
 
         output.positionWS = positionWS + mul(transformMatrix, float3(-width, 0, 0));
         output.positionCS = WorldToHClip(output.positionWS, normalWS);
         output.uv = float2(0, 0);
         triStream.Append(output);
 
         // Final vertex at top of blade
         output.positionWS = positionWS + mul(transformMatrixWithWind, float3(0, bend, height));
         output.positionCS = WorldToHClip(output.positionWS, normalWS);
         output.uv = float2(0, 1);
         triStream.Append(output);
 
         triStream.RestartStrip();
     }
 }
And here the structs: grass_struct.hlsl
 struct Attributes {
     float4 positionOS   : POSITION;
     float3 normal        : NORMAL;
     float4 tangent        : TANGENT;
     float2 uv             : TEXCOORD0;
 };
 
 struct Varyings {
     float4 positionOS   : SV_POSITION;
     float3 positionWS    : TEXCOORD1;
     float2 uv            : TEXCOORD0;
     float3 normal        : NORMAL;
     float4 tangent        : TANGENT;
 };
 
 struct GeometryOutput {
     float4 positionCS    : SV_POSITION;
     float3 positionWS    : TEXCOORD1;
     float2 uv            : TEXCOORD0;
 };
In the grass.hlsl file I try to achieve the effect with these lines:
 float grassVisibility = tex2Dlod(_GrassMap, float4(input[0].uv, 0, 0)).r;
 
     if(grassVisibility >= _GrassThreshold) {
 ...
 }
The input[0].uv does not return the appropriate values
,Hello, I am trying to add a Height Map in a Grass Shader in URP. However, I am not quite getting anywhere. I know that I have to check the UVs and which value is there on the texture. But my problem is that I can't get the UVs from the object and query them. Does anyone have any ideas? It would help me a lot. Thanks
Here is the Grass Shader:
 Shader "Unlit/GeoGrass" {
         Properties {
             _Color("Colour", Color) = (1,1,1,1)
             _Color2("Colour2", Color) = (1,1,1,1)
             _Width("Width", Float) = 1
             _RandomWidth("Random Width", Float) = 1
             _Height("Height", Float) = 1
             _RandomHeight("Random Height", Float) = 1
             _WindStrength("Wind Strength", Float) = 0.1
             [Space]
             _TessellationUniform("Tessellation Uniform", Range(1, 64)) = 1
             _GrassMap("GrassVisibilityMap", 2D) = "white" {}
             _GrassThreshold("Grass Visibility Threshold", Range(-0.1, 1)) = 0.5
         }
 
         SubShader {
             Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
             LOD 300
 
             Cull Off
 
             Pass {
                 Name "ForwardLit"
                 Tags {"LightMode" = "UniversalForward"}
 
                 HLSLPROGRAM
                 // Required to compile gles 2.0 with standard srp library
                 #pragma prefer_hlslcc gles
                 #pragma exclude_renderers d3d11_9x gles
                 #pragma target 4.5
 
                 #pragma require geometry
 
                 #pragma vertex vert
                 #pragma geometry geom
                 #pragma fragment frag
                 #pragma hull hull
                 #pragma domain domain
 
                 #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
                 #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
                 #pragma multi_compile _ _SHADOWS_SOFT
 
                 // Defines
 
                 #define BLADE_SEGMENTS 1
 
                 // Includes
 
                 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
                 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
                 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
                 #include "grass_structs.hlsl"
                 #include "CustomTessellation.hlsl"
                 #include "grass.hlsl"
 
                 // Fragment
 
                 float4 frag(GeometryOutput input) : SV_Target {
                     #if SHADOWS_SCREEN
                         float4 clipPos = TransformWorldToHClip(input.positionWS);
                         float4 shadowCoord = ComputeScreenPos(clipPos);
                     #else
                         float4 shadowCoord = TransformWorldToShadowCoord(input.positionWS);
                     #endif
 
                     Light mainLight = GetMainLight(shadowCoord);
 
                     return lerp(_Color, _Color2, input.uv.y) * mainLight.shadowAttenuation;
                 }
 
                 ENDHLSL
             }
         }
 }
Here is the code that is accessed
grass_struct.hlsl
 struct Attributes {
     float4 positionOS   : POSITION;
     float3 normal        : NORMAL;
     float4 tangent        : TANGENT;
     float2 uv             : TEXCOORD0;
 };
 
 struct Varyings {
     float4 positionOS   : SV_POSITION;
     float3 positionWS    : TEXCOORD1;
     float2 uv            : TEXCOORD0;
     float3 normal        : NORMAL;
     float4 tangent        : TANGENT;
 };
 
 struct GeometryOutput {
     float4 positionCS    : SV_POSITION;
     float3 positionWS    : TEXCOORD1;
     float2 uv            : TEXCOORD0;
 };
grass.hlsl
 float rand(float3 seed) {
     return frac(sin(dot(seed.xyz, float3(12.9898, 78.233, 53.539))) * 43758.5453);
 }
 
 // https://gist.github.com/keijiro/ee439d5e7388f3aafc5296005c8c3f33
 float3x3 AngleAxis3x3(float angle, float3 axis) {
     float c, s;
     sincos(angle, s, c);
 
     float t = 1 - c;
     float x = axis.x;
     float y = axis.y;
     float z = axis.z;
 
     return float3x3(
         t * x * x + c, t * x * y - s * z, t * x * z + s * y,
         t * x * y + s * z, t * y * y + c, t * y * z - s * x,
         t * x * z - s * y, t * y * z + s * x, t * z * z + c
     );
 }
 
 float3 _LightDirection;
 
 float4 GetShadowPositionHClip(float3 positionWS, float3 normalWS) {
     float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, _LightDirection));
 
 #if UNITY_REVERSED_Z
     positionCS.z = min(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE);
 #else
     positionCS.z = max(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE);
 #endif
 
     return positionCS;
 }
 
 float4 WorldToHClip(float3 positionWS, float3 normalWS) {
 #ifdef SHADOW
     return GetShadowPositionHClip(positionWS, normalWS);
 #else
     return TransformWorldToHClip(positionWS);
 #endif
 }
 
 // Variables
 CBUFFER_START(UnityPerMaterial) // Required to be compatible with SRP Batcher
 float4 _Color;
 float4 _Color2;
 float _Width;
 float _RandomWidth;
 float _WindStrength;
 float _Height;
 float _RandomHeight;
 
 sampler2D _GrassMap;
 float4 _GrassMap_ST;
 float  _GrassThreshold;
 CBUFFER_END
 
 // Vertex, Geometry & Fragment Shaders
 
 Varyings vert(Attributes input) {
     Varyings output = (Varyings)0;
 
     VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
     // Seems like GetVertexPositionInputs doesn't work with SRP Batcher inside geom function?
     // Had to move it here, in order to obtain positionWS and pass it through the Varyings output.
 
     output.positionOS = input.positionOS; //vertexInput.positionCS; //
     output.positionWS = vertexInput.positionWS;
     output.normal = input.normal;
     output.tangent = input.tangent;
     return output;
 }
 
 [maxvertexcount(BLADE_SEGMENTS * 2 + 1)]
 void geom(uint primitiveID : SV_PrimitiveID, triangle Varyings input[3], inout TriangleStream<GeometryOutput> triStream) {
     GeometryOutput output = (GeometryOutput)0;
 
     float grassVisibility = tex2Dlod(_GrassMap, float4(input[0].uv, 0, 0)).r;
 
     if(grassVisibility >= _GrassThreshold) {
         // Construct World -> Tangent Matrix (for aligning grass with mesh normals)
         float3 normal = input[0].normal;
         float4 tangent = input[0].tangent;
         float3 binormal = cross(normal, tangent) * tangent.w;
 
         float3x3 tangentToLocal = float3x3(
             tangent.x, binormal.x, normal.x,
             tangent.y, binormal.y, normal.y,
             tangent.z, binormal.z, normal.z
             );
 
         float3 positionWS = input[0].positionWS;
 
         float r = rand(positionWS.xyz);
         float3x3 randRotation = AngleAxis3x3(r * TWO_PI, float3(0, 0, 1));
 
         // Wind (based on sin / cos, aka a circular motion, but strength of 0.1 * sine)
         float2 wind = float2(sin(_Time.y + positionWS.x * 0.5), cos(_Time.y + positionWS.z * 0.5)) * _WindStrength * sin(_Time.y + r);
         float3x3 windMatrix = AngleAxis3x3((wind * PI).y, normalize(float3(wind.x, wind.y, 0)));
 
         float3x3 transformMatrix = mul(tangentToLocal, randRotation);
         float3x3 transformMatrixWithWind = mul(mul(tangentToLocal, windMatrix), randRotation);
 
         float bend = rand(positionWS.xyz) - 0.5;
         float width = _Width + _RandomWidth * (rand(positionWS.zyx) - 0.5);
         float height = _Height + _RandomHeight * (rand(positionWS.yxz) - 0.5);
 
         float3 normalWS = mul(transformMatrix, float3(0, 1, 0)); //?
 
         // Handle Geometry
 
         // Base 2 vertices
         output.positionWS = positionWS + mul(transformMatrix, float3(width, 0, 0));
         output.positionCS = WorldToHClip(output.positionWS, normalWS);
         output.uv = float2(0, 0);
         triStream.Append(output);
 
         output.positionWS = positionWS + mul(transformMatrix, float3(-width, 0, 0));
         output.positionCS = WorldToHClip(output.positionWS, normalWS);
         output.uv = float2(0, 0);
         triStream.Append(output);
 
         // Final vertex at top of blade
         output.positionWS = positionWS + mul(transformMatrixWithWind, float3(0, bend, height));
         output.positionCS = WorldToHClip(output.positionWS, normalWS);
         output.uv = float2(0, 1);
         triStream.Append(output);
 
         triStream.RestartStrip();
     }
 }
With grass.hlsl I try to achieve the effect with these lines:
 float grassVisibility = tex2Dlod(_GrassMap, float4(input[0].uv, 0, 0)).r;
     
 if(grassVisibility >= _GrassThreshold) {
 ...
 }
 
 
Your answer
 
 
              koobas.hobune.stream
koobas.hobune.stream 
                       
               
 
			 
                