4
\$\begingroup\$

I'm still very new to all this but learning a lot. I'm putting together an application using Ogre3d as the rendering engine. So far I've got it running, with a simple scene, a day/night cycle system which is working okay.

I'm now moving on to looking at changing the color of the skydome material based on the time of day. What I've done so far is to create a struct to hold the ColourValues for the different aspects of the scene.

struct todColors {
    Ogre::ColourValue sky;
    Ogre::ColourValue ambient;
    Ogre::ColourValue sun;
};

I created an array to store all the colours

todColors   sceneColours [4];

I populated the array with the colours I want to use for the various times of the day. For instance DayTime (when the sun is high in the sky)

sceneColours[2].sky = Ogre::ColourValue(135/255, 206/255, 235/255, 255);
sceneColours[2].ambient = Ogre::ColourValue(135/255, 206/255, 235/255, 255);
sceneColours[2].sun = Ogre::ColourValue(135/255, 206/255, 235/255, 255);

I've got code to work out the time of the day using a float currentHours to store the current hour of the day 10.5 = 10:30 am. This updates constantly and updates the sun as required.

I am then calculating the appropriate colours for the time of day when relevant using

else if( currentHour >= 4 && currentHour < 7) {

    // Lerp from night to morning
    Ogre::ColourValue lerp = Ogre::Math::lerp<Ogre::ColourValue, float>(sceneColours[GT_TOD_NIGHT].sky , sceneColours[GT_TOD_MORNING].sky, (currentHour - 4) / (7 - 4));

}

My original attempt to get this to work was to dynamically generate a material with the new colour and apply that material to the skydome. This, as you can probably guess... didn't go well.

I know it's possible to use shaders where you can pass information such as colour to the shader from the code but I am unsure if there is an existing simple shader to change a colour like this or if I need to create one.

What is involved in creating a shader and material definition that would allow me to change the colour of a material without the overheads of dynamically generating materials all the time?

EDIT : I've created a glsl vertex and fragment shaders as follows.

Vertex

uniform vec4 newColor;

void main()
{
gl_FrontColor = newColor;
gl_Position = ftransform();
}

Fragment

void main()
{
gl_FragColor = gl_Color;
}

I can pass a colour to it using ShaderDesigner and it seems to work. I now need to investigate how to use it within Ogre as a material.

EDIT :

I created a material file like this :

vertex_program colour_vs_test glsl
{
source test.vert
default_params
{
    param_named newColor float4 0.0 0.0 0.0 1
}
}

fragment_program colour_fs_glsl glsl
{
source test.frag
}

material Test/SkyColor
{
technique
{
    pass
    {
        lighting off

        fragment_program_ref colour_fs_glsl
        {
        }
        vertex_program_ref colour_vs_test
        {
        }
    }
}
}

In the code I have tried :

Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName("Test/SkyColor");
Ogre::GpuProgramParametersSharedPtr params = material->getTechnique(0)->getPass(0)->getVertexProgramParameters();
params->setNamedConstant("newcolor", Ogre::Vector4(0.7, 0.5, 0.3, 1));

I've set that as the Skydome material which seems to work initially. I am doing the same with the code that is attempting to lerp between colours, but when I include it there, it all goes black.

Seems like there is now a problem with my colour lerping.

\$\endgroup\$
  • 1
    \$\begingroup\$ Keep in mind, there is an Ogre add-on that will do all of this for you (free) ogre3d.org/tikiwiki/tiki-index.php?page=SkyX \$\endgroup\$ – Blue Wizard Jun 3 '14 at 14:48
  • 1
    \$\begingroup\$ If I recall correctly, in c++ 135/255 is an int division and the result will be rounded \$\endgroup\$ – Luke B. Sep 1 '14 at 16:58
  • \$\begingroup\$ @LukeB. Truncated, actually. All of those values will end up as 0. It's better to just deal with the colors as floats to begin with; the fact that the system may or may not use a uint8_t internally is irrelevant to your goals. \$\endgroup\$ – fluffy Nov 1 '14 at 20:55
  • \$\begingroup\$ Also, the alpha channel should be 1.0, not 255 in sceneColours[2].sky = Ogre::ColourValue(135/255, 206/255, 235/255, 255); (or at least 255/255) \$\endgroup\$ – user1118321 Dec 10 '16 at 3:34
1
\$\begingroup\$

Okay well... I couldn't work out what was going on with the lerp in Ogre. I tried vectors and floats and it just wasn't happening as expected. However, it occurred to me that surely the shaders would have a lerp functionality in them. Perhaps one that actually works.

I modified my vertex shader like this :

uniform vec4 oldcolor;
uniform vec4 newcolor;
uniform float time;

void main() {
    gl_FrontColor = mix(oldcolor, newcolor, time);
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

Turns out in glsl the lerp equivalent is mix.

Then I modified the code where I was setting the sky colour based on the time of day in order to pass both the oldcolor and the newcolor. The colours I wanted to lerp between.

Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName("Test/SkyColor");
Ogre::GpuProgramParametersSharedPtr params = material->getTechnique(0)->getPass(0)->getVertexProgramParameters();
params->setNamedConstant("oldcolor", nightSkyColor);
params->setNamedConstant("newcolor", morningSkyColor);
params->setNamedConstant("time", lerpAmount);

Then update the skyDome with the modified material

OgreFramework::getSingletonPtr()->m_pSceneMgr->setSkyDome(true, "OpenZone/SkyColor", 5, 8);

That is a very basic GLSL shader to blend the colour of a material with Ogre3d.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.