1
\$\begingroup\$

I'm currently trying to build a game with Ogre3D that is basically a moving vehicle that leaves a green trail (2D manual mesh) in it's path, what i'm trying to achieve is exactly what this image shows: enter image description here

My problem is that i need to change, by some method/technique, the color of the intersected path where the two meshes overlap (red area). I've been searching around the Ogre forum and found this thread http://www.ogre3d.org/forums/viewtopic.php?f=2&t=47674, I've replicated that solution in my code but now on the screen i only see the intersected path. I'm a total newbie in stencil buffers and in Ogre generally, so I'm still not sure if this is the best approach to solve my problem. should I try another method rather than applying a stencil buffer? vertex/fragment shader code that could help?

Any advice or direction that you could provide will be very appreciated. Thanks a lot

***** UPDATE *****

According to JasonPh's answers i've managed to start adding some code:

1) Create manual texture

Ogre::TextureManager* tmgr = Ogre::TextureManager::getSingletonPtr();
gkString mMapTextureName = "pathTexture";
if (!tmgr->resourceExists(mMapTextureName)) {
    Ogre::TexturePtr ptr = tmgr->createManual(mMapTextureName,
                           Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                           Ogre::TEX_TYPE_2D,
                           480,  // Width
                           640,    // Height
                           1, // Depth
                           0,
                           Ogre::PF_A8R8G8B8,
                           Ogre::TU_RENDERTARGET);

    ptr->createInternalResources();
    ptr->load();

    Ogre::RenderTexture* pathTexture = ptr->getBuffer()->getRenderTarget();
    gkEngine* engine = gkEngine::getSingletonPtr();
    Ogre::Camera* camera = engine->getActiveScene()->getMainCamera()->getCamera();
    pathTexture->addViewport(camera);
    pathTexture->getViewport(0)->setClearEveryFrame(true);
    pathTexture->getViewport(0)->setBackgroundColour(Ogre::ColourValue::Black);
    pathTexture->getViewport(0)->setOverlaysEnabled(false);
    pathTexture->setAutoUpdated(true);
}

2) Create material from scratch and use the previously created texture. This material is then assigned to my "path" entity.

Ogre::MaterialManager* mmgr = Ogre::MaterialManager::getSingletonPtr();
mMaterialName = uniqueMaterialName("pathMaterial");
mMaterial = mmgr->create(mMaterialName, "General");

Ogre::Technique* tec = mMaterial->getTechnique(0);
tec->setSchemeName("ShaderGeneratorDefaultScheme");
Ogre::Pass* pass = tec->getPass(0);
pass->setVertexProgram("pathMaterial/vs", false);
pass->setFragmentProgram("pathMaterial/fs", false);
pass->setCullingMode(Ogre::CULL_NONE);
pass->setColourWriteEnabled(true);
pass->setLightingEnabled(true);
Ogre::TextureUnitState* tus = pass->createTextureUnitState();
tus->setTextureFiltering(Ogre::TFO_NONE);
tus->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP, Ogre::TextureUnitState::TAM_CLAMP, Ogre::TextureUnitState::TAM_CLAMP);
tus->setTexture(tmgr->getByName(mMapTextureName));

mMaterial->prepare();
mMaterial->load();

3) Fragment shader code

uniform sampler2D pathTexture; 

void main() 
{ 
   vec4 color = texture2D(pathTexture, gl_TexCoord[0].xy); =  
   if(color == vec4(0.0, 1.0, 0.0, 1) //green
       gl_FragColor = vec4(1.0, 0.0, 0.0, 1) //red
   else
       gl_FragColor = vec4(0.0, 1.0, 0.0, 1) //green       
}

This still needs some fixes to work, so new questions have emerged:

1) Do I realy need to render "pathTexture" on screen to this to work? Maybe that texture could only be used to decide pixel colors an then discard it?

2) To only use "pathTexture" as an "input" for my shader, should I add a second pass on my material file with "pathTexture" as a texture unit?

Thanks!

\$\endgroup\$

2 Answers 2

0
\$\begingroup\$

First you will want to render your path to a separate texture(let's call it "pathTexure"), and when you create it you will fill it with white. When you render a pixel that is part of the path, you will check if the pixel is green, if it is you will set that pixel to red, else set it to green. Finally, you add the "pathTexure" onto whatever you are drawing on the scene(cars, backgrounds, etc.).

\$\endgroup\$
6
  • \$\begingroup\$ Thanks for your answer, how exactly can I implement this step: "...you will check if the pixel is green...", fragment shader? \$\endgroup\$
    – EzeEst
    Nov 1, 2016 at 19:58
  • \$\begingroup\$ Yes you can do it using the fragment shader. You can sample the texture at the current texture coordinate. \$\endgroup\$
    – JasonPh
    Nov 1, 2016 at 20:49
  • \$\begingroup\$ Ok, let's see if I'm getting this right: 1- Render the actual path into a texture (pathTexture). 2- When rendering a new path (white) check (in fragment shader) against pathTexture if the pixel to be rendered is already green, then decide with that info. Is this right?. Thanks again. \$\endgroup\$
    – EzeEst
    Nov 2, 2016 at 17:39
  • \$\begingroup\$ Yes, and at the end add the pathTexture with whatever you are drawing on the scene. \$\endgroup\$
    – JasonPh
    Nov 2, 2016 at 18:20
  • \$\begingroup\$ Added some code to my post \$\endgroup\$
    – EzeEst
    Nov 7, 2016 at 12:13
0
\$\begingroup\$

What you are essentially doing is counting the number of times each pixel is drawn to. There are two obvious ways to do this: incrementing the stencil buffer, or incrementing the color buffer using additive blending. Due to the difficulty of using a texture as a stencil buffer in OpenGL, I recommend using additive blending in this case.

The basic steps are:

  1. Create a framebuffer with a texture as the color attachment and prepare to render to it. See https://learnopengl.com/Advanced-OpenGL/Framebuffers for how to do this. Because we're only tracking one thing, it can be a single-channel texture format (e.g. GL_R8).
  2. Set the blend mode to additive blending using glBlendFunc(GL_ONE, GL_ONE).
  3. Render the entire path mesh in a solid off-black color. Doesn't matter how you do this - you could e.g. write a shader that sets gl_FragColor.r = 1 / 255.0 (for an 8-bit texture). You could use other values here depending on how many stops you want and the precision of the color buffer, but beware of rounding errors and sRGB conversion.
  4. At this point, you now have a texture with the information you want: every pixel stores how many times it was covered by the path mesh.
  5. Draw the texture you just rendered into as a fullscreen quad, using a lookup table in the fragment shader to convert the texture values to the corresponding colors (e.g. white, green, red, etc.). The lookup table can be accomplished either by indexing into a uniform array, or sampling a 1D texture. Once again, take care to map the values correctly, avoiding sRGB conversions and, if you use an array for the lookup table, clamping the maximum value to avoid indexing past the end of the array.
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .