Created
October 7, 2025 20:22
-
-
Save jesterswilde/88741820a5938e243a444b516f4047c3 to your computer and use it in GitHub Desktop.
Raymarcher
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma kernel CSMain | |
| Texture2D<float4> Source; | |
| RWTexture2D<float4> Destination; | |
| float4x4 _CameraToWorld; | |
| float4x4 _CameraInverseProjection; | |
| float3 _Light; | |
| bool positionLight; | |
| static const float maxDst = 80; | |
| static const float epsilon = 0.001f; | |
| static const float shadowBias = epsilon * 50; | |
| struct Shape { | |
| float3 position; | |
| float3 size; | |
| float3 colour; | |
| int shapeType; | |
| int operation; | |
| float blendStrength; | |
| int numChildren; | |
| }; | |
| StructuredBuffer<Shape> shapes; | |
| Buffer<float> data; | |
| Buffer<int> instructions; | |
| RWBuffer<float> debug; | |
| int numShapes; | |
| struct Ray { | |
| float3 origin; | |
| float3 direction; | |
| }; | |
| Ray CreateRay(float3 origin, float3 direction) { | |
| Ray ray; | |
| ray.origin = origin; | |
| ray.direction = direction; | |
| return ray; | |
| } | |
| Ray CreateCameraRay(float2 uv) { | |
| float3 origin = mul(_CameraToWorld, float4(0,0,0,1)).xyz; | |
| float3 direction = mul(_CameraInverseProjection, float4(uv,0,1)).xyz; | |
| direction = mul(_CameraToWorld, float4(direction,0)).xyz; | |
| direction = normalize(direction); | |
| return CreateRay(origin,direction); | |
| } | |
| float4x4 makeMatrix(inout int i){ | |
| float4x4 m; | |
| m[0] = float4(data[i++],data[i++],data[i++],data[i++]); | |
| m[1] = float4(data[i++],data[i++],data[i++],data[i++]); | |
| m[2] = float4(data[i++],data[i++],data[i++],data[i++]); | |
| m[3] = float4(0,0,0,1); | |
| return m; | |
| } | |
| /* | |
| Operations Reference: | |
| Push - 0, | |
| Push3 - 1, | |
| Push_N - 2, | |
| CopyPosition - 3, | |
| Translate 4, | |
| Matrix 5, | |
| Union - 6, | |
| Subtract - 7, | |
| Intersect - 8, | |
| Blend - 9, | |
| Sphere - 10, | |
| Box - 11, | |
| Torus - 12, | |
| InfiniteCylinder - 13 | |
| Mandlebulb - 14 | |
| */ | |
| const int OpLength[9] = {-1,-1,-1,-2,1,0,-3,-5,3}; | |
| const int stackSize = 64; | |
| int numInstructions; | |
| float Evaluate(float3 pos, int id){ | |
| int stackIndex = -1; | |
| int dataIndex = 0; | |
| float stack[32]; | |
| bool hasMatrix = false; | |
| float4x4 curMatrix; | |
| for(int i = 0; i < 32; i++){ | |
| stack[i] = 0; | |
| } | |
| for(int instI = 0; instI < numInstructions; instI++){ | |
| int operation = instructions[instI]; | |
| //ToPush Val | |
| if (operation == 0) { //Push | |
| stack[++stackIndex] = data[dataIndex++]; | |
| } | |
| else if(operation == 1){//Push3 | |
| stack[++stackIndex] = data[dataIndex++]; | |
| stack[++stackIndex] = data[dataIndex++]; | |
| stack[++stackIndex] = data[dataIndex++]; | |
| } | |
| //N Val | |
| else if (operation == 2) { //PushN | |
| for(int i = 0; i < data[dataIndex++]; i++) { | |
| stack[++stackIndex] = data[dataIndex++]; | |
| } | |
| } | |
| else if (operation == 3){//CopyPosition | |
| stack[++stackIndex] = pos.x; | |
| stack[++stackIndex] = pos.y; | |
| stack[++stackIndex] = pos.z; | |
| } | |
| else if(operation == 4){//Translate | |
| stack[stackIndex-3] -= stack[stackIndex]; | |
| stack[stackIndex-4] -= stack[stackIndex-1]; | |
| stack[stackIndex-5] -= stack[stackIndex-2]; | |
| stackIndex -= 3; | |
| } | |
| else if(operation == 5){//Matrix | |
| hasMatrix = true; | |
| curMatrix = makeMatrix(dataIndex); | |
| } | |
| //2 Val1 Val2 | |
| else if (operation == 6) { //Union | |
| stack[stackIndex-1] = min(stack[stackIndex], stack[stackIndex-1]); | |
| stackIndex -= 1; | |
| } | |
| //2 Val1 Val2 | |
| else if (operation == 7) { // Subtract | |
| stack[stackIndex-1] = max(stack[stackIndex-1], -stack[stackIndex]); | |
| stackIndex -= 1; | |
| } | |
| //2 Val1 Val2 | |
| else if (operation == 8) { //Intersect | |
| stack[stackIndex-1] = max(stack[stackIndex-1], stack[stackIndex]); | |
| stackIndex -= 1; | |
| } | |
| //3 Val1 Val2 BlendStrength | |
| else if (operation == 9) { //Blend | |
| float a = stack[stackIndex - 2]; | |
| float b = stack[stackIndex - 1]; | |
| float k = stack[stackIndex]; | |
| float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 ); | |
| stackIndex -= 2; | |
| stack[stackIndex] = lerp( b, a, h ) - k*h*(1.0-h); | |
| } | |
| //4 PosX PosY PosZ Radius | |
| else if (operation == 10) { //Sphere | |
| float3 p = float3(stack[stackIndex-3], stack[stackIndex-2], stack[stackIndex-1]); | |
| if(hasMatrix) | |
| p = mul(curMatrix, float4(p,1)).xyz; | |
| stack[stackIndex - 3] = length(p) - stack[stackIndex]; | |
| stackIndex -= 3; | |
| //stack[stackIndex] = 0.5f; | |
| } | |
| //[1,2,3,2,2,3] | |
| // ^ | |
| //6 PointX PointY PointZ BoundsX BoudnsY BoundsZ | |
| else if (operation == 11) { //Box | |
| float3 p = float3(stack[stackIndex-5], stack[stackIndex-4], stack[stackIndex-3]); | |
| if(hasMatrix) | |
| p = mul(curMatrix, float4(p,1)).xyz; | |
| float3 b = float3(stack[stackIndex-2], stack[stackIndex-1], stack[stackIndex]); | |
| float3 q = abs(p) - b; | |
| stack[stackIndex - 5] = length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0); | |
| stackIndex -= 5; | |
| } | |
| //5 PosX PosY PosZ InnerRadius OuterRadius | |
| else if (operation == 12) { //Torus | |
| float3 p = float3(stack[stackIndex-4], stack[stackIndex-3], stack[stackIndex-2]); | |
| if(hasMatrix) | |
| p = mul(curMatrix, float4(p,1)).xyz; | |
| stack[stackIndex-4] = length(float2(length(p.xz) - stack[stackIndex-1], p.y)) - stack[stackIndex]; | |
| stackIndex -= 4; | |
| } | |
| else if (operation == 13) { //InfiniteCylinder | |
| float3 p = float3(stack[stackIndex-5], stack[stackIndex-4], stack[stackIndex-3]); | |
| if(hasMatrix) | |
| p = mul(curMatrix, float4(p,1)).xyz; | |
| float3 c = float3(stack[stackIndex-2], stack[stackIndex-1], stack[stackIndex]); | |
| stack[stackIndex-5] = length(p.xz-c.xy)-c.z; | |
| stackIndex -= 5; | |
| } else if (operation == 14){ //SmoothSubtract | |
| float a = stack[stackIndex - 2]; | |
| float b = stack[stackIndex - 1]; | |
| float k = stack[stackIndex]; | |
| float h = clamp( 0.5-0.5*(b+a)/k, 0.0, 1.0 ); | |
| stackIndex -= 2; | |
| stack[stackIndex] = lerp(b, -a, h) + k*h*(1.0-h); | |
| }else if (operation == 15){//SmoothIntersect | |
| float a = stack[stackIndex - 2]; | |
| float b = stack[stackIndex - 1]; | |
| float k = stack[stackIndex]; | |
| float h = clamp( 0.5-0.5*(b-a)/k, 0.0, 1.0 ); | |
| stackIndex -= 2; | |
| stack[stackIndex] = lerp(b, a, h) + k*h*(1.0-h); | |
| } | |
| else if(operation == 16){// NullMatrix | |
| hasMatrix = false; | |
| } | |
| else if (operation == 17){ // Capsule | |
| float3 p = float3(stack[stackIndex-4], stack[stackIndex-3], stack[stackIndex-2]); | |
| if(hasMatrix) | |
| p = mul(curMatrix, float4(p,1)).xyz; | |
| p.y -= clamp(p.y, 0.0, stack[stackIndex-1]); | |
| stack[stackIndex-4] = length(p) - stack[stackIndex]; | |
| stackIndex -= 4; | |
| } | |
| } | |
| debug[id*10] = stackIndex; | |
| for(int i = 0; i < 9; i++){ | |
| debug[id*10 + i + 1] = stack[i]; | |
| } | |
| return stack[stackIndex]; | |
| } | |
| float3 EstimateNormal(float3 p) { | |
| float x = Evaluate(float3(p.x+epsilon,p.y,p.z),0) - Evaluate(float3(p.x-epsilon,p.y,p.z),0); | |
| float y = Evaluate(float3(p.x,p.y+epsilon,p.z),0) - Evaluate(float3(p.x,p.y-epsilon,p.z),0); | |
| float z = Evaluate(float3(p.x,p.y,p.z+epsilon),0) - Evaluate(float3(p.x,p.y,p.z-epsilon),0); | |
| return normalize(float3(x,y,z)); | |
| } | |
| [numthreads(8,8,1)] | |
| void CSMain (uint3 id : SV_DispatchThreadID) | |
| { | |
| uint width,height; | |
| Destination.GetDimensions(width, height); | |
| int index = id.x + id.y * width; | |
| Destination[id.xy] = Source[id.xy]; | |
| float2 uv = id.xy / float2(width,height) * 2 - 1; | |
| float rayDst = 0; | |
| Ray ray = CreateCameraRay(uv); | |
| int maxMarchSteps = 64; | |
| int marchSteps = 0; | |
| while (rayDst < maxDst && marchSteps < maxMarchSteps) { | |
| marchSteps ++; | |
| float dst = Evaluate(ray.origin,index); | |
| if (dst <= epsilon) { | |
| float3 pointOnSurface = ray.origin + ray.direction * dst; | |
| float3 normal = EstimateNormal(pointOnSurface - ray.direction * epsilon); | |
| float3 lightDir = (positionLight)?normalize(_Light-ray.origin):-_Light; | |
| float val = dot(normal,lightDir); | |
| Destination[id.xy] = float4(val,val,val,1); | |
| break; | |
| } | |
| ray.origin += ray.direction * dst; | |
| rayDst += dst; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment