All pastes #762891 Raw Edit

Unnamed

public text v1 · immutable
·published 2007-11-05 23:45 UTC
rendered paste body
	  m_update = RM_BEGIN {
		Out<Value3f> RM_DECL(color);						// color output
		In<Value2f> RM_DECL(tex);							// (x,y) coordinate input

		Value3f test = 0;

		Value1ui hitpoint = 0;								// variables that determines whether we've hit something
		Value1ui zbit = 0, z = 0;							// depth bitpacking variables

		Value3ui block;
		Value3f vox;										// current voxel

		color = Value3f(0,0,0);								// sets the default color output to black

		////////// origin and direction calculation
		Value3f origin = m_gpu_origin;						// reads the origin from the device memory
		Value3f direction = m_gpu_p1 + m_gpu_dx*tex[0] + m_gpu_dy*tex[1];
		direction = direction - origin;						// gets the correct direction from device memory
		direction = normalize(direction);					// calculates the normalized direction vector
		//////////

		////////// 3d-dda grid traversal initialisation
		Value3f smin = Value3f(0,0,0);						// scene minimum boundary

		Value3f cellStep = sign(direction);					// returns the sign of the distance (-1 negative | 0 | positive 1)
		Value3f cellI = (cellStep == Value3f(1,1,1));

		Value3i voxelid = 0;								// determines the starting voxel id (using the camera origin)
		Value3i voxelid_next;								// contains the next voxel id

		Value3f t = 0, tstep;								// vector t determines the distance (in each iteration) to the nearest boundary on each axis
		Value3f world;										// contains the world coordinates of a voxel

		Value1ui safe = 0;									// safeguard to prevent endless loops and Bad Things (debugging purpose)
		//////////

		////////// voxel grid traversal code
		RM_WHILE(
			rapidmind::min(voxelid) >= 0
			&& rapidmind::max(voxelid) <= 8
			&& voxelid[1] < 1				// just some scene boundaries (stay within 0,0,0 and 8,5,8)
			&& safe <= (Value1ui)32			// as long as our safeguard check is within reasonable bounds
			&& hitpoint == (Value1ui)0		// and we haven't hit anything
			) {

			// calculate the voxel according to the current t vector along the ray
			voxelid = (Value3i)(origin + t*direction);

			// calculate the voxel that is the next to hit our ray
			voxelid_next = voxelid + cellI;
			tstep = (voxelid_next - origin)/direction + (Value1f)0.00001f;

			// calculate the world coordinates of the voxel
			world = voxelid - smin;

			// use t to calculate the exact (entry) hit point and subtract the world coordinates
			// of the voxel so we get the entry point relative to the box (instead of the entry point in the world)
			Value3f hit_entry = ((t-(Value1f)0.00002f)*direction + origin) - world;

			// calculate the distance (in each iteration) to the nearest boundary on each axis
			t = rapidmind::min(tstep);

			// the t above gives us the distance (along the ray) to the entry point of our next voxel,
			// which is the exit point of our current voxel, so calculate the exact (exit) hit point
			// and subtract the world coordinates of the voxel so we get the local exit point
			Value3f hit_exit = ((t-(Value1f)0.00002f)*direction + origin) - world;

			////////// HACK: swap the y and z axes and reverse the x axis (perhaps a proper fix would be to turn the world and the camera)
			Value1f temp;
			temp = hit_entry[2];
			hit_entry[2] = hit_entry[1];
			hit_entry[1] = temp;
			
			temp = hit_exit[2];
			hit_exit[2] = hit_exit[1];
			hit_exit[1] = temp;
			//////////

			////////// HACK: boundary check (prevents the caster from traversing blocks outside the scene)
			RM_IF(rapidmind::min(voxelid) < 0 || rapidmind::max(voxelid) > 8 || voxelid[1] >= (Value1ui)1){
				hitpoint = 1;
			}RM_ENDIF;
			//////////

			////////// bresenham traversal initialisation
			Value3f steps, delta;
			Value1ui asteps_max, len;
			Value3ui asteps_cmb, asteps_neg;
			Value3i asteps;

			// calculate the data offsets for the horizontally aligned textures
			Value1ui off_volume = (voxelid[0]+voxelid[2]*8) * (Value1ui)RES;
			Value1ui off_lod = off_volume / (Value1ui)LOD_SIZE;

			////////////////////////////////
			// scale the entry and exit points according to the box resolution
			hit_entry *= (Value1f)RES-(Value1f)1;
			hit_exit *= (Value1f)RES-(Value1f)1;

			// determine the bresenham traversal derivatives according to the entry and exit points
			steps = (hit_exit - hit_entry);
			asteps = abs(steps);

			// these instructions return delta (Value3) with "delta[biggest axis]=1.0*sign(steps[biggest axis])" and "delta[x]=(steps[x]/asteps[biggest axis])"
			asteps_max = rapidmind::max(asteps);							// gets the maximum value for abs(steps)
			asteps_cmb = (asteps(0,1,2) == asteps_max(0,0,0));				// returns 1 for the maximum value, otherwise 0
			asteps_neg = (asteps_cmb == Value3ui(0,0,0));					// returns 1 for everything except the maximum value (which returns 0)
			delta = asteps_cmb*sign(steps) + (asteps_neg * (steps/asteps_max));		// creates delta out of an addition of:
																					//   1.0 or -1.0 (depending on the value's sign) for the biggest axis (and 0.0 elsewhere)
																					//   steps/asteps_max everywhere except for the biggest axis (which is 0.0)
			Value3i sgn = dot(asteps_cmb,sign(steps));
			
			// determine the length of the traversal path
			len = asteps_max;

			// HACK: set a boundary safeguard, in case something went wrong (to prevent GPU freezing)
			RM_IF(len>=(Value1ui)300){
				len = 0;
			}RM_ENDIF;

			// initialize the depth (z) value
			z = 0;
			//////////

			////////// bresenham traversal code
			vox = hit_entry;
			Value1ui i;

			// critical loop! this loop consumes most power so should be optimized down to the bare metal
			RM_FOR(i = 0, i < (Value1ui)len && hitpoint==(Value1ui)0, i+=1) {
				////////// lod empty space skipping
				block = vox / (Value1ui)LOD_SIZE;									// calculate the current block
				Value3ui block_next = (block + (Value1ui)1) * (Value1ui)LOD_SIZE;	// determine the voxel position of the next block

				// optimize!
				Value3i delta_s = sign(delta);
				delta_s = (delta_s(0,1,2) == Value3i(-1,-1,-1));			// 1 for 0,1 --- 0 for -1

				Value3ui block_dist = (block_next-(delta_s*(Value1ui)LOD_SIZE) - vox)/delta;			// distance between the current voxel and the next block
				Value1ui boundary = rapidmind::min(block_dist);				// find the smallest multiple of delta for which we cross a block boundary

				test = vox;

				Value1ub l = m_lod[Value2ub(off_lod+block[0],block[1])];	// get the lod data
                zbit = (Value1ui)1 << block[2];								// calculate the z-value
				Value1ui empty = sign(l & zbit);							// empty: 1 for empty voxel, 0 for full voxel
				//////////
				i += boundary*empty;

				Value4ui v = m_volume[Value2ub(off_volume+vox[0],vox[1])];	// get the volume data

				////////// bitwise decoding
				z = vox[2];													// gets the z value from the traversal point
				zbit = (Value1ui)1 << (z & (Value1ui)31);					// convert the z value into a bitvector with 1 on the location of z

				Value4ui div = floor( (z/(Value1ui)32) + (Value1f)0.5f );	// floor/+0.5f is a hack to work around rapidmind's native integer issues
				Value4ui mask = (div(0,0,0,0) == Value4ui(0,1,2,3));		// returns 1 for the corresponding index if div is 0, 1, 2 or 3 (e.g. if div is 2, mask is [0,0,1,0])
				hitpoint = rapidmind::max(v*mask) & zbit;					// gets the appropriate value from v, according to the mask generated by div, by using the bitvector zbit
				//////////

				// increment the traversal point
				vox += delta;
				vox += (delta*boundary*empty);
			}RM_ENDFOR;
			//////////

			////////// HACK: safeguard to prevent Bad Things like endless loops
			safe += (Value1ui)1;
			//////////
		}RM_ENDWHILE;
		//////////

		////////// HACK: output some debug colors
		Value1ui siz = (Value1f)RES;
		//color = vox/siz;
		color = test/siz;
		RM_IF(hitpoint){							// if we hit something
			Value1f d = z / siz;					// calculate the color according to the depth
			//color = Value3f(d, d, d);
		}RM_ENDIF;
		//////////
	} RM_END;