Monday, January 23, 2017

Textures Textures Textures

So I started with diffuse maps on level surfaces. Which is fairly straightforward. I did have to rearrange the rendering loop a little bit because in order to minimize texture binding switching I need to group polygons with the same textures together.

It didn't take me very long to get a shot like the above.  As you can see all the static level surfaces were textured.  It looked a lot more like Quake, even though sky, water, lava, portal and entity textures were still missing.

As I had mentioned in the previous post, Quakes uses a rather peculiar way to store the level texture coordinates.  Each polygon surface has 2 vectors that describe 2 axis of the UV plane and 2 offset values.  In order to get the texture coordinate, we perform a dot product of the vertex coordinate with the 2 axis and add the offsets (see this link under Texture Information Lump section)

Next thing to implement was entity textures.  Each entity in Quake has only one texture image, which usually has two parts.  The left half is for the front side of the object and the right half for the back side.  In entity models, vertexes are shared across triangles so each triangle has a flag indicating whether this is a front side triangle or a back side one and the vertexes texture coordinates needs to be adjusted if this vertex 1) is shared by both front side and back side triangles AND 2) is being used to render a back side triangle.

I ended up with an entity model renderer that renders each model in 2 steps.  First render all the front side triangles, then modify a uniform flag and render all back side triangles.

Quake uses the flag SURF_DRAWTURB to describe surfaces that has water, lava or portal textures.  It means to draw the textures with a turbulence effect.  This is fairly easy to implement in a fragment shader using the global time as a uniform and add an offset to the UV coordinates based on a Sin curve.

The last and most difficult texture type is SURF_DRAWSKY.  Quake's sky texture is like this

The left part is the foreground layer and the right part background.  The 2 parts scroll at different speeds to create an illusion of depth.

Now the tricky part is Quake doesn't have a sky box.  It just seals all openings of the level with polygons with the SURF_DRAWSKY flag.  Even though these polygons all have different facing and at different distance,  they need to look completely transparent and uniform.  This means the polygons' texture coordinates are completely useless,  if I use them to address the sky texture I would end up with seams on those sky polygons.

So I need to calculate the UV textures completely base on the sky's world coordinate.  And I did this in the pixel shader with a ray cast from the view point through the fragment's world coordinate to the sky:

scale = (SkyY - FragY)
Sky = ViewPoint + (Fragment - ViewPoint) * scale

So here we go, sky texture!

No comments: