1. Summary
  2. Files
  3. Support
  4. Report Spam
  5. Create account
  6. Log in

Some useful tips

From g3d

(Difference between revisions)
Jump to: navigation, search
(How to configure shader)
(How to configure shader)
 
(3 intermediate revisions not shown)
Line 38: Line 38:
Note that this is just example and this code works quite slowly. It needs to be hard optimized.
Note that this is just example and this code works quite slowly. It needs to be hard optimized.
-
[[File:2013-05-31_000_Loki.jpg|100px]] [[File:2013-05-31_001_Loki.jpg|100px]]
+
[[File:2013-05-31_000_Loki.jpg|100px]] [[File:2013-05-31_001_Loki.jpg|100px]] [[File:2013-06-16_000_Loki.jpg|100px]]
== How to configure shader ==
== How to configure shader ==
Line 51: Line 51:
But before we start let's define some helper function which will let us easily create shader:
But before we start let's define some helper function which will let us easily create shader:
-
  Shader::Ref createShader(std::string shaderName) {
+
  shared_ptr<Shader> createShader(std::string shaderName) {
   if(FileSystem::exists("data/shaders/" + shaderName + ".vrt",false) && FileSystem::exists("data/shaders/" + shaderName + ".pix",false))
   if(FileSystem::exists("data/shaders/" + shaderName + ".vrt",false) && FileSystem::exists("data/shaders/" + shaderName + ".pix",false))
   return Shader::fromFiles("data/shaders/" + shaderName + ".vrt", "data/shaders/" + shaderName + ".pix");
   return Shader::fromFiles("data/shaders/" + shaderName + ".vrt", "data/shaders/" + shaderName + ".pix");
Line 182: Line 182:
So now when enemy will cast curse to your character you can easily render magic effect just calling setShader() method:
So now when enemy will cast curse to your character you can easily render magic effect just calling setShader() method:
-
  person->setShader("curse");
+
  person->setShader("curse"); //of course person must know what spell it caught (just pass it with other parameters like damage and so on)
Of course you have to define structure for shader uniforms, make additions to setShaderFunc(..) and define configure shader function for curse shader (e.g. confCurseShader). I hope general principle is clear.
Of course you have to define structure for shader uniforms, make additions to setShaderFunc(..) and define configure shader function for curse shader (e.g. confCurseShader). I hope general principle is clear.
Sky, terrain and water in section above are made in this way.
Sky, terrain and water in section above are made in this way.

Current revision as of 17:40, 22 June 2013

How to get reflection map for using with water or mirror shader.

In simple words you should render the scene above the water to texture with fliped Y-axis.

Assume you placed water at [0,1,0] with such code:

shared_ptr<ArticulatedModel> water = ArticulatedModel::create(PARSE_ANY(
 ArticulatedModel::Specification {
  filename = "data/Textures/white_blank_square.png";
  preprocess = (
   setCFrame("root", CFrame::fromXYZYPRDegrees(0, 1, 0));
   transformGeometry(root(), Matrix4::scale(300, 1, 300));
  );
 }
));

So you can get reflection map with this example:

m_frameBuffer->set(Framebuffer::COLOR0, water_reflection);		
renderDevice->pushState(m_frameBuffer); {
   CoordinateFrame cf;
   cf.lookAt(renderDevice->cameraToWorldMatrix().lookVector() * Vector3(1,-1,1));
   cf.translation = renderDevice->cameraToWorldMatrix().translation * Vector3(1,-1,1);
   renderDevice->setInvertY(true);
   renderDevice->setCameraToWorldMatrix(cf);		
   renderDevice->setProjectionMatrix(renderDevice->projectionMatrix() * Matrix4::scale(1,-1,1));

   {
      GLdouble plane[] = {0,-1,0,0}; //this is equation for plane we want to clip
      glEnable(GL_CLIP_PLANE0);
      glClipPlane(GL_CLIP_PLANE0, plane);

      drawWholeScene(renderDevice);
	
      glDisable(GL_CLIP_PLANE0);
   }
} renderDevice->popState();

Now you can use "water_reflection" as sampler2D reflection map in your water shader. Note that this is just example and this code works quite slowly. It needs to be hard optimized.

How to configure shader

If you look at the G3D samples, you'll see that shader configuring is hard coded into main loop. This is fine if you exactly know what shader you have to configure (sky, water and so on). But in real game you often don't know what shader is applied to object. Let me explain. You control the character and no shader is applied to render it, but a minute later you've met the enemy and he put a curse to your character. Now you need to apply curse shader to render magic special effect around your person. But it could be any other magic and you don't know what spell enemy will cast therefore you don't know what shader you need to configure.

I'd like to suggest one way to solve this problem. The key point is to use function pointers to set proper configuring function. But before we start let's define some helper function which will let us easily create shader:

shared_ptr<Shader> createShader(std::string shaderName) {
 if(FileSystem::exists("data/shaders/" + shaderName + ".vrt",false) && FileSystem::exists("data/shaders/" + shaderName + ".pix",false))
  return Shader::fromFiles("data/shaders/" + shaderName + ".vrt", "data/shaders/" + shaderName + ".pix");
 else if(FileSystem::exists("data/shaders/" + shaderName + ".vrt",false))
  return  Shader::fromFiles("data/shaders/" + shaderName + ".vrt", "");
 else
  return Shader::fromFiles("", "data/shaders/" + shaderName + ".pix");
}

First you have to define all shader uniform arguments as a structure. Suppose you have such shader (it paints object with specified color):

fragment shader:

#version 330

uniform sampler2D lambertianMap;
uniform vec3 Color;
out vec4 outputF;

in vec4 out_texcoord0;

void main()
{
 vec4 fColor = texture2D(lambertianMap, out_texcoord0.st);
 outputF = fColor * vec4(Color, 0.0);
}

vertex shader:

#version 330

in vec4 vertex;
in vec4 texcoord0;
uniform mat4 MVP;

out vec4 out_texcoord0;

void main()
{
 out_texcoord0 = texcoord0;
 gl_Position = MVP * vertex;
}

So your structure will be:

struct ColorShaderArgs {
 Color3 Color;
 Matrix4 MVP;
};

Second step is to define configure function for this shader:

void confColorShader(shared_ptr<UniversalSurface::GPUGeom> gpuGeom, Args *shaderArgs, void *uniforms) {
 const UniversalBSDF::Ref& bsdf = gpuGeom->material->bsdf();
 shaderArgs->setUniform("lambertianMap", bsdf->lambertian().texture());
 shaderArgs->setUniform("Color", ((ColorShaderArgs*)uniforms)->Color);
 shaderArgs->setUniform("MVP", renderDevice->projectionMatrix() *
    renderDevice->modelViewMatrix());
 shaderArgs->setStream("texcoord0", gpuGeom->texCoord0);
 shaderArgs->setStream("vertex", surface->gpuGeom()->vertex);
 shaderArgs->setIndexStream(surface->gpuGeom()->index);

 //Here you should pass all values to shader, not only from structure.
 //This shader has only three parameters but more complex shader can have much more.
}

As you can see gpuGeom is used to pass vertex attributes, index attributes, some texture and also can be used to pass other things stored in UniversalSurface::GPUGeom.

Further we define function which will set proper configure function for shader. This function looks at the shader name and returns pointer to right configure shader function.

typedef void (*pFunc)(shared_ptr<UniversalSurface::GPUGeom>, Args*, void*);
pFunc setShaderFunc(std::string shaderName, void ** uniforms) {
 if(shaderName == "color") {
  ColorShaderArgs * tmp = new ColorShaderArgs;
  *uniforms = tmp;
  tmp->Color = Color3::green();
  //here you should create all things needed to pass to the shader: normal maps, distortion maps, noise maps and so on.
  //so if you have terrian shader and it requires normal map, you can create it here like this:
  //tmp->normalMap = Texture::fromFile("data/textures/normalMap.png");
  //then yo should pass this texture to the shaderArgs in confColorShader(...)

  return confColorShader;
 }

 *uniforms = NULL;
 return NULL;
}

Suppose your drawable class looks like this:

class Drawable {
 ArticulatedModel::Ref model;
 Shader::Ref shader;
 pFunc configureShaderArgs;		//pointer to conf function;
 void * uniforms;			//here we store uniforms arguments we'll pass to the G3D::Args. There is void* cause' it can be any structure (e.g. shader);
public:
 void setModel(std::string modelName) {...}
 void setShader(std::string shaderName);
};

void Drawable::setShader(std::string shaderName) {
 shader = createShader(shaderName);
 configureShaderArgs = setShaderFunc(shaderName, &uniforms);
}

Then create character:

//create drawable object:
Drawable * person = new Drawable;
preson->setModel("archer");
person->setShader("color");

Now configureShaderArgs points to right configure function and uniform pointer has right type and you can render it with shader in such way. In person's render method:

if(notNull(shader)) {
...
 if(configureShaderArgs != NULL) {
  rd->pushState();

  // Send model geometry to the graphics card
   for (int i = 0; i < s.size(); ++i) {
    // Downcast to UniversalSurface to access its fields
    shared_ptr<UniversalSurface> surface = dynamic_pointer_cast<UniversalSurface>(s[i]);
    if (notNull(surface)) {
     rd->setObjectToWorldMatrix(cf);
     
     Args shaderArgs;
     (*configureShaderArgs)(surface->gpuGeom(), &shaderArgs, uniforms ? uniforms : NULL);	// Configure Shader Arguments
     rd->apply(shader, shaderArgs);
    }
   }
...
  rd->popState();
}

So now when enemy will cast curse to your character you can easily render magic effect just calling setShader() method:

person->setShader("curse"); //of course person must know what spell it caught (just pass it with other parameters like damage and so on) 

Of course you have to define structure for shader uniforms, make additions to setShaderFunc(..) and define configure shader function for curse shader (e.g. confCurseShader). I hope general principle is clear. Sky, terrain and water in section above are made in this way.

Personal tools