-
Notifications
You must be signed in to change notification settings - Fork 211
/
SphereTracingShading.shader
122 lines (100 loc) · 4.46 KB
/
SphereTracingShading.shader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
Shader "Tutorial/044_SphereTracingShading"{
//show values to edit in inspector
Properties{
_Color ("Color", Color) = (0, 0, 0, 1)
}
SubShader{
//the material is completely non-transparent and is rendered at the same time as transparent geometry
Tags{ "RenderType"="Opaque" "Queue"="Transparent" "DisableBatching"="True"}
Pass{
ZWrite Off
CGPROGRAM
#include "UnityCG.cginc"
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
//surface color
fixed4 _Color;
//maximum amount of steps
#define MAX_STEPS 10
//furthest distance that's accepted as inside surface
#define THICKNESS 0.01
//distance from rendered point to sample SDF for normal calculation
#define NORMAL_EPSILON 0.01
//input data
struct appdata{
float4 vertex : POSITION;
};
//data that goes from vertex to fragment shader
struct v2f{
float4 position : SV_POSITION; //position in clip space
float4 localPosition : TEXCOORD0; //position in local space
float4 viewDirection : TEXCOORD1; //view direction in local space (not normalized!)
};
v2f vert(appdata v){
v2f o;
//position for rendering
o.position = UnityObjectToClipPos(v.vertex);
//save local position for origin
o.localPosition = v.vertex;
//get camera position in local space
float4 objectSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1));
//get local view vector
o.viewDirection = v.vertex - objectSpaceCameraPos;
return o;
}
float scene(float3 pos){
return length(pos) - 0.5;
}
float3 normal(float3 pos){
//determine change in signed distance
float changeX = scene(pos + float3(NORMAL_EPSILON, 0, 0)) - scene(pos - float3(NORMAL_EPSILON, 0, 0));
float changeY = scene(pos + float3(0, NORMAL_EPSILON, 0)) - scene(pos - float3(0, NORMAL_EPSILON, 0));
float changeZ = scene(pos + float3(0, 0, NORMAL_EPSILON)) - scene(pos - float3(0, 0, NORMAL_EPSILON));
//construct normal vector
float3 surfaceNormal = float3(changeX, changeY, changeZ);
//convert normal vector into worldspace and make it uniform length
surfaceNormal = mul(unity_ObjectToWorld, float4(surfaceNormal, 0));
return normalize(surfaceNormal);
}
float4 lightColor(float3 position){
//calculate needed surface and light data
float3 surfaceNormal = normal(position);
float3 lightDirection = _WorldSpaceLightPos0.xyz;
//calculate simple shading
float lightAngle = saturate(dot(surfaceNormal, lightDirection));
return lightAngle * _LightColor0;
}
float4 material(float3 position){
//get light color
float4 light = lightColor(position);
//combine base color and light color
float4 color = _Color * light;
return color;
}
fixed4 frag(v2f i) : SV_TARGET{
//ray information
float3 pos = i.localPosition;
float3 dir = normalize(i.viewDirection.xyz);
float progress = 0;
//tracing loop
for (uint iter = 0; iter < MAX_STEPS; iter++) {
//get current location on ray
float3 samplePoint = pos + dir * progress;
//get distance to closest shape
float distance = scene(samplePoint);
//return color if inside shape
if(distance < THICKNESS){
return material(samplePoint);
}
//go forwards
progress = progress + distance;
}
//discard pixel if no shape was hit (previously used clip(-1), discard is better!!)
discard;
return 0;
}
ENDCG
}
}
}