Exemple #1
0
///////////////////////////////////////////////////////////////////////
// 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);
	}
}
Exemple #2
0
///////////////////////////////////////////////////////////////////////
// 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);
	}
}
Exemple #3
0
///////////////////////////////////////////////////////////////////////
// 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);
}
Exemple #4
0
///////////////////////////////////////////////////////////////////////
// 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);
}
Exemple #5
0
///////////////////////////////////////////////////////////////////////
// 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);
	}
}
Exemple #6
0
///////////////////////////////////////////////////////////////////////
// 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;
}