/ Assets / shaders / silhoutte / test.shader
test.shader
  1  Shader "Custom/test"
  2  {
  3      Properties
  4      {
  5          [MainColor] _BaseColor("Base Color", Color) = (1, 1, 1, 1)
  6          [MainTexture] _BaseMap("Base Map", 2D) = "white"
  7          _PyramidHeight("Pyramid Height", Float) = 1
  8      }
  9      SubShader
 10      {
 11          Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
 12  
 13          Pass
 14          {
 15              Name "ForwardLit"
 16              Tags { "LightMode" = "UniversalForward" }
 17              Cull Off
 18              
 19              HLSLPROGRAM
 20  
 21              #pragma prefer_hlslcc gles
 22              #pragma exclude_renderers d3d11_9x
 23              #pragma target 2.0
 24              #pragma require geometry
 25                          
 26              #pragma vertex vert
 27              #pragma fragment frag
 28  
 29              #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
 30              #include "Assets/Resources/GreasePencil/common_shader_util.hlsl"
 31              // Define a struct to match the one in your C# script
 32              struct VertexData
 33              {
 34                  float3 position;
 35                  float3 normal;
 36              };
 37              
 38              struct StrokeData
 39              {
 40                  float3 pos[2];
 41                  int adj[2];
 42              };
 43  
 44              // Declare the GraphicsBuffers that we will set from the C# script
 45              StructuredBuffer<int> _MeshIndices;
 46              StructuredBuffer<int> _AdjIndices;
 47              
 48              StructuredBuffer<VertexData> _Vertices;
 49  
 50              struct v2f
 51              {
 52                  float3 normalWS : TEXCOORD0; // World space normal
 53                  float4 vertex : SV_POSITION;
 54              };
 55  
 56              TEXTURE2D(_BaseMap);
 57              SAMPLER(sampler_BaseMap);
 58              
 59              CBUFFER_START(UnityPerMaterial)
 60                  half4 _BaseColor;
 61                  float4 _BaseMap_ST;
 62              CBUFFER_END
 63  
 64              float2 project_to_screenspace(float4 v)
 65              {
 66                  return ((v.xy / v.w) * 0.5f + 0.5f) * _ScreenParams.xy;
 67              }
 68              float stroke_radius_modulate(float radius)
 69              {
 70                  float3x3 obj3x3 = (float3x3)unity_ObjectToWorld;
 71                  float3 scaled = mul(obj3x3, float3(radius * 0.57735, radius * 0.57735, radius * 0.57735));
 72                  radius = length(scaled);
 73  
 74                  float screen_radius = radius * -(UNITY_MATRIX_P[1][1]) * _ScreenParams.y;
 75                  
 76                  return screen_radius;
 77              }
 78              
 79              bool TryGetZeroPoint(VertexData v1, VertexData v2, out float3 zeroPoint)
 80              {
 81                  // We need to find the interpolation factor 't' such that
 82                  // lerp(vA.scalar, vB.scalar, t) == 0
 83                  //
 84                  // sA * (1-t) + sB * t = 0
 85                  // sA - sA*t + sB*t = 0
 86                  // sA = t * (sA - sB)
 87                  // t = sA / (sA - sB)
 88                  
 89                  // Avoid division by zero, though this case (sA == sB)
 90                  // should be filtered out by the (sA * sB < 0) check.
 91                  float3 dirToCam1 = normalize(_WorldSpaceCameraPos - v1.position);
 92                  float3 dirToCam2 = normalize(_WorldSpaceCameraPos - v2.position);
 93  
 94                  float dot1 = dot(v1.normal, dirToCam1);
 95                  float dot2 = dot(v2.normal, dirToCam2);
 96                  if (dot1 * dot2 > 0)
 97                  {
 98                      zeroPoint = float3(0,0,0);
 99                      return false;
100                  }
101                  float t = dot1 / (dot1 - dot2);
102  
103                  // Linearly interpolate the clip-space positions
104                  zeroPoint = lerp(v1.position, v2.position, t);
105                  return true;
106              }
107              
108              bool TryGetZeroLine(VertexData v0, VertexData v1, VertexData v2, out float3 points[2], uint faceIdx)
109              {
110                  int points_found = 0;
111  
112                  if (points_found < 2 && TryGetZeroPoint(v0, v1, points[points_found]))
113                  {
114                      points_found++;
115                  }
116                  if (points_found < 2 && TryGetZeroPoint(v1, v2, points[points_found]))
117                  {
118                      points_found++;
119                  }
120                  if (points_found < 2 && TryGetZeroPoint(v2, v0, points[points_found]))
121                  {
122                      points_found++;
123                  }
124                  
125                  if (points_found == 2)
126                  {
127                      return true;
128                  }
129                  return false;
130              }
131              
132              // Vertex Shader
133              // We use SV_VertexID to get the index of the vertex being processed
134              v2f vert (uint vertexID : SV_VertexID)
135              {
136                  v2f o;
137  
138                  // 1. Use the vertexID to find the correct index from the index buffer
139                  uint faceIdx = vertexID / 6;
140                  
141                  int vIdx0 = _MeshIndices[faceIdx*3+0];
142                  int vIdx1 = _MeshIndices[faceIdx*3+1];
143                  int vIdx2 = _MeshIndices[faceIdx*3+2];
144  
145                  VertexData v0 = _Vertices[vIdx0];
146                  VertexData v1 = _Vertices[vIdx1];
147                  VertexData v2 = _Vertices[vIdx2];
148                  
149                  // 2. Use that index to get the actual vertex data (pos/normal)
150                  float3 p0 = v0.position;
151                  float3 p1 = v1.position;
152                  float3 p2 = v2.position;
153                  float3 n0 = v0.normal;
154                  float3 n1 = v1.normal;
155                  float3 n2 = v2.normal;
156  
157                  float3 zeroLine[2];
158                  if (!TryGetZeroLine(v0, v1, v2, zeroLine, faceIdx))
159                  {
160                      //discard
161                      o.vertex = float4(0.0f, 0.0f, -3e36f, 0.0f);
162                      o.normalWS = float3(0,0,0);
163                      return o;
164                  }
165                  bool isSecond = (vertexID%6 > 2);
166                  int vI = vertexID%6;
167  
168                  float x;
169                  float y;
170  
171                  if (!isSecond)
172                  {
173                      x = float(vI & 1) * 2.0f - 1.0f; /* [-1..1] */
174                      y = float(vI & 2) - 1.0f;        /* [-1..1] */
175                  }
176                  else
177                  {
178                      x = -(float(vI+1 & 1) * 2.0f - 1.0f); /* [-1..1] */
179                      y = -(float(vI+1 & 2) - 1.0f);        /* [-1..1] */
180                  }
181  
182                  bool is_on_zp1 = (x == -1.0f);
183                  
184                  float3 wpos1 = TransformObjectToWorld(zeroLine[0]);
185                  float3 wpos2 = TransformObjectToWorld(zeroLine[1]);
186                  // float4 ndc_adj = TransformWorldToHClip(wpos_adj);
187                  float4 ndc1 = TransformWorldToHClip(wpos1.xyz);
188                  float4 ndc2 = TransformWorldToHClip(wpos2.xyz);
189  
190                  o.vertex = (is_on_zp1) ? ndc1 : ndc2;
191  
192                  float2 ss1 = project_to_screenspace(ndc1);
193                  float2 ss2 = project_to_screenspace(ndc2);
194  
195                  float edge_len;
196                  float2 edge_dir = safe_normalize_and_get_length(ss2 - ss1, edge_len);
197  
198                  float radius = 0.1;
199                  radius = stroke_radius_modulate(radius);
200                  float clamped_radius = max(0.0f, radius);
201                  
202                  /* Mitter tangent vector. */
203                  float2 miter_tan = edge_dir;
204                  /* Rotate 90 degrees counter-clockwise. */
205                  float2 miter = float2(-miter_tan.y, miter_tan.x);
206                  float2 screen_ofs = miter * y;
207                  
208                  float2 clip_space_per_pixel = float2(1.0 / _ScreenParams.x, 1.0 / _ScreenParams.y);
209                  o.vertex.xy += screen_ofs * clip_space_per_pixel * clamped_radius;
210                  // if (isSecond)
211                  // {
212                  //     p0+=n0;
213                  //     p1+=n1;
214                  //     p2+=n2;
215                  // }
216                  // // 3. Transform the vertex position from object space to clip space
217                  // if (vI==0)
218                  // {
219                  //     o.vertex = TransformObjectToHClip(p0);
220                  //     o.normalWS = TransformObjectToWorldDir(n0);
221                  // }
222                  // else if (vI==1)
223                  // {
224                  //     o.vertex = TransformObjectToHClip(p1);
225                  //     o.normalWS = TransformObjectToWorldDir(n1);
226                  // }
227                  // else if (vI==2)
228                  // {
229                  //     o.vertex = TransformObjectToHClip(p2);
230                  //     o.normalWS = TransformObjectToWorldDir(n2);
231                  // }
232                  
233                  // else // (vI==3)
234                  // {
235                  //     o.vertex = TransformObjectToHClip(p2);
236                  //     o.normalWS = TransformObjectToWorldDir(n2);
237                  // }
238                  //get normals
239                  //find zero points
240                  
241                  return o;
242              }
243  
244              // Fragment Shader
245              // This is a simple implementation that uses the normal for basic lighting
246              half4 frag (v2f i) : SV_Target
247              {
248                  // Normalize the incoming normal vector
249                  float3 normal = normalize(i.normalWS);
250                  half4 color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, float2(0,0)) * _BaseColor;
251                  return color;
252                  // // Get the main light direction from Unity's built-in variables
253                  // float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
254                  //
255                  // // Calculate basic Lambertian lighting
256                  // float lightIntensity = saturate(dot(normal, lightDir));
257                  //
258                  // // Define a base color (e.g., grey)
259                  // fixed3 albedo = fixed3(0.8, 0.8, 0.8);
260                  //
261                  // // Combine lighting and color
262                  // fixed3 finalColor = albedo * lightIntensity;
263                  //
264                  // return fixed4(finalColor, 1.0);
265              }
266              ENDHLSL
267          }
268      }
269  }