Realtime Fractal Renderer Documentation
main.cl
Go to the documentation of this file.
1#ifndef MAIN_CL
3#define MAIN_CL
5
6#include "defines.cl"
7#include "types.cl"
8
21__kernel void getSceneInformation(
22 __global float3* camera_up_axis, const uint array_capacity,
23 __global uint* number_camera_positions, __global float4* camera_positions_at_time,
24 __global uint* number_camera_facing, __global float4* camera_facing_at_time,
25 __global bool* do_camera_loop, __global float* camera_speed,
26 __global float2* benchmark_start_stop_time)
27{
28 *camera_up_axis = CAMERA_UP_AXIS;
29 *number_camera_positions = CAMERA_POSITIONS_LENGTH;
30 *number_camera_facing = CAMERA_FACING_DIRECTIONS_LENGTH;
31 *benchmark_start_stop_time = BENCHMARK_START_STOP_TIME;
32 *do_camera_loop = CAMERA_DO_LOOP;
33 *camera_speed = CAMERA_SPEED;
34
35#if FORCE_FREE_CAMERA
36 * number_camera_positions = 1;
37 *number_camera_facing = 1;
38 *benchmark_start_stop_time = BENCHMARK_START_STOP_TIME_DONT_DO_TIMED;
39#endif
40
41 // Construct compile time arrays
44
45 // Fill the arrays as much as we can
46 for (int i = 0; i < CAMERA_POSITIONS_LENGTH && i < array_capacity; i++)
47 {
48 camera_positions_at_time[i] = positions[i];
49 }
50 for (int i = 0; i < CAMERA_FACING_DIRECTIONS_LENGTH && i < array_capacity; i++)
51 {
52 camera_facing_at_time[i] = facing[i];
53 }
54}
55
62float3 estimateSurfaceNormal(const float3 position, const float time)
63{
64 const float3 xOffset = (float3)(SURFACE_NORMAL_EPSILON, 0, 0);
65 const float3 yOffset = (float3)(0, SURFACE_NORMAL_EPSILON, 0);
66 const float3 zOffset = (float3)(0, 0, SURFACE_NORMAL_EPSILON);
67
68 float x = DE(position + xOffset, time) - DE(position - xOffset, time);
69 float y = DE(position + yOffset, time) - DE(position - yOffset, time);
70 float z = DE(position + zOffset, time) - DE(position - zOffset, time);
71
72 return normalize((float3)(x, y, z));
73}
74
82float calculateSoftShadow(const float3 pointOnGeometry, const float time, const float3 lightPosition)
83{
84 // https://www.iquilezles.org/www/articles/rmshadows/rmshadows.htm
85
86 float shadow = 1.0f;
87 float ph = 1e20;
88
89 float3 distanceVector = lightPosition - pointOnGeometry;
90 float3 directionFromGeometryToLight = normalise(distanceVector);
91 float distanceFromGeometryToLight = magnitude(distanceVector);
92
93 for (float totalDistance = SURFACE_SHADOW_EPSILON; totalDistance < distanceFromGeometryToLight; )
94 {
95 float3 currentPosition = pointOnGeometry + directionFromGeometryToLight * totalDistance;
96 float distance = DE(currentPosition, time);
97
98 // Hit the surface of an object
99 // Therefore the original point must be in shadow
100 if (distance <= SURFACE_INTERSECTION_EPSILON)
101 {
102 return 0.0f;
103 }
104
105 // Calculate soft shadow values
106 float y = distance * distance / (2.0f * ph);
107 float d = sqrt(distance * distance - y * y);
108 shadow = min(shadow, SURFACE_SHADOW_FALLOFF * d / max(0.0f, totalDistance - y));
109 ph = distance;
110
111 totalDistance += distance;
112 }
113
114 return shadow;
115}
116
124float calculateHardShadow(const float3 pointOnGeometry, const float time, const float3 lightPosition)
125{
126 // https://www.iquilezles.org/www/articles/rmshadows/rmshadows.htm
127
128 float3 distanceVector = lightPosition - pointOnGeometry;
129 float3 directionFromGeometryToLight = normalise(distanceVector);
130 float distanceFromGeometryToLight = magnitude(distanceVector);
131
132 for (float totalDistance = SURFACE_SHADOW_EPSILON; totalDistance < distanceFromGeometryToLight; )
133 {
134 float3 currentPosition = pointOnGeometry + directionFromGeometryToLight * totalDistance;
135 float distance = DE(currentPosition, time);
136
137 // Hit the surface of an object
138 // Therefore the original point must be in shadow
139 if (distance <= SURFACE_INTERSECTION_EPSILON)
140 {
141 return 0.0f;
142 }
143
144 totalDistance += distance;
145 }
146
147 return 1.0f;
148}
149
150float3 reflect(float3 incident, float3 normal)
151{
152 return incident - 2.0f * dot(normal, incident) * normal;
153}
154
161float3 trace(const Ray ray, const float time)
162{
163 float totalDistance = 0.0f;
164 float closestDistanceToGeometry = FLOAT_MAX_VALUE;
165 float3 currentPosition;
166 int steps = 0;
167 for (; steps < MAXIMUM_MARCH_STEPS && totalDistance < MAXIMUM_MARCH_DISTANCE; steps++)
168 {
169 currentPosition = ray.position + (ray.direction * totalDistance);
170
171 // Check the bounding volume before the actual geometry
172#if USE_BOUNDING_VOLUME
173 float distance = boundingVolumeDE(currentPosition, time);
174
175#if DISPLAY_BOUNDING_VOLUME
176 bool isBoundingVolume = true;
177#endif
178
179 // Overwrite the distance with the actual distance if we are close enough
181 {
182 // Display both the bounding volume and geometry
183#if DISPLAY_BOUNDING_VOLUME
184 float actual = DE(currentPosition, time);
185
186 if (actual <= distance)
187 {
188 distance = actual;
189 isBoundingVolume = false;
190 }
191#else
192 // Only update value with accurate value if we don't want to see the bounding volume
193 distance = DE(currentPosition, time);
194#endif
195
196 // Record the closest distance to the geometry
197 if (distance < closestDistanceToGeometry)
198 {
199 closestDistanceToGeometry = distance;
200 }
201 }
202
203 // Just calculate distance as normal
204#else
205 float distance = DE(currentPosition, time);
206
207 // Record the closest distance to the geometry
208 if (distance < closestDistanceToGeometry)
209 {
210 closestDistanceToGeometry = distance;
211 }
212
213#endif
214
215 totalDistance += distance;
216
217 // Hit the surface of an object
218#if INCREASE_INTERSECTION_EPSILON_LINEARLY
220#else
221 if (distance <= SURFACE_INTERSECTION_EPSILON)
222#endif
223 {
224 // Render the scene using a heatmap for number of ray marching iterations
225#if DO_RENDER_MARCHING_ITERATIONS
226 return (float3)((float)(steps) / (float)(MAXIMUM_MARCH_STEPS), 0.0f, 0.0f);
227#endif
228
229 Material material = getMaterial(currentPosition, time);
230 Light light = getLight(time);
231
232 float3 ambient = 0.0f;
233 float3 diffuse = 0.0f;
234 float3 specular = 0.0f;
235 float shadow = 1.0f;
236
237 const float3 normal = estimateSurfaceNormal(currentPosition, time);
238 const float3 lightDirection = normalise(light.position - currentPosition);
239
240 // Ambient
241#if DO_AMBIENT_LIGHTING
242 ambient = material.ambient * light.ambient;
243#endif
244
245 // Diffuse
246#if DO_DIFFUSE_LIGHTING
247
248 diffuse = material.diffuse * light.diffuse * max(dot(normal, lightDirection), 0.0f);
249#endif
250
251 // Specular
252#if DO_SPECULAR_HIGHLIGHTS
253
254 // Phong
255 //float3 viewDirection = normalise(ray.position - currentPosition);
256 //float3 reflectDirection = reflect(-lightDirection, normal);
257 //specular *= light.specular * pow(max(dot(viewDirection, reflectDirection), 0.0f), material.shininess);
258
259 // Blinn-Phong
260 float3 viewDirection = normalise(ray.position - currentPosition);
261 float3 halfwayVector = normalise(lightDirection + viewDirection);
262 specular = material.specular * light.specular * pow(max(dot(normal, halfwayVector), 0.0f), material.shininess);
263#endif
264
265#if DO_RENDER_SURFACE_NORMALS
266 // Set ambient and diffuse colours to be surface normal
267 ambient = (normal + (float3)(1.0f)) * 0.5f;
268 diffuse = ambient;
269#endif
270
271#if DISPLAY_BOUNDING_VOLUME
272 if (isBoundingVolume)
273 {
274 ambient = BOUNDING_VOLUME_COLOUR;
275 diffuse = ambient;
276 specular = (float3)(0);
277 }
278#endif
279
280#if DO_EDGE_SHADING
281 shadow = 1 - ((float)(steps) / (float)(MAXIMUM_MARCH_STEPS));
282#endif
283
284 // Soft shadows
285#if DO_SOFT_SHADOWS
286 shadow = calculateSoftShadow(currentPosition, time, light.position);
287
288 // Hard shadows
289#elif DO_HARD_SHADOWS
290 shadow = calculateHardShadow(currentPosition, time, light.position);
291#endif
292
293 return ambient + shadow * (diffuse + specular);
294 }
295 }
296
297 // Render the scene using a heatmap for number of ray marching iterations
298#if DO_RENDER_MARCHING_ITERATIONS
299 return (float3)((float)(steps) / (float)(MAXIMUM_MARCH_STEPS), 0.0f, 0.0f);
300#endif
301
302 // Apply a glow colour around the geometry
303#if DO_GEOMETRY_GLOW
304
305 if (closestDistanceToGeometry <= SCENE_MAX_GLOW_DISTANCE)
306 {
307 float glow_strength = 1 - closestDistanceToGeometry / SCENE_MAX_GLOW_DISTANCE;
308 return SCENE_BACKGROUND_COLOUR + glow_strength * SCENE_GLOW_COLOUR;
309 }
310
311#endif
312
314}
315
324Ray getCameraRay(const float2 screen_coordinate, const float3 camera_position, const float3 camera_facing, const float aspect_ratio)
325{
326 const float theta = CAMERA_VERTICAL_FOV_DEGREES * PI / 180.0f;
327 const float h = tan(theta / 2);
328 const float viewport_height = 2.0f * h;
329 const float viewport_width = aspect_ratio * viewport_height;
330
331 float3 w = normalise(camera_facing);
332 float3 u = normalise(crossProduct(CAMERA_UP_AXIS, w));
333 float3 v = crossProduct(w, u);
334
335 float3 horizontal = u * CAMERA_FOCUS_DISTANCE * viewport_width;
336 float3 vertical = v * CAMERA_FOCUS_DISTANCE * viewport_height;
337 float3 screenLowerLeftCorner = camera_position - horizontal / 2 - vertical / 2 - w * CAMERA_FOCUS_DISTANCE;
338
339 float3 screenPosition = screenLowerLeftCorner + horizontal * screen_coordinate.x + vertical * screen_coordinate.y - camera_position;
340
341 Ray r;
342 r.position = camera_position + screenPosition;
343 r.direction = normalise(screenPosition);
344 return r;
345}
346
352uchar3 convertColourTo8Bit(const float3 colour)
353{
354 return (uchar3)((uchar)(clamp01(colour.x) * 255), (uchar)(clamp01(colour.y) * 255), (uchar)(clamp01(colour.z) * 255));
355}
356
366__attribute__((vec_type_hint(float3)))
367__kernel void calculatePixelColour(
368 __global uchar* colours, const uint width, const uint height, const float time, const float3 camera_position, const float3 camera_facing)
369{
370 // Get gloabl thread ID
371 const int ID = get_global_id(0);
372
373 // Make sure we are within the array size
374 if (ID < width * height)
375 {
376 // Get x and y pixel coordinates
377 int x = ID % width;
378 int y = ID / width;
379 // Calculate the screen position
380 const float2 screen_coordinate = (float2)((float)(x) / (float)(width), (float)(y) / (float)(height));
381
382 const Ray ray = getCameraRay(screen_coordinate, camera_position, camera_facing, (float)(width) / (float)(height));
383 float3 colour = trace(ray, time);
384
385#if DO_GAMMA_CORRECTION
386 // Apply gamma correction
387 colour = pow(colour, GAMMA_CORRECTION_STRENGTH);
388#endif
389
390 const uchar3 colour_8_bit = convertColourTo8Bit(colour);
391
392 const int output_ID = ID * 4;
393 colours[output_ID] = colour_8_bit.x;
394 colours[output_ID + 1] = colour_8_bit.y;
395 colours[output_ID + 2] = colour_8_bit.z;
396 colours[output_ID + 3] = 255;
397 }
398}
399
400#endif
401
#define CAMERA_VERTICAL_FOV_DEGREES
Camera vertical field of view in degrees
Definition: defines.cl:103
#define BENCHMARK_START_STOP_TIME_DONT_DO_TIMED
Definition: defines.cl:194
#define BOUNDING_VOLUME_INTERSECTION_EPSILON
Epsilon value used for determining ray collisions with the a bounding volume
Definition: defines.cl:262
#define SURFACE_SHADOW_EPSILON
Epsilon value used when calculating shadows on geometry. Represents the distance at which shadow chec...
Definition: defines.cl:269
#define SURFACE_INTERSECTION_EPSILON
Epsilon value used to define the maximum distance which is considered a ray collision
Definition: defines.cl:244
#define SCENE_MAX_GLOW_DISTANCE
Maximum distance of the glow effect. DO_GEOMETRY_GLOW must be enabled
Definition: defines.cl:212
#define SURFACE_SHADOW_FALLOFF
Falloff value used when calculating soft shadows
Definition: defines.cl:275
#define CAMERA_FOCUS_DISTANCE
Camera focus distance in world units
Definition: defines.cl:109
#define SCENE_GLOW_COLOUR
Colour of the glow effect in the scene. DO_GEOMETRY_GLOW must be enabled
Definition: defines.cl:206
#define LINEAR_INTERSECTION_EPSILON_MULTIPLIER
Multiplier used to determine how quickly SURFACE_INTERSECTION_EPSILON should increase as each ray get...
Definition: defines.cl:250
#define BOUNDING_VOLUME_COLOUR
Colour to display the bounding volume when DISPLAY_BOUNDING_VOLUME is enabled
Definition: defines.cl:91
#define SURFACE_NORMAL_EPSILON
Epsilon value used to calculate surface the normal of geometry
Definition: defines.cl:256
#define CAMERA_UP_AXIS
Camera up axis. Must be a normalised float3
Definition: defines.cl:115
#define FLOAT_MAX_VALUE
Approximate value for a float
Definition: defines.cl:226
#define GAMMA_CORRECTION_STRENGTH
Strength of gamma correction. DO_GAMMA_CORRECTION must be enabled
Definition: defines.cl:281
Light getLight(float time)
Definition: hello_world.cl:19
#define CAMERA_SPEED
Definition: hello_world.cl:11
Material getMaterial(float3 position, float time)
Definition: hello_world.cl:45
#define MAXIMUM_MARCH_STEPS
Definition: hello_world.cl:16
float DE(float3 position, float time)
Definition: hello_world.cl:51
#define MAXIMUM_MARCH_DISTANCE
Definition: hello_world.cl:17
#define SCENE_BACKGROUND_COLOUR
Definition: hello_world.cl:13
float3 estimateSurfaceNormal(const float3 position, const float time)
Calculates the surface normal for a any point in the scene.
Definition: main.cl:62
const uint const uint const float const float3 camera_position
Definition: main.cl:368
const uint const uint height
Definition: main.cl:368
uchar3 convertColourTo8Bit(const float3 colour)
Converts a colour range 0-1 to an integer colour with range 0-255.
Definition: main.cl:352
const uint width
Definition: main.cl:368
float calculateHardShadow(const float3 pointOnGeometry, const float time, const float3 lightPosition)
Calculates hard shadows for a point on geometry in the scene.
Definition: main.cl:124
Ray getCameraRay(const float2 screen_coordinate, const float3 camera_position, const float3 camera_facing, const float aspect_ratio)
Creates a ray for the specified position on the camera screen.
Definition: main.cl:324
__attribute__((vec_type_hint(float3))) __kernel void calculatePixelColour(__global uchar *colours
Main kernel function. Calculates the colour for a pixel with the specified coordinate position range ...
float3 reflect(float3 incident, float3 normal)
Definition: main.cl:150
const uint const uint const float const float3 const float3 camera_facing
Definition: main.cl:369
float3 trace(const Ray ray, const float time)
Traces the path of a ray.
Definition: main.cl:161
const uint const uint const float time
Definition: main.cl:368
__kernel void getSceneInformation(__global float3 *camera_up_axis, const uint array_capacity, __global uint *number_camera_positions, __global float4 *camera_positions_at_time, __global uint *number_camera_facing, __global float4 *camera_facing_at_time, __global bool *do_camera_loop, __global float *camera_speed, __global float2 *benchmark_start_stop_time)
Kernel function used to pass scene information to the C++ interface.
Definition: main.cl:21
float calculateSoftShadow(const float3 pointOnGeometry, const float time, const float3 lightPosition)
Calculates soft shadows for a point on geometry in the scene.
Definition: main.cl:82
float boundingVolumeDE(float3 position, float time)
Definition: mandelbulb.cl:103
#define BENCHMARK_START_STOP_TIME
#define CAMERA_FACING_DIRECTIONS_LENGTH
#define CAMERA_POSITIONS_ARRAY
#define CAMERA_DO_LOOP
#define CAMERA_FACING_DIRECTIONS_ARRAY
#define CAMERA_POSITIONS_LENGTH
A struct representing a light, for use with the phong illumination model.
Definition: types.cl:32
float3 ambient
Definition: types.cl:34
float3 position
Definition: types.cl:33
float3 diffuse
Definition: types.cl:35
float3 specular
Definition: types.cl:36
A struct representing a geometry material, for use with the Phong reflection model.
Definition: types.cl:20
float3 ambient
Definition: types.cl:21
float3 diffuse
Definition: types.cl:22
float shininess
Definition: types.cl:24
float3 specular
Definition: types.cl:23
A struct representing a line in 3D space.
Definition: types.cl:10
float3 position
Definition: types.cl:11
float3 direction
Definition: types.cl:12