// Foley & vanDam: Computer Graphics: Principles and Practice, // 2nd Ed. pp 756ff. Point3 SContext::RefractVector(float ior) { Point3 N = Normal(); float VN,nur,k; VN = DotProd(-viewDir,N); if (backFace) nur = ior; else nur = (ior!=0.0f) ? 1.0f/ior: 1.0f; k = 1.0f-nur*nur*(1.0f-VN*VN); if (k<=0.0f) { // Total internal reflection: return ReflectVector(); } else { return (nur*VN-(float)sqrt(k))*N + nur*viewDir; } }
static void TraceLine( VECTOR *LinP, VECTOR *LinD, VECTOR *Color, int reccount ) { VECTOR Pnt, Norm, LDir, NewDir, NewDir2, TmpCol, TmpCol2; VECTOR TmpPnt, TmpNorm, D; double t, A, cosfi; TEXTURE *txt, *tmptxt; int i, shadowcount, usedist; Color->x = Color->y = Color->z = 0.0; if( reccount > 0 ) { /* Only use distributed tracing in higher nodes of the recursion tree */ usedist = ( (MAXREC-reccount) < DISTLEVELS ) ? 1 : 0; /* Try intersection with objects */ t = IntersectObjs( LinP, LinD, &Pnt, &Norm, &txt ); /* Get light-intensity in intersection-point (store in cosfi) */ if( t > EPSILON ) { LDir.x = Lightpos.x-Pnt.x; /* Get line to light from surface */ LDir.y = Lightpos.y-Pnt.y; LDir.z = Lightpos.z-Pnt.z; cosfi = LDir.x*Norm.x + LDir.y*Norm.y + LDir.z*Norm.z; if(cosfi > 0.0) { /* If angle between lightline and normal < PI/2 */ shadowcount = 0; if( usedist ) { A = Lightr / VectorLength( &LDir ); for( i = 0; i < DISTRIB; i++ ) { DistribVector( &D, &LDir, A, A ); NewDir = LDir; NewDir.x += D.x; NewDir.y += D.y; NewDir.z += D.z; /* Check for shadows (ignore hit info, may be used though) */ t = IntersectObjs( &Pnt, &NewDir, &TmpPnt, &TmpNorm, &tmptxt ); if( ( t < EPSILON ) || ( t > 1.0 ) ) shadowcount++; } } else { t = IntersectObjs( &Pnt, &LDir, &TmpPnt, &TmpNorm, &tmptxt ); if( ( t < EPSILON ) || ( t > 1.0 ) ) shadowcount = DISTRIB; } if( shadowcount > 0 ) { A = Norm.x*Norm.x + Norm.y*Norm.y + Norm.z*Norm.z; A *= LDir.x*LDir.x + LDir.y*LDir.y + LDir.z*LDir.z; cosfi = (cosfi/sqrt(A))*txt->diffuse*(double)shadowcount/DISTRIB; } else { cosfi = 0.0; } } else { cosfi = 0.0; } Color->x = txt->color.x*(Ambient+cosfi); Color->y = txt->color.y*(Ambient+cosfi); Color->z = txt->color.z*(Ambient+cosfi); if( txt->reflect > EPSILON ) { ReflectVector( &NewDir, LinD, &Norm ); TmpCol.x = TmpCol.y = TmpCol.z = 0.0; if( usedist && ( txt->roughness > EPSILON ) ) { for( i = 0; i < DISTRIB; i++ ) { DistribVector( &D, &NewDir, txt->roughness, txt->roughness ); NewDir2 = NewDir; NewDir2.x += D.x; NewDir2.y += D.y; NewDir2.z += D.z; TraceLine( &Pnt, &NewDir2, &TmpCol2, reccount-1 ); TmpCol.x += TmpCol2.x; TmpCol.y += TmpCol2.y; TmpCol.z += TmpCol2.z; } ScaleVector( &TmpCol, 1.0/DISTRIB ); } else { TraceLine( &Pnt, &NewDir, &TmpCol, reccount-1 ); } Color->x += TmpCol.x * txt->reflect; Color->y += TmpCol.y * txt->reflect; Color->z += TmpCol.z * txt->reflect; } } else { /* Get sky-color (interpolate between horizon and zenit) */ A = sqrt( LinD->x*LinD->x + LinD->y*LinD->y ); if( A > 0.0 ) A = atan( fabs( LinD->z ) / A )*0.63661977; else A = 1.0; Color->x = Skycolor[1].x*A + Skycolor[0].x*(1.0-A); Color->y = Skycolor[1].y*A + Skycolor[0].y*(1.0-A); Color->z = Skycolor[1].z*A + Skycolor[0].z*(1.0-A); } /* Make sure that the color does not exceed the maximum level */ if(Color->x > 1.0) Color->x = 1.0; if(Color->y > 1.0) Color->y = 1.0; if(Color->z > 1.0) Color->z = 1.0; } }