/**************************************************************************** * normal.c * * This module implements solid texturing functions that perturb the surface * normal to create a bumpy effect. * * from Persistence of Vision Raytracer * Copyright 1993 Persistence of Vision Team *--------------------------------------------------------------------------- * NOTICE: This source code file is provided so that users may experiment * with enhancements to POV-Ray and to port the software to platforms other * than those supported by the POV-Ray Team. There are strict rules under * which you are permitted to use this file. The rules are in the file * named POVLEGAL.DOC which should be distributed with this file. If * POVLEGAL.DOC is not available or for more info please contact the POV-Ray * Team Coordinator by leaving a message in CompuServe's Graphics Developer's * Forum. The latest version of POV-Ray may be found there as well. * * This program is based on the popular DKB raytracer version 2.12. * DKBTrace was originally written by David K. Buck. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. * *****************************************************************************/ /* Some texture ideas garnered from SIGGRAPH '85 Volume 19 Number 3, "An Image Synthesizer" By Ken Perlin. Further Ideas Garnered from "The RenderMan Companion" (Addison Wesley) */ #include "frame.h" #include "vector.h" #include "povproto.h" #include "texture.h" extern unsigned short crctab[256]; void ripples (x, y, z, Tnormal, normal) DBL x, y, z; TNORMAL *Tnormal; VECTOR *normal; { register int i; VECTOR point; register DBL length, scalar, index; if (Options & DEBUGGING) printf ("ripples %g %g %g", x, y, z); for (i = 0 ; i < NUMBER_OF_WAVES ; i++) { point.x = x; point.y = y; point.z = z; VSub (point, point, Wave_Sources[i]); VDot (length, point, point); if (length == 0.0) length = 1.0; length = sqrt(length); index = length*Tnormal->Frequency + Tnormal -> Phase; scalar = cycloidal (index) * Tnormal -> Amount; if (Options & DEBUGGING) printf (" index %g scalar %g length %g\n", index, scalar, length); VScale (point, point, scalar/length/(DBL)NUMBER_OF_WAVES); VAdd (*normal, *normal, point); } VNormalize (*normal, *normal); } void waves (x, y, z, Tnormal, normal) DBL x, y, z; TNORMAL *Tnormal; VECTOR *normal; { register int i; VECTOR point; register DBL length, scalar, index, sinValue ; if (Options & DEBUGGING) printf ("waves %g %g %g\n", x, y, z); for (i = 0 ; i < NUMBER_OF_WAVES ; i++) { point.x = x; point.y = y; point.z = z; VSub (point, point, Wave_Sources[i]); VDot (length, point, point); if (length == 0.0) length = 1.0; length = sqrt(length); index = (length * Tnormal -> Frequency * frequency[i]) + Tnormal -> Phase; sinValue = cycloidal (index); scalar = sinValue * Tnormal -> Amount / frequency[i]; VScale (point, point, scalar/length/(DBL)NUMBER_OF_WAVES); VAdd (*normal, *normal, point); } VNormalize (*normal, *normal); } void bumps (x, y, z, Tnormal, normal) DBL x, y, z; TNORMAL *Tnormal; VECTOR *normal; { VECTOR bump_turb; if (Tnormal -> Amount == 0.0) return; /* why are we here?? */ if (Options & DEBUGGING) printf ("bumps %g %g %g\n", x, y, z); DNoise (&bump_turb, x, y, z); /* Get Normal Displacement Val. */ VScale(bump_turb, bump_turb, Tnormal->Amount); VAdd (*normal, *normal, bump_turb); /* displace "normal" */ VNormalize (*normal, *normal); /* normalize normal! */ return; } /* dents is similar to bumps, but uses noise() to control the amount of dnoise() perturbation of the object normal... */ void dents (x, y, z, Tnormal, normal) DBL x, y, z; TNORMAL *Tnormal; VECTOR *normal; { VECTOR stucco_turb; DBL noise; if (Tnormal -> Amount == 0.0) return; /* why are we here?? */ noise = Noise (x, y, z); noise = noise * noise * noise * Tnormal->Amount; if (Options & DEBUGGING) printf ("dents %g %g %g noise %g\n", x, y, z, noise); DNoise (&stucco_turb, x, y, z); /* Get Normal Displacement Val. */ VScale (stucco_turb, stucco_turb, noise); VAdd (*normal, *normal, stucco_turb); /* displace "normal" */ VNormalize (*normal, *normal); /* normalize normal! */ return; } /* Ideas garnered from the April 89 Byte Graphics Supplement on RenderMan, refined from "The RenderMan Companion, by Steve Upstill of Pixar, (C) 1990 Addison-Wesley. */ /* wrinkles - This is my implementation of the dented() routine, using a surface iterative fractal derived from DTurbulence. This is a 3-D vers. (thanks to DNoise()...) of the usual version using the singular Noise()... Seems to look a lot like wrinkles, however... (hmmm) */ void wrinkles (x, y, z, Tnormal, normal) DBL x, y, z; TNORMAL *Tnormal; VECTOR *normal; { register int i; register DBL scale = 1.0; VECTOR result, value; if (Tnormal -> Amount == 0.0) return; /* why are we here?? */ if (Options & DEBUGGING) printf ("wrinkles %g %g %g\n", x, y, z); result.x = 0.0; result.y = 0.0; result.z = 0.0; for (i = 0; i < 10 ; scale *= 2.0, i++) { DNoise(&value, x * scale, y * scale, z * scale); /* * scale,*/ result.x += FABS (value.x / scale); result.y += FABS (value.y / scale); result.z += FABS (value.z / scale); } VScale(result, result, Tnormal->Amount); VAdd (*normal, *normal, result); /* displace "normal" */ VNormalize (*normal, *normal); /* normalize normal! */ return; } TNORMAL *Create_Tnormal () { TNORMAL *New; if ((New = (TNORMAL *) malloc (sizeof (TNORMAL))) == NULL) MAError ("normal"); INIT_TPATTERN_FIELDS(New,NO_NORMAL); New->Amount = 0.0; return (New); } TNORMAL *Copy_Tnormal (Old) TNORMAL *Old; { TNORMAL *New; if (Old != NULL) { New = Create_Tnormal (); *New = *Old; New->Image = Copy_Image (Old->Image); New->Trans = Copy_Transform (Old->Trans); } else New = NULL; return (New); } void Translate_Tnormal(Tnormal,Vector) TNORMAL *Tnormal; VECTOR *Vector; { TRANSFORM Trans; if (Tnormal == NULL) return; Compute_Translation_Transform (&Trans, Vector); Transform_Tnormal (Tnormal, &Trans); } void Rotate_Tnormal(Tnormal,Vector) TNORMAL *Tnormal; VECTOR *Vector; { TRANSFORM Trans; if (Tnormal == NULL) return; Compute_Rotation_Transform (&Trans, Vector); Transform_Tnormal (Tnormal, &Trans); } void Scale_Tnormal(Tnormal,Vector) TNORMAL *Tnormal; VECTOR *Vector; { TRANSFORM Trans; if (Tnormal == NULL) return; Compute_Scaling_Transform (&Trans, Vector); Transform_Tnormal (Tnormal, &Trans); } void Transform_Tnormal(Tnormal,Trans) TNORMAL *Tnormal; TRANSFORM *Trans; { if (Tnormal == NULL) return; if (!Tnormal->Trans) Tnormal->Trans = Create_Transform (); Compose_Transforms (Tnormal->Trans, Trans); } void Destroy_Tnormal(Tnormal) TNORMAL *Tnormal; { if (Tnormal == NULL) return; Destroy_Image (Tnormal->Image); Destroy_Transform (Tnormal->Trans); free (Tnormal); } void Post_Tnormal (Tnormal) TNORMAL *Tnormal; { if (Tnormal == NULL) return; if (Tnormal->Type == NO_NORMAL) Error("No normal type given"); Tnormal->Flags |= POST_DONE; return; }