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 }