| 1 | #ifndef lint | 
| 2 | static const char RCSid[] = "$Id: glass.c,v 2.28 2019/04/19 19:01:32 greg Exp $"; | 
| 3 | #endif | 
| 4 | /* | 
| 5 | *  glass.c - simpler shading function for thin glass surfaces. | 
| 6 | */ | 
| 7 |  | 
| 8 | #include "copyright.h" | 
| 9 |  | 
| 10 | #include  "ray.h" | 
| 11 | #include  "otypes.h" | 
| 12 | #include  "rtotypes.h" | 
| 13 | #include  "pmapmat.h" | 
| 14 |  | 
| 15 | /* | 
| 16 | *  This definition of glass provides for a quick calculation | 
| 17 | *  using a single surface where two closely spaced parallel | 
| 18 | *  dielectric surfaces would otherwise be used.  The chief | 
| 19 | *  advantage to using this material is speed, since internal | 
| 20 | *  reflections are avoided. | 
| 21 | * | 
| 22 | *  The specification for glass is as follows: | 
| 23 | * | 
| 24 | *      modifier glass id | 
| 25 | *      0 | 
| 26 | *      0 | 
| 27 | *      3+ red grn blu [refractive_index] | 
| 28 | * | 
| 29 | *  The color is used for the transmission at normal incidence. | 
| 30 | *  To compute transmissivity (tn) from transmittance (Tn) use: | 
| 31 | * | 
| 32 | *      tn = (sqrt(.8402528435+.0072522239*Tn*Tn)-.9166530661)/.0036261119/Tn | 
| 33 | * | 
| 34 | *  The transmissivity of standard 88% transmittance glass is 0.96. | 
| 35 | *  A refractive index other than the default can be used by giving | 
| 36 | *  it as the fourth real argument.  The above formula no longer applies. | 
| 37 | * | 
| 38 | *  If we appear to hit the back side of the surface, then we | 
| 39 | *  turn the normal around. | 
| 40 | */ | 
| 41 |  | 
| 42 | #define  RINDEX         1.52            /* refractive index of glass */ | 
| 43 |  | 
| 44 |  | 
| 45 | int | 
| 46 | m_glass(                /* color a ray which hit a thin glass surface */ | 
| 47 | OBJREC  *m, | 
| 48 | RAY  *r | 
| 49 | ) | 
| 50 | { | 
| 51 | COLOR  mcolor; | 
| 52 | SCOLOR  scoef; | 
| 53 | double  ctemp[3]; | 
| 54 | double  pdot; | 
| 55 | FVECT  pnorm; | 
| 56 | double  rindex=0, cos2; | 
| 57 | int  hastexture, hastrans; | 
| 58 | double  d, r1e, r1m; | 
| 59 | RAY  p; | 
| 60 | int  i; | 
| 61 |  | 
| 62 | /* PMAP: skip refracted shadow or ambient ray if accounted for in | 
| 63 | photon map */ | 
| 64 | if (shadowRayInPmap(r) || ambRayInPmap(r)) | 
| 65 | return(1); | 
| 66 | /* check arguments */ | 
| 67 | if (m->oargs.nfargs == 3) | 
| 68 | rindex = RINDEX;                /* default value of n */ | 
| 69 | else if (m->oargs.nfargs == 4) | 
| 70 | rindex = m->oargs.farg[3];      /* use their value */ | 
| 71 | else | 
| 72 | objerror(m, USER, "bad arguments"); | 
| 73 | /* check back face visibility */ | 
| 74 | if (!backvis && r->rod <= 0.0) { | 
| 75 | raytrans(r); | 
| 76 | return(1); | 
| 77 | } | 
| 78 | /* check transmission */ | 
| 79 | setcolor(mcolor, m->oargs.farg[0], m->oargs.farg[1], m->oargs.farg[2]); | 
| 80 | if ((hastrans = (intens(mcolor) > 1e-15))) { | 
| 81 | for (i = 0; i < 3; i++) | 
| 82 | if (colval(mcolor,i) < 1e-15) | 
| 83 | colval(mcolor,i) = 1e-15; | 
| 84 | } else if (r->crtype & SHADOW) | 
| 85 | return(1); | 
| 86 | /* get modifiers */ | 
| 87 | raytexture(r, m->omod); | 
| 88 | if (r->rod < 0.0)                       /* reorient if necessary */ | 
| 89 | flipsurface(r); | 
| 90 | /* perturb normal */ | 
| 91 | hastexture = (DOT(r->pert,r->pert) > FTINY*FTINY); | 
| 92 | if (hastexture) { | 
| 93 | pdot = raynormal(pnorm, r); | 
| 94 | } else { | 
| 95 | VCOPY(pnorm, r->ron); | 
| 96 | pdot = r->rod; | 
| 97 | } | 
| 98 | /* angular transmission */ | 
| 99 | cos2 = sqrt( (1.0-1.0/(rindex*rindex)) + | 
| 100 | pdot*pdot/(rindex*rindex) ); | 
| 101 | if (hastrans) | 
| 102 | setcolor(mcolor, pow(colval(mcolor,RED), 1.0/cos2), | 
| 103 | pow(colval(mcolor,GRN), 1.0/cos2), | 
| 104 | pow(colval(mcolor,BLU), 1.0/cos2)); | 
| 105 |  | 
| 106 | /* compute reflection */ | 
| 107 | r1e = (pdot - rindex*cos2) / (pdot + rindex*cos2); | 
| 108 | r1e *= r1e; | 
| 109 | r1m = (1.0/pdot - rindex/cos2) / (1.0/pdot + rindex/cos2); | 
| 110 | r1m *= r1m; | 
| 111 | /* compute transmission */ | 
| 112 | if (hastrans) { | 
| 113 | for (i = 0; i < 3; i++) { | 
| 114 | d = colval(mcolor, i); | 
| 115 | ctemp[i] = .5*(1.0-r1e)*(1.0-r1e)*d / | 
| 116 | (1.0-r1e*r1e*d*d) + | 
| 117 | .5*(1.0-r1m)*(1.0-r1m)*d / | 
| 118 | (1.0-r1m*r1m*d*d); | 
| 119 | } | 
| 120 | setscolor(scoef, ctemp[RED], ctemp[GRN], ctemp[BLU]); | 
| 121 | smultscolor(scoef, r->pcol);    /* modify by pattern */ | 
| 122 | /* transmitted ray */ | 
| 123 | if (rayorigin(&p, TRANS, r, scoef) == 0) { | 
| 124 | if (!(r->crtype & (SHADOW|AMBIENT)) && hastexture) { | 
| 125 | VSUM(p.rdir, r->rdir, r->pert, 2.*(1.-rindex)); | 
| 126 | if (normalize(p.rdir) == 0.0) { | 
| 127 | objerror(m, WARNING, "bad perturbation"); | 
| 128 | VCOPY(p.rdir, r->rdir); | 
| 129 | } | 
| 130 | } else { | 
| 131 | VCOPY(p.rdir, r->rdir); | 
| 132 | } | 
| 133 | rayvalue(&p); | 
| 134 | smultscolor(p.rcol, p.rcoef); | 
| 135 | saddscolor(r->rcol, p.rcol); | 
| 136 | if (!hastexture || r->crtype & (SHADOW|AMBIENT)) | 
| 137 | r->rxt = r->rot + raydistance(&p); | 
| 138 | } | 
| 139 | } | 
| 140 | if (r->crtype & SHADOW)                 /* skip reflected ray */ | 
| 141 | return(1); | 
| 142 | /* compute reflectance */ | 
| 143 | for (i = 0; i < 3; i++) { | 
| 144 | d = colval(mcolor, i); | 
| 145 | d *= d; | 
| 146 | ctemp[i] = .5*r1e*(1.0+(1.0-2.0*r1e)*d)/(1.0-r1e*r1e*d) + | 
| 147 | .5*r1m*(1.0+(1.0-2.0*r1m)*d)/(1.0-r1m*r1m*d); | 
| 148 | } | 
| 149 | setscolor(scoef, ctemp[RED], ctemp[GRN], ctemp[BLU]); | 
| 150 | /* reflected ray */ | 
| 151 | if (rayorigin(&p, REFLECTED, r, scoef) == 0) { | 
| 152 | VSUM(p.rdir, r->rdir, pnorm, 2.*pdot); | 
| 153 | checknorm(p.rdir); | 
| 154 | rayvalue(&p); | 
| 155 | smultscolor(p.rcol, p.rcoef); | 
| 156 | copyscolor(r->mcol, p.rcol); | 
| 157 | saddscolor(r->rcol, p.rcol); | 
| 158 | r->rmt = r->rot; | 
| 159 | if (r->ro != NULL && isflat(r->ro->otype) && | 
| 160 | !hastexture | (r->crtype & AMBIENT)) | 
| 161 | r->rmt += raydistance(&p); | 
| 162 | } | 
| 163 | return(1); | 
| 164 | } |