/////////////////////////////////////////////////////////////////////// // Class : CDelayedObject // Method : intersect // Description : See object.h // Return Value : - // Comments : void CDelayedObject::intersect(CShadingContext *context,CRay *cRay) { // Process the object if (processed == FALSE) { osLock(CRenderer::delayedMutex); if (processed == FALSE) { CRenderer::context->processDelayedObject(context,this,subdivisionFunction,data,bmin,bmax); processed = TRUE; } osUnlock(CRenderer::delayedMutex); } }
/////////////////////////////////////////////////////////////////////// // Class : CDelayedInstance // Method : intersect // Description : See object.h // Return Value : - // Comments : void CDelayedInstance::intersect(CShadingContext *context,CRay *cRay) { // Process the instance if (processed == FALSE) { osLock(CRenderer::delayedMutex); if (processed == FALSE) { CRenderer::context->processDelayedInstance(context,this); processed = TRUE; } osUnlock(CRenderer::delayedMutex); } }
/////////////////////////////////////////////////////////////////////// // Class : CDelayedInstance // Method : dice // Description : See object.h // Return Value : - // Comments : void CDelayedInstance::dice(CShadingContext *r) { // Process the instance if (processed == FALSE) { osLock(CRenderer::delayedMutex); if (processed == FALSE) { CRenderer::context->processDelayedInstance(r,this); processed = TRUE; } osUnlock(CRenderer::delayedMutex); } // Let the parent take care of the instance CObject::dice(r); }
/////////////////////////////////////////////////////////////////////// // Class : CDelayedObject // Method : dice // Description : See object.h // Return Value : - // Comments : void CDelayedObject::dice(CShadingContext *r) { // Process the object if (processed == FALSE) { osLock(CRenderer::delayedMutex); if (processed == FALSE) { CRenderer::context->processDelayedObject(r,this,subdivisionFunction,data,bmin,bmax); processed = TRUE; } osUnlock(CRenderer::delayedMutex); } // Let the parent dice it CObject::dice(r); }
/////////////////////////////////////////////////////////////////////// // Class : CSurface // Method : intersect // Description : /// \brief Intersect the surface // Return Value : // Comments : void CSurface::intersect(CShadingContext *context,CRay *cRay) { if (! (cRay->flags & attributes->flags) ) return; if (attributes->flags & ATTRIBUTES_FLAGS_LOD) { const float importance = attributes->lodImportance; if (importance >= 0) { if (cRay->jimp > importance) return; } else { if ((1-cRay->jimp) >= -importance) return; } } // Do we have a grid ? if (children == NULL) { // Intersect with our bounding box float t = nearestBox(bmin,bmax,cRay->from,cRay->invDir,cRay->tmin,cRay->t); // Bail out if the hit point is already further than the ray got // Note: this avoids unneeded top level tesselations if (!(t < cRay->t)) return; // We must lock the tesselateMutex so that the list of known tesselation patches // is maintained in a thread safe manner osLock(CRenderer::tesselateMutex); if (children == NULL) { CTesselationPatch *tesselation = new CTesselationPatch(attributes,xform,this,0,1,0,1,0,0,-1); tesselation->initTesselation(context); tesselation->attach(); children = tesselation; } osUnlock(CRenderer::tesselateMutex); } }
/////////////////////////////////////////////////////////////////////// // Class : CIrradianceCache // Method : sample // Description : Sample the occlusion // Return Value : // Comments : void CIrradianceCache::sample(float *C,const float *P,const float *dPdu,const float *dPdv,const float *N,CShadingContext *context) { CCacheSample *cSample; int i,j; float coverage; vector irradiance; vector envdir; float rMean; CRay ray; vector X,Y; CCacheNode *cNode; int depth; // Allocate memory const CShadingScratch *scratch = &(context->currentShadingState->scratch); const int nt = (int) (sqrtf(scratch->traceParams.samples / (float) C_PI) + 0.5); const int np = (int) (C_PI*nt + 0.5); const int numSamples = nt*np; CHemisphereSample *hemisphere = (CHemisphereSample *) alloca(numSamples*sizeof(CHemisphereSample)); // initialize texture lookups if needed if (scratch->occlusionParams.environment) { CTextureLookup::staticInit(&(context->currentShadingState->scratch)); } // Create an orthanormal coordinate system if (dotvv(dPdu,dPdu) > 0) { normalizevf(X,dPdu); crossvv(Y,N,X); } else if (dotvv(dPdv,dPdv) > 0) { normalizevf(X,dPdv); crossvv(Y,N,X); } else { // At this point, we're pretty screwed, so why not use the P normalizevf(X,P); crossvv(Y,N,X); } // Sample the hemisphere coverage = 0; initv(irradiance,0); initv(envdir,0); rMean = C_INFINITY; // Calculate the ray differentials (use average spread in theta and phi) const float da = tanf((float) C_PI/(2*(nt+np))); const float db = (lengthv(dPdu) + lengthv(dPdv))*0.5f; if (scratch->occlusionParams.occlusion == TRUE) { // We're shading for occlusion context->numOcclusionRays += numSamples; context->numOcclusionSamples++; for (i=0;i<nt;i++) { for (j=0;j<np;j++,hemisphere++) { float rv[2]; context->random2d.get(rv); float tmp = sqrtf((i+context->urand()) / (float) nt); const float phi = (float) (2*C_PI*(j+context->urand()) / (float) np); const float cosPhi = (cosf(phi)*tmp); const float sinPhi = (sinf(phi)*tmp); tmp = sqrtf(1 - tmp*tmp); ray.dir[0] = X[0]*cosPhi + Y[0]*sinPhi + N[0]*tmp; ray.dir[1] = X[1]*cosPhi + Y[1]*sinPhi + N[1]*tmp; ray.dir[2] = X[2]*cosPhi + Y[2]*sinPhi + N[2]*tmp; const float originJitterX = (rv[0] - 0.5f)*scratch->traceParams.sampleBase; const float originJitterY = (rv[1] - 0.5f)*scratch->traceParams.sampleBase; ray.from[COMP_X] = P[COMP_X] + originJitterX*dPdu[0] + originJitterY*dPdv[0]; ray.from[COMP_Y] = P[COMP_Y] + originJitterX*dPdu[1] + originJitterY*dPdv[1]; ray.from[COMP_Z] = P[COMP_Z] + originJitterX*dPdu[2] + originJitterY*dPdv[2]; ray.flags = ATTRIBUTES_FLAGS_DIFFUSE_VISIBLE; ray.tmin = scratch->traceParams.bias; ray.t = scratch->traceParams.maxDist; ray.time = 0; ray.da = da; ray.db = db; // Transform the ray into the right coordinate system mulmp(ray.from,from,ray.from); mulmv(ray.dir,from,ray.dir); context->trace(&ray); // Do we have an intersection ? if (ray.object != NULL) { const float *color = ray.object->attributes->surfaceColor; // Yes coverage++; addvv(irradiance,color); hemisphere->coverage = 1; initv(hemisphere->envdir,0); movvv(hemisphere->irradiance,color); } else { // No hemisphere->coverage = 0; addvv(envdir,ray.dir); movvv(hemisphere->envdir,ray.dir); // GSH : Texture lookup for misses if(scratch->occlusionParams.environment != NULL){ CEnvironment *tex = scratch->occlusionParams.environment; vector D0,D1,D2,D3; vector color; // GSHTODO: Add in the dCosPhi and dSinPhi movvv(D0,ray.dir); movvv(D1,ray.dir); movvv(D2,ray.dir); movvv(D3,ray.dir); float savedSamples = scratch->traceParams.samples; context->currentShadingState->scratch.traceParams.samples = 1; tex->lookup(color,D0,D1,D2,D3,context); context->currentShadingState->scratch.traceParams.samples = savedSamples; addvv(irradiance,color); movvv(hemisphere->irradiance,color); } else{ initv(hemisphere->irradiance,0); } } hemisphere->depth = ray.t; hemisphere->invDepth = 1 / ray.t; if (tmp > horizonCutoff) rMean = min(rMean,ray.t); movvv(hemisphere->dir,ray.dir); assert(hemisphere->invDepth > 0); } } } else { // We're shading for indirectdiffuse context->numIndirectDiffuseRays += numSamples; context->numIndirectDiffuseSamples++; for (i=0;i<nt;i++) { for (j=0;j<np;j++,hemisphere++) { float rv[2]; context->random2d.get(rv); float tmp = sqrtf((i+context->urand()) / (float) nt); const float phi = (float) (2*C_PI*(j+context->urand()) / (float) np); const float cosPhi = (cosf(phi)*tmp); const float sinPhi = (sinf(phi)*tmp); tmp = sqrtf(1 - tmp*tmp); ray.dir[0] = X[0]*cosPhi + Y[0]*sinPhi + N[0]*tmp; ray.dir[1] = X[1]*cosPhi + Y[1]*sinPhi + N[1]*tmp; ray.dir[2] = X[2]*cosPhi + Y[2]*sinPhi + N[2]*tmp; const float originJitterX = (rv[0] - 0.5f)*scratch->traceParams.sampleBase; const float originJitterY = (rv[1] - 0.5f)*scratch->traceParams.sampleBase; ray.from[COMP_X] = P[COMP_X] + originJitterX*dPdu[0] + originJitterY*dPdv[0]; ray.from[COMP_Y] = P[COMP_Y] + originJitterX*dPdu[1] + originJitterY*dPdv[1]; ray.from[COMP_Z] = P[COMP_Z] + originJitterX*dPdu[2] + originJitterY*dPdv[2]; ray.flags = ATTRIBUTES_FLAGS_DIFFUSE_VISIBLE; ray.tmin = scratch->traceParams.bias; ray.t = scratch->traceParams.maxDist; ray.time = 0; ray.da = da; ray.db = db; // Transform the ray into the right coordinate system mulmp(ray.from,from,ray.from); mulmv(ray.dir,from,ray.dir); context->trace(&ray); // Do we have an intersection ? if (ray.object != NULL) { vector P,N,C; CAttributes *attributes = ray.object->attributes; CPhotonMap *globalMap; if ((globalMap = attributes->globalMap) != NULL) { normalizev(N,ray.N); mulvf(P,ray.dir,ray.t); addvv(P,ray.from); if(dotvv(ray.dir,N) > 0) mulvf(N,-1); globalMap->lookup(C,P,N,attributes->photonEstimator); // HACK: Avoid too bright spots tmp = max(max(C[0],C[1]),C[2]); if (tmp > scratch->occlusionParams.maxBrightness) mulvf(C,scratch->occlusionParams.maxBrightness/tmp); mulvv(C,attributes->surfaceColor); addvv(irradiance,C); movvv(hemisphere->irradiance,C); context->numIndirectDiffusePhotonmapLookups++; } else { initv(hemisphere->irradiance,0); } // Yes coverage++; hemisphere->coverage = 1; initv(hemisphere->envdir,0); } else { // No hemisphere->coverage = 0; addvv(envdir,ray.dir); movvv(hemisphere->envdir,ray.dir); // GSH : Texture lookup for misses if(scratch->occlusionParams.environment != NULL){ CEnvironment *tex = scratch->occlusionParams.environment; vector D0,D1,D2,D3; vector color; // GSHTODO: Add in the dCosPhi and dSinPhi movvv(D0,ray.dir); movvv(D1,ray.dir); movvv(D2,ray.dir); movvv(D3,ray.dir); float savedSamples = scratch->traceParams.samples; context->currentShadingState->scratch.traceParams.samples = 1; tex->lookup(color,D0,D1,D2,D3,context); context->currentShadingState->scratch.traceParams.samples = savedSamples; addvv(irradiance,color); movvv(hemisphere->irradiance,color); } else{ movvv(hemisphere->irradiance,scratch->occlusionParams.environmentColor); addvv(irradiance,scratch->occlusionParams.environmentColor); } } hemisphere->depth = ray.t; hemisphere->invDepth = 1 / ray.t; if (tmp > horizonCutoff) rMean = min(rMean,ray.t); movvv(hemisphere->dir,ray.dir); assert(hemisphere->invDepth > 0); } } } hemisphere -= np*nt; // Normalize const float tmp = 1 / (float) numSamples; coverage *= tmp; mulvf(irradiance,tmp); normalizevf(envdir); // Record the value C[0] = irradiance[0]; C[1] = irradiance[1]; C[2] = irradiance[2]; C[3] = coverage; C[4] = envdir[0]; C[5] = envdir[1]; C[6] = envdir[2]; // Should we save it ? if ((scratch->occlusionParams.maxError != 0) && (coverage < 1-C_EPSILON)) { // We're modifying, lock the thing osLock(mutex); // Create the sample cSample = (CCacheSample *) memory->alloc(sizeof(CCacheSample)); // Compute the gradients of the illumination posGradient(cSample->gP,np,nt,hemisphere,X,Y); rotGradient(cSample->gR,np,nt,hemisphere,X,Y); // Compute the radius of validity rMean *= 0.5f; // Clamp the radius of validity rMean = min(rMean,db*scratch->occlusionParams.maxPixelDist); // Record the data (in the target coordinate system) movvv(cSample->P,P); movvv(cSample->N,N); cSample->dP = rMean; cSample->coverage = coverage; movvv(cSample->envdir,envdir); movvv(cSample->irradiance,irradiance); // Do the neighbour clamping trick clamp(cSample); rMean = cSample->dP; // copy dP back so we get the right place in the octree // The error multiplier const float K = 0.4f / scratch->occlusionParams.maxError; rMean /= K; // Insert the new sample into the cache cNode = root; depth = 0; while(cNode->side > (2*rMean)) { depth++; for (j=0,i=0;i<3;i++) { if (P[i] > cNode->center[i]) { j |= 1 << i; } } if (cNode->children[j] == NULL) { CCacheNode *nNode = (CCacheNode *) memory->alloc(sizeof(CCacheNode)); for (i=0;i<3;i++) { if (P[i] > cNode->center[i]) { nNode->center[i] = cNode->center[i] + cNode->side*0.25f; } else { nNode->center[i] = cNode->center[i] - cNode->side*0.25f; } } cNode->children[j] = nNode; nNode->side = cNode->side*0.5f; nNode->samples = NULL; for (i=0;i<8;i++) nNode->children[i] = NULL; } cNode = cNode->children[j]; } cSample->next = cNode->samples; cNode->samples = cSample; maxDepth = max(depth,maxDepth); osUnlock(mutex); } }
/////////////////////////////////////////////////////////////////////// // Class : CRenderer // Method : locateFile // Description : Locate a file on disk // Return Value : TRUE if found // Comments : int CRenderer::locateFile(char *result,const char *name,TSearchpath *searchpath) { if (netClient != INVALID_SOCKET) { // check netfile mappings CNetFileMapping* mapping; if (netFileMappings->find(name,mapping)) { name = mapping->to; } } if (strchr(name,OS_DIR_SEPERATOR)) { // Supplied path // Check if the file exists if (osFileExists(name)) { strcpy(result,name); info(CODE_RESOLUTION,"\"%s\" -> \"%s\"\n",name,name); return TRUE; } } else { // Only filename // Look at the search path for (; searchpath!=NULL; searchpath=searchpath->next) { sprintf(result,"%s%s",searchpath->directory,name); osFixSlashes(result); if (osFileExists(result)) { info(CODE_RESOLUTION,"\"%s\" -> \"%s\"\n",name,result); return TRUE; } } // Last resort, look into the temporary directory sprintf(result,"%s%s",temporaryPath,name); osFixSlashes(result); if (osFileExists(result)) { info(CODE_RESOLUTION,"\"%s\" -> \"%s\"\n",name,result); return TRUE; } } // Unable to find the file, check the network // Check the net if we can find the file if (netClient != INVALID_SOCKET) { // Lock the network osLock(networkMutex); if (getFile(result,name) == TRUE) { if (osFileExists(result)) { info(CODE_RESOLUTION,"\"%s\" -> \"%s\"\n",name,result); osUnlock(networkMutex); return TRUE; } } // Unlock the network osUnlock(networkMutex); } info(CODE_RESOLUTION,"\"%s\" -> ???\n",name); return FALSE; }