GPU-based volume raycasting

hello, i have download an source code of GPU-based volume raycasting,which is based on Qt. And i upload it to my google code as below:
http://code.google.com/p/qt-color-delegate/downloads/list
I have read several times of the source code, but in some place i still cannot understand.
in frag_shader


vec2 intersectBox(vec4 texel_zero, vec4 texel_dir_norm)
{
	float t1,t2;
	t1=(0.0-texel_zero.x)/texel_dir_norm.x;
	t2=(1.0-texel_zero.x)/texel_dir_norm.x;
	float tminX=min(t1,t2);
	float tmaxX=max(t1,t2);
	t1=(0.0-texel_zero.y)/texel_dir_norm.y;
	t2=(1.0-texel_zero.y)/texel_dir_norm.y;
	float tminY=min(t1,t2);
	float tmaxY=max(t1,t2);
	t1=(0.0-texel_zero.z)/texel_dir_norm.z;
	t2=(1.0-texel_zero.z)/texel_dir_norm.z;
	float tminZ=min(t1,t2);
	float tmaxZ=max(t1,t2);
	float largest_tmin = max(max(tminX, tminY), max(tminX, tminZ));
	float smallest_tmax = min(min(tmaxX, tmaxY), min(tmaxX, tmaxZ));
	vec2 result=vec2(largest_tmin,smallest_tmax);
	return result;
}

Can somebody tell me how this function get the near and far .

That looks like a (fairly standard) algorithm to intersect a ray with an axis aligned box (i.e. your favourite search engine should produce a better explanation than what follows :wink: ). The basic idea is for each axis to determine the distances (t1, t2) along the ray where it enters/leaves the box. Since this is done for each axis separately you only care about where the ray crosses the planes that coincide with the box sides that are orthogonal to the axis you are processing. The ray is inside the box when it has entered it over all three planes and leaves the box as soon as it exits the first one again, that’s why you want the largest of the tmin (enter distances), and the smallest of the tmax (leave distances).

FWIW, I’m pretty sure this can be vectorized for better efficiency.

Thank you very much, but i still donot know what does “t1=(0.0-texel_zero.x)/texel_dir_norm.x” mean.

Ok, fair enough. I’m afraid I don’t know how to describe this substantially different from what I already wrote. Perhaps someone else wants to give it a try.

haha~~ i got it. thanks a lot!

The last question about this code is the main render code:


bool VolRenCore::Render()
{
		glClearColor(m_BackgroundColor[0], m_BackgroundColor[1], m_BackgroundColor[2], 1.0f);
		glClearDepth(1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glFrontFace(GL_CCW);
		if (!m_Data || !m_Data->GetData()) return false;
		if (m_DataModified || m_Data->GetVersion()!=m_DataVersion)
		{
			_updateData();
			m_DataModified=false;
			m_DataVersion=m_Data->GetVersion();
			m_VolTextureNeedUpdate=true;
		}
		if (!m_glewInit)
		{
			glewInit();
			_initA2OTexture();
			m_glewInit=true;
		}	
	
		if (!m_shaderInit)
		{
			_initShaders();
			m_shaderInit=true;
		}
	
		if (m_NeedCalculateMatrix) 
		{
			_calculateMatrix();
			m_NeedCalculateMatrix=false;
		}
		
		if (!_calculateBounds()) return false;
	
		//Setup Shader
		glUseProgramObjectARB(m_GLSLProgram);
		
		GLint var = glGetUniformLocationARB(m_GLSLProgram, "P2MMatrix");
		glUniformMatrix4fvARB(var,1,0,m_PixelsToModelMatrix.ele);
	
		var   = glGetUniformLocationARB(m_GLSLProgram, "M2TMatrix");
		glUniformMatrix4fvARB(var,1,0,m_ModelToTextureMatrix.ele);
	
		var   = glGetUniformLocationARB(m_GLSLProgram, "sampleDistance");
		glUniform1fARB(var,GetSampleDistance());
		
		var   = glGetUniformLocationARB(m_GLSLProgram, "A2OTexture");
		glUniform1iARB(var, 0);
	
		if (m_VolTexture ==0 || m_VolTextureNeedUpdate) 
		{	
			_genVolTexture();
			m_VolTextureNeedUpdate=false;		
		}
	
		var   = glGetUniformLocationARB(m_GLSLProgram, "VolTexture");
		glUniform1iARB(var, 1);
		
		if (m_TFTexture==0 || m_TF->IsModified()) 
		{
			_genTFTexture();
			m_TF->SetUnmodified();
		}
		
		var   = glGetUniformLocationARB(m_GLSLProgram, "TF");
		glUniform1iARB(var, 2);
	
		float typeMin,typeMax;
		if (m_Data->GetDataType()!=VolumeData::FLOAT)
		{
			VolumeData::DataType type=m_Data->GetDataType();
			typeMin=(float)VolumeData::typemin[type];
			typeMax=(float)VolumeData::typemax[type];
		}
		else 
		{
			typeMin=0.0f; 
			typeMax=1.0f;
		}
		float tfMax=m_TF->GetMaxPos();
		float tfMin=m_TF->GetMinPos();
		
		var   = glGetUniformLocationARB(m_GLSLProgram, "scale");
		glUniform1fARB(var, (typeMax-typeMin)/(tfMax-tfMin));
		
		var   = glGetUniformLocationARB(m_GLSLProgram, "shift");
		glUniform1fARB(var, (typeMin-tfMin)/(tfMax-tfMin));
	
		int shade=m_Shade?1:0;
		var   = glGetUniformLocationARB(m_GLSLProgram, "shade");
	 	glUniform1iARB(var, shade);
	
		if (m_Shade)
		{
			Vector worldPoint;
			Vector modelPoint;
			float lightPosition[3], lightFocalPoint[3];
			Vector lightDirection;
	
			worldPoint.ele[3]=1.0f;
	
			worldPoint.ele[0]=m_LightPosition[0];
			worldPoint.ele[1]=m_LightPosition[1];
			worldPoint.ele[2]=m_LightPosition[2];
			modelPoint=m_InvertModelViewMatrix*worldPoint;
	
			lightPosition[0]=modelPoint.ele[0];
			lightPosition[1]=modelPoint.ele[1];
			lightPosition[2]=modelPoint.ele[2];
	
			worldPoint.ele[0]=m_LightFocalPoint[0];
			worldPoint.ele[1]=m_LightFocalPoint[1];
			worldPoint.ele[2]=m_LightFocalPoint[2];
			modelPoint=m_InvertModelViewMatrix*worldPoint;
	
			lightFocalPoint[0]=modelPoint.ele[0];
			lightFocalPoint[1]=modelPoint.ele[1];
			lightFocalPoint[2]=modelPoint.ele[2];
	
			lightDirection.ele[0]=lightFocalPoint[0]-lightPosition[0];
			lightDirection.ele[1]=lightFocalPoint[1]-lightPosition[1];
			lightDirection.ele[2]=lightFocalPoint[2]-lightPosition[2];
	
			lightDirection.Normalize();
	
			float lightColor[3];
			lightColor[0]=m_LightColor[0]*m_LightIntensity;
			lightColor[1]=m_LightColor[1]*m_LightIntensity;
			lightColor[2]=m_LightColor[2]*m_LightIntensity;
	
			float ambient[3];
			float diffuse[3];
			float specular[3];
			float spacings[3];
			float specThreshold;			
	
			ambient[0]=m_Ambient*lightColor[0];
			ambient[1]=m_Ambient*lightColor[1];
			ambient[2]=m_Ambient*lightColor[2];
	
			diffuse[0]=m_Diffuse*lightColor[0];
			diffuse[1]=m_Diffuse*lightColor[1];
			diffuse[2]=m_Diffuse*lightColor[2];
	
			specular[0]=m_Specular*lightColor[0];
			specular[1]=m_Specular*lightColor[1];
			specular[2]=m_Specular*lightColor[2];
	
			m_Data->GetSpacings(spacings);
	
			specThreshold=pow(0.001f/max(max(specular[0],specular[1]),specular[2]),1.0f/m_SpecularPower);
	
			var   = glGetUniformLocationARB(m_GLSLProgram, "ambient");
			glUniform3fARB(var, ambient[0],ambient[1],ambient[2]);
	
			var   = glGetUniformLocationARB(m_GLSLProgram, "diffuse");
			glUniform3fARB(var, diffuse[0],diffuse[1],diffuse[2]);
	
			var   = glGetUniformLocationARB(m_GLSLProgram, "specular");
			glUniform3fARB(var, diffuse[0],diffuse[1],diffuse[2]);
	
			var   = glGetUniformLocationARB(m_GLSLProgram, "specular_power");
			glUniform1fARB(var, m_SpecularPower);
	
			var   = glGetUniformLocationARB(m_GLSLProgram, "light_direction");
			glUniform4fARB(var, lightDirection.ele[0],lightDirection.ele[1],lightDirection.ele[2],0.0f);
			
			var   = glGetUniformLocationARB(m_GLSLProgram, "spacings");
			glUniform4fARB(var,spacings[0],spacings[1],spacings[2],1.0f);
	
			var   = glGetUniformLocationARB(m_GLSLProgram, "spec_threshold");
			glUniform1fARB(var, specThreshold);
		}
		
		float ratio=m_SampleDistance/m_StdSampleDistance;
		float alphaToOpacity[256];
		int i;
		for (i=0;i<256;i++) 
			alphaToOpacity[i]=1.0f-pow(1.0f-i/256.0f,ratio);
	
		glActiveTextureARB(GL_TEXTURE1_ARB);
		glBindTexture(GL_TEXTURE_1D,m_A2OTexture);
		glTexSubImage1D(GL_TEXTURE_1D,0,0,256,GL_LUMINANCE,GL_FLOAT,alphaToOpacity);
	
	// render texture
	
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		glMultMatrixf(m_PixelsToViewMatrix);	
	
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
	
		glBegin(GL_QUADS);
		glTexCoord2i(m_ImageOrigin[0],m_ImageOrigin[1]);
		glVertex2i(m_ImageOrigin[0],m_ImageOrigin[1]);
		glTexCoord2i(m_ImageOrigin[0],m_ImageOrigin[1]+m_ImageInUseSize[1]);
		glVertex2i(m_ImageOrigin[0],m_ImageOrigin[1]+m_ImageInUseSize[1]);
		glTexCoord2i(m_ImageOrigin[0]+m_ImageInUseSize[0],m_ImageOrigin[1]+m_ImageInUseSize[1]);
		glVertex2i(m_ImageOrigin[0]+m_ImageInUseSize[0],m_ImageOrigin[1]+m_ImageInUseSize[1]);
		glTexCoord2i(m_ImageOrigin[0]+m_ImageInUseSize[0],m_ImageOrigin[1]);
		glVertex2i(m_ImageOrigin[0]+m_ImageInUseSize[0],m_ImageOrigin[1]);
		glEnd();
	
		glUseProgramObjectARB(0);
		glActiveTextureARB(GL_TEXTURE0_ARB);

	return true;
}

I donot understand about the below codes:

 // render texture
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glMultMatrixf(m_PixelsToViewMatrix);	

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

  glBegin(GL_QUADS);
  glTexCoord2i(m_ImageOrigin[0],m_ImageOrigin[1]);
  glVertex2i(m_ImageOrigin[0],m_ImageOrigin[1]);
  glTexCoord2i(m_ImageOrigin[0],m_ImageOrigin[1]+m_ImageInUseSize[1]);
  glVertex2i(m_ImageOrigin[0],m_ImageOrigin[1]+m_ImageInUseSize[1]);
  glTexCoord2i(m_ImageOrigin[0]+m_ImageInUseSize[0],m_ImageOrigin[1]+m_ImageInUseSize[1]);
  glVertex2i(m_ImageOrigin[0]+m_ImageInUseSize[0],m_ImageOrigin[1]+m_ImageInUseSize[1]);
  glTexCoord2i(m_ImageOrigin[0]+m_ImageInUseSize[0],m_ImageOrigin[1]);
  glVertex2i(m_ImageOrigin[0]+m_ImageInUseSize[0],m_ImageOrigin[1]);
  glEnd();

  glUseProgramObjectARB(0);
  glActiveTextureARB(GL_TEXTURE0_ARB);

why need to render texture and the texture is GL_TEXTURE1_ARB ?

As far as I can tell the program uses two textures, one 3D one that contains the volume data and a 1D texture that contains some lookup table (for alpha values, going by the name). The use of texture unit 1 is a fairly arbitrary choice, the author could have used texture units 3 and 6 just as well. The only thing that needs to match is which texture is bound to which texture unit and the values assigned to the sampler uniforms (i.e.


var   = glGetUniformLocationARB(m_GLSLProgram, "VolTexture");
glUniform1iARB(var, 1);

)

Hmm, those actually seem to be mixed up in the code you posted. The “VolTexture” sampler is assigned value 1, but then


glActiveTextureARB(GL_TEXTURE1_ARB);
 glBindTexture(GL_TEXTURE_1D,m_A2OTexture);

binds the lookup table texture to texture unit 1.

Yes, i think it use texture m_A2OTexture, and then render it to a 2D quads. It is hard to understand. If you have time , you can download the source code.

When i change it to


glActiveTextureARB(GL_TEXTURE0_ARB);
 glBindTexture(GL_TEXTURE_1D,m_A2OTexture);

it shows the same output.