User:Doug Sheets/Journal

From GPWiki
Jump to: navigation, search


Took some time off from my actual game project to explore rendering trees with 3d textures. The results are encouraging, I think there's some real potential here given proper art. Good lighting would probably be a real problem though, maybe thats why I don't see it in any games.

One of these days I need to write another tutorial. Cubemaps maybe? On the other hand I could start using that boring time stuck in hotel rooms all across the country (travel for work) to write up basic tutorials, since the laptop I have to haul around is about 6 years old and doesn't support any of the really cool stuff.  :)


Finally able to tear myself away from that godforsaken game, my account canceled. Much have I forgotten, too long have I been gone. Back, until my will falters again. (hey, that was almost a haiku)



No! I'm not dead! I just haven't felt the need to write down some thoughts in awhile. I've been doing lots of LAN Partying and playing D&D the last couple weeks so I haven't had a chance to do much game programming. For Xmas I got two graphics books (OpenGL Shading Language and The OpenGL Extensions Guide) and two game programming books (Game Physics and Game Programming Gems 4) and two t-shirts from Jinx Hackware ("Talk nerdy to me" and "Choose your weapon"). The OpenGL books have come in handy several times already but the extension one is (C) 2003 so its a bit out of date. Doh! I should've looked at that before I asked for it. Still, some of the explanations in it are less cryptic than just reading the specs for the extensions (Especially if you don't know what a given extension is used for).

The last couple days I've been working on similar lines to Codehead. I finally got around to adding a skybox to my terrain generator (cube maps work very well for this I might add) skybox cubemap function: <pre> void DrawSkyBox(CTGACubeMap &cubemap) { glDisable(GL_LIGHTING); cubemap.Bind(); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glPushMatrix(); glScalef(1.0, -1.0, 1.0); glRotated(worldstate->m_viewangle.x, 0.0, 1.0, 0.0); glRotated(worldstate->m_viewangle.y, 1.0, 0.0, 0.0); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_PLANE); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_PLANE); glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_PLANE); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_GEN_R); glCullFace(GL_FRONT); auxSolidCube(50.0); glCullFace(GL_BACK); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glDisable(GL_TEXTURE_GEN_R); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glPopMatrix(); glMatrixMode(GL_MODELVIEW);

} </pre>

The reflection effect I'm using is different than Codehead's:


  • It's quicker (no extra geometry, just some texture look ups)
  • can vary the reflective surface to get some nice mirror effects, like in funhouse mirrors or a realistic reflection in rippling/waving water. (I'm not sure how/if you could do this while reflecting the local geometry and keep it looking right in all cases.)


  • Doesn't reflect local geometry, just the sky texture
  • Per vertex texturing causes some visual artifacts if there isn't enough geometry in the reflective surface.

One caveat I've noticed when using cubemaps I didn't think of right off: If you use GL_REPEAT wrapping it wraps around the same face of the cubemap, which can lead to a box outline on anything you use the cubemap on due to filtering. The solution is to use GL_CLAMP_TO_EDGE for wrapping on all dimensions. John Carmack's recent blog/.plan update also contains some interesting cubemap related issues. (So far I haven't combined bumpmapping and environment mapping, but what he's saying makes sense.)

Here are some screenshots of the effect:

reflection 1 reflection 2

And the bump mapping shader mentioned in earlier entries, the yellow point is the light origin, relevant GL state: /OpenGL lighting is disabled/ so the light is being done purely by the shader, the geometry being rendered is a sphere.

bump 1 bump 2

12-11-04 18:10

Fog shader, fogs everything below plane y=4.0 with exponential fog, everything else is untouched. Looks pretty cool in my terrain generator. <pre> void main() { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; vec4 n; = gl_Normal; n.w = 0.0; n = gl_ModelViewMatrix * n; gl_FrontColor.a = gl_FrontMaterial.diffuse.a; gl_FrontColor.rgb = gl_FrontMaterial.ambient * gl_LightModel.ambient; vec4 lightv = normalize(gl_ModelViewMatrix * gl_LightSource[0].position - gl_Vertex); gl_FrontColor.rgb += gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse * dot(, lightv); gl_FogFragCoord = pow(4.0 - gl_Vertex.y, 2.0); if (gl_FogFragCoord < 0.0) { gl_FogFragCoord = 0.0; } } </pre> It really should take into account the vector to the viewpoint.

12-3-04 23:00

I think I got it (#2) <pre> void main() { gl_Position = ftransform(); vec4 n = normalize(vec4(gl_Normal.x, gl_Normal.y, gl_Normal.z, 0.0)); n = gl_ModelViewMatrix * n; vec4 s; = normalize(gl_ObjectPlaneS[0].xyz); s.w = 1.0; vec4 t; = normalize(gl_ObjectPlaneT[0].xyz); t.w = 1.0; mat3 texcoord = mat3(s.x, t.x, n.x, s.y, t.y, n.y, s.z, t.z, n.z); vec3 lightv = normalize(gl_LightSource[0].position - gl_ModelViewMatrix * gl_Vertex).xyz; gl_FrontColor.rgb = texcoord * lightv * 0.5 + 0.5; gl_TexCoord[0] = gl_MultiTexCoord0; gl_TexCoord[1] = gl_MultiTexCoord1; } </pre> It appears that GL keeps track of what texture space is in object space. Woot! I don't see any artifacts in this one (yet). Half hour later: took out two lines, makes it look better, and I wasn't sure they were necessary anyway.  :)

12-3-04 19:09 EST

Found a resource on the web that says I need to multiply the light vector by a 3x3 matrix consisting of the definitions of S and T axes and the normal of the vertex in world coordinates to convert the light vector to texture coordinates. Calculating the normal is a no-brainer, I have that calculated anyway for standard OpenGL lighting, just need to multiply it by the modelview matrix. The resource does not, that I see, contain any information on calculating what the S and T axes are in world coodinates.

  • The S and T axes must be perpendicular and in the plane defined by the normal.
  • I have 3 points in world space and their cooresponding coordinates in the S and T axes. Well, sort of, my vertex class automatically interpolates the normal at a vertex between all the triangles connected to it, so none of the points are exactly on the axes, but interpolation of the frontcolor between the vertices should limit the approximation error to an acceptable level.

I keep waivering back and forth on using linear equations S(x), and T(y) derived from the known points. If the axes are translated and/or scaled relative to X, Y I think it would work but rotation creates a whole new ball of wax and I think I'd need S(x,y) and T(x,y), and my intuition tells me curved surfaces would present special problems as well. Suggestions/Hints/Ideas welcome.

This all seems much more difficult than it should be. Is there a simpler way to convert a vector into a different coordinate system that I'm overlooking? Or a simple way to calculate the S and T axes in world coordinates? I should probably think this out some more and post on the forums as well.

11-30-04 18:11 EST

Found another problem with my bump mapping algorithm: normal maps assume the normal is (0 0 1) (and it looks perfect when thats the case), but I can't always assume that with my surfaces (especially since I'm using a sphere). I can't change the normal map vectors (not without fragment shaders anyway), but I can control the per-vertex light vectors, so the solution is to transform the light vector into texture space and use that for the front color. Hmmm... going to have to look up some math.


I'm so close to get bump mapping to work I can taste it. Contrary to what I was thinking, really high quality effects that have so far eluded me such as Phong shading and Bump mapping are quite possible using only Vertex Shaders. Fragment shaders aren't necessary. I don't believe I didn't see it before. The secret is to store a vector in the RGB components of the front color, instead of an actual color and use a dot product with some form of the light position. Right now my shader is <pre> vec4 temp; void main() { gl_Position = ftransform(); gl_FrontColor = normalize( ( ( gl_ModelViewMatrixInverse * gl_LightSource[0].position ) - gl_Vertex)); gl_TexCoord[0] = gl_MultiTexCoord0; } </pre> I'm getting some kind of weird bug where when objects are rotated by about 180 degrees they go completely black: (0, 0, 0) vector, which obviously is an incorrect when I'm trying to put the light vector in there. So close...

Devised a debug test: Take a sphere model, use the shader on it without any other texturing, keep the light position constant, rotate the sphere. The colors will stay in position on the sphere when the shader is working properly.

11-29-04 7:19 PM - I think I got it.

Shader: <pre> void main() { gl_Position = ftransform(); gl_FrontColor.rgb = (normalize(gl_LightSource[0].position - gl_ModelViewMatrix * gl_Vertex).xyz) * 0.5 + 0.5; gl_TexCoord[0] = gl_MultiTexCoord0;" } </pre> Texture environment options: <pre> glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB); </pre> And a bump map texture loaded.

11-29-04 8:09 PM

Found a bug in the shader and corrected it. When tesselated over a large area, one quadrant was darker than it should've been, rgb components are unsigned but the calculation for them was signed, so I converted to unsigned and the blackness went away. Its looking better.