GLSL Implementation

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
Paddon
Posts: 43
Joined: Thu Jul 06, 2006 4:09 pm

GLSL Implementation

Post by Paddon »

Hey all,

I am using the Irrlicht3D engine to develop a Visualization application for my current research. However, since I am developing on a mac I am using OpenGL rendering with Irrlicht. I have written my own, basic shader to use with irrlicht but I am not quite sure how I communicate from within the program, to the shader. Essentially I want to be able to draw a 3d cube (or sphere) and control the color and alpha value of it from within my program. Does anyone know how I do this?
Here are my working vertex and fragment shaders, and everything looks exactly how I would like it to, all that is left is figureing out how to mesh it with my code.

Vertex Shader:

Code: Select all

	void main() {
	
		vec3 normal, lightDir;
		vec4 diffuse;
		float NdotL;
		
		/* first transform the normal into eye space and normalize the result */
		normal = normalize(gl_NormalMatrix * gl_Normal);
		
		/* now normalize the light's direction. Note that according to the
		OpenGL specification, the light is stored in eye space. Also since 
		we're talking about a directional light, the position field is actually 
		direction */
		lightDir = normalize(vec3(gl_LightSource[0].position));
		
		/* compute the cos of the angle between the normal and lights direction. 
		The light is directional so the direction is constant for every vertex.
		Since these two are normalized the cosine is the dot product. We also 
		need to clamp the result to the [0,1] range. */
		NdotL = max(dot(normal, lightDir), 0.0);
		
		/* Compute the diffuse term */
		diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
		
		gl_FrontColor =  NdotL * diffuse;
		
		gl_Position = ftransform();
	}
Fragment Shader:

Code: Select all

void main()
	{
		gl_FragColor = gl_Color;
	}
I think I understand that you can just communicate with the shader via the setPixalShaderConstant() function. However, does this mean I can just define a uniform vec4 named color. Then set it gl_FragColor = color. And use the setPixalShaderConstant() function to assign this variable color the color and alpha values I choose? Or is it more difficult then that.

Also, which matricies do I have to set. I notice in the irrlicht tutorial they set the mInvWorld, mWorldViewProj, mLightPos, mLightColor, mTransWorld. What are the neccessary, analogous matricies I must send for GLSL?

Here is my ShaderCallBack class, with all the highlevel checking removed since I know I am going to use it, and have to use OpenGL.

Code: Select all


class MyShaderCallBack : public video::IShaderConstantSetCallBack
{
public:

	virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
	{
		video::IVideoDriver* driver = services->getVideoDriver();

		// set inverted world matrix
		// if we are using highlevel shaders (the user can select this when
		// starting the program), we must set the constants by name.

		core::matrix4 World = driver->getTransform(video::ETS_WORLD);
		


			services->setVertexShaderConstant("mInvWorld", &invWorld.M[0], 16);

		// set clip matrix

		core::matrix4 worldViewProj;
		worldViewProj = driver->getTransform(video::ETS_PROJECTION);			
		worldViewProj *= driver->getTransform(video::ETS_VIEW);
		worldViewProj *= driver->getTransform(video::ETS_WORLD);

			services->setVertexShaderConstant("mWorldViewProj", &worldViewProj.M[0], 16);
	

		// set camera position

		core::vector3df pos = device->getSceneManager()->
			getActiveCamera()->getAbsolutePosition();

			services->setVertexShaderConstant("mLightPos", reinterpret_cast<f32*>(&pos), 3);

		// set light color 

		video::SColorf col(0.0f,1.0f,1.0f,0.0f);

			services->setVertexShaderConstant("mLightColor", reinterpret_cast<f32*>(&col), 4);

		// set transposed world matrix
			
		core::matrix4 world = driver->getTransform(video::ETS_WORLD);
		world = world.getTransposed();

			services->setVertexShaderConstant("mTransWorld", &world.M[0], 16);
	}
};



I assume here I am not seting the correct matrix constants.... I just need the basic ones to get this working so a little help in that department would be awesome.

Thanks all,
- Jeff Paddon
Undergraduate Research Assistant
Physics Department
St. Francis Xavier University
omaremad
Competition winner
Posts: 1027
Joined: Fri Jul 15, 2005 11:30 pm
Location: Cairo,Egypt

Post by omaremad »

Your understanding of passing variables is correct.

As for the matrices you dont need to send any at all if you are not going to transform your vertices in a complex way;

In opengl shading you have direct acess to the state so no need to send any of the standard matrices.
The vertex posistions can just be made equal to ftransform (fixed function transform behaviour) and normals can just be transformed by the current normal matrix

Code: Select all

gl_Position = ftransform();
   Texcoord    = gl_MultiTexCoord0.xy;
   Normal=gl_Normal*gl_NormalMatrix;
Settable constantas need to be declared before the main function (global) using the sytax:

Code: Select all

uniform 'datatype' 'var name';
to pass data from the vertex shader to the pixel shader without using common state variables (you used gl colour) use

Code: Select all

varying 'datatype' 'var name';
where that line is used in both the pixel and vertex shader before the main function
"Irrlicht is obese"

If you want modern rendering techniques learn how to make them or go to the engine next door =p
Paddon
Posts: 43
Joined: Thu Jul 06, 2006 4:09 pm

Post by Paddon »

ok I think I understand... so how do I, then, load the shaders if I do not use the shader callback class (it seems I do not need it for my purposes)
- Jeff Paddon
Undergraduate Research Assistant
Physics Department
St. Francis Xavier University
Paddon
Posts: 43
Joined: Thu Jul 06, 2006 4:09 pm

Post by Paddon »

Ok so this is what I have so far, it is not working though, can anyone see why?

Vertex Shader:

Code: Select all

	void main() {
	
		vec3 normal, lightDir;
		vec4 diffuse;
		float NdotL;
		
		normal = normalize(gl_NormalMatrix * gl_Normal);

		lightDir = normalize(vec3(gl_LightSource[0].position));

		NdotL = max(dot(normal, lightDir), 0.0);
	
		diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
		
		gl_FrontColor =  NdotL * diffuse;
		
		gl_Position = ftransform();
		
	}
Fragment Shader:

Code: Select all

void main()
	{    
         
		gl_FragColor = gl_Color;
	}
MyShaderCallBack class:

Code: Select all

class MyShaderCallBack : public video::IShaderConstantSetCallBack
{
public:

	virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
	{
		video::IVideoDriver* driver = services->getVideoDriver();

		// set inverted world matrix
		// if we are using highlevel shaders (the user can select this when
		// starting the program), we must set the constants by name.
       f32 color[4] = {1.0,0.0,0.0,0.5};
	   services->setVertexShaderConstant("gl_Color",color, 4);
	
	}
};
Useage in main:

Code: Select all

int main()
{
  
  ICameraSceneNode* camera = smgr->addCameraSceneNodeMaya();  
  device->setEventReceiver(&reciever);
  device->getCursorControl()->setVisible(true);	
  	
	c8* vsFileName = "../../VertexShader"; // filename for the vertex shader
	c8* psFileName = "../../FragmentShader"; // filename for the pixel shader
	
	// create matrerials
	
	video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
	s32 newMaterialType = 0;
	
	if (gpu)
	{
		MyShaderCallBack* mc = new MyShaderCallBack();
		
		newMaterialType = gpu->addHighLevelShaderMaterialFromFiles(
				vsFileName,	"vertexMain", video::EVST_VS_1_1,
				psFileName, "pixelMain", video::EPST_PS_1_1,
				mc, video::EMT_SOLID);
	    mc->drop();
	}
	
	
	
    createGUI();
   
	ISceneNode* ball = smgr->addCubeSceneNode();
	
	ball->setMaterialTexture(0, driver->getTexture("wall.bmp")); // I also tried without this line (edit)
    ball->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType);
   
   while(device->run() && driver)
  {
     if (device->isWindowActive())
     {
		driver->beginScene(true, true, SColor(100,200,200,200));

	   
	   smgr->drawAll();
	   
	   env -> drawAll();
        
		 
	   driver->endScene();

      }
  }	  
 
 device->drop();
 return 0;
}
This is what I get, with and without the setMaterialTexture line

Image
- Jeff Paddon
Undergraduate Research Assistant
Physics Department
St. Francis Xavier University
omaremad
Competition winner
Posts: 1027
Joined: Fri Jul 15, 2005 11:30 pm
Location: Cairo,Egypt

Post by omaremad »

Read my post, you cant set any variable via the cpu, you have to declare it as a uniform.
"Irrlicht is obese"

If you want modern rendering techniques learn how to make them or go to the engine next door =p
Paddon
Posts: 43
Joined: Thu Jul 06, 2006 4:09 pm

Post by Paddon »

Yes, I understand that I cannot assign a variable in the cpu, but I don't think I understand how I use the variable I define as uniform.

eg

Code: Select all


uniform vec4 color

void main(){

   gl_FragColor = color;
 
}

Now in main.cpp do I just do something like this

Code: Select all

setPixalShaderConstant(color, 'value', 4)
will that assign my value for color to the shader?
- Jeff Paddon
Undergraduate Research Assistant
Physics Department
St. Francis Xavier University
omaremad
Competition winner
Posts: 1027
Joined: Fri Jul 15, 2005 11:30 pm
Location: Cairo,Egypt

Post by omaremad »

correct! remember the ; at the end of that uniform declaration.
"Irrlicht is obese"

If you want modern rendering techniques learn how to make them or go to the engine next door =p
Paddon
Posts: 43
Joined: Thu Jul 06, 2006 4:09 pm

Post by Paddon »

I am still having problems getting this to work. I will post my main method, my shader callback and my shader programs. It is not doing nearly what it should. I believe the cubs should be red and half transparent.

Shader.h

Code: Select all

/*
 *  shader.h
 *  VisApp2
 *
 *  Created by Jeff Paddon on 11/05/07.
 *  Copyright 2007 __MyCompanyName__. All rights reserved.
 *
 */
 
 #include <irrlicht.h>
 
using namespace irr;


class MyShaderCallBack : public video::IShaderConstantSetCallBack
{
public:

	virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
	{
		video::IVideoDriver* driver = services->getVideoDriver();

		// set inverted world matrix
		// if we are using highlevel shaders (the user can select this when
		// starting the program), we must set the constants by name.
       f32 color[4] = {1.0,0.0,0.0,0.5};
	   services->setVertexShaderConstant("gl_Color",color, 4);
	
	}
};
Main()

Code: Select all

int main()
{
  
  ICameraSceneNode* camera = smgr->addCameraSceneNodeMaya();  
  device->setEventReceiver(&reciever);
  device->getCursorControl()->setVisible(true);	
  	
	c8* vsFileName = "../../VertexShader"; // filename for the vertex shader
	c8* psFileName = "../../FragmentShader"; // filename for the pixel shader
	
	// create matrerials
	
	video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
	s32 newMaterialType = 0;
	
	if (gpu)
	{
		MyShaderCallBack* mc = new MyShaderCallBack();
		
		newMaterialType = gpu->addHighLevelShaderMaterialFromFiles(
				vsFileName,	"vertexMain", video::EVST_VS_1_1,
				psFileName, "pixelMain", video::EPST_PS_1_1,
				mc, video::EMT_SOLID);
	    mc->drop();
	}
	
	
	
    createGUI();
   
	ISceneNode* ball = smgr->addCubeSceneNode();
	
    ball->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType);
   
   while(device->run() && driver)
  {
     if (device->isWindowActive())
     {
		driver->beginScene(true, true, SColor(100,200,200,200));

	   
	   smgr->drawAll();
	   
	   env -> drawAll();
        
		 
	   driver->endScene();

      }
  }	  
 
 device->drop();
 return 0;
}
Fragment

Code: Select all

uniform vec4 color;

void main()
	{    
         
		gl_FragColor = color;
	}
Vertex

Code: Select all

uniform vec4 color;	

void main() {
	
		vec3 normal, lightDir;
		vec4 diffuse;
		float NdotL;
		
		normal = normalize(gl_NormalMatrix * gl_Normal);

		lightDir = normalize(vec3(gl_LightSource[0].position));

		NdotL = max(dot(normal, lightDir), 0.0);
	
		diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
		
		gl_FrontColor =  NdotL * diffuse;
		
		gl_Position = ftransform();
		
	}



I am still getting the same results as when I posted that first screen shot.


[edit]
I have tried adding the line ball->setMaterialFlag(video::EMF_LIGHTING, false); after the material is set but that changed nothing.
- Jeff Paddon
Undergraduate Research Assistant
Physics Department
St. Francis Xavier University
omaremad
Competition winner
Posts: 1027
Joined: Fri Jul 15, 2005 11:30 pm
Location: Cairo,Egypt

Post by omaremad »

That lighting flag sets the settings for T&L rendering (non programmable graphics) once you use a shader all lighting is lost and you have to program evrything yourself.


services->setVertexShaderConstant("gl_Color",color, 4);

here you set gl_Color while in your shader you declare the uniform as color, shaders dont complain if you set things wrongly so its hard to debug them.

only declare the uniform where you need it not in both the pixel and vertex shader.

Check your pm's.
"Irrlicht is obese"

If you want modern rendering techniques learn how to make them or go to the engine next door =p
Post Reply