/****************************************************************************** * Illuminate the given point on an object *****************************************************************************/ ntlColor ntlLightObject::illuminatePoint(ntlRay &reflectedRay, ntlGeometryObject *closest, ntlColor &highlight ) { /* is this light active? */ if(!mActive) { return ntlColor(0.0); } gfxReal visibility = 1.0; // how much of light is visible ntlVec3Gfx intersectionPos = reflectedRay.getOrigin(); ntlColor current_color = ntlColor(0.0); ntlMaterial *clossurf = closest->getMaterial(); ntlVec3Gfx lightDir = (mvPosition - intersectionPos); gfxReal lightDirNorm = normalize(lightDir); // where is the lightsource ? ntlRay rayOfLight(intersectionPos, lightDir, 0, 1.0, mpGlob ); if( (1) && (mCastShadows)&&(closest->getReceiveShadows()) ) { ntlTriangle *tri; ntlVec3Gfx triNormal; gfxReal trit; mpGlob->getRenderScene()->intersectScene(rayOfLight, trit, triNormal, tri, TRI_CASTSHADOWS); if(( trit>0 )&&( trit<lightDirNorm )) visibility = 0.0; if(mpGlob->getDebugOut() > 5) errorOut("Omni lighting with "<<visibility ); } /* is light partly visible ? */ //? visibility=1.; if (visibility>0.0) { ntlColor highTemp(0.0); // temporary highlight color to multiply highTemp with offFac current_color = getShadedColor(reflectedRay, lightDir, clossurf, highTemp) * visibility; highlight += highTemp * visibility; if(mpGlob->getDebugOut() > 5) errorOut("Omni lighting color "<<current_color ); } return current_color; }
/****************************************************************************** * distance to plane function for nodes *****************************************************************************/ gfxReal ntlTree::distanceToPlane(BSPNode *curr, ntlVec3Gfx plane, ntlRay ray) const { return ( (plane[curr->axis]-ray.getOrigin()[curr->axis]) / ray.getDirection()[curr->axis] ); }
void ntlTree::intersectX(const ntlRay &ray, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags, bool forceNonsmooth) const { gfxReal mint = GFX_REAL_MAX; /* current minimal t */ ntlVec3Gfx retnormal; /* intersection (interpolated) normal */ gfxReal mintu=0.0, mintv=0.0; /* u,v for min t intersection */ BSPNode *curr, *nearChild, *farChild; /* current node and children */ gfxReal planedist, mindist, maxdist; ntlVec3Gfx pos; ntlTriangle *hit = NULL; tri = NULL; ray.intersectCompleteAABB(mStart,mEnd,mindist,maxdist); // +X if((maxdist < 0.0) || (!mpRoot) || (mindist == GFX_REAL_MAX) || (maxdist == GFX_REAL_MAX) ) { distance = -1.0; return; } mindist -= getVecEpsilon(); maxdist += getVecEpsilon(); /* stack init */ mpNodeStack->elem[0].node = NULL; mpNodeStack->stackPtr = 1; curr = mpRoot; mint = GFX_REAL_MAX; while(curr != NULL) { // +X while( !curr->isLeaf() ) { planedist = distanceToPlane(curr, curr->child[0]->max, ray ); getChildren(curr, ray.getOrigin(), nearChild, farChild ); // check ray direction for small plane distances if( (planedist>-getVecEpsilon() )&&(planedist< getVecEpsilon() ) ) { // ray origin on intersection plane planedist = 0.0; if(ray.getDirection()[curr->axis]>getVecEpsilon() ) { // larger coords curr = curr->child[1]; } else if(ray.getDirection()[curr->axis]<-getVecEpsilon() ) { // smaller coords curr = curr->child[0]; } else { // paralell, order doesnt really matter are min/max/plane ok? mpNodeStack->elem[ mpNodeStack->stackPtr ].node = curr->child[0]; mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist; mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist; (mpNodeStack->stackPtr)++; curr = curr->child[1]; maxdist = planedist; } } else { // normal ray if( (planedist>maxdist) || (planedist<0.0-getVecEpsilon() ) ) { curr = nearChild; } else if(planedist < mindist) { curr = farChild; } else { mpNodeStack->elem[ mpNodeStack->stackPtr ].node = farChild; mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist; mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist; (mpNodeStack->stackPtr)++; curr = nearChild; maxdist = planedist; } } } // +X /* intersect with current node */ for (vector<ntlTriangle *>::iterator iter = curr->members->begin(); iter != curr->members->end(); iter++ ) { /* check for triangle flags before intersecting */ if((!flags) || ( ((*iter)->getFlags() & flags) > 0 )) { if( ((*iter)->getLastRay() == ray.getID() )&&((*iter)->getLastRay()>0) ) { // was already intersected... } else { // we still need to intersect this triangle gfxReal u=0.0,v=0.0, t=-1.0; ray.intersectTriangleX( mpVertices, (*iter), t,u,v); (*iter)->setLastRay( ray.getID() ); if( (t > 0.0) && (t<mint) ) { mint = t; hit = (*iter); mintu = u; mintv = v; } } } // flags check } // +X /* check if intersection is valid */ if( (mint>0.0) && (mint < GFX_REAL_MAX) ) { pos = ray.getOrigin() + ray.getDirection()*mint; if( (pos[0] >= curr->min[0]) && (pos[0] <= curr->max[0]) && (pos[1] >= curr->min[1]) && (pos[1] <= curr->max[1]) && (pos[2] >= curr->min[2]) && (pos[2] <= curr->max[2]) ) { if(forceNonsmooth) { // calculate triangle normal ntlVec3Gfx e0,e1,e2; e0 = (*mpVertices)[ hit->getPoints()[0] ]; e1 = (*mpVertices)[ hit->getPoints()[1] ]; e2 = (*mpVertices)[ hit->getPoints()[2] ]; retnormal = cross( -(e2-e0), (e1-e0) ); } else { // calculate interpolated normal retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv; } normalize(retnormal); normal = retnormal; distance = mint; tri = hit; return; } } // +X (mpNodeStack->stackPtr)--; curr = mpNodeStack->elem[ mpNodeStack->stackPtr ].node; mindist = mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist; maxdist = mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist; } /* traverse tree */ if(mint == GFX_REAL_MAX) { distance = -1.0; } else { // intersection outside the BSP bounding volumes might occur due to roundoff... if(forceNonsmooth) { // calculate triangle normal ntlVec3Gfx e0,e1,e2; e0 = (*mpVertices)[ hit->getPoints()[0] ]; e1 = (*mpVertices)[ hit->getPoints()[1] ]; e2 = (*mpVertices)[ hit->getPoints()[2] ]; retnormal = cross( -(e2-e0), (e1-e0) ); } else { // calculate interpolated normal retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv; } normalize(retnormal); normal = retnormal; distance = mint; tri = hit; } // +X return; }