1 /****************************************************************************
2 * atmosph.cpp
3 *
4 * This module contains all functions for atmospheric effects.
5 *
6 * from Persistence of Vision(tm) Ray Tracer version 3.6.
7 * Copyright 1991-2003 Persistence of Vision Team
8 * Copyright 2003-2004 Persistence of Vision Raytracer Pty. Ltd.
9 *---------------------------------------------------------------------------
10 * NOTICE: This source code file is provided so that users may experiment
11 * with enhancements to POV-Ray and to port the software to platforms other
12 * than those supported by the POV-Ray developers. There are strict rules
13 * regarding how you are permitted to use this file. These rules are contained
14 * in the distribution and derivative versions licenses which should have been
15 * provided with this file.
16 *
17 * These licences may be found online, linked from the end-user license
18 * agreement that is located at http://www.povray.org/povlegal.html
19 *---------------------------------------------------------------------------
20 * This program is based on the popular DKB raytracer version 2.12.
21 * DKBTrace was originally written by David K. Buck.
22 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
23 *---------------------------------------------------------------------------
24 * $File: //depot/povray/3.6-release/source/atmosph.cpp $
25 * $Revision: #3 $
26 * $Change: 3032 $
27 * $DateTime: 2004/08/02 18:43:41 $
28 * $Author: chrisc $
29 * $Log$
30 *****************************************************************************/
31
32 #include "frame.h"
33 #include "vector.h"
34 #include "atmosph.h"
35 #include "chi2.h"
36 #include "colour.h"
37 #include "povray.h"
38 #include "texture.h"
39 #include "pigment.h"
40 #include "objects.h"
41 #include "lighting.h"
42 #include "matrices.h"
43 #include "media.h"
44 #include "texture.h"
45 #include "ray.h"
46 #include "render.h" /* for In_Reflection_Ray */
47 #include "octree.h" /* for radiosit.h */
48 #include "radiosit.h" /* for Radiosity_Trace_Level */
49
50 #include <algorithm>
51
52 BEGIN_POV_NAMESPACE
53
54 /*****************************************************************************
55 * Local preprocessor defines
56 ******************************************************************************/
57
58 /*****************************************************************************
59 * Local typedefs
60 ******************************************************************************/
61
62 /*****************************************************************************
63 * Local variables
64 ******************************************************************************/
65
66 /*****************************************************************************
67 * Static functions
68 ******************************************************************************/
69
70 static DBL constant_fog (RAY *Ray, DBL Depth, DBL Width, FOG *Fog, COLOUR Colour);
71 static DBL ground_fog (RAY *Ray, DBL Depth, DBL Width, FOG *Fog, COLOUR Colour);
72
73 static void do_fog (RAY *Ray, INTERSECTION *Intersection, COLOUR Colour, int Light_Ray_Flag);
74 static void do_rainbow (RAY *Ray, INTERSECTION *Intersection, COLOUR Colour);
75 static void do_skysphere (RAY *Ray, COLOUR Colour);
76
77
78
79 /*****************************************************************************
80 *
81 * FUNCTION
82 *
83 * Initialize_Atmosphere_Code
84 *
85 * INPUT
86 *
87 * OUTPUT
88 *
89 * RETURNS
90 *
91 * AUTHOR
92 *
93 * Dieter Bayer
94 *
95 * DESCRIPTION
96 *
97 * Initialize atmosphere specific variables.
98 *
99 * CHANGES
100 *
101 * Aug 1995 : Creation.
102 *
103 ******************************************************************************/
104
Initialize_Atmosphere_Code()105 void Initialize_Atmosphere_Code()
106 {
107 }
108
109
110
111 /*****************************************************************************
112 *
113 * FUNCTION
114 *
115 * Deinitialize_Atmosphere_Code
116 *
117 * INPUT
118 *
119 * OUTPUT
120 *
121 * RETURNS
122 *
123 * AUTHOR
124 *
125 * Dieter Bayer
126 *
127 * DESCRIPTION
128 *
129 * Deinitialize atmosphere specific variables.
130 *
131 * CHANGES
132 *
133 * Aug 1995 : Creation.
134 *
135 ******************************************************************************/
136
Deinitialize_Atmosphere_Code()137 void Deinitialize_Atmosphere_Code()
138 {
139 }
140
141
142
143 /*****************************************************************************
144 *
145 * FUNCTION
146 *
147 * Do_Infinite_Atmosphere
148 *
149 * INPUT
150 *
151 * Ray - Current ray
152 *
153 * OUTPUT
154 *
155 * Colour - Color of the current ray
156 *
157 * RETURNS
158 *
159 * AUTHOR
160 *
161 * Dieter Bayer
162 *
163 * DESCRIPTION
164 *
165 * Apply atmospheric effects to an infinite ray.
166 *
167 * CHANGES
168 *
169 * Feb 1995 : Creation.
170 *
171 * Jun 1995 : Added code for alpha channel support. [DB]
172 *
173 * Feb 2001 : Fixed alpha channel code. [NK]
174 *
175 ******************************************************************************/
176
Do_Infinite_Atmosphere(RAY * Ray,COLOUR Colour)177 void Do_Infinite_Atmosphere(RAY *Ray, COLOUR Colour)
178 {
179 if (opts.Options & OUTPUT_ALPHA &&
180 !(In_Reflection_Ray || (Radiosity_Trace_Level>1)))
181 {
182 /*
183 If we are using the alpha channel, then the background
184 must be black - this is necessary for proper antialiasing
185 of the alpha channel, and assures overall correctness and
186 consistency.
187
188 However, we do want to use the background and sky sphere for radiosity
189 and for reflections.
190 */
191 Colour[pRED] = Colour[pGREEN] = Colour[pBLUE] = Colour[pFILTER] = 0.0;
192 Colour[pTRANSM] = 1.0;
193 }
194 else
195 {
196 /* Set background color. */
197 Assign_Colour(Colour, Frame.Background_Colour);
198
199 Colour[pFILTER] = 0.0;
200 Colour[pTRANSM] = 1.0;
201
202 /* Determine atmospheric effects for infinite ray. */
203 do_skysphere(Ray, Colour);
204 }
205 }
206
207
208
209 /*****************************************************************************
210 *
211 * FUNCTION
212 *
213 * Do_Finite_Atmosphere
214 *
215 * INPUT
216 *
217 * Ray - Current ray
218 * Intersection - Current intersection
219 * Light_Ray_Flag - true if ray is a light source ray
220 *
221 * OUTPUT
222 *
223 * Colour - Color of the current ray
224 *
225 * RETURNS
226 *
227 * AUTHOR
228 *
229 * Dieter Bayer
230 *
231 * DESCRIPTION
232 *
233 * Apply atmospheric effects to a finite ray.
234 *
235 * CHANGES
236 *
237 * Feb 1995 : Creation.
238 *
239 ******************************************************************************/
240
Do_Finite_Atmosphere(RAY * Ray,INTERSECTION * Intersection,COLOUR Colour,int Light_Ray_Flag)241 void Do_Finite_Atmosphere(RAY *Ray, INTERSECTION *Intersection, COLOUR Colour, int Light_Ray_Flag)
242 {
243 IMEDIA *Media_List[2];
244
245 if (!Light_Ray_Flag)
246 {
247 do_rainbow(Ray, Intersection, Colour);
248 }
249
250 Media_List[0] = Frame.Atmosphere;
251 Media_List[1] = NULL;
252
253 Simulate_Media(Media_List, Ray, Intersection, Colour, Light_Ray_Flag);
254
255 do_fog(Ray, Intersection, Colour, Light_Ray_Flag);
256 }
257
258
259
260 /*****************************************************************************
261 *
262 * FUNCTION
263 *
264 * do_fog
265 *
266 * INPUT
267 *
268 * Ray - current ray
269 * Intersection - current intersection
270 * Light_Ray_Flag - true if ray is a light source ray
271 *
272 * OUTPUT
273 *
274 * Colour - color of current ray
275 *
276 * RETURNS
277 *
278 * AUTHOR
279 *
280 * POV-Ray Team
281 *
282 * DESCRIPTION
283 *
284 * Evaluate all fogs for the current ray and intersection.
285 *
286 * CHANGES
287 *
288 * Dec 1994 : Rewritten to allow multiple fogs. [DB]
289 *
290 * Apr 1995 : Added transmittance threshold and filtering. [DB]
291 *
292 * Jun 1995 : Added code for alpha channel support. [DB]
293 *
294 ******************************************************************************/
295
do_fog(RAY * Ray,INTERSECTION * Intersection,COLOUR Colour,int Light_Ray_Flag)296 static void do_fog(RAY *Ray, INTERSECTION *Intersection, COLOUR Colour, int Light_Ray_Flag)
297 {
298 DBL att, att_inv, width;
299 COLOUR Col_Fog;
300 COLOUR sum_att; /* total attenuation. */
301 COLOUR sum_col; /* total color. */
302 FOG *Fog;
303
304 /* Why are we here. */
305
306 if (Frame.Fog == NULL)
307 {
308 return;
309 }
310
311 /* Init total attenuation and total color. */
312
313 Make_ColourA(sum_att, 1.0, 1.0, 1.0, 1.0, 1.0);
314 Make_ColourA(sum_col, 0.0, 0.0, 0.0, 0.0, 0.0);
315
316 /* Loop over all fogs. */
317
318 for (Fog = Frame.Fog; Fog != NULL; Fog = Fog->Next)
319 {
320 /* Don't care about fogs with zero distance. */
321
322 if (fabs(Fog->Distance) > EPSILON)
323 {
324 width = Intersection->Depth;
325
326 switch (Fog->Type)
327 {
328 case GROUND_MIST:
329
330 att = ground_fog(Ray, 0.0, width, Fog, Col_Fog);
331
332 break;
333
334 default:
335
336 att = constant_fog(Ray, 0.0, width, Fog, Col_Fog);
337
338 break;
339 }
340
341 /* Check for minimum transmittance. */
342
343 if (att < Col_Fog[pTRANSM])
344 {
345 att = Col_Fog[pTRANSM];
346 }
347
348 /* Get attenuation sum due to filtered/unfiltered translucency. */
349
350 sum_att[pRED] *= att * ((1.0 - Col_Fog[pFILTER]) + Col_Fog[pFILTER] * Col_Fog[pRED]);
351 sum_att[pGREEN] *= att * ((1.0 - Col_Fog[pFILTER]) + Col_Fog[pFILTER] * Col_Fog[pGREEN]);
352 sum_att[pBLUE] *= att * ((1.0 - Col_Fog[pFILTER]) + Col_Fog[pFILTER] * Col_Fog[pBLUE]);
353 sum_att[pFILTER] *= att * Col_Fog[pFILTER];
354 sum_att[pTRANSM] *= att * Col_Fog[pTRANSM];
355
356 if (!Light_Ray_Flag)
357 {
358 att_inv = 1.0 - att;
359
360 CRGBAddScaledEq(sum_col, att_inv, Col_Fog);
361 }
362 }
363 }
364
365 /* Add light coming from background. */
366
367 Colour[pRED] = sum_col[pRED] + sum_att[pRED] * Colour[pRED];
368 Colour[pGREEN] = sum_col[pGREEN] + sum_att[pGREEN] * Colour[pGREEN];
369 Colour[pBLUE] = sum_col[pBLUE] + sum_att[pBLUE] * Colour[pBLUE];
370 Colour[pTRANSM] *= GREY_SCALE(sum_att);
371 }
372
373
374
375 /*****************************************************************************
376 *
377 * FUNCTION
378 *
379 * do_rainbow
380 *
381 * INPUT
382 *
383 * Ray - Current ray
384 * Intersection - Cuurent intersection
385 *
386 * OUTPUT
387 *
388 * Colour - Current colour
389 *
390 * RETURNS
391 *
392 * AUTHOR
393 *
394 * Dieter Bayer
395 *
396 * DESCRIPTION
397 *
398 * Create a rainbow using an impressionistic model.
399 *
400 * The model was taken from:
401 *
402 * Musgrave, F. Kenton, "Prisms and Rainbows: a Dispersion Model
403 * for Computer Graphics", Proceedings of Graphics Interface '89 -
404 * Vision Interface '89, p. 227-234.
405 *
406 * CHANGES
407 *
408 * Jul 1994 : Creation.
409 *
410 * Dec 1994 : Modified to allow multiple rainbows. [DB]
411 *
412 * Apr 1995 : Added rainbow arcs and filtering. [DB]
413 *
414 * Jun 1995 : Added code for alpha channel support. [DB]
415 *
416 ******************************************************************************/
417
do_rainbow(RAY * Ray,INTERSECTION * Intersection,COLOUR Colour)418 static void do_rainbow(RAY *Ray, INTERSECTION *Intersection, COLOUR Colour)
419 {
420 int n;
421 DBL dot, k, ki, index, x, y, l, angle, fade, f;
422 VECTOR Temp;
423 COLOUR Cr, Ct;
424 RAINBOW *Rainbow;
425
426 /* Why are we here. */
427
428 if (Frame.Rainbow == NULL)
429 {
430 return;
431 }
432
433 Make_ColourA(Ct, 0.0, 0.0, 0.0, 1.0, 1.0);
434
435 n = 0;
436
437 for (Rainbow = Frame.Rainbow; Rainbow != NULL; Rainbow = Rainbow->Next)
438 {
439 if ((Rainbow->Pigment != NULL) && (Rainbow->Distance != 0.0) && (Rainbow->Width != 0.0))
440 {
441 /* Get angle between ray direction and rainbow's up vector. */
442
443 VDot(x, Ray->Direction, Rainbow->Right_Vector);
444 VDot(y, Ray->Direction, Rainbow->Up_Vector);
445
446 l = Sqr(x) + Sqr(y);
447
448 if (l > 0.0)
449 {
450 l = sqrt(l);
451
452 y /= l;
453 }
454
455 angle = fabs(acos(y));
456
457 if (angle <= Rainbow->Arc_Angle)
458 {
459 /* Get dot product between ray direction and antisolar vector. */
460
461 VDot(dot, Ray->Direction, Rainbow->Antisolar_Vector);
462
463 if (dot >= 0.0)
464 {
465 /* Get index ([0;1]) into rainbow's colour map. */
466
467 index = (acos(dot) - Rainbow->Angle) / Rainbow->Width;
468
469 /* Jitter index. */
470
471 if (Rainbow->Jitter > 0.0)
472 {
473 index += (2.0 * FRAND() - 1.0) * Rainbow->Jitter;
474 }
475
476 if ((index >= 0.0) && (index <= 1.0 - EPSILON))
477 {
478 /* Get colour from rainbow's colour map. */
479
480 Make_Vector(Temp, index, 0.0, 0.0);
481
482 Compute_Pigment(Cr, Rainbow->Pigment, Temp, Intersection);
483
484 /* Get fading value for falloff. */
485
486 if ((Rainbow->Falloff_Width > 0.0) && (angle > Rainbow->Falloff_Angle))
487 {
488 fade = (angle - Rainbow->Falloff_Angle) / Rainbow->Falloff_Width;
489
490 fade = (3.0 - 2.0 * fade) * fade * fade;
491 }
492 else
493 {
494 fade = 0.0;
495 }
496
497 /* Get attenuation factor due to distance. */
498
499 k = exp(-Intersection->Depth / Rainbow->Distance);
500
501 /* Colour's transm value is used as minimum attenuation value. */
502
503 k = max(k, fade * (1.0 - Cr[pTRANSM]) + Cr[pTRANSM]);
504
505 /* Now interpolate the colours. */
506
507 ki = 1.0 - k;
508
509 /* Attenuate filter value. */
510
511 f = Cr[pFILTER] * ki;
512
513 Ct[pRED] += k * Colour[pRED] * ((1.0 - f) + f * Cr[pRED]) + ki * Cr[pRED];
514 Ct[pGREEN] += k * Colour[pGREEN] * ((1.0 - f) + f * Cr[pGREEN]) + ki * Cr[pGREEN];
515 Ct[pBLUE] += k * Colour[pBLUE] * ((1.0 - f) + f * Cr[pBLUE]) + ki * Cr[pBLUE];
516 Ct[pFILTER] *= k * Cr[pFILTER];
517 Ct[pTRANSM] *= k * Cr[pTRANSM];
518
519 n++;
520 }
521 }
522 }
523 }
524 }
525
526 if (n > 0)
527 {
528 COLC tmp = 1.0 / n;
529
530 Colour[pRED] = Ct[pRED] * tmp;
531 Colour[pGREEN] = Ct[pGREEN] * tmp;
532 Colour[pBLUE] = Ct[pBLUE] * tmp;
533
534 Colour[pFILTER] *= Ct[pFILTER];
535 Colour[pTRANSM] *= Ct[pTRANSM];
536 }
537 }
538
539
540
541 /*****************************************************************************
542 *
543 * FUNCTION
544 *
545 * do_skysphere
546 *
547 * INPUT
548 *
549 * Ray - Current ray
550 *
551 * OUTPUT
552 *
553 * Colour - Current color
554 *
555 * RETURNS
556 *
557 * AUTHOR
558 *
559 * Dieter Bayer
560 *
561 * DESCRIPTION
562 *
563 * Calculate color of the sky.
564 *
565 * Use the ray direction as a point on the skysphere. Thus the sky can
566 * easily be colored with all kinds of pigments.
567 *
568 * CHANGES
569 *
570 * Jul 1994 : Creation.
571 *
572 * Dec 1994 : Modified to allow layered pigments. [DB]
573 *
574 * Jun 1995 : Added code for alpha channel support. [DB]
575 *
576 ******************************************************************************/
577
do_skysphere(RAY * Ray,COLOUR Colour)578 static void do_skysphere(RAY *Ray, COLOUR Colour)
579 {
580 int i;
581 DBL att, trans;
582 COLOUR Col, Col_Temp, Filter;
583 VECTOR P;
584 SKYSPHERE *Skysphere;
585
586 /* Why are we here. */
587
588 if (Frame.Skysphere == NULL)
589 {
590 return;
591 }
592
593 Make_Colour(Col, 0.0, 0.0, 0.0);
594
595 if (((Skysphere = Frame.Skysphere) != NULL) && (Skysphere->Pigments != NULL))
596 {
597 Make_ColourA(Filter, 1.0, 1.0, 1.0, 1.0, 1.0);
598
599 trans = 1.0;
600
601 /* Transform point on unit sphere. */
602
603 if (Skysphere->Trans != NULL)
604 {
605 MInvTransPoint(P, Ray->Direction, Skysphere->Trans);
606 }
607 else
608 {
609 Assign_Vector(P, Ray->Direction);
610 }
611
612 for (i = Skysphere->Count-1; i >= 0; i--)
613 {
614 /* Compute sky colour from colour map. */
615
616 /* NK 1998 - added NULL as final parameter */
617 Compute_Pigment(Col_Temp, Skysphere->Pigments[i], P, NULL);
618 /* NK ---- */
619
620 att = trans * (1.0 - Col_Temp[pFILTER] - Col_Temp[pTRANSM]);
621
622 CRGBAddScaledEq(Col, att, Col_Temp);
623
624 Filter[pRED] *= Col_Temp[pRED];
625 Filter[pGREEN] *= Col_Temp[pGREEN];
626 Filter[pBLUE] *= Col_Temp[pBLUE];
627 Filter[pFILTER] *= Col_Temp[pFILTER];
628 Filter[pTRANSM] *= Col_Temp[pTRANSM];
629
630 trans = fabs(Filter[pFILTER]) + fabs(Filter[pTRANSM]);
631 }
632
633 Colour[pRED] = Col[pRED] + Colour[pRED] * (Filter[pRED] * Filter[pFILTER] + Filter[pTRANSM]);
634 Colour[pGREEN] = Col[pGREEN] + Colour[pGREEN] * (Filter[pGREEN] * Filter[pFILTER] + Filter[pTRANSM]);
635 Colour[pBLUE] = Col[pBLUE] + Colour[pBLUE] * (Filter[pBLUE] * Filter[pFILTER] + Filter[pTRANSM]);
636 Colour[pFILTER] = Colour[pFILTER] * Filter[pFILTER];
637 Colour[pTRANSM] = Colour[pTRANSM] * Filter[pTRANSM];
638 }
639 }
640
641
642
643 /*****************************************************************************
644 *
645 * FUNCTION
646 *
647 * constant_fog
648 *
649 * INPUT
650 *
651 * Ray - current ray
652 * Depth - intersection depth with fog's boundary
653 * Width - width of the fog along the ray
654 * Fog - current fog
655 *
656 * OUTPUT
657 *
658 * Colour - color of the fog
659 *
660 * RETURNS
661 *
662 * AUTHOR
663 *
664 * POV-Ray Team
665 *
666 * DESCRIPTION
667 *
668 * Apply distance attenuated fog.
669 *
670 * CHANGES
671 *
672 * Dec 1994 : Modified to work with multiple fogs. [DB]
673 *
674 ******************************************************************************/
675
constant_fog(RAY * Ray,DBL Depth,DBL Width,FOG * Fog,COLOUR Colour)676 static DBL constant_fog(RAY *Ray, DBL Depth, DBL Width, FOG *Fog, COLOUR Colour)
677 {
678 DBL k;
679 VECTOR P;
680
681 if (Fog->Turb != NULL)
682 {
683 Depth += Width / 2.0;
684
685 VEvaluateRay(P, Ray->Initial, Depth, Ray->Direction);
686
687 VEvaluateEq(P, Fog->Turb->Turbulence);
688
689 /* The further away the less influence turbulence has. */
690
691 k = exp(-Width / Fog->Distance);
692
693 Width *= 1.0 - k * min(1.0, Turbulence(P, Fog->Turb, NULL)*Fog->Turb_Depth);
694 }
695
696 Assign_Colour(Colour, Fog->Colour);
697
698 return (exp(-Width / Fog->Distance));
699 }
700
701
702
703 /*****************************************************************************
704 *
705 * FUNCTION
706 *
707 * ground_fog
708 *
709 * INPUT
710 *
711 * Ray - current ray
712 * Depth - intersection depth with fog's boundary
713 * Width - width of the fog along the ray
714 * Fog - current fog
715 *
716 * OUTPUT
717 *
718 * Colour - color of the fog
719 *
720 * RETURNS
721 *
722 * AUTHOR
723 *
724 * Eric Barish
725 *
726 * DESCRIPTION
727 *
728 * Here is an ascii graph of the ground fog density, it has a maximum
729 * density of 1.0 at Y <= 0, and approaches 0.0 as Y goes up:
730 *
731 * ***********************************
732 * | | | ****
733 * | | | ***
734 * | | | ***
735 * | | | | ****
736 * | | | | *****
737 * | | | | *******
738 * -----+-----------+------------+------------+-----------+-----
739 * Y=-2 Y=-1 Y=0 Y=1 Y=2
740 *
741 * ground fog density is 1 / (Y*Y+1) for Y >= 0 and equals 1.0 for Y <= 0.
742 * (It behaves like regular fog for Y <= 0.)
743 *
744 * The integral of the density is atan(Y) (for Y >= 0).
745 *
746 * CHANGES
747 *
748 * Feb 1996 : Changed to behave like normal fog for Y <= 0.
749 * Fixed bug with reversed offset effect. [DB]
750 *
751 ******************************************************************************/
752
ground_fog(RAY * Ray,DBL Depth,DBL Width,FOG * Fog,COLOUR Colour)753 static DBL ground_fog(RAY *Ray, DBL Depth, DBL Width, FOG *Fog, COLOUR Colour)
754 {
755 DBL fog_density, delta;
756 DBL start, end;
757 DBL y1, y2, k;
758 VECTOR P, P1, P2;
759
760 /* Get start point. */
761
762 VEvaluateRay(P1, Ray->Initial, Depth, Ray->Direction);
763
764 /* Get end point. */
765
766 VLinComb2(P2, 1.0, P1, Width, Ray->Direction);
767
768 /*
769 * Could preform transfomation here to translate Start and End
770 * points into ground fog space.
771 */
772
773 VDot(y1, P1, Fog->Up);
774 VDot(y2, P2, Fog->Up);
775
776 start = (y1 - Fog->Offset) / Fog->Alt;
777 end = (y2 - Fog->Offset) / Fog->Alt;
778
779 /* Get integral along y-axis from start to end. */
780
781 if (start <= 0.0)
782 {
783 if (end <= 0.0)
784 {
785 fog_density = 1.0;
786 }
787 else
788 {
789 fog_density = (atan(end) - start) / (end - start);
790 }
791 }
792 else
793 {
794 if (end <= 0.0)
795 {
796 fog_density = (atan(start) - end) / (start - end);
797 }
798 else
799 {
800 delta = start - end;
801
802 if (fabs(delta) > EPSILON)
803 {
804 fog_density = (atan(start) - atan(end)) / delta;
805 }
806 else
807 {
808 fog_density = 1.0 / (Sqr(start) + 1.0);
809 }
810 }
811 }
812
813 /* Apply turbulence. */
814
815 if (Fog->Turb != NULL)
816 {
817 VHalf(P, P1, P2);
818
819 VEvaluateEq(P, Fog->Turb->Turbulence);
820
821 /* The further away the less influence turbulence has. */
822
823 k = exp(-Width / Fog->Distance);
824
825 Width *= 1.0 - k * min(1.0, Turbulence(P, Fog->Turb, NULL)*Fog->Turb_Depth);
826 }
827
828 Assign_Colour(Colour, Fog->Colour);
829
830 return (exp(-Width * fog_density / Fog->Distance));
831 }
832
833
834
835 /*****************************************************************************
836 *
837 * FUNCTION
838 *
839 * Create_Fog
840 *
841 * INPUT
842 *
843 * OUTPUT
844 *
845 * RETURNS
846 *
847 * FOG * - created fog
848 *
849 * AUTHOR
850 *
851 * Dieter Bayer
852 *
853 * DESCRIPTION
854 *
855 * Create a fog.
856 *
857 * CHANGES
858 *
859 * Dec 1994 : Creation.
860 *
861 ******************************************************************************/
862
Create_Fog()863 FOG *Create_Fog()
864 {
865 FOG *New;
866
867 New = (FOG *)POV_MALLOC(sizeof(FOG), "fog");
868
869 New->Type = ORIG_FOG;
870
871 New->Distance = 0.0;
872 New->Alt = 0.0;
873 New->Offset = 0.0;
874
875 Make_ColourA(New->Colour, 0.0, 0.0, 0.0, 0.0, 0.0);
876
877 Make_Vector(New->Up, 0.0, 1.0, 0.0);
878
879 New->Turb = NULL;
880 New->Turb_Depth = 0.5;
881
882 New->Next = NULL;
883
884 return (New);
885 }
886
887
888
889 /*****************************************************************************
890 *
891 * FUNCTION
892 *
893 * Copy_Fog
894 *
895 * INPUT
896 *
897 * Old - fog to copy
898 *
899 * OUTPUT
900 *
901 * RETURNS
902 *
903 * FOG * - new fog
904 *
905 * AUTHOR
906 *
907 * Dieter Bayer
908 *
909 * DESCRIPTION
910 *
911 * Copy a fog.
912 *
913 * CHANGES
914 *
915 * Dec 1994 : Creation.
916 *
917 ******************************************************************************/
918
Copy_Fog(FOG * Old)919 FOG *Copy_Fog(FOG *Old)
920 {
921 FOG *New;
922
923 New = Create_Fog();
924
925 *New = *Old;
926
927 New->Turb = (TURB *)Copy_Warps(((WARP *)Old->Turb));
928
929 return (New);
930 }
931
932
933
934 /*****************************************************************************
935 *
936 * FUNCTION
937 *
938 * Destroy_Fog
939 *
940 * INPUT
941 *
942 * Fog - fog to destroy
943 *
944 * OUTPUT
945 *
946 * RETURNS
947 *
948 * AUTHOR
949 *
950 * Dieter Bayer
951 *
952 * DESCRIPTION
953 *
954 * Destroy a fog.
955 *
956 * CHANGES
957 *
958 * Dec 1994 : Creation.
959 *
960 ******************************************************************************/
961
Destroy_Fog(FOG * Fog)962 void Destroy_Fog(FOG *Fog)
963 {
964 if (Fog != NULL)
965 {
966 Destroy_Turb(Fog->Turb);
967
968 POV_FREE(Fog);
969 }
970 }
971
972
973
974 /*****************************************************************************
975 *
976 * FUNCTION
977 *
978 * Create_Rainbow
979 *
980 * INPUT
981 *
982 * OUTPUT
983 *
984 * RETURNS
985 *
986 * RAINBOW * - created rainbow
987 *
988 * AUTHOR
989 *
990 * Dieter Bayer
991 *
992 * DESCRIPTION
993 *
994 * Create a rainbow.
995 *
996 * CHANGES
997 *
998 * Dec 1994 : Creation.
999 *
1000 ******************************************************************************/
1001
Create_Rainbow()1002 RAINBOW *Create_Rainbow()
1003 {
1004 RAINBOW *New;
1005
1006 New = (RAINBOW *)POV_MALLOC(sizeof(RAINBOW), "fog");
1007
1008 New->Distance = Max_Distance;
1009 New->Jitter = 0.0;
1010 New->Angle = 0.0;
1011 New->Width = 0.0;
1012
1013 New->Falloff_Width = 0.0;
1014 New->Arc_Angle = 180.0;
1015 New->Falloff_Angle = 180.0;
1016
1017 New->Pigment = NULL;
1018
1019 Make_Vector(New->Antisolar_Vector, 0.0, 0.0, 0.0);
1020
1021 Make_Vector(New->Right_Vector, 1.0, 0.0, 0.0);
1022 Make_Vector(New->Up_Vector, 0.0, 1.0, 0.0);
1023
1024 New->Next = NULL;
1025
1026 return (New);
1027 }
1028
1029
1030
1031 /*****************************************************************************
1032 *
1033 * FUNCTION
1034 *
1035 * Copy_Rainbow
1036 *
1037 * INPUT
1038 *
1039 * Old - rainbow to copy
1040 *
1041 * OUTPUT
1042 *
1043 * RETURNS
1044 *
1045 * RAINBOW * - new rainbow
1046 *
1047 * AUTHOR
1048 *
1049 * Dieter Bayer
1050 *
1051 * DESCRIPTION
1052 *
1053 * Copy a rainbow.
1054 *
1055 * CHANGES
1056 *
1057 * Dec 1994 : Creation.
1058 *
1059 ******************************************************************************/
1060
Copy_Rainbow(RAINBOW * Old)1061 RAINBOW *Copy_Rainbow(RAINBOW *Old)
1062 {
1063 RAINBOW *New;
1064
1065 New = Create_Rainbow();
1066
1067 *New = *Old;
1068
1069 return (New);
1070 }
1071
1072
1073
1074 /*****************************************************************************
1075 *
1076 * FUNCTION
1077 *
1078 * Destroy_Rainbow
1079 *
1080 * INPUT
1081 *
1082 * Rainbow - rainbow to destroy
1083 *
1084 * OUTPUT
1085 *
1086 * RETURNS
1087 *
1088 * AUTHOR
1089 *
1090 * Dieter Bayer
1091 *
1092 * DESCRIPTION
1093 *
1094 * Destroy a rainbow.
1095 *
1096 * CHANGES
1097 *
1098 * Dec 1994 : Creation.
1099 *
1100 ******************************************************************************/
1101
Destroy_Rainbow(RAINBOW * Rainbow)1102 void Destroy_Rainbow(RAINBOW *Rainbow)
1103 {
1104 if (Rainbow != NULL)
1105 {
1106 Destroy_Pigment(Rainbow->Pigment);
1107
1108 POV_FREE(Rainbow);
1109 }
1110 }
1111
1112
1113
1114 /*****************************************************************************
1115 *
1116 * FUNCTION
1117 *
1118 * Create_Skysphere
1119 *
1120 * INPUT
1121 *
1122 * OUTPUT
1123 *
1124 * RETURNS
1125 *
1126 * SKYSPHERE * - created skysphere
1127 *
1128 * AUTHOR
1129 *
1130 * Dieter Bayer
1131 *
1132 * DESCRIPTION
1133 *
1134 * Create a skysphere.
1135 *
1136 * CHANGES
1137 *
1138 * Dec 1994 : Creation.
1139 *
1140 ******************************************************************************/
1141
Create_Skysphere()1142 SKYSPHERE *Create_Skysphere()
1143 {
1144 SKYSPHERE *New;
1145
1146 New = (SKYSPHERE *)POV_MALLOC(sizeof(SKYSPHERE), "fog");
1147
1148 New->Count = 0;
1149
1150 New->Pigments = NULL;
1151
1152 New->Trans = Create_Transform();
1153
1154 return (New);
1155 }
1156
1157
1158
1159 /*****************************************************************************
1160 *
1161 * FUNCTION
1162 *
1163 * Copy_Skysphere
1164 *
1165 * INPUT
1166 *
1167 * Old - skysphere to copy
1168 *
1169 * OUTPUT
1170 *
1171 * RETURNS
1172 *
1173 * SKYSPHERE * - copied skysphere
1174 *
1175 * AUTHOR
1176 *
1177 * Dieter Bayer
1178 *
1179 * DESCRIPTION
1180 *
1181 * Copy a skysphere.
1182 *
1183 * CHANGES
1184 *
1185 * Dec 1994 : Creation.
1186 *
1187 ******************************************************************************/
1188
Copy_Skysphere(SKYSPHERE * Old)1189 SKYSPHERE *Copy_Skysphere(SKYSPHERE *Old)
1190 {
1191 int i;
1192 SKYSPHERE *New;
1193
1194 New = Create_Skysphere();
1195
1196 Destroy_Transform(New->Trans);
1197
1198 *New = *Old;
1199
1200 New->Trans = Copy_Transform(Old->Trans);
1201
1202 if (New->Count > 0)
1203 {
1204 New->Pigments = (PIGMENT **)POV_MALLOC(New->Count*sizeof(PIGMENT *), "skysphere pigment");
1205
1206 for (i = 0; i < New->Count; i++)
1207 {
1208 New->Pigments[i] = Copy_Pigment(Old->Pigments[i]);
1209 }
1210 }
1211
1212 return (New);
1213 }
1214
1215
1216
1217 /*****************************************************************************
1218 *
1219 * FUNCTION
1220 *
1221 * Destroy_Skysphere
1222 *
1223 * INPUT
1224 *
1225 * Skysphere - skysphere to destroy
1226 *
1227 * OUTPUT
1228 *
1229 * RETURNS
1230 *
1231 * AUTHOR
1232 *
1233 * Dieter Bayer
1234 *
1235 * DESCRIPTION
1236 *
1237 * Destroy a skysphere.
1238 *
1239 * CHANGES
1240 *
1241 * Dec 1994 : Creation.
1242 *
1243 ******************************************************************************/
1244
Destroy_Skysphere(SKYSPHERE * Skysphere)1245 void Destroy_Skysphere(SKYSPHERE *Skysphere)
1246 {
1247 int i;
1248
1249 if (Skysphere != NULL)
1250 {
1251 for (i = 0; i < Skysphere->Count; i++)
1252 {
1253 Destroy_Pigment(Skysphere->Pigments[i]);
1254 }
1255
1256 POV_FREE(Skysphere->Pigments);
1257
1258 Destroy_Transform(Skysphere->Trans);
1259
1260 POV_FREE(Skysphere);
1261 }
1262 }
1263
1264
1265
1266 /*****************************************************************************
1267 *
1268 * FUNCTION
1269 *
1270 * Rotate_Skysphere
1271 *
1272 * INPUT
1273 *
1274 * Vector - Rotation vector
1275 *
1276 * OUTPUT
1277 *
1278 * Skysphere - Pointer to skysphere structure
1279 *
1280 * RETURNS
1281 *
1282 * AUTHOR
1283 *
1284 * Dieter Bayer
1285 *
1286 * DESCRIPTION
1287 *
1288 * Rotate a skysphere.
1289 *
1290 * CHANGES
1291 *
1292 * Feb 1996 : Creation.
1293 *
1294 ******************************************************************************/
1295
Rotate_Skysphere(SKYSPHERE * Skysphere,VECTOR Vector)1296 void Rotate_Skysphere(SKYSPHERE *Skysphere, VECTOR Vector)
1297 {
1298 TRANSFORM Trans;
1299
1300 Compute_Rotation_Transform(&Trans, Vector);
1301
1302 Transform_Skysphere(Skysphere, &Trans);
1303 }
1304
1305
1306
1307 /*****************************************************************************
1308 *
1309 * FUNCTION
1310 *
1311 * Scale_Skysphere
1312 *
1313 * INPUT
1314 *
1315 * Vector - Scaling vector
1316 *
1317 * OUTPUT
1318 *
1319 * Skysphere - Pointer to skysphere structure
1320 *
1321 * RETURNS
1322 *
1323 * AUTHOR
1324 *
1325 * Dieter Bayer
1326 *
1327 * DESCRIPTION
1328 *
1329 * Scale a skysphere.
1330 *
1331 * CHANGES
1332 *
1333 * Feb 1996 : Creation.
1334 *
1335 ******************************************************************************/
1336
Scale_Skysphere(SKYSPHERE * Skysphere,VECTOR Vector)1337 void Scale_Skysphere(SKYSPHERE *Skysphere, VECTOR Vector)
1338 {
1339 TRANSFORM Trans;
1340
1341 Compute_Scaling_Transform(&Trans, Vector);
1342
1343 Transform_Skysphere(Skysphere, &Trans);
1344 }
1345
1346
1347
1348 /*****************************************************************************
1349 *
1350 * FUNCTION
1351 *
1352 * Translate_Skysphere
1353 *
1354 * INPUT
1355 *
1356 * Vector - Translation vector
1357 *
1358 * OUTPUT
1359 *
1360 * Skysphere - Pointer to skysphere structure
1361 *
1362 * RETURNS
1363 *
1364 * AUTHOR
1365 *
1366 * Dieter Bayer
1367 *
1368 * DESCRIPTION
1369 *
1370 * Translate a skysphere.
1371 *
1372 * CHANGES
1373 *
1374 * Feb 1996 : Creation.
1375 *
1376 ******************************************************************************/
1377
Translate_Skysphere(SKYSPHERE * Skysphere,VECTOR Vector)1378 void Translate_Skysphere(SKYSPHERE *Skysphere, VECTOR Vector)
1379 {
1380 TRANSFORM Trans;
1381
1382 Compute_Translation_Transform(&Trans, Vector);
1383
1384 Transform_Skysphere(Skysphere, &Trans);
1385 }
1386
1387
1388
1389 /*****************************************************************************
1390 *
1391 * FUNCTION
1392 *
1393 * Transform_Skysphere
1394 *
1395 * INPUT
1396 *
1397 * Trans - Pointer to transformation
1398 *
1399 * OUTPUT
1400 *
1401 * Skysphere - Pointer to skysphere structure
1402 *
1403 * RETURNS
1404 *
1405 * AUTHOR
1406 *
1407 * Dieter Bayer
1408 *
1409 * DESCRIPTION
1410 *
1411 * Transform a skysphere.
1412 *
1413 * CHANGES
1414 *
1415 * Feb 1996 : Creation.
1416 *
1417 ******************************************************************************/
1418
Transform_Skysphere(SKYSPHERE * Skysphere,TRANSFORM * Trans)1419 void Transform_Skysphere(SKYSPHERE *Skysphere, TRANSFORM *Trans)
1420 {
1421 if (Skysphere->Trans == NULL)
1422 {
1423 Skysphere->Trans = Create_Transform();
1424 }
1425
1426 Compose_Transforms(Skysphere->Trans, Trans);
1427 }
1428
1429 END_POV_NAMESPACE
1430