# Tweening Colors in OpenGL

I'm making a sky gradient in OpenGL by drawing with glColorPointer and glDrawArrays. I would like to be able to change the sky colour from morning to daytime to evening etc. I can either:

• Make a number of sprites and fade them in with my framework
• Somehow tween the color vector in openGL over time and use a single sprite

The second one seems like a more efficient option, but my framework doesn't pass the time delta into the draw method for me to decide how far I've progressed into fading.

Here's my current code:

glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_FOG);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);

CGSize size = [[CCDirector sharedDirector] winSize];
float w = size.width;
float h = size.height;

const GLfloat vertices[] = {
0, 0,
w, 0,
0, h/3,
w, h/3,
0, h*2/3,
w, h*2/3,
0, h,
w, h,
};

const GLubyte colors[] = {
254,255,134,255,
254,255,134,255,
230,157,0,255,
230,157,0,255,
230,60,0,255,
230,60,0,255,
167,0,86,255,
167,0,86,255,
};

glVertexPointer(2, GL_FLOAT, 0, vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
glEnableClientState(GL_COLOR_ARRAY);

glDrawArrays(GL_TRIANGLE_STRIP, 0, 8);

glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

glEnable(GL_TEXTURE_2D);


Which gives me:

• "but my framework doesn't pass the time delta into the draw method" Then your framework is terrible and should be fixed and/or abandoned ASAP. If your drawing code has no way to get a time delta, then that's something that needs to be fixed. Jan 31 '12 at 7:41
• @Nicol I don't think I've ever used a framework that passed dT into the draw method. And you could just as easily encapsulate that functionality in a class in which draw method uses a variable that gets updated in its update method (which presumably has access to dT). Jan 31 '12 at 7:49
• This doesn't really answer your question - but you may get better results by tweening Hue-Saturation-Lightness/Value instead of RGB. It should result in a seemingly more natural transition. Also, nothing is stopping you from calculating the time deltas yourself; or update the sky entity from the update function with the time of day. Jan 31 '12 at 8:22
• @NicolBolas: Excuse me, but why would you need the time delta in the drawing method? Isn't the time delta only interesting in the update-logic, f.e. to know how much to move the ball down the slope? Jan 31 '12 at 8:34
• @Bobby: It depends on what you mean by "the draw method". That is, what the main drawing function's responsibilities are. The OP, for example, wants his drawing function to perform animation on drawing parameters. Is that something he should compute outside of the draw function? It depends on how he wants to structure his code. If there were serious animation, then there would need to be a system to handle animation of all kinds, then feed those values into hooks to the rendering system. But again, it depends on what he wants. Jan 31 '12 at 16:10

I fail to see what's the problem you're having. Update the time of day and tween the colors in the Update method (assuming it has access to the dt) and leave the Draw method only for rendering. I think that's the more logical solution. Also, encapsulate this in some sort of Sky class if you haven't done so already. So I'd definetly stick to the 2nd option. Something like:

class Sky
{
void Update(float dt)
{
// Update timeOfDay based on dt
// Update colors array based on timeOfDay
}

void Draw()
{
// Render sprite using current colors
}

float timeOfDay;
}


Edit

In particular, I think it would be a good idea to start by encapsulating the vertex/color generation code in a method that given a simple array of colors, would return the vertex/color arrays required for calling glVertexPointer and glColorPointer. Then use this method to generate each of the gradient sprites, and finally, given the timeOfDay determine which two of these sprites should be interpolated and by what amount. Then draw them on top of each other and interpolate the alpha value so that there's a cross-fade between them.
• I figured I only need two "GradientFill" sprites and I can load the nextState texture and fade into the current state, then unload the old state and load the next etc. Jan 31 '12 at 12:57