SLfloat SLLightRect::shadowTestMC(SLRay* ray, // ray of hit point const SLVec3f& L, // vector from hit point to light const SLfloat lightDist) // distance to light { SLVec3f SP; // vector hit point to sample point in world coords SLfloat randX = rnd01(); SLfloat randY = rnd01(); // choose random point on rect as sample SP.set(updateAndGetWM().multVec(SLVec3f((randX*_width)-(_width*0.5f), (randY*_height)-(_height*0.5f), 0)) - ray->hitPoint); SLfloat SPDist = SP.length(); SP.normalize(); SLRay shadowRay(SPDist, SP, ray); SLScene::current->root3D()->hitRec(&shadowRay); if (shadowRay.length >= SPDist - FLT_EPSILON) return 1.0f; else return 0.0f; }
/*! SLLightRect::shadowTest returns 0.0 if the hit point is completely shaded and 1.0 if it is 100% lighted. A return value inbetween is calculate by the ratio of the shadow rays not blocked to the total number of casted shadow rays. */ SLfloat SLLightRect::shadowTest(SLRay* ray, // ray of hit point const SLVec3f& L, // vector from hit point to light const SLfloat lightDist) // distance to light { if (_samples.x==1 && _samples.y==1) { // define shadow ray SLRay shadowRay(lightDist, L, ray); SLScene::current->root3D()->hitRec(&shadowRay); return (shadowRay.length < lightDist) ? 0.0f : 1.0f; } else // do light sampling for soft shadows { SLfloat dw = (SLfloat)_width/(SLfloat)_samples.x; // width of a sample cell SLfloat dl = (SLfloat)_height/(SLfloat)_samples.y;// length of a sample cell SLint x, y, hx=_samples.x/2, hy=_samples.y/2; SLint samples = _samples.x*_samples.y; SLbool* isSampled = new SLbool[samples]; SLbool importantPointsAreLighting = true; SLfloat lighted = 0.0f; // return value SLfloat invSamples = 1.0f/(SLfloat)(samples); SLVec3f SP; // vector hitpoint to samplepoint in world coords for (y=0; y<_samples.y; ++y) { for (x=0; x<_samples.x; ++x) { SLint iSP = y*_samples.x + x; isSampled[iSP]=false; } } /* Important sample points (X) on a 7 by 5 rectangular light. If all of them are lighting the hitpoint the sample points in between (O) are not tested anymore. 0 1 2 3 4 5 6 +---+---+---+---+---+---+---+ 0 | X | . | . | X | . | . | X | +---+---+---+---+---+---+---+ 1 | . | . | . | . | . | . | . | +---+---+---+---+---+---+---+ 2 | X | . | . | X | . | . | X | +---+---+---+---+---+---+---+ 3 | . | . | . | . | . | . | . | +---+---+---+---+---+---+---+ 4 | X | . | . | X | . | . | X | +---+---+---+---+---+---+---+ */ // Double loop for the important sample points for (y=-hy; y<=hy; y+=hy) { for (x=-hx; x<=hx; x+=hx) { SLint iSP = (y+hy)*_samples.x + x+hx; isSampled[iSP]=true; SP.set(updateAndGetWM().multVec(SLVec3f(x*dw, y*dl, 0)) - ray->hitPoint); SLfloat SPDist = SP.length(); SP.normalize(); SLRay shadowRay(SPDist, SP, ray); SLScene::current->root3D()->hitRec(&shadowRay); if (shadowRay.length >= SPDist-FLT_EPSILON) lighted += invSamples; // sum up the light else importantPointsAreLighting = false; } } if (importantPointsAreLighting) lighted = 1.0f; else { // Double loop for the samplepoints inbetween for (y=-hy; y<=hy; ++y) { for (x=-hx; x<=hx; ++x) { SLint iSP = (y+hy)*_samples.x + x+hx; if (!isSampled[iSP]) { SP.set(updateAndGetWM().multVec(SLVec3f(x*dw, y*dl, 0)) - ray->hitPoint); SLfloat SPDist = SP.length(); SP.normalize(); SLRay shadowRay(SPDist, SP, ray); SLScene::current->root3D()->hitRec(&shadowRay); // sum up the light if (shadowRay.length >= SPDist-FLT_EPSILON) lighted += invSamples; } } } } if (isSampled) delete [] isSampled; return lighted; } }