-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathraytrace.glsl
218 lines (166 loc) · 5.29 KB
/
raytrace.glsl
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
precision mediump float;
const float INFINITY = 1e9;
const int MAX_MARCHING_STEPS = 400;
// -------------------------------------------------------------------------
// Camera uniforms
struct Camera
{
vec3 up; // Up-vector
vec3 right; // Right-vector
vec3 forward; // Forward-vector
vec3 eye; // Eye position
float aspectRatio; // Ratio between screen width and height
float focalLength; // Distance between the eye and the image plane
};
uniform Camera uCamera;
// -------------------------------------------------------------------------
struct Light
{
vec3 position;
vec3 color;
};
uniform Light uLights[2];
// -------------------------------------------------------------------------
struct Settings
{
int numberSteps; // Max number of raymarch steps
float epsilon; // Surface threshold
vec2 resolution; // Resolution of the view port
};
uniform Settings uSettings;
// -------------------------------------------------------------------------
// DISTANCE FUNCTIONS FOR OBJECTS
// plane
float dPlane( vec3 x )
{
return x.y;
}
// sphere
float dSphere( vec3 x, vec3 c, float r )
{
return length( x-c ) - r;
}
// -------------------------------------------------------------------------
struct Dist
{
int index;
float distance;
};
// helper function to find if a new object is closer along a ray than the
// previous one; return the closer object index
Dist closer( Dist current, int index, float t )
{
if( t <= current.distance )
{
current.distance = t;
current.index = index;
}
return current;
}
// -------------------------------------------------------------------------
// OVERALL SCENE DISTANCE FUNCTION
// return Dist instance of the object closest to the current
// position on the ray
Dist dScene( vec3 p )
{
Dist hit = Dist( -1, INFINITY );
hit = closer( hit, 1, dPlane(p) );
hit = closer( hit, 2, dSphere(p, vec3(-0.5,0.5,0), 0.5) );
hit = closer( hit, 3, dSphere(p, vec3(0.4,0.4,0), 0.4) );
// more objects here ...
return hit;
}
// use dScene and finite differences to estimate the normal of the object
// at position x
vec3 nScene( in vec3 x )
{
vec3 n;
float epsilon = uSettings.epsilon;
n.x = dScene( x + vec3(epsilon,0,0) ).distance - dScene( x - vec3(epsilon,0,0) ).distance;
n.y = dScene( x + vec3(0,epsilon,0) ).distance - dScene( x - vec3(0,epsilon,0) ).distance;
n.z = dScene( x + vec3(0,0,epsilon) ).distance - dScene( x - vec3(0,0,epsilon) ).distance;
float nl = length(n);
if( nl > 0.0 )
n /= nl;
return n;
}
// -------------------------------------------------------------------------
struct Ray
{
vec3 o; // origin
vec3 d; // direction (normalized)
};
// march along a ray using the distance field, until an object is approached
// very closely (ro: ray origin, rd: ray direction)
// returns index -1 if no hit is discovered
Dist raymarch( Ray r )
{
float t = 0.0;
for(int j = 0; j < MAX_MARCHING_STEPS; j++)
{
// calculate the current position on the ray
vec3 pos = r.o + r.d * t;
// get the distance and index of the object closest to position
Dist result = dScene(pos);
// if the distance is under the threshold, return the RayHit
if( result.distance < uSettings.epsilon )
{
result.distance += t;
return result;
}
// add the current distance to the raymarch step length
t += result.distance;
}
return Dist( -1, INFINITY );
}
// -------------------------------------------------------------------------
// helper function to obtain the ray direction of the ray going through
// the pixel this shader instance is called for
Ray getRayForCurrentPixel()
{
// compute normalized viewport coordinates
vec2 pixelCoord = -1.0 + 2.0*(gl_FragCoord.xy / uSettings.resolution);
// set ray direction
return Ray( uCamera.eye, normalize( uCamera.forward * uCamera.focalLength +
uCamera.right * pixelCoord.x * uCamera.aspectRatio +
uCamera.up * pixelCoord.y) );
}
// main raytracing loop, automatically called for each viewport pixel
void main(void)
{
// compute initial (primary) ray origin and direction
Ray r = getRayForCurrentPixel();
vec3 finalColor = vec3(0,0,0);
// determine the closest object hit along the ray
Dist hit = raymarch( r );
// if an object was hit, add light reflected from it
// to overall light along the current ray
if( hit.index != -1 )
{
vec3 pos = r.o + r.d * hit.distance;
vec3 nrm = nScene( pos );
vec3 Cd = vec3(0);
// based upon the index of the object hit,
// set material properties (for now only diffuse color Cd)
if( hit.index == 1 )
{
// the plane shall have a checkerboard pattern
float f = mod( floor(2.0*pos.z) + floor(2.0*pos.x), 2.0);
Cd = vec3( 0.8 + 0.1*f*vec3(1.0) );
}
else if( hit.index == 2 )
{
// thist sphere shall be red
Cd = vec3( 1.0, 0.0, 0.0 );
}
else if( hit.index == 3 )
{
// thist sphere shall be blue
Cd = vec3( 0.0, 0.0, 1.0 );
}
// add light to overall color
finalColor += Cd;
}
// output pixel color
gl_FragColor = vec4( finalColor, 1.0 );
}