1 //******************************************************************************
2 ///
3 /// @file core/shape/box.cpp
4 ///
5 /// Implementation of the box geometric primitive.
6 ///
7 /// @author Alexander Enzmann
8 ///
9 /// @copyright
10 /// @parblock
11 ///
12 /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
13 /// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd.
14 ///
15 /// POV-Ray is free software: you can redistribute it and/or modify
16 /// it under the terms of the GNU Affero General Public License as
17 /// published by the Free Software Foundation, either version 3 of the
18 /// License, or (at your option) any later version.
19 ///
20 /// POV-Ray is distributed in the hope that it will be useful,
21 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
22 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 /// GNU Affero General Public License for more details.
24 ///
25 /// You should have received a copy of the GNU Affero General Public License
26 /// along with this program. If not, see <http://www.gnu.org/licenses/>.
27 ///
28 /// ----------------------------------------------------------------------------
29 ///
30 /// POV-Ray is based on the popular DKB raytracer version 2.12.
31 /// DKBTrace was originally written by David K. Buck.
32 /// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
33 ///
34 /// @endparblock
35 ///
36 //******************************************************************************
37
38 // Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config)
39 #include "core/shape/box.h"
40
41 #include "base/pov_err.h"
42
43 #include "core/bounding/boundingbox.h"
44 #include "core/math/matrix.h"
45 #include "core/render/ray.h"
46 #include "core/scene/tracethreaddata.h"
47
48 // this must be the last file included
49 #include "base/povdebug.h"
50
51 namespace pov
52 {
53
54 /*****************************************************************************
55 * Local preprocessor defines
56 ******************************************************************************/
57
58 /* Minimal intersection depth. */
59
60 const DBL DEPTH_TOLERANCE = 1.0e-6;
61
62 /* Two values are equal if their difference is small than CLOSE_TOLERANCE. */
63
64 const DBL CLOSE_TOLERANCE = 1.0e-6;
65
66
67 /*****************************************************************************
68 *
69 * FUNCTION
70 *
71 * All_Box_Intersections
72 *
73 * INPUT
74 *
75 * OUTPUT
76 *
77 * RETURNS
78 *
79 * AUTHOR
80 *
81 * Alexander Enzmann
82 *
83 * DESCRIPTION
84 *
85 * -
86 *
87 * CHANGES
88 *
89 * -
90 *
91 ******************************************************************************/
92
All_Intersections(const Ray & ray,IStack & Depth_Stack,TraceThreadData * Thread)93 bool Box::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadData *Thread)
94 {
95 int Intersection_Found;
96 int Side1, Side2;
97 DBL Depth1, Depth2;
98 Vector3d IPoint;
99
100 Thread->Stats()[Ray_Box_Tests]++;
101
102 Intersection_Found = false;
103
104 if (Intersect(ray, Trans, bounds[0], bounds[1], &Depth1, &Depth2, &Side1, &Side2))
105 {
106 if (Depth1 > DEPTH_TOLERANCE)
107 {
108 IPoint = ray.Evaluate(Depth1);
109
110 if (Clip.empty() || Point_In_Clip(IPoint, Clip, Thread))
111 {
112 Depth_Stack->push(Intersection(Depth1,IPoint,this,Side1));
113
114 Intersection_Found = true;
115 }
116 }
117
118 IPoint = ray.Evaluate(Depth2);
119
120 if (Clip.empty() || Point_In_Clip(IPoint, Clip, Thread))
121 {
122 Depth_Stack->push(Intersection(Depth2,IPoint,this,Side2));
123
124 Intersection_Found = true;
125 }
126 }
127
128 if (Intersection_Found)
129 Thread->Stats()[Ray_Box_Tests_Succeeded]++;
130
131 return (Intersection_Found);
132 }
133
134
135
136 /*****************************************************************************
137 *
138 * FUNCTION
139 *
140 * Intersect_Box
141 *
142 * INPUT
143 *
144 * OUTPUT
145 *
146 * RETURNS
147 *
148 * AUTHOR
149 *
150 * Alexander Enzmann
151 *
152 * DESCRIPTION
153 *
154 * -
155 *
156 * CHANGES
157 *
158 * Sep 1994 : Added code to decide which side was hit in the case
159 * intersection points are close to each other. This removes
160 * some ugly artefacts one could observe at the corners of
161 * boxes due to the usage of the wrong normal vector. [DB]
162 *
163 ******************************************************************************/
164
Intersect(const BasicRay & ray,const TRANSFORM * Trans,const Vector3d & Corner1,const Vector3d & Corner2,DBL * Depth1,DBL * Depth2,int * Side1,int * Side2)165 bool Box::Intersect(const BasicRay& ray, const TRANSFORM *Trans, const Vector3d& Corner1, const Vector3d& Corner2, DBL *Depth1, DBL *Depth2, int *Side1, int *Side2)
166 {
167 int smin = 0, smax = 0; /* Side hit for min/max intersection. */
168 DBL t, tmin, tmax;
169 Vector3d P, D;
170
171 /* Transform the point into the boxes space */
172
173 if (Trans != nullptr)
174 {
175 MInvTransPoint(P, ray.Origin, Trans);
176 MInvTransDirection(D, ray.Direction, Trans);
177 }
178 else
179 {
180 P = ray.Origin;
181 D = ray.Direction;
182 }
183
184 tmin = 0.0;
185 tmax = BOUND_HUGE;
186
187 /*
188 * Sides first.
189 */
190
191 if (D[X] < -EPSILON)
192 {
193 t = (Corner1[X] - P[X]) / D[X];
194
195 if (t < tmin) return(false);
196
197 if (t <= tmax)
198 {
199 smax = kSideHit_X0;
200 tmax = t;
201 }
202
203 t = (Corner2[X] - P[X]) / D[X];
204
205 if (t >= tmin)
206 {
207 if (t > tmax) return(false);
208
209 smin = kSideHit_X1;
210 tmin = t;
211 }
212 }
213 else
214 {
215 if (D[X] > EPSILON)
216 {
217 t = (Corner2[X] - P[X]) / D[X];
218
219 if (t < tmin) return(false);
220
221 if (t <= tmax)
222 {
223 smax = kSideHit_X1;
224 tmax = t;
225 }
226
227 t = (Corner1[X] - P[X]) / D[X];
228
229 if (t >= tmin)
230 {
231 if (t > tmax) return(false);
232
233 smin = kSideHit_X0;
234 tmin = t;
235 }
236 }
237 else
238 {
239 if ((P[X] < Corner1[X]) || (P[X] > Corner2[X]))
240 {
241 return(false);
242 }
243 }
244 }
245
246 /*
247 * Check Top/Bottom.
248 */
249
250 if (D[Y] < -EPSILON)
251 {
252 t = (Corner1[Y] - P[Y]) / D[Y];
253
254 if (t < tmin) return(false);
255
256 if (t <= tmax - CLOSE_TOLERANCE)
257 {
258 smax = kSideHit_Y0;
259 tmax = t;
260 }
261 else
262 {
263 /*
264 * If intersection points are close to each other find out
265 * which side to use, i.e. is most probably hit. [DB 9/94]
266 */
267
268 if (t <= tmax + CLOSE_TOLERANCE)
269 {
270 if (-D[Y] > fabs(D[X])) smax = kSideHit_Y0;
271 }
272 }
273
274 t = (Corner2[Y] - P[Y]) / D[Y];
275
276 if (t >= tmin + CLOSE_TOLERANCE)
277 {
278 if (t > tmax) return(false);
279
280 smin = kSideHit_Y1;
281 tmin = t;
282 }
283 else
284 {
285 /*
286 * If intersection points are close to each other find out
287 * which side to use, i.e. is most probably hit. [DB 9/94]
288 */
289
290 if (t >= tmin - CLOSE_TOLERANCE)
291 {
292 if (-D[Y] > fabs(D[X])) smin = kSideHit_Y1;
293 }
294 }
295 }
296 else
297 {
298 if (D[Y] > EPSILON)
299 {
300 t = (Corner2[Y] - P[Y]) / D[Y];
301
302 if (t < tmin) return(false);
303
304 if (t <= tmax - CLOSE_TOLERANCE)
305 {
306 smax = kSideHit_Y1;
307 tmax = t;
308 }
309 else
310 {
311 /*
312 * If intersection points are close to each other find out
313 * which side to use, i.e. is most probably hit. [DB 9/94]
314 */
315
316 if (t <= tmax + CLOSE_TOLERANCE)
317 {
318 if (D[Y] > fabs(D[X])) smax = kSideHit_Y1;
319 }
320 }
321
322 t = (Corner1[Y] - P[Y]) / D[Y];
323
324 if (t >= tmin + CLOSE_TOLERANCE)
325 {
326 if (t > tmax) return(false);
327
328 smin = kSideHit_Y0;
329 tmin = t;
330 }
331 else
332 {
333 /*
334 * If intersection points are close to each other find out
335 * which side to use, i.e. is most probably hit. [DB 9/94]
336 */
337
338 if (t >= tmin - CLOSE_TOLERANCE)
339 {
340 if (D[Y] > fabs(D[X])) smin = kSideHit_Y0;
341 }
342 }
343 }
344 else
345 {
346 if ((P[Y] < Corner1[Y]) || (P[Y] > Corner2[Y]))
347 {
348 return(false);
349 }
350 }
351 }
352
353 /* Now front/back */
354
355 if (D[Z] < -EPSILON)
356 {
357 t = (Corner1[Z] - P[Z]) / D[Z];
358
359 if (t < tmin) return(false);
360
361 if (t <= tmax - CLOSE_TOLERANCE)
362 {
363 smax = kSideHit_Z0;
364 tmax = t;
365 }
366 else
367 {
368 /*
369 * If intersection points are close to each other find out
370 * which side to use, i.e. is most probably hit. [DB 9/94]
371 */
372
373 if (t <= tmax + CLOSE_TOLERANCE)
374 {
375 switch (smax)
376 {
377 case kSideHit_X0 :
378 case kSideHit_X1 : if (-D[Z] > fabs(D[X])) smax = kSideHit_Z0; break;
379
380 case kSideHit_Y0 :
381 case kSideHit_Y1 : if (-D[Z] > fabs(D[Y])) smax = kSideHit_Z0; break;
382 }
383 }
384 }
385
386 t = (Corner2[Z] - P[Z]) / D[Z];
387
388 if (t >= tmin + CLOSE_TOLERANCE)
389 {
390 if (t > tmax) return(false);
391
392 smin = kSideHit_Z1;
393 tmin = t;
394 }
395 else
396 {
397 /*
398 * If intersection points are close to each other find out
399 * which side to use, i.e. is most probably hit. [DB 9/94]
400 */
401
402 if (t >= tmin - CLOSE_TOLERANCE)
403 {
404 switch (smin)
405 {
406 case kSideHit_X0 :
407 case kSideHit_X1 : if (-D[Z] > fabs(D[X])) smin = kSideHit_Z1; break;
408
409 case kSideHit_Y0 :
410 case kSideHit_Y1 : if (-D[Z] > fabs(D[Y])) smin = kSideHit_Z1; break;
411 }
412 }
413 }
414 }
415 else
416 {
417 if (D[Z] > EPSILON)
418 {
419 t = (Corner2[Z] - P[Z]) / D[Z];
420
421 if (t < tmin) return(false);
422
423 if (t <= tmax - CLOSE_TOLERANCE)
424 {
425 smax = kSideHit_Z1;
426 tmax = t;
427 }
428 else
429 {
430 /*
431 * If intersection points are close to each other find out
432 * which side to use, i.e. is most probably hit. [DB 9/94]
433 */
434
435 if (t <= tmax + CLOSE_TOLERANCE)
436 {
437 switch (smax)
438 {
439 case kSideHit_X0 :
440 case kSideHit_X1 : if (D[Z] > fabs(D[X])) smax = kSideHit_Z1; break;
441
442 case kSideHit_Y0 :
443 case kSideHit_Y1 : if (D[Z] > fabs(D[Y])) smax = kSideHit_Z1; break;
444 }
445 }
446 }
447
448 t = (Corner1[Z] - P[Z]) / D[Z];
449
450 if (t >= tmin + CLOSE_TOLERANCE)
451 {
452 if (t > tmax) return(false);
453
454 smin = kSideHit_Z0;
455 tmin = t;
456 }
457 else
458 {
459 /*
460 * If intersection points are close to each other find out
461 * which side to use, i.e. is most probably hit. [DB 9/94]
462 */
463
464 if (t >= tmin - CLOSE_TOLERANCE)
465 {
466 switch (smin)
467 {
468 case kSideHit_X0 :
469 case kSideHit_X1 : if (D[Z] > fabs(D[X])) smin = kSideHit_Z0; break;
470
471 case kSideHit_Y0 :
472 case kSideHit_Y1 : if (D[Z] > fabs(D[Y])) smin = kSideHit_Z0; break;
473 }
474 }
475 }
476 }
477 else
478 {
479 if ((P[Z] < Corner1[Z]) || (P[Z] > Corner2[Z]))
480 {
481 return(false);
482 }
483 }
484 }
485
486 if (tmax < DEPTH_TOLERANCE)
487 {
488 return (false);
489 }
490
491 *Depth1 = tmin;
492 *Depth2 = tmax;
493
494 *Side1 = smin;
495 *Side2 = smax;
496
497 return(true);
498 }
499
500
501
502 /*****************************************************************************
503 *
504 * FUNCTION
505 *
506 * Inside_Box
507 *
508 * INPUT
509 *
510 * OUTPUT
511 *
512 * RETURNS
513 *
514 * AUTHOR
515 *
516 * Alexander Enzmann
517 *
518 * DESCRIPTION
519 *
520 * -
521 *
522 * CHANGES
523 *
524 * -
525 *
526 ******************************************************************************/
527
Inside(const Vector3d & IPoint,TraceThreadData * Thread) const528 bool Box::Inside(const Vector3d& IPoint, TraceThreadData *Thread) const
529 {
530 Vector3d New_Point;
531
532 /* Transform the point into box space. */
533
534 if (Trans != nullptr)
535 {
536 MInvTransPoint(New_Point, IPoint, Trans);
537 }
538 else
539 {
540 New_Point = IPoint;
541 }
542
543 /* Test to see if we are outside the box. */
544
545 if ((New_Point[X] < bounds[0][X]) || (New_Point[X] > bounds[1][X]))
546 {
547 return (Test_Flag(this, INVERTED_FLAG));
548 }
549
550 if ((New_Point[Y] < bounds[0][Y]) || (New_Point[Y] > bounds[1][Y]))
551 {
552 return (Test_Flag(this, INVERTED_FLAG));
553 }
554
555 if ((New_Point[Z] < bounds[0][Z]) || (New_Point[Z] > bounds[1][Z]))
556 {
557 return (Test_Flag(this, INVERTED_FLAG));
558 }
559
560 /* Inside the box. */
561
562 return (!Test_Flag(this, INVERTED_FLAG));
563 }
564
565
566
567 /*****************************************************************************
568 *
569 * FUNCTION
570 *
571 * Box_Normal
572 *
573 * INPUT
574 *
575 * OUTPUT
576 *
577 * RETURNS
578 *
579 * AUTHOR
580 *
581 * Alexander Enzmann
582 *
583 * DESCRIPTION
584 *
585 * -
586 *
587 * CHANGES
588 *
589 * -
590 *
591 ******************************************************************************/
592
Normal(Vector3d & Result,Intersection * Inter,TraceThreadData * Thread) const593 void Box::Normal(Vector3d& Result, Intersection *Inter, TraceThreadData *Thread) const
594 {
595 switch (Inter->i1)
596 {
597 case kSideHit_X0: Result = Vector3d(-1.0, 0.0, 0.0); break;
598 case kSideHit_X1: Result = Vector3d( 1.0, 0.0, 0.0); break;
599 case kSideHit_Y0: Result = Vector3d( 0.0, -1.0, 0.0); break;
600 case kSideHit_Y1: Result = Vector3d( 0.0, 1.0, 0.0); break;
601 case kSideHit_Z0: Result = Vector3d( 0.0, 0.0, -1.0); break;
602 case kSideHit_Z1: Result = Vector3d( 0.0, 0.0, 1.0); break;
603
604 default: throw POV_EXCEPTION_STRING("Unknown box side in Box_Normal().");
605 }
606
607 /* Transform the point into the boxes space. */
608
609 if (Trans != nullptr)
610 {
611 MTransNormal(Result, Result, Trans);
612
613 Result.normalize();
614 }
615 }
616
617
618
619 /*****************************************************************************
620 *
621 * FUNCTION
622 *
623 * Translate_Box
624 *
625 * INPUT
626 *
627 * OUTPUT
628 *
629 * RETURNS
630 *
631 * AUTHOR
632 *
633 * Alexander Enzmann
634 *
635 * DESCRIPTION
636 *
637 * -
638 *
639 * CHANGES
640 *
641 * -
642 *
643 ******************************************************************************/
644
Translate(const Vector3d & Vector,const TRANSFORM * tr)645 void Box::Translate(const Vector3d& Vector, const TRANSFORM *tr)
646 {
647 if (Trans == nullptr)
648 {
649 bounds[0] += Vector;
650
651 bounds[1] += Vector;
652
653 Compute_BBox();
654 }
655 else
656 {
657 Transform(tr);
658 }
659 }
660
661
662
663 /*****************************************************************************
664 *
665 * FUNCTION
666 *
667 * Rotate_Box
668 *
669 * INPUT
670 *
671 * OUTPUT
672 *
673 * RETURNS
674 *
675 * AUTHOR
676 *
677 * Alexander Enzmann
678 *
679 * DESCRIPTION
680 *
681 * -
682 *
683 * CHANGES
684 *
685 * -
686 *
687 ******************************************************************************/
688
Rotate(const Vector3d &,const TRANSFORM * tr)689 void Box::Rotate(const Vector3d&, const TRANSFORM *tr)
690 {
691 Transform(tr);
692 }
693
694
695
696 /*****************************************************************************
697 *
698 * FUNCTION
699 *
700 * Scale_Box
701 *
702 * INPUT
703 *
704 * OUTPUT
705 *
706 * RETURNS
707 *
708 * AUTHOR
709 *
710 * Alexander Enzmann
711 *
712 * DESCRIPTION
713 *
714 * -
715 *
716 * CHANGES
717 *
718 * -
719 *
720 ******************************************************************************/
721
Scale(const Vector3d & Vector,const TRANSFORM * tr)722 void Box::Scale(const Vector3d& Vector, const TRANSFORM *tr)
723 {
724 DBL temp;
725
726 if (Trans == nullptr)
727 {
728 bounds[0] *= Vector;
729 bounds[1] *= Vector;
730
731 if (bounds[0][X] > bounds[1][X])
732 {
733 temp = bounds[0][X];
734
735 bounds[0][X] = bounds[1][X];
736 bounds[1][X] = temp;
737 }
738
739 if (bounds[0][Y] > bounds[1][Y])
740 {
741 temp = bounds[0][Y];
742
743 bounds[0][Y] = bounds[1][Y];
744 bounds[1][Y] = temp;
745 }
746
747 if (bounds[0][Z] > bounds[1][Z])
748 {
749 temp = bounds[0][Z];
750
751 bounds[0][Z] = bounds[1][Z];
752 bounds[1][Z] = temp;
753 }
754
755 Compute_BBox();
756 }
757 else
758 {
759 Transform(tr);
760 }
761 }
762
763
764
765 /*****************************************************************************
766 *
767 * FUNCTION
768 *
769 * Transform_Box
770 *
771 * INPUT
772 *
773 * OUTPUT
774 *
775 * RETURNS
776 *
777 * AUTHOR
778 *
779 * Alexander Enzmann
780 *
781 * DESCRIPTION
782 *
783 * -
784 *
785 * CHANGES
786 *
787 * -
788 *
789 ******************************************************************************/
790
Transform(const TRANSFORM * tr)791 void Box::Transform(const TRANSFORM *tr)
792 {
793 if (Trans == nullptr)
794 Trans = Create_Transform();
795
796 Compose_Transforms(Trans, tr);
797
798 Compute_BBox();
799 }
800
801
802
803 /*****************************************************************************
804 *
805 * FUNCTION
806 *
807 * Create_Box
808 *
809 * INPUT
810 *
811 * OUTPUT
812 *
813 * RETURNS
814 *
815 * AUTHOR
816 *
817 * Alexander Enzmann
818 *
819 * DESCRIPTION
820 *
821 * -
822 *
823 * CHANGES
824 *
825 * -
826 *
827 ******************************************************************************/
828
Box()829 Box::Box() : ObjectBase(BOX_OBJECT)
830 {
831 bounds[0] = Vector3d(-1.0, -1.0, -1.0);
832 bounds[1] = Vector3d( 1.0, 1.0, 1.0);
833
834 Make_BBox(BBox, -1.0, -1.0, -1.0, 2.0, 2.0, 2.0);
835
836 Trans = nullptr;
837 }
838
839
840
841 /*****************************************************************************
842 *
843 * FUNCTION
844 *
845 * Copy_Box
846 *
847 * INPUT
848 *
849 * OUTPUT
850 *
851 * RETURNS
852 *
853 * AUTHOR
854 *
855 * Alexander Enzmann
856 *
857 * DESCRIPTION
858 *
859 * -
860 *
861 * CHANGES
862 *
863 * -
864 *
865 ******************************************************************************/
866
Copy()867 ObjectPtr Box::Copy()
868 {
869 Box *New = new Box();
870 Destroy_Transform(New->Trans);
871 *New = *this;
872 New->Trans = Copy_Transform(Trans);
873
874 return (New);
875 }
876
877
878
879 /*****************************************************************************
880 *
881 * FUNCTION
882 *
883 * Destroy_Box
884 *
885 * INPUT
886 *
887 * OUTPUT
888 *
889 * RETURNS
890 *
891 * AUTHOR
892 *
893 * Alexander Enzmann
894 *
895 * DESCRIPTION
896 *
897 * -
898 *
899 * CHANGES
900 *
901 * -
902 *
903 ******************************************************************************/
904
~Box()905 Box::~Box()
906 {}
907
908
909
910 /*****************************************************************************
911 *
912 * FUNCTION
913 *
914 * Compute_Box_BBox
915 *
916 * INPUT
917 *
918 * Box - Box
919 *
920 * OUTPUT
921 *
922 * Box
923 *
924 * RETURNS
925 *
926 * AUTHOR
927 *
928 * Dieter Bayer
929 *
930 * DESCRIPTION
931 *
932 * Calculate the bounding box of a box.
933 *
934 * CHANGES
935 *
936 * Aug 1994 : Creation.
937 *
938 ******************************************************************************/
939
Compute_BBox()940 void Box::Compute_BBox()
941 {
942 BBox.lowerLeft = BBoxVector3d(bounds[0]);
943
944 BBox.size = BBoxVector3d(bounds[1] - bounds[0]);
945
946 if (Trans != nullptr)
947 {
948 Recompute_BBox(&BBox, Trans);
949 }
950 }
951
952 /*****************************************************************************
953 *
954 * FUNCTION
955 *
956 * Box_UVCoord
957 *
958 * INPUT
959 *
960 * OUTPUT
961 *
962 * RETURNS
963 *
964 * AUTHOR
965 *
966 * Nathan Kopp, Lutz Kretzschmar
967 *
968 * DESCRIPTION
969 *
970 * +-----+
971 * ^ 4 |
972 * z |
973 * +-----+--x>-#--z>-+-<x--+
974 * | ^ | | |
975 * | 1 y 5 | 2 | 6 |
976 * | | | | |
977 * +-----O--x>-+-----+-----+
978 * | |
979 * | 3 |
980 * +-----+
981 *
982 * planes:
983 * 1: min x 2: max x
984 * 3: min y 4: max y
985 * 5: min z 6: max z
986 *
987 * O : Origin
988 * # : <1,1,0>
989 *
990 * CHANGES
991 *
992 * The code was changed to use somthing similar to environmental cube mappping
993 *
994 * 1 +-----+ #
995 * | |
996 * V z 4 |
997 * | |
998 * .6 +--z>-+--x>-+-<z--+-<x--+
999 * | ^ | | |
1000 * | 1 y 5 | 2 | 6 |
1001 * | | | | |
1002 * .3 +-----+--x>-+-----+-----+
1003 * ^ |
1004 * z 3 |
1005 * | |
1006 * 0 O +-----+
1007 *
1008 * 0 .25 .5 .75 1
1009 * U
1010 *
1011 * planes:
1012 * 1: min x 2: max x
1013 * 3: min y 4: max y
1014 * 5: max z 6: min z
1015 *
1016 * O : Origin of U,V map
1017 * # : <1,1,0>
1018 *
1019 ******************************************************************************/
1020
UVCoord(Vector2d & Result,const Intersection * Inter,TraceThreadData * Thread) const1021 void Box::UVCoord(Vector2d& Result, const Intersection *Inter, TraceThreadData *Thread) const
1022 {
1023 Vector3d P, Box_Diff;
1024
1025 /* Transform the point into the cube's space */
1026 if (Trans != nullptr)
1027 MInvTransPoint(P, Inter->IPoint, Trans);
1028 else
1029 P = Inter->IPoint;
1030
1031 Box_Diff = bounds[1] - bounds[0];
1032
1033 /* this line moves the bottom,left,front corner of the box to <0,0,0> */
1034 P -= bounds[0];
1035 /* this line normalizes the face offsets */
1036 P /= Box_Diff;
1037
1038 /* The following code does a variation of cube environment mapping. All the
1039 textures are not mirrored when the cube is viewed from outside. */
1040
1041 switch (Inter->i1)
1042 {
1043 case kSideHit_X0:
1044 Result[U] = (P[Z] / 4.0);
1045 Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
1046 break;
1047 case kSideHit_X1:
1048 Result[U] = (3.0 / 4.0) - (P[Z] / 4.0);
1049 Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
1050 break;
1051 case kSideHit_Y0:
1052 Result[U] = (1.0 / 4.0) + (P[X] / 4.0);
1053 Result[V] = (P[Z] / 3.0);
1054 break;
1055 case kSideHit_Y1:
1056 Result[U] = (1.0 / 4.0) + (P[X] / 4.0);
1057 Result[V] = (3.0 / 3.0) - (P[Z] / 3.0);
1058 break;
1059 case kSideHit_Z0:
1060 Result[U] = 1.0 - (P[X] / 4.0);
1061 Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
1062 break;
1063 case kSideHit_Z1:
1064 Result[U] = (1.0 / 4.0) + (P[X] / 4.0);
1065 Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
1066 break;
1067
1068 default: throw POV_EXCEPTION_STRING("Unknown box side in Box_Normal().");
1069 }
1070 }
1071
Intersect_BBox(BBoxDirection,const BBoxVector3d &,const BBoxVector3d &,BBoxScalar) const1072 bool Box::Intersect_BBox(BBoxDirection, const BBoxVector3d&, const BBoxVector3d&, BBoxScalar) const
1073 {
1074 return true;
1075 }
1076
1077 }
1078