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
=255, g
=255, b
=255}).
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
, 20).
17 raytraced_pixel_list(0, 0, _
) ->
19 raytraced_pixel_list(Width
, Height
, Scene
) when Width
> 0, Height
> 0 ->
24 % coordinates passed as a percentage
25 trace_ray_from_pixel({X
/Width
, Y
/Height
}, Scene
) end,
26 lists:seq(0, Width
- 1)) end,
27 lists:seq(0, Height
- 1)).
29 trace_ray_from_pixel({X
, Y
}, [Camera
|Rest_of_scene
]) ->
30 Ray
= ray_through_pixel(X
, Y
, Camera
),
31 case nearest_object_intersecting_ray(Ray
, Rest_of_scene
) of
32 {Nearest_object
, _Distance
} ->
33 %io:format("hit: ~w~n", [{Nearest_object, _Distance}]),
34 colour_to_pixel(object_colour(Nearest_object
));
36 colour_to_pixel(?BACKGROUND_COLOUR
);
38 colour_to_pixel(?ERROR_COLOUR
)
41 nearest_object_intersecting_ray(Ray
, Scene
) ->
42 nearest_object_intersecting_ray(Ray
, none
, infinity
, Scene
).
43 nearest_object_intersecting_ray(_Ray
, _NearestObj
, infinity
, []) ->
45 nearest_object_intersecting_ray(_Ray
, NearestObj
, Distance
, []) ->
46 % io:format("intersecting ~w at ~w~n", [NearestObj, Distance]),
47 {NearestObj
, Distance
};
48 nearest_object_intersecting_ray(Ray
,
51 [CurrentObject
|Rest_of_scene
]) ->
52 NewDistance
= ray_object_intersect(Ray
, CurrentObject
),
53 %io:format("Distace=~w NewDistace=~w~n", [Distance, NewDistance]),
54 if (NewDistance
/= infinity
)
55 and ((Distance
== infinity
) or (Distance
> NewDistance
)) ->
56 %io:format("another closer object found~n", []),
57 nearest_object_intersecting_ray(
63 %io:format("no closer obj found~n", []),
64 nearest_object_intersecting_ray(Ray
,
70 ray_object_intersect(Ray
, Object
) ->
73 ray_sphere_intersect(Ray
, Object
);
83 #sphere
{radius
=Radius
, center
=#vector
{
84 x
=Xc
, y
=Yc
, z
=Zc
}}) ->
85 A
= Xd
*Xd
+ Yd
*Yd
+ Zd
*Zd
,
86 B
= 2 * (Xd
*(X0
-Xc
) + Yd
*(Y0
-Yc
) + Zd
*(Z0
-Zc
)),
87 C
= (X0
-Xc
)*(X0
-Xc
) + (Y0
-Yc
)*(Y0
-Yc
) + (Z0
-Zc
)*(Z0
-Zc
) - Radius
*Radius
,
88 Discriminant
= B
*B
- 4*A
*C
,
89 %io:format("A=~w B=~w C=~w discriminant=~w~n",
90 % [A, B, C, Discriminant]),
91 if Discriminant
>= 0 ->
92 T0
= (-B
+ math:sqrt(Discriminant
))/2,
93 T1
= (-B
- math:sqrt(Discriminant
))/2,
94 if (T0
>= 0) and (T1
>= 0) ->
95 %io:format("T0=~w T1=~w~n", [T0, T1]),
106 focal_length(Angle
, Dimension
) ->
107 Dimension
/(2*math:tan(Angle
*(math:pi()/180)/2)).
109 point_on_screen(X
, Y
, Camera
) ->
110 %TODO: implement rotation (using quaternions)
111 Screen_width
= (Camera#camera
.screen
)#screen
.width
,
112 Screen_height
= (Camera#camera
.screen
)#screen
.height
,
113 lists:foldl(fun(Vect
, Sum
) -> vector_add(Vect
, Sum
) end,
114 Camera#camera
.location
,
116 #vector
{x
=0, y
=0, z
=1},
120 #vector
{x
= (X
-0.5) * Screen_width
,
124 y
= (Y
-0.5) * Screen_height
,
129 shoot_ray(From
, Through
) ->
130 #ray
{origin
=From
, direction
=vector_sub(Through
, From
)}.
132 % assume that X and Y are percentages of the 3D world screen dimensions
133 ray_through_pixel(X
, Y
, Camera
) ->
134 shoot_ray(Camera#camera
.location
, point_on_screen(X
, Y
, Camera
)).
136 vectors_equal(V1
, V2
) ->
137 vectors_equal(V1
, V2
, 0.0001).
138 vectors_equal(V1
, V2
, Epsilon
) ->
139 (V1#vector
.x
+ Epsilon
>= V2#vector
.x
)
140 and (V1#vector
.x
- Epsilon
=<V2#vector
.x
)
141 and (V1#vector
.y
+ Epsilon
>= V2#vector
.y
)
142 and (V1#vector
.y
- Epsilon
=<V2#vector
.y
)
143 and (V1#vector
.z
+ Epsilon
>= V2#vector
.z
)
144 and (V1#vector
.z
- Epsilon
=<V2#vector
.z
).
147 vector_add(V1
, V2
) ->
148 #vector
{x
= V1#vector
.x
+ V2#vector
.x
,
149 y
= V1#vector
.y
+ V2#vector
.y
,
150 z
= V1#vector
.z
+ V2#vector
.z
}.
152 vector_sub(V1
, V2
) ->
153 #vector
{x
= V1#vector
.x
- V2#vector
.x
,
154 y
= V1#vector
.y
- V2#vector
.y
,
155 z
= V1#vector
.z
- V2#vector
.z
}.
157 vector_square_mag(#vector
{x
=X
, y
=Y
, z
=Z
}) ->
161 math:sqrt(vector_square_mag(V
)).
163 vector_scalar_mult(#vector
{x
=X
, y
=Y
, z
=Z
}, Scalar
) ->
164 #vector
{x
=X
*Scalar
, y
=Y
*Scalar
, z
=Z
*Scalar
}.
166 vector_dot_product(#vector
{x
=A1
, y
=A2
, z
=A3
}, #vector
{x
=B1
, y
=B2
, z
=B3
}) ->
167 A1
*B1
+ A2
*B2
+ A3
*B3
.
169 vector_cross_product(#vector
{x
=A1
, y
=A2
, z
=A3
}, #vector
{x
=B1
, y
=B2
, z
=B3
}) ->
170 #vector
{x
= A2
*B3
- A3
*B2
,
174 vector_normalize(V
) ->
177 #vector
{x
=0, y
=0, z
=0};
179 vector_scalar_mult(V
, 1/vector_mag(V
))
182 vector_neg(#vector
{x
=X
, y
=Y
, z
=Z
}) ->
183 #vector
{x
=-X
, y
=-Y
, z
=-Z
}.
185 vector_rotate(V1
, _V2
) ->
186 %TODO: implement using quaternions
189 object_colour(#sphere
{ colour
=C
}) ->
191 object_colour(_Unknown
) ->
194 colour_to_vector(#colour
{r
=R
, g
=G
, b
=B
}) ->
195 #vector
{x
=R
, y
=G
, z
=B
}.
196 vector_to_colour(#vector
{x
=X
, y
=Y
, z
=Z
}) ->
197 #colour
{r
=X
, g
=Y
, b
=Z
}.
198 colour_to_pixel(#colour
{r
=R
, g
=G
, b
=B
}) ->
201 % returns a list of objects in the scene
202 % camera is assumed to be the first element in the scene
204 [#camera
{location
=#vector
{x
=0, y
=0, z
=0},
205 rotation
=#vector
{x
=0, y
=0, z
=0},
207 screen
=#screen
{width
=4, height
=3}},
208 #point_light
{colour
=#colour
{r
=255, g
=255, b
=128},
210 location
=#vector
{x
=5, y
=5, z
=1}},
212 center
=#vector
{x
=0, y
=0, z
=7},
213 colour
=#colour
{r
=0, g
=128, b
=255}},
215 center
=#vector
{x
=-5, y
=3, z
=9},
216 colour
=#colour
{r
=255, g
=128, b
=0}},
218 center
=#vector
{x
=-5, y
=-2, z
=10},
219 colour
=#colour
{r
=128, g
=255, b
=0}}
223 % assumes Pixels are ordered in a row by row fasion
224 write_pixels_to_ppm(Width
, Height
, MaxValue
, Pixels
, Filename
) ->
225 case file:open(Filename
, write
) of
227 io:format("file opened~n", []),
228 io:format(IoDevice
, "P3~n", []),
229 io:format(IoDevice
, "~p ~p~n", [Width
, Height
]),
230 io:format(IoDevice
, "~p~n", [MaxValue
]),
233 io:format(IoDevice
, "~p ~p ~p ",
236 file:close(IoDevice
),
237 io:format("done~n", []);
239 io:format("error opening file~n", [])
243 go(16, 12, "/tmp/traced.ppm").
244 go(Width
, Height
, Filename
) ->
245 write_pixels_to_ppm(Width
,
248 raytraced_pixel_list(Width
,
255 io:format("testing the scene function", []),
263 {colour
, 255, 255, 128},
269 {colour
, 0, 128, 255}},
273 {colour
, 255, 128, 0}},
276 {vector
, -5, -2, 10},
277 {colour
, 128, 255, 0}}] ->
284 io:format("this test always fails", []),
288 io:format("this test always passes", []),
292 Tests
= [fun scene_test
/0,
294 fun vector_equality_test
/0,
295 fun vector_addition_test
/0,
296 fun vector_subtraction_test
/0,
297 fun vector_square_mag_test
/0,
298 fun vector_mag_test
/0,
299 fun vector_scalar_multiplication_test
/0,
300 fun vector_dot_product_test
/0,
301 fun vector_cross_product_test
/0,
302 fun vector_normalization_test
/0,
303 fun vector_negation_test
/0,
304 fun ray_through_pixel_test
/0,
305 fun ray_shooting_test
/0,
306 fun point_on_screen_test
/0,
307 fun nearest_object_intersecting_ray_test
/0,
308 fun focal_length_test
/0,
309 fun vector_rotation_test
/0
311 run_tests(Tests
, 1, true
).
313 run_tests([], _Num
, Success
) ->
316 io:format("Success!~n", []),
319 io:format("some tests failed~n", []),
323 run_tests([First_test
|Rest_of_tests
], Num
, Success_so_far
) ->
324 io:format("test #~p: ", [Num
]),
325 Current_success
= First_test(),
326 case Current_success
of
328 io:format(" - OK~n", []);
330 io:format(" - FAILED~n", [])
332 run_tests(Rest_of_tests
, Num
+ 1, Current_success and Success_so_far
).
334 vector_equality_test() ->
335 io:format("vector equality"),
336 Vector1
= #vector
{x
=0, y
=0, z
=0},
337 Vector2
= #vector
{x
=1234, y
=-234, z
=0},
338 Vector3
= #vector
{x
=0.0983, y
=0.0214, z
=0.12342},
339 Vector4
= #vector
{x
=0.0984, y
=0.0213, z
=0.12341},
340 Vector5
= #vector
{x
=10/3, y
=-10/6, z
=8/7},
341 Vector6
= #vector
{x
=3.3, y
=-1.6, z
=1.1},
343 Subtest1
= vectors_equal(Vector1
, Vector1
)
344 and
vectors_equal(Vector2
, Vector2
)
345 and
not (vectors_equal(Vector1
, Vector2
))
346 and
not (vectors_equal(Vector2
, Vector1
)),
347 Subtest2
= vectors_equal(Vector3
, Vector4
, 0.0001),
348 Subtest3
= vectors_equal(Vector5
, Vector6
, 0.1),
350 Subtest1 and Subtest2 and Subtest3
.
353 vector_addition_test() ->
354 io:format("vector addition", []),
355 Vector0
= vector_add(
356 #vector
{x
=3, y
=7, z
=-3},
357 #vector
{x
=0, y
=-24, z
=123}),
358 Subtest1
= (Vector0#vector
.x
== 3)
359 and (Vector0#vector
.y
== -17)
360 and (Vector0#vector
.z
== 120),
362 Vector1
= #vector
{x
=5, y
=0, z
=984},
363 Vector2
= vector_add(Vector1
, Vector1
),
364 Subtest2
= (Vector2#vector
.x
== Vector1#vector
.x
*2)
365 and (Vector2#vector
.y
== Vector1#vector
.y
*2)
366 and (Vector2#vector
.z
== Vector1#vector
.z
*2),
368 Vector3
= #vector
{x
=908, y
=-098, z
=234},
369 Vector4
= vector_add(Vector3
, #vector
{x
=0, y
=0, z
=0}),
370 Subtest3
= vectors_equal(Vector3
, Vector4
),
372 Subtest1 and Subtest2 and Subtest3
.
374 vector_subtraction_test() ->
375 io:format("vector subtraction", []),
376 Vector1
= #vector
{x
=0, y
=0, z
=0},
377 Vector2
= #vector
{x
=8390, y
=-2098, z
=939},
378 Vector3
= #vector
{x
=1, y
=1, z
=1},
379 Vector4
= #vector
{x
=-1, y
=-1, z
=-1},
381 Subtest1
= vectors_equal(Vector1
, vector_sub(Vector1
, Vector1
)),
382 Subtest2
= vectors_equal(Vector3
, vector_sub(Vector3
, Vector1
)),
383 Subtest3
= not
vectors_equal(Vector3
, vector_sub(Vector1
, Vector3
)),
384 Subtest4
= vectors_equal(Vector4
, vector_sub(Vector4
, Vector1
)),
385 Subtest5
= not
vectors_equal(Vector4
, vector_sub(Vector1
, Vector4
)),
386 Subtest5
= vectors_equal(vector_add(Vector2
, Vector4
),
387 vector_sub(Vector2
, Vector3
)),
389 Subtest1 and Subtest2 and Subtest3 and Subtest4 and Subtest5
.
391 vector_square_mag_test() ->
392 io:format("vector square magnitude test", []),
393 Vector1
= #vector
{x
=0, y
=0, z
=0},
394 Vector2
= #vector
{x
=1, y
=1, z
=1},
395 Vector3
= #vector
{x
=3, y
=-4, z
=0},
397 Subtest1
= (0 == vector_square_mag(Vector1
)),
398 Subtest2
= (3 == vector_square_mag(Vector2
)),
399 Subtest3
= (25 == vector_square_mag(Vector3
)),
401 Subtest1 and Subtest2 and Subtest3
.
404 io:format("vector magnitude test", []),
405 Vector1
= #vector
{x
=0, y
=0, z
=0},
406 Vector2
= #vector
{x
=1, y
=1, z
=1},
407 Vector3
= #vector
{x
=3, y
=-4, z
=0},
409 Subtest1
= (0 == vector_mag(Vector1
)),
410 Subtest2
= (math:sqrt(3) == vector_mag(Vector2
)),
411 Subtest3
= (5 == vector_mag(Vector3
)),
413 Subtest1 and Subtest2 and Subtest3
.
415 vector_scalar_multiplication_test() ->
416 io:format("scalar multiplication test", []),
417 Vector1
= #vector
{x
=0, y
=0, z
=0},
418 Vector2
= #vector
{x
=1, y
=1, z
=1},
419 Vector3
= #vector
{x
=3, y
=-4, z
=0},
421 Subtest1
= vectors_equal(Vector1
, vector_scalar_mult(Vector1
, 45)),
422 Subtest2
= vectors_equal(Vector1
, vector_scalar_mult(Vector1
, -13)),
423 Subtest3
= vectors_equal(Vector1
, vector_scalar_mult(Vector3
, 0)),
424 Subtest4
= vectors_equal(#vector
{x
=4, y
=4, z
=4},
425 vector_scalar_mult(Vector2
, 4)),
426 Subtest5
= vectors_equal(Vector3
, vector_scalar_mult(Vector3
, 1)),
427 Subtest6
= not
vectors_equal(Vector3
, vector_scalar_mult(Vector3
, -3)),
429 Subtest1 and Subtest2 and Subtest3 and Subtest4 and Subtest5 and Subtest6
.
431 vector_dot_product_test() ->
432 io:format("dot product test", []),
433 Vector1
= #vector
{x
=1, y
=3, z
=-5},
434 Vector2
= #vector
{x
=4, y
=-2, z
=-1},
435 Vector3
= #vector
{x
=0, y
=0, z
=0},
436 Vector4
= #vector
{x
=1, y
=0, z
=0},
437 Vector5
= #vector
{x
=0, y
=1, z
=0},
439 Subtest1
= 3 == vector_dot_product(Vector1
, Vector2
),
440 Subtest2
= vector_dot_product(Vector2
, Vector2
)
441 == vector_square_mag(Vector2
),
442 Subtest3
= 0 == vector_dot_product(Vector3
, Vector1
),
443 Subtest4
= 0 == vector_dot_product(Vector4
, Vector5
),
445 Subtest1 and Subtest2 and Subtest3 and Subtest4
.
447 vector_cross_product_test() ->
448 io:format("cross product test", []),
449 Vector1
= #vector
{x
=0, y
=0, z
=0},
450 Vector2
= #vector
{x
=1, y
=0, z
=0},
451 Vector3
= #vector
{x
=0, y
=1, z
=0},
452 Vector4
= #vector
{x
=0, y
=0, z
=1},
453 Vector5
= #vector
{x
=1, y
=2, z
=3},
454 Vector6
= #vector
{x
=4, y
=5, z
=6},
455 Vector7
= #vector
{x
=-3, y
=6, z
=-3},
456 Vector8
= #vector
{x
=-1, y
=0, z
=0},
457 Vector9
= #vector
{x
=-9, y
=8, z
=433},
459 Subtest1
= vectors_equal(Vector1
, vector_cross_product(Vector2
, Vector2
)),
460 Subtest2
= vectors_equal(Vector1
, vector_cross_product(Vector2
, Vector8
)),
461 Subtest3
= vectors_equal(Vector2
, vector_cross_product(Vector3
, Vector4
)),
462 Subtest4
= vectors_equal(Vector7
, vector_cross_product(Vector5
, Vector6
)),
463 Subtest5
= vectors_equal(
464 vector_cross_product(Vector7
,
465 vector_add(Vector8
, Vector9
)),
467 vector_cross_product(Vector7
, Vector8
),
468 vector_cross_product(Vector7
, Vector9
))),
469 Subtest6
= vectors_equal(Vector1
,
472 vector_cross_product(
474 vector_cross_product(Vector8
, Vector9
)),
475 vector_cross_product(
477 vector_cross_product(Vector9
, Vector7
))),
478 vector_cross_product(
480 vector_cross_product(Vector7
, Vector8
)))),
482 Subtest1 and Subtest2 and Subtest3 and Subtest4 and Subtest5 and Subtest6
.
484 vector_normalization_test() ->
485 io:format("normalization test", []),
486 Vector1
= #vector
{x
=0, y
=0, z
=0},
487 Vector2
= #vector
{x
=1, y
=0, z
=0},
488 Vector3
= #vector
{x
=5, y
=0, z
=0},
490 Subtest1
= vectors_equal(Vector1
, vector_normalize(Vector1
)),
491 Subtest2
= vectors_equal(Vector2
, vector_normalize(Vector2
)),
492 Subtest3
= vectors_equal(Vector2
, vector_normalize(Vector3
)),
493 Subtest4
= vectors_equal(Vector2
, vector_normalize(
494 vector_scalar_mult(Vector2
, 324))),
496 Subtest1 and Subtest2 and Subtest3 and Subtest4
.
498 vector_negation_test() ->
499 io:format("vector negation test", []),
500 Vector1
= #vector
{x
=0, y
=0, z
=0},
501 Vector2
= #vector
{x
=4, y
=-5, z
=6},
503 Subtest1
= vectors_equal(Vector1
, vector_neg(Vector1
)),
504 Subtest2
= vectors_equal(Vector2
, vector_neg(vector_neg(Vector2
))),
506 Subtest1 and Subtest2
.
508 ray_through_pixel_test() ->
509 io:format("ray through pixel test", []),
512 ray_shooting_test() ->
513 io:format("ray shooting test"),
514 Vector1
= #vector
{x
=0, y
=0, z
=0},
515 Vector2
= #vector
{x
=1, y
=0, z
=0},
517 Subtest1
= vectors_equal(
518 (shoot_ray(Vector1
, Vector2
))#ray
.direction
,
523 ray_sphere_intersection_test() ->
526 center
=#vector
{x
= 0, y
=0, z
=10},
527 colour
=#colour
{r
=111, g
=111, b
=111}},
529 origin
=#vector
{x
=0, y
=0, z
=0},
530 direction
=#vector
{x
=0, y
=0, z
=1}},
532 origin
=#vector
{x
=3, y
=0, z
=0},
533 direction
=#vector
{x
=0, y
=0, z
=1}},
535 origin
=#vector
{x
=4, y
=0, z
=0},
536 direction
=#vector
{x
=0, y
=0, z
=1}},
537 io:format("ray/sphere intersection=~w~n", [ray_sphere_intersect(Ray1
, Sphere
)]),
538 Subtest1
= ray_sphere_intersect(Ray1
, Sphere
) == 7.0,
539 Subtest2
= ray_sphere_intersect(Ray2
, Sphere
) == 10.0,
540 Subtest3
= ray_sphere_intersect(Ray3
, Sphere
) == none
,
541 io:format("ray/sphere intersection=~w~n", [ray_sphere_intersect(Ray2
, Sphere
)]),
542 io:format("ray/sphere intersection=~w~n", [ray_sphere_intersect(Ray3
, Sphere
)]),
543 Subtest1 and Subtest2 and Subtest3
.
545 point_on_screen_test() ->
546 io:format("point on screen test", []),
547 Camera1
= #camera
{location
=#vector
{x
=0, y
=0, z
=0},
548 rotation
=#vector
{x
=0, y
=0, z
=0},
550 screen
=#screen
{width
=1, height
=1}},
551 Camera2
= #camera
{location
=#vector
{x
=0, y
=0, z
=0},
552 rotation
=#vector
{x
=0, y
=0, z
=0},
554 screen
=#screen
{width
=640, height
=480}},
556 Subtest1
= vectors_equal(
557 #vector
{x
=0, y
=0, z
=0.5},
558 point_on_screen(0.5, 0.5, Camera1
)),
559 Subtest2
= vectors_equal(
560 #vector
{x
=-0.5, y
=-0.5, z
=0.5},
561 point_on_screen(0, 0, Camera1
)),
562 Subtest3
= vectors_equal(
563 #vector
{x
=0.5, y
=0.5, z
=0.5},
564 point_on_screen(1, 1, Camera1
)),
565 Subtest4
= vectors_equal(
566 point_on_screen(0, 0, Camera2
),
567 #vector
{x
=-320, y
=-240, z
=320}),
568 Subtest5
= vectors_equal(
569 point_on_screen(1, 1, Camera2
),
570 #vector
{x
=320, y
=240, z
=320}),
571 Subtest6
= vectors_equal(
572 point_on_screen(0.5, 0.5, Camera2
),
573 #vector
{x
=0, y
=0, z
=320}),
575 Subtest1 and Subtest2 and Subtest3 and Subtest4 and Subtest5 and Subtest6
.
577 nearest_object_intersecting_ray_test() ->
578 io:format("nearest object intersecting ray test", []),
579 % test to make sure that we really get the closest object
580 Sphere1
=#sphere
{radius
=5,
581 center
=#vector
{x
=0, y
=0, z
=10},
582 colour
=#colour
{r
=0, g
=0, b
=10}},
583 Sphere2
=#sphere
{radius
=5,
584 center
=#vector
{x
=0, y
=0, z
=20},
585 colour
=#colour
{r
=0, g
=0, b
=20}},
586 Sphere3
=#sphere
{radius
=5,
587 center
=#vector
{x
=0, y
=0, z
=30},
588 colour
=#colour
{r
=0, g
=0, b
=30}},
589 Sphere4
=#sphere
{radius
=5,
590 center
=#vector
{x
=0, y
=0, z
=-10},
591 colour
=#colour
{r
=0, g
=0, b
=-10}},
592 Scene1
=[Sphere1
, Sphere2
, Sphere3
, Sphere4
],
593 Ray1
=#ray
{origin
=#vector
{x
=0, y
=0, z
=0},
594 direction
=#vector
{x
=0, y
=0, z
=1}},
596 Subtest1
= {Sphere1
, 5} == nearest_object_intersecting_ray(Ray1
, Scene1
),
600 focal_length_test() ->
603 io:format("focal length test", []),
605 fun({Focal_length
, Dimension
}, Matches
) ->
606 %Result = focal_length(Dimension, Size),
607 %io:format("comparing ~w ~w ~w ~w~n", [Focal_length, Dimension, Result, Matches]),
609 and ((Focal_length
+ Epsilon
>= focal_length(
611 and (Focal_length
- Epsilon
=< focal_length(
614 [{13, 108}, {15, 100.4}, {18, 90}, {21, 81.2}]).
616 vector_rotation_test() ->
617 io:format("vector rotation test", []),
618 Vector1
= #vector
{x
=0, y
=0, z
=0},
619 Vector2
= #vector
{x
=0, y
=1, z
=0},
620 Vector3
= #vector
{x
=90, y
=0, z
=0},
621 Vector4
= #vector
{x
=45, y
=0, z
=0},
622 Vector5
= #vector
{x
=30.11, y
=-988.2, z
=92.231},
623 Vector6
= #vector
{x
=0, y
=0, z
=1},
625 Subtest1
= vectors_equal(
626 vector_rotate(Vector1
, Vector1
),
628 Subtest2
= vectors_equal(
629 vector_rotate(Vector5
, Vector1
),
631 Subtest3
= vectors_equal(
633 vector_rotate(Vector5
, Vector4
),
635 vector_rotate(Vector5
, Vector3
)),
636 Subtest4
= vectors_equal(
638 vector_rotate(Vector2
, Vector3
)),
640 Subtest1 and Subtest2 and Subtest3 and Subtest4
.