4 -record(vector
, {x
, y
, z
}).
5 -record(colour
, {r
, g
, b
}).
6 -record(ray
, {origin
, direction
}).
7 -record(screen
, {width
, height
}). % screen dimensions in the 3D world
8 -record(camera
, {location
, rotation
, fov
, screen
}).
9 -record(sphere
, {radius
, center
, colour
}).
10 -record(point_light
, {colour
, intensity
, location
}).
11 %-record(axis_aligned_cube, {size, location}).
12 -define(BACKGROUND_COLOUR
, #colour
{r
=0, g
=0, b
=0}).
13 -define(ERROR_COLOUR
, #colour
{r
=255, g
=0, b
=0}).
14 -define(UNKNOWN_COLOUR
, #colour
{r
=0, g
=255, b
=0}).
15 -define(FOG_DISTANCE
, 40).
18 raytraced_pixel_list(0, 0, _
) ->
20 raytraced_pixel_list(Width
, Height
, Scene
) when Width
> 0, Height
> 0 ->
25 % coordinates passed as a percentage
29 {X
/Width
, Y
/Height
}, Scene
))) end,
30 lists:seq(0, Width
- 1)) end,
31 lists:seq(0, Height
- 1)).
33 trace_ray_from_pixel({X
, Y
}, [Camera
|Rest_of_scene
]) ->
34 Ray
= ray_through_pixel(X
, Y
, Camera
),
35 case nearest_object_intersecting_ray(Ray
, Rest_of_scene
) of
36 {Nearest_object
, Distance
} ->
37 %io:format("hit: ~w~n", [{Nearest_object, _Distance}]),
38 lighting_function(Nearest_object
, Distance
);
45 lighting_function(Object
, Distance
) ->
46 if Distance
=< ?FOG_DISTANCE
->
49 colour_to_vector(object_colour(Object
)),
50 (?FOG_DISTANCE
- Distance
)/?FOG_DISTANCE
));
52 #colour
{r
=0, g
=0, b
=0}
56 nearest_object_intersecting_ray(Ray
, Scene
) ->
57 nearest_object_intersecting_ray(Ray
, none
, infinity
, Scene
).
58 nearest_object_intersecting_ray(_Ray
, _NearestObj
, infinity
, []) ->
60 nearest_object_intersecting_ray(_Ray
, NearestObj
, Distance
, []) ->
61 % io:format("intersecting ~w at ~w~n", [NearestObj, Distance]),
62 {NearestObj
, Distance
};
63 nearest_object_intersecting_ray(Ray
,
66 [CurrentObject
|Rest_of_scene
]) ->
67 NewDistance
= ray_object_intersect(Ray
, CurrentObject
),
68 %io:format("Distace=~w NewDistace=~w~n", [Distance, NewDistance]),
69 if (NewDistance
/= infinity
)
70 and ((Distance
== infinity
) or (Distance
> NewDistance
)) ->
71 %io:format("another closer object found~n", []),
72 nearest_object_intersecting_ray(
78 %io:format("no closer obj found~n", []),
79 nearest_object_intersecting_ray(Ray
,
85 ray_object_intersect(Ray
, Object
) ->
88 ray_sphere_intersect(Ray
, Object
);
98 #sphere
{radius
=Radius
, center
=#vector
{
99 x
=Xc
, y
=Yc
, z
=Zc
}}) ->
100 A
= Xd
*Xd
+ Yd
*Yd
+ Zd
*Zd
,
101 B
= 2 * (Xd
*(X0
-Xc
) + Yd
*(Y0
-Yc
) + Zd
*(Z0
-Zc
)),
102 C
= (X0
-Xc
)*(X0
-Xc
) + (Y0
-Yc
)*(Y0
-Yc
) + (Z0
-Zc
)*(Z0
-Zc
) - Radius
*Radius
,
103 Discriminant
= B
*B
- 4*A
*C
,
104 %io:format("A=~w B=~w C=~w discriminant=~w~n",
105 % [A, B, C, Discriminant]),
106 if Discriminant
>= 0 ->
107 T0
= (-B
+ math:sqrt(Discriminant
))/2,
108 T1
= (-B
- math:sqrt(Discriminant
))/2,
109 if (T0
>= 0) and (T1
>= 0) ->
110 %io:format("T0=~w T1=~w~n", [T0, T1]),
121 focal_length(Angle
, Dimension
) ->
122 Dimension
/(2*math:tan(Angle
*(math:pi()/180)/2)).
124 point_on_screen(X
, Y
, Camera
) ->
125 %TODO: implement rotation (using quaternions)
126 Screen_width
= (Camera#camera
.screen
)#screen
.width
,
127 Screen_height
= (Camera#camera
.screen
)#screen
.height
,
128 lists:foldl(fun(Vect
, Sum
) -> vector_add(Vect
, Sum
) end,
129 Camera#camera
.location
,
131 #vector
{x
=0, y
=0, z
=1},
135 #vector
{x
= (X
-0.5) * Screen_width
,
139 y
= (Y
-0.5) * Screen_height
,
144 shoot_ray(From
, Through
) ->
145 #ray
{origin
=From
, direction
=vector_sub(Through
, From
)}.
147 % assume that X and Y are percentages of the 3D world screen dimensions
148 ray_through_pixel(X
, Y
, Camera
) ->
149 shoot_ray(Camera#camera
.location
, point_on_screen(X
, Y
, Camera
)).
151 vectors_equal(V1
, V2
) ->
152 vectors_equal(V1
, V2
, 0.0001).
153 vectors_equal(V1
, V2
, Epsilon
) ->
154 (V1#vector
.x
+ Epsilon
>= V2#vector
.x
)
155 and (V1#vector
.x
- Epsilon
=<V2#vector
.x
)
156 and (V1#vector
.y
+ Epsilon
>= V2#vector
.y
)
157 and (V1#vector
.y
- Epsilon
=<V2#vector
.y
)
158 and (V1#vector
.z
+ Epsilon
>= V2#vector
.z
)
159 and (V1#vector
.z
- Epsilon
=<V2#vector
.z
).
162 vector_add(V1
, V2
) ->
163 #vector
{x
= V1#vector
.x
+ V2#vector
.x
,
164 y
= V1#vector
.y
+ V2#vector
.y
,
165 z
= V1#vector
.z
+ V2#vector
.z
}.
167 vector_sub(V1
, V2
) ->
168 #vector
{x
= V1#vector
.x
- V2#vector
.x
,
169 y
= V1#vector
.y
- V2#vector
.y
,
170 z
= V1#vector
.z
- V2#vector
.z
}.
172 vector_square_mag(#vector
{x
=X
, y
=Y
, z
=Z
}) ->
176 math:sqrt(vector_square_mag(V
)).
178 vector_scalar_mult(#vector
{x
=X
, y
=Y
, z
=Z
}, Scalar
) ->
179 #vector
{x
=X
*Scalar
, y
=Y
*Scalar
, z
=Z
*Scalar
}.
181 vector_dot_product(#vector
{x
=A1
, y
=A2
, z
=A3
}, #vector
{x
=B1
, y
=B2
, z
=B3
}) ->
182 A1
*B1
+ A2
*B2
+ A3
*B3
.
184 vector_cross_product(#vector
{x
=A1
, y
=A2
, z
=A3
}, #vector
{x
=B1
, y
=B2
, z
=B3
}) ->
185 #vector
{x
= A2
*B3
- A3
*B2
,
189 vector_normalize(V
) ->
192 #vector
{x
=0, y
=0, z
=0};
194 vector_scalar_mult(V
, 1/vector_mag(V
))
197 vector_neg(#vector
{x
=X
, y
=Y
, z
=Z
}) ->
198 #vector
{x
=-X
, y
=-Y
, z
=-Z
}.
200 vector_rotate(V1
, _V2
) ->
201 %TODO: implement using quaternions
204 object_colour(#sphere
{ colour
=C
}) ->
206 object_colour(_Unknown
) ->
209 colour_to_vector(#colour
{r
=R
, g
=G
, b
=B
}) ->
210 #vector
{x
=R
, y
=G
, z
=B
}.
211 vector_to_colour(#vector
{x
=X
, y
=Y
, z
=Z
}) ->
212 #colour
{r
=X
, g
=Y
, b
=Z
}.
213 colour_to_pixel(#colour
{r
=R
, g
=G
, b
=B
}) ->
215 colour_trunc(#colour
{r
=R
, g
=G
, b
=B
}) ->
216 #colour
{r
=trunc(R
), g
=trunc(G
), b
=trunc(B
)}.
218 % returns a list of objects in the scene
219 % camera is assumed to be the first element in the scene
221 [#camera
{location
=#vector
{x
=0, y
=0, z
=0},
222 rotation
=#vector
{x
=0, y
=0, z
=0},
224 screen
=#screen
{width
=4, height
=3}},
225 #point_light
{colour
=#colour
{r
=255, g
=255, b
=128},
227 location
=#vector
{x
=5, y
=5, z
=1}},
229 center
=#vector
{x
=0, y
=0, z
=7},
230 colour
=#colour
{r
=0, g
=128, b
=255}},
232 center
=#vector
{x
=-5, y
=3, z
=9},
233 colour
=#colour
{r
=255, g
=128, b
=0}},
235 center
=#vector
{x
=-5, y
=-2, z
=10},
236 colour
=#colour
{r
=128, g
=255, b
=0}}
240 % assumes Pixels are ordered in a row by row fasion
241 write_pixels_to_ppm(Width
, Height
, MaxValue
, Pixels
, Filename
) ->
242 case file:open(Filename
, write
) of
244 io:format("file opened~n", []),
245 io:format(IoDevice
, "P3~n", []),
246 io:format(IoDevice
, "~p ~p~n", [Width
, Height
]),
247 io:format(IoDevice
, "~p~n", [MaxValue
]),
250 io:format(IoDevice
, "~p ~p ~p ",
253 file:close(IoDevice
),
254 io:format("done~n", []);
256 io:format("error opening file~n", [])
260 go(16, 12, "/tmp/traced.ppm").
261 go(Width
, Height
, Filename
) ->
262 write_pixels_to_ppm(Width
,
265 raytraced_pixel_list(Width
,
272 io:format("testing the scene function", []),
280 {colour
, 255, 255, 128},
286 {colour
, 0, 128, 255}},
290 {colour
, 255, 128, 0}},
293 {vector
, -5, -2, 10},
294 {colour
, 128, 255, 0}}] ->
301 io:format("this test always fails", []),
305 io:format("this test always passes", []),
309 Tests
= [fun scene_test
/0,
311 fun vector_equality_test
/0,
312 fun vector_addition_test
/0,
313 fun vector_subtraction_test
/0,
314 fun vector_square_mag_test
/0,
315 fun vector_mag_test
/0,
316 fun vector_scalar_multiplication_test
/0,
317 fun vector_dot_product_test
/0,
318 fun vector_cross_product_test
/0,
319 fun vector_normalization_test
/0,
320 fun vector_negation_test
/0,
321 fun ray_through_pixel_test
/0,
322 fun ray_shooting_test
/0,
323 fun point_on_screen_test
/0,
324 fun nearest_object_intersecting_ray_test
/0,
325 fun focal_length_test
/0,
326 fun vector_rotation_test
/0
328 run_tests(Tests
, 1, true
).
330 run_tests([], _Num
, Success
) ->
333 io:format("Success!~n", []),
336 io:format("some tests failed~n", []),
340 run_tests([First_test
|Rest_of_tests
], Num
, Success_so_far
) ->
341 io:format("test #~p: ", [Num
]),
342 Current_success
= First_test(),
343 case Current_success
of
345 io:format(" - OK~n", []);
347 io:format(" - FAILED~n", [])
349 run_tests(Rest_of_tests
, Num
+ 1, Current_success and Success_so_far
).
351 vector_equality_test() ->
352 io:format("vector equality"),
353 Vector1
= #vector
{x
=0, y
=0, z
=0},
354 Vector2
= #vector
{x
=1234, y
=-234, z
=0},
355 Vector3
= #vector
{x
=0.0983, y
=0.0214, z
=0.12342},
356 Vector4
= #vector
{x
=0.0984, y
=0.0213, z
=0.12341},
357 Vector5
= #vector
{x
=10/3, y
=-10/6, z
=8/7},
358 Vector6
= #vector
{x
=3.3, y
=-1.6, z
=1.1},
360 Subtest1
= vectors_equal(Vector1
, Vector1
)
361 and
vectors_equal(Vector2
, Vector2
)
362 and
not (vectors_equal(Vector1
, Vector2
))
363 and
not (vectors_equal(Vector2
, Vector1
)),
364 Subtest2
= vectors_equal(Vector3
, Vector4
, 0.0001),
365 Subtest3
= vectors_equal(Vector5
, Vector6
, 0.1),
367 Subtest1 and Subtest2 and Subtest3
.
370 vector_addition_test() ->
371 io:format("vector addition", []),
372 Vector0
= vector_add(
373 #vector
{x
=3, y
=7, z
=-3},
374 #vector
{x
=0, y
=-24, z
=123}),
375 Subtest1
= (Vector0#vector
.x
== 3)
376 and (Vector0#vector
.y
== -17)
377 and (Vector0#vector
.z
== 120),
379 Vector1
= #vector
{x
=5, y
=0, z
=984},
380 Vector2
= vector_add(Vector1
, Vector1
),
381 Subtest2
= (Vector2#vector
.x
== Vector1#vector
.x
*2)
382 and (Vector2#vector
.y
== Vector1#vector
.y
*2)
383 and (Vector2#vector
.z
== Vector1#vector
.z
*2),
385 Vector3
= #vector
{x
=908, y
=-098, z
=234},
386 Vector4
= vector_add(Vector3
, #vector
{x
=0, y
=0, z
=0}),
387 Subtest3
= vectors_equal(Vector3
, Vector4
),
389 Subtest1 and Subtest2 and Subtest3
.
391 vector_subtraction_test() ->
392 io:format("vector subtraction", []),
393 Vector1
= #vector
{x
=0, y
=0, z
=0},
394 Vector2
= #vector
{x
=8390, y
=-2098, z
=939},
395 Vector3
= #vector
{x
=1, y
=1, z
=1},
396 Vector4
= #vector
{x
=-1, y
=-1, z
=-1},
398 Subtest1
= vectors_equal(Vector1
, vector_sub(Vector1
, Vector1
)),
399 Subtest2
= vectors_equal(Vector3
, vector_sub(Vector3
, Vector1
)),
400 Subtest3
= not
vectors_equal(Vector3
, vector_sub(Vector1
, Vector3
)),
401 Subtest4
= vectors_equal(Vector4
, vector_sub(Vector4
, Vector1
)),
402 Subtest5
= not
vectors_equal(Vector4
, vector_sub(Vector1
, Vector4
)),
403 Subtest5
= vectors_equal(vector_add(Vector2
, Vector4
),
404 vector_sub(Vector2
, Vector3
)),
406 Subtest1 and Subtest2 and Subtest3 and Subtest4 and Subtest5
.
408 vector_square_mag_test() ->
409 io:format("vector square magnitude test", []),
410 Vector1
= #vector
{x
=0, y
=0, z
=0},
411 Vector2
= #vector
{x
=1, y
=1, z
=1},
412 Vector3
= #vector
{x
=3, y
=-4, z
=0},
414 Subtest1
= (0 == vector_square_mag(Vector1
)),
415 Subtest2
= (3 == vector_square_mag(Vector2
)),
416 Subtest3
= (25 == vector_square_mag(Vector3
)),
418 Subtest1 and Subtest2 and Subtest3
.
421 io:format("vector magnitude test", []),
422 Vector1
= #vector
{x
=0, y
=0, z
=0},
423 Vector2
= #vector
{x
=1, y
=1, z
=1},
424 Vector3
= #vector
{x
=3, y
=-4, z
=0},
426 Subtest1
= (0 == vector_mag(Vector1
)),
427 Subtest2
= (math:sqrt(3) == vector_mag(Vector2
)),
428 Subtest3
= (5 == vector_mag(Vector3
)),
430 Subtest1 and Subtest2 and Subtest3
.
432 vector_scalar_multiplication_test() ->
433 io:format("scalar multiplication test", []),
434 Vector1
= #vector
{x
=0, y
=0, z
=0},
435 Vector2
= #vector
{x
=1, y
=1, z
=1},
436 Vector3
= #vector
{x
=3, y
=-4, z
=0},
438 Subtest1
= vectors_equal(Vector1
, vector_scalar_mult(Vector1
, 45)),
439 Subtest2
= vectors_equal(Vector1
, vector_scalar_mult(Vector1
, -13)),
440 Subtest3
= vectors_equal(Vector1
, vector_scalar_mult(Vector3
, 0)),
441 Subtest4
= vectors_equal(#vector
{x
=4, y
=4, z
=4},
442 vector_scalar_mult(Vector2
, 4)),
443 Subtest5
= vectors_equal(Vector3
, vector_scalar_mult(Vector3
, 1)),
444 Subtest6
= not
vectors_equal(Vector3
, vector_scalar_mult(Vector3
, -3)),
446 Subtest1 and Subtest2 and Subtest3 and Subtest4 and Subtest5 and Subtest6
.
448 vector_dot_product_test() ->
449 io:format("dot product test", []),
450 Vector1
= #vector
{x
=1, y
=3, z
=-5},
451 Vector2
= #vector
{x
=4, y
=-2, z
=-1},
452 Vector3
= #vector
{x
=0, y
=0, z
=0},
453 Vector4
= #vector
{x
=1, y
=0, z
=0},
454 Vector5
= #vector
{x
=0, y
=1, z
=0},
456 Subtest1
= 3 == vector_dot_product(Vector1
, Vector2
),
457 Subtest2
= vector_dot_product(Vector2
, Vector2
)
458 == vector_square_mag(Vector2
),
459 Subtest3
= 0 == vector_dot_product(Vector3
, Vector1
),
460 Subtest4
= 0 == vector_dot_product(Vector4
, Vector5
),
462 Subtest1 and Subtest2 and Subtest3 and Subtest4
.
464 vector_cross_product_test() ->
465 io:format("cross product test", []),
466 Vector1
= #vector
{x
=0, y
=0, z
=0},
467 Vector2
= #vector
{x
=1, y
=0, z
=0},
468 Vector3
= #vector
{x
=0, y
=1, z
=0},
469 Vector4
= #vector
{x
=0, y
=0, z
=1},
470 Vector5
= #vector
{x
=1, y
=2, z
=3},
471 Vector6
= #vector
{x
=4, y
=5, z
=6},
472 Vector7
= #vector
{x
=-3, y
=6, z
=-3},
473 Vector8
= #vector
{x
=-1, y
=0, z
=0},
474 Vector9
= #vector
{x
=-9, y
=8, z
=433},
476 Subtest1
= vectors_equal(Vector1
, vector_cross_product(Vector2
, Vector2
)),
477 Subtest2
= vectors_equal(Vector1
, vector_cross_product(Vector2
, Vector8
)),
478 Subtest3
= vectors_equal(Vector2
, vector_cross_product(Vector3
, Vector4
)),
479 Subtest4
= vectors_equal(Vector7
, vector_cross_product(Vector5
, Vector6
)),
480 Subtest5
= vectors_equal(
481 vector_cross_product(Vector7
,
482 vector_add(Vector8
, Vector9
)),
484 vector_cross_product(Vector7
, Vector8
),
485 vector_cross_product(Vector7
, Vector9
))),
486 Subtest6
= vectors_equal(Vector1
,
489 vector_cross_product(
491 vector_cross_product(Vector8
, Vector9
)),
492 vector_cross_product(
494 vector_cross_product(Vector9
, Vector7
))),
495 vector_cross_product(
497 vector_cross_product(Vector7
, Vector8
)))),
499 Subtest1 and Subtest2 and Subtest3 and Subtest4 and Subtest5 and Subtest6
.
501 vector_normalization_test() ->
502 io:format("normalization test", []),
503 Vector1
= #vector
{x
=0, y
=0, z
=0},
504 Vector2
= #vector
{x
=1, y
=0, z
=0},
505 Vector3
= #vector
{x
=5, y
=0, z
=0},
507 Subtest1
= vectors_equal(Vector1
, vector_normalize(Vector1
)),
508 Subtest2
= vectors_equal(Vector2
, vector_normalize(Vector2
)),
509 Subtest3
= vectors_equal(Vector2
, vector_normalize(Vector3
)),
510 Subtest4
= vectors_equal(Vector2
, vector_normalize(
511 vector_scalar_mult(Vector2
, 324))),
513 Subtest1 and Subtest2 and Subtest3 and Subtest4
.
515 vector_negation_test() ->
516 io:format("vector negation test", []),
517 Vector1
= #vector
{x
=0, y
=0, z
=0},
518 Vector2
= #vector
{x
=4, y
=-5, z
=6},
520 Subtest1
= vectors_equal(Vector1
, vector_neg(Vector1
)),
521 Subtest2
= vectors_equal(Vector2
, vector_neg(vector_neg(Vector2
))),
523 Subtest1 and Subtest2
.
525 ray_through_pixel_test() ->
526 io:format("ray through pixel test", []),
529 ray_shooting_test() ->
530 io:format("ray shooting test"),
531 Vector1
= #vector
{x
=0, y
=0, z
=0},
532 Vector2
= #vector
{x
=1, y
=0, z
=0},
534 Subtest1
= vectors_equal(
535 (shoot_ray(Vector1
, Vector2
))#ray
.direction
,
540 ray_sphere_intersection_test() ->
543 center
=#vector
{x
= 0, y
=0, z
=10},
544 colour
=#colour
{r
=111, g
=111, b
=111}},
546 origin
=#vector
{x
=0, y
=0, z
=0},
547 direction
=#vector
{x
=0, y
=0, z
=1}},
549 origin
=#vector
{x
=3, y
=0, z
=0},
550 direction
=#vector
{x
=0, y
=0, z
=1}},
552 origin
=#vector
{x
=4, y
=0, z
=0},
553 direction
=#vector
{x
=0, y
=0, z
=1}},
554 io:format("ray/sphere intersection=~w~n", [ray_sphere_intersect(Ray1
, Sphere
)]),
555 Subtest1
= ray_sphere_intersect(Ray1
, Sphere
) == 7.0,
556 Subtest2
= ray_sphere_intersect(Ray2
, Sphere
) == 10.0,
557 Subtest3
= ray_sphere_intersect(Ray3
, Sphere
) == none
,
558 io:format("ray/sphere intersection=~w~n", [ray_sphere_intersect(Ray2
, Sphere
)]),
559 io:format("ray/sphere intersection=~w~n", [ray_sphere_intersect(Ray3
, Sphere
)]),
560 Subtest1 and Subtest2 and Subtest3
.
562 point_on_screen_test() ->
563 io:format("point on screen test", []),
564 Camera1
= #camera
{location
=#vector
{x
=0, y
=0, z
=0},
565 rotation
=#vector
{x
=0, y
=0, z
=0},
567 screen
=#screen
{width
=1, height
=1}},
568 Camera2
= #camera
{location
=#vector
{x
=0, y
=0, z
=0},
569 rotation
=#vector
{x
=0, y
=0, z
=0},
571 screen
=#screen
{width
=640, height
=480}},
573 Subtest1
= vectors_equal(
574 #vector
{x
=0, y
=0, z
=0.5},
575 point_on_screen(0.5, 0.5, Camera1
)),
576 Subtest2
= vectors_equal(
577 #vector
{x
=-0.5, y
=-0.5, z
=0.5},
578 point_on_screen(0, 0, Camera1
)),
579 Subtest3
= vectors_equal(
580 #vector
{x
=0.5, y
=0.5, z
=0.5},
581 point_on_screen(1, 1, Camera1
)),
582 Subtest4
= vectors_equal(
583 point_on_screen(0, 0, Camera2
),
584 #vector
{x
=-320, y
=-240, z
=320}),
585 Subtest5
= vectors_equal(
586 point_on_screen(1, 1, Camera2
),
587 #vector
{x
=320, y
=240, z
=320}),
588 Subtest6
= vectors_equal(
589 point_on_screen(0.5, 0.5, Camera2
),
590 #vector
{x
=0, y
=0, z
=320}),
592 Subtest1 and Subtest2 and Subtest3 and Subtest4 and Subtest5 and Subtest6
.
594 nearest_object_intersecting_ray_test() ->
595 io:format("nearest object intersecting ray test", []),
596 % test to make sure that we really get the closest object
597 Sphere1
=#sphere
{radius
=5,
598 center
=#vector
{x
=0, y
=0, z
=10},
599 colour
=#colour
{r
=0, g
=0, b
=10}},
600 Sphere2
=#sphere
{radius
=5,
601 center
=#vector
{x
=0, y
=0, z
=20},
602 colour
=#colour
{r
=0, g
=0, b
=20}},
603 Sphere3
=#sphere
{radius
=5,
604 center
=#vector
{x
=0, y
=0, z
=30},
605 colour
=#colour
{r
=0, g
=0, b
=30}},
606 Sphere4
=#sphere
{radius
=5,
607 center
=#vector
{x
=0, y
=0, z
=-10},
608 colour
=#colour
{r
=0, g
=0, b
=-10}},
609 Scene1
=[Sphere1
, Sphere2
, Sphere3
, Sphere4
],
610 Ray1
=#ray
{origin
=#vector
{x
=0, y
=0, z
=0},
611 direction
=#vector
{x
=0, y
=0, z
=1}},
613 Subtest1
= {Sphere1
, 5} == nearest_object_intersecting_ray(Ray1
, Scene1
),
617 focal_length_test() ->
620 io:format("focal length test", []),
622 fun({Focal_length
, Dimension
}, Matches
) ->
623 %Result = focal_length(Dimension, Size),
624 %io:format("comparing ~w ~w ~w ~w~n", [Focal_length, Dimension, Result, Matches]),
626 and ((Focal_length
+ Epsilon
>= focal_length(
628 and (Focal_length
- Epsilon
=< focal_length(
631 [{13, 108}, {15, 100.4}, {18, 90}, {21, 81.2}]).
633 vector_rotation_test() ->
634 io:format("vector rotation test", []),
635 Vector1
= #vector
{x
=0, y
=0, z
=0},
636 Vector2
= #vector
{x
=0, y
=1, z
=0},
637 Vector3
= #vector
{x
=90, y
=0, z
=0},
638 Vector4
= #vector
{x
=45, y
=0, z
=0},
639 Vector5
= #vector
{x
=30.11, y
=-988.2, z
=92.231},
640 Vector6
= #vector
{x
=0, y
=0, z
=1},
642 Subtest1
= vectors_equal(
643 vector_rotate(Vector1
, Vector1
),
645 Subtest2
= vectors_equal(
646 vector_rotate(Vector5
, Vector1
),
648 Subtest3
= vectors_equal(
650 vector_rotate(Vector5
, Vector4
),
652 vector_rotate(Vector5
, Vector3
)),
653 Subtest4
= vectors_equal(
655 vector_rotate(Vector2
, Vector3
)),
657 Subtest1 and Subtest2 and Subtest3 and Subtest4
.