Esempio n. 1
0
static void
tcoord_to_pcoord(struct vec3 * pcoord, float x, float y, mat4x4 * M)
{
	vec4 tc, pc;
	tc.x = x;
	tc.y = y;
	tc.z = 1.0;
	tc.w = 0.0;
	mulmv(&pc, M, &tc);
	pcoord->x = pc.x;
	pcoord->y = pc.y;
	pcoord->z = pc.z;

	TRACE(OPENGL, "tcoord (%f, %f) to pcoord (%f, %f, %f)\n",
			x, y, pcoord->x, pcoord->y, pcoord->z);
}
Esempio n. 2
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);
	}
}
Esempio n. 3
0
///////////////////////////////////////////////////////////////////////
// Class				:	CIrradianceCache
// Method				:	lookup
// Description			:	Lookup da cache
// Return Value			:
// Comments				:
void	CIrradianceCache::lookup(float *C,const float *cP,const float *cdPdu,const float *cdPdv,const float *cN,CShadingContext *context) {
	const CShadingScratch	*scratch		=	&(context->currentShadingState->scratch);

	// Is this a point based lookup?
	if ((scratch->occlusionParams.pointbased) && (scratch->occlusionParams.pointHierarchy != NULL)) {
		int	i;

		for (i=0;i<7;i++)	C[i]	=	0;

		scratch->occlusionParams.pointHierarchy->lookup(C,cP,cdPdu,cdPdv,cN,context);
	} else {
		CCacheSample		*cSample;
		CCacheNode			*cNode;
		float				totalWeight		=	0;
		CCacheNode			**stackBase		=	(CCacheNode **)	alloca(maxDepth*sizeof(CCacheNode *)*8);
		CCacheNode			**stack;
		int					i;
		float				coverage;
		vector				irradiance,envdir;
		vector				P,N;
		
		// A small value for discard-smoothing of irradiance
		const float			smallSampleWeight = (flags & CACHE_SAMPLE) ? 0.1f : 0.0f;

		// Transform the lookup point to the correct coordinate system
		mulmp(P,to,cP);
		mulmn(N,from,cN);
		
		// Init the result
		coverage	=	0;
		initv(irradiance,0);
		initv(envdir,0);

		// The weighting algorithm is that described in [Tabellion and Lamorlette 2004]
		// We need to convert the max error as in Wald to Tabellion 
		// The default value of maxError is 0.4f
		const float			K		=	0.4f / scratch->occlusionParams.maxError;

		// Note, we do not need to lock the data for reading
		// if word-writes are atomic
		
		// Prepare for the non recursive tree traversal
		stack		=	stackBase;
		*stack++	=	root;
		while(stack > stackBase) {
			cNode	=	*(--stack);

			// Sum the values in this level
			for (cSample=cNode->samples;cSample!=NULL;cSample=cSample->next) {
				vector	D;

				// D = vector from sample to query point
				subvv(D,P,cSample->P);

				// Ignore sample in the front
				float	a	=	dotvv(D,cSample->N);
				if ((a*a / (dotvv(D,D) + C_EPSILON)) > 0.1)	continue;

				// Positional error
				float	e1 = sqrtf(dotvv(D,D)) / cSample->dP;

				// Directional error
				float	e2 =	1 - dotvv(N,cSample->N);
				if (e2 < 0)	e2	=	0;
				e2		=	sqrtf(e2*weightNormalDenominator);

				// Compute the weight
				float	w		=	1 - K*max(e1,e2);
				if (w > context->urand()*smallSampleWeight) {
					vector	ntmp;

					crossvv(ntmp,cSample->N,N);
					
					// Sum the sample
					totalWeight		+=	w;
					coverage		+=	w*(cSample->coverage		+ dotvv(cSample->gP+0*3,D) + dotvv(cSample->gR+0*3,ntmp));
					irradiance[0]	+=	w*(cSample->irradiance[0]	+ dotvv(cSample->gP+1*3,D) + dotvv(cSample->gR+1*3,ntmp));
					irradiance[1]	+=	w*(cSample->irradiance[1]	+ dotvv(cSample->gP+2*3,D) + dotvv(cSample->gR+2*3,ntmp));
					irradiance[2]	+=	w*(cSample->irradiance[2]	+ dotvv(cSample->gP+3*3,D) + dotvv(cSample->gR+3*3,ntmp));
					envdir[0]		+=	w*(cSample->envdir[0]		+ dotvv(cSample->gP+4*3,D) + dotvv(cSample->gR+4*3,ntmp));
					envdir[1]		+=	w*(cSample->envdir[1]		+ dotvv(cSample->gP+5*3,D) + dotvv(cSample->gR+5*3,ntmp));
					envdir[2]		+=	w*(cSample->envdir[2]		+ dotvv(cSample->gP+6*3,D) + dotvv(cSample->gR+6*3,ntmp));
				}
			}

			// Check the children
			for (i=0;i<8;i++) {
				CCacheNode	*tNode;

				if ((tNode = cNode->children[i]) != NULL) {
					const float	tSide	=	tNode->side;

					if (	((tNode->center[0] + tSide) > P[0])	&&
							((tNode->center[1] + tSide) > P[1])	&&
							((tNode->center[2] + tSide) > P[2])	&&
							((tNode->center[0] - tSide) < P[0])	&&
							((tNode->center[1] - tSide) < P[1])	&&
							((tNode->center[2] - tSide) < P[2])) {
						*stack++	=	tNode;
					}
				}
			}
		}

		// Do we have anything ?
		if (totalWeight > C_EPSILON) {
			double	normalizer	=	1 / totalWeight;

			normalizevf(envdir);

			C[0]			=	(float) (irradiance[0]*normalizer);
			C[1]			=	(float) (irradiance[1]*normalizer);
			C[2]			=	(float) (irradiance[2]*normalizer);
			C[3]			=	(float) (coverage*normalizer);
			mulmv(C+4,from,envdir);		// envdir is stored in the target coordinate system
		} else {
			// Are we sampling the cache ?
			if (flags & CACHE_SAMPLE) {
				vector	dPdu,dPdv;

				// Convert the tangent space
				mulmv(dPdu,to,cdPdu);
				mulmv(dPdv,to,cdPdv);

				// Create a new sample
				sample(C,P,dPdu,dPdv,N,context);
				mulmv(C+4,from,C+4);	// envdir is stored in the target coordinate system
			} else {

				// No joy
				C[0]	=	0;
				C[1]	=	0;
				C[2]	=	0;
				C[3]	=	1;
				C[4]	=	0;
				C[5]	=	0;
				C[6]	=	0;
			}
		}

		// Make sure we don't have NaNs
		assert(dotvv(C,C) >= 0);
	}
}