racer home

Blog

 

Home Daily (well) diary.


Dolphinity Organiser - free planning, project management and organizing software for all your action lists

(this is the Blog for 2008, for later Blogs go to this page)

15-12-2008 - Flares in lights

Although car lights should be rethought a bit, I've been adding a start of car light flares. Flares are linked to a car and have properties such as a normal, a position, color and size factor (front lights will have bigger flares than those for rear lights).

4-11-2008 - Projected lights

Some testing with projected lights (still very much in alpha). All objects are currently redrawn using the projected texture (which is clamped to avoid it repeating all over the scene). You can see that it misbehaves with alpha (blended) polygons, such as the trees in the image below. Also, it is flickering quite badly (Z-buffering issues) even with glPolygonOffset. Still, the potential shows for a reasonably convincing light. Also required is culling out the objects that are not near the light to avoid rendering the entire scene twice.

22-09-2008 - Bumpmapping

Next is bumpmapping; that meant this shader works in tangent space (to support a normal .tga map) which took quite some changes. The envmap on top is still done in world space, as the env(cube)map is rendered in world space, not tangent space. The only downside to this is that the reflection is calculated per vertex, not per fragment, so reflections don't take into account the bumpmap. Not a problem mostly, since it is only apparent at creases. The image below does diffuse, specular, fresnel reflection (more reflection as the viewing direction gets aligned with the surface), bumpmapping all at once. Notice the specular highlight breaks at the creases since it follows the normal map. The slight 'ghosting' effect at the creases is due to the fact that a fixed bumpmap effect is already in the diffuse map itself, so at most angles the real bumpmap works against the burned-in diffuse map. I'll have to change the body.tga to rip out those lines, or make them equally lit.

bumpmap car reflection

Some painting in Photoshop later I detached the crease line in the body .tga. Unfortunately specular banding seems to creep up, but from a distance things are fine:

bumpmapping car

Some mistakes actually look kind-of nice. :)

 

18-09-2008 - Road specularity

Road shine has always been done it seems with a sun(cube)map and some added grain on top of that. Today I tried getting this all to work in a shader with only 1 texturemap; the road. I then took the Red channel as a gloss map. Lots of parameters to tweak (specular intensity, mixing diffuse/specular etc) and you get for example:

Perhaps the Cg files are interesting for anyone new to it. I added a fresnel component so the specularity becomes more visible as you look more parallel to the ground.

[road_v.cg]

void main(
float4 inPosition : POSITION,
float3 inNormal : NORMAL,
float2 inTC0 : TEXCOORD0,
// Output
out float4 outPosition : POSITION,
out float2 outTC0 : TEXCOORD0,
out float3 outNormal : TEXCOORD1,
out float3 outPosW : TEXCOORD2,
out float reflectionFactor : TEXCOORD3,

// Params
uniform float4x4 modelViewProj,
uniform float4x4 modelMatrix,
uniform float3 eyePosW
)
{
float fresnelBias=0;
float fresnelScale=1.0;
float fresnelPower=4.0;

// Transform vertex
outPosition = mul(modelViewProj,inPosition);
outPosW = mul(modelMatrix,inPosition).xyz; // Object space to eye space with model transform

// Pass texcoords
outTC0 = inTC0;

// Transform normal with model transformation (not required for track objects)
//float3 N = mul((float3x3)modelMatrix, inNormal);
float3 N=normalize(inNormal);
outNormal=N;

// Fresnel
//
// Compute position and normal in world space
float3 posW = mul(modelMatrix, inPosition).xyz;

// Compute the incident, reflected, and refracted vectors
float3 I;
I=posW-eyePosW;
I=normalize(I);

// Compute reflection factor according to Fresnel
reflectionFactor=fresnelBias+fresnelScale*pow(1+dot(I,N),fresnelPower);
}

[road_f.cg]

void main(
// In
float2 tc0 : TEXCOORD0,
float3 normal : TEXCOORD1,
float3 inPosW : TEXCOORD2,
float inReflectionFactor : TEXCOORD3,
// Out
out float4 outColor : COLOR,
uniform sampler2D baseMap : TEXUNIT0,
uniform float3 lightDirection,
uniform float3 eyePosW
)
{
const float Ka=0.3;
const float Kd=1.0;
const float Ks=1.5;
const float shininess=4.0;
const float3 lightColor=float3(1,1,1);

float4 baseCol=tex2D(baseMap,tc0);

// Note that 'normal' is interpolated across the triangle, so it may not be normalized
float3 N=normalize(normal);

// Compute diffuse term
float3 L=lightDirection;
float diffuseLight=max(dot(N,L),0);
float3 diffuse=(Kd*diffuseLight+Ka)*baseCol.xyz; // Ambient+diffuse

// Compute the specular term
float3 V=normalize(eyePosW-inPosW);
float3 H=normalize(L+V);

float specularLight;
if (diffuseLight <= 0)specularLight=0;
else specularLight=pow(max(dot(N,H),0),shininess);

float3 specular=Ks*lightColor*specularLight*min(baseCol.r*1.0,1)*inReflectionFactor*1.5;

// Output total color
outColor.rgb=diffuse+specular;
outColor.a=1.0;
}

Sorry to say the shadow of the car is getting specular lighting where it shouldn't, but that may be done in multiple passes one day. Also, Carlswood is beginning to show its age as the texture coordinates are all going from 0..1 on the road, making it impossible to smear out tiremarks along longer stretches of road for example. No normals were also defined on the road, something which you really need at some point.

Adding some sun color later on ('lightColor'):

17-09-2008 - Specular & fresnel

Specular didn't really work well, since 'eyePosW' in Cg shaders wasn't right. It took quite a bit of fighting to get the math right, but the camera position is now ok for old-style Racer camera types (I have to check the spring types). Now per-pixel specular lighting is correct. I also added a texture lookup to get a better look. Starting on having global shaders in data/renderer/shaders as well, since these shaders are no trivial thing, so a bit of sharing between cars will surely be helpful.

per pixel specular lighting

After that, it was onto fresnel. Fresnel 'lighting' is used to determine the amount of reflection vs decal texturing. Imagine a pool of water; looking straight down you can look into the water, but the more you look along the water surface, the more reflective it seems. The pure fresnel reflection factor can be seen below (white=reflective, black=non-reflective):

Mixing this with the envmap in the Racer shader's 2nd layer ($trackenvmap) and using the fresnel value for the amount of envmapping mix gives this (notice that the reflection gets more visible where the surface is more aligned with the viewing direction; the side of the car stays relatively unreflective):

16-09-2008

More work on Cg shaders. I wanted to do Fresnel lighting but had some bad luck where some Cg parameters were not working correctly (such as eyePosW). So back to less interesting stuff like diffuse, ambient and specular lighting. Got that to work (specular needed working eyePosW). I managed to get that working at the end of the day; for clarity I skipped texturing so it's easier to see the effects of separate parts of the lighting. The nice thing is that this method uses per-pixel lighting, instead of OpenGL's default per-vertex lighting.

per pixel diffuse lighting

The vertex shader:

[diffuse_v.cg]
//
// Diffuse color only (demo)
// Base for per-fragment lighting
//

void main(
float4 inPosition : POSITION,
float3 inNormal : NORMAL,
float2 inTC0 : TEXCOORD0,
// Output
out float4 outPosition : POSITION,
//out float4 outColor : COLOR,
out float2 outTC0 : TEXCOORD0,
out float3 outNormal : TEXCOORD1,
out float3 outPosW : TEXCOORD2,

// Params
uniform float4x4 modelViewProj,
uniform float4x4 modelMatrix
)
{
// Transform vertex
outPosition = mul(modelViewProj,inPosition);
outPosW=inPosition;

// Pass texcoords
outTC0 = inTC0;

// Transform normal with model transformation
outNormal = mul(float3x3(modelMatrix),inNormal);
}

and fragment shader:

[diffuse_f.cg]
//
// Diffuse color (demo)
//

void main(
// In
float3 normal : TEXCOORD1,
float3 inPosW : TEXCOORD2,
// Out
out float4 outColor : COLOR,
uniform float3 lightDirection,
uniform float3 eyePosW
)
{
const float Ka=0.1;
const float Kd=0.6;
const float Ks=1.0;
const float shininess=10.0;
const float3 lightColor=float3(1,1,1);

// Note that 'normal' is interpolated across the triangle, so it may not be normalized
float3 N=normalize(normal);

// Compute diffuse term
float3 L=normalize(lightDirection);
float diffuseLight=max(dot(N,L),0);
float3 diffuse=Kd*diffuseLight; // Colorize?

// Ambient light
float ambient=Ka;

// Compute the specular term
float3 V=normalize(eyePosW - inPosW);
float3 H=normalize(L + V);

float specularLight;
if (diffuseLight <= 0)
specularLight=0;
else
specularLight=pow(max(dot(N,H),0),shininess);

float3 specular=Ks*lightColor*specularLight;

// Output total color
outColor.rgb=diffuse+ambient+specular;
outColor.a=1;
}

05-09-2008

Been progressing finally a bit more with bumpmapping in combination with Cg. Currently it's just using 1 texturemap (the normal map itself) and drawn as a grayscale image, but it works. Yesterday I got bumpmapping for track with 1 texturemap to work (it doesn't require transforming normals/tangents to the model transformation, so it's a bit easier).

Now the trick is to get Racer shaders (shader_body) to accept multiple layers and multitexture, so the Cg shaders have 2 texturemaps to work with (body.tga and body_normal.tga).

An hour or so later I've managed to add the diffuse map (the texture map as you normally would think of it) and a crooked environment map (the environment direction is still off). The graphics engine was already capable of multi-texturing, although it very quickly fell back to effectively single-pass layers. This next image shows a 3-texture unit multitextured single pass rendered with a vertex & fragment shader, where the fragment shader combines the 3 maps to do bump- and environment mapping. The lighting model doesn't do specular (yet?) but has a slight ambient fill light.


Dolphinity Organiser - free planning, project management and organizing software for all your action lists

(last updated December 30, 2014 )