# Thread: My attempt at lighting math

1. ## My attempt at lighting math

Anyone who has seen any of my other threads, knows that 3D math isn't exactly my strong point. However, i'm trying to do a static lighting system based on the OpenGL lighting model.
At this point, my light is dynamic (was easier to do this for testing purposes). The faces light up as they should, but I think Iv'e done somthing wrong with the vertex normals, as a normal that faces the opposite direction of the light is still fully lit.

Here is my StaticLight.cpp, then StaticLight.h, and then a snippit from the rendering code where the light is applied.

Code:
```/*static lighting code. Still needs alot of work. Currently only supports diffuse lighting*/
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <math.h>

#include "StaticLight.h"

bool pe_lightenabled;
pe_staticLight pe_sL;

//may remove the setupLighting function
GLvoid staticLight::setupLighting(GLfloat glbAmbient[3], GLfloat pos[3], GLfloat norm[3])
{
pe_sL.glbAmb = glbAmbient[3];
pe_sL.vPos3f[3] = pos[3];
pe_sL.vNormal3f = norm[3];
}

GLvoid staticLight::CalculateLighting(int ID, UINT lArray[],
float x, float y, float z,
float r, float g, float b,
float ca, float la, float qa)
{
//while (pe_lightenabled)
//{
//Setup:
//assign ID to the light
int id = lArray[ID];

//light positioning:
pe_sL.x = x;
pe_sL.y = y;
pe_sL.z = z;

//light coloring (diffuse):
pe_sL.r = r;
pe_sL.g = g;
pe_sL.b = b;

//light attenuation:
/*pe_sL.constant_attenuation = ca;
pe_sL.linear_attenuation = la;

//Render:
float L = sqrt( (pe_sL.vPos3f[0]-pe_sL.x)*(pe_sL.vPos3f[0]-pe_sL.x)+ \
(pe_sL.vPos3f[1]-pe_sL.y)*(pe_sL.vPos3f[1]-pe_sL.y)+ \
(pe_sL.vPos3f[2]-pe_sL.z)*(pe_sL.vPos3f[2]-pe_sL.z) );
float N = pe_sL.vNormal3f;

//calculate diffuse color:
float diffuser = pe_sL.r * (L*N);
float diffuseg = pe_sL.g * (L*N);
float diffuseb = pe_sL.b * (L*N);

if (pe_sL.r > 1.0)
pe_sL.r == 1.0;
if (pe_sL.g > 1.0)
pe_sL.g == 1.0;
if (pe_sL.b > 1.0)
pe_sL.b == 1.0;

pe_sL.finalColor3f[1] = diffuser; pe_sL.finalColor3f[2] = diffuseg; pe_sL.finalColor3f[3] = diffuseb;
//}

}

//this function, once/if finished, will tell a vertex to illuminate only when within the lights radius.
GLvoid staticLight::Vertex_In_Radius(float x, float y, float z)
{
/*some pseudo(spelling?) code for calculating the x:
diameter = total_attenuation/2 - lightposx;
if ( x < diameter | x > -diameter) then
light_the_vertex();*/
}

GLvoid staticLight::enableLighting(int type)
{
if (type == 1)
glDisable(GL_LIGHTING);
pe_lightenabled = TRUE;
if (type == 2)
glEnable(GL_LIGHTING);
pe_lightenabled = TRUE;
if (type == 3)//default
glEnable(GL_LIGHTING);
pe_lightenabled = FALSE;
if (type == 4)
glDisable(GL_LIGHTING);
pe_lightenabled = FALSE;

}```
Code:
```//hold information about our light
struct pe_staticLight
{
public:
GLfloat x, y, z;
GLfloat r, g, b, a;
GLfloat vPos3f[3];
GLfloat vNormal3f;
GLfloat finalColor3f[3], finalColor4f[4];
GLfloat glbAmb;
};

//static light class
class staticLight
{
private:
staticLight();
virtual ~staticLight();

public:
GLvoid setupLighting(GLfloat glbAmbient[3], GLfloat pos[3], GLfloat norm[3]);
//GLvoid drawLight();
GLvoid CalculateLighting(int ID, UINT lArray[], float x, float y, float z, float r, float g, float b, float ca, float la, float qa);
GLvoid Vertex_In_Radius(float x, float y, float z);
GLvoid enableLighting(int type);
};```
Code:
```	glBegin(GL_QUADS);
//-------front-------//
glNormal3f(0.0, 0.0, 1.0);
for (i=0; i<4; i++) {
c[0]=SolidCubeData[5*i+2];
c[1]=SolidCubeData[5*i+3];
c[2]=SolidCubeData[5*i+4];
glMultiTexCoord2fARB(GL_TEXTURE0_ARB,SolidCubeData[5*i]     , SolidCubeData[5*i+1]);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB,SolidCubeData[5*i], SolidCubeData[5*i+1]);

//_peStaticLight->enableLighting(4);
GLfloat global_ambient[3] = {0.75, 0.75, 0.75};
GLfloat vert_position[3] = {5*i+2, 5*i+3, 5*i+4};
GLfloat vert_normal[3] = {0.0, 0.0, 1.0};
_peStaticLight->setupLighting(global_ambient, vert_position, vert_normal);
_peStaticLight->CalculateLighting(0, lightID, 10, 10, 10, 1, 1, 1, 0, 1.5, 0);
glColor3f(pe_sL.finalColor3f[1], pe_sL.finalColor3f[2], pe_sL.finalColor3f[3]);
glVertex3f(SolidCubeData[5*i+2], SolidCubeData[5*i+3], SolidCubeData[5*i+4]);
}
glEnd();

//-------back-------//
glColor3f(1.0, 1.0, 1.0);
glNormal3f(0.0, 0.0, -1.0);
for (i=4; i<8; i++) {
c[0]=SolidCubeData[5*i+2];
c[1]=SolidCubeData[5*i+3];
c[2]=SolidCubeData[5*i+4];
glMultiTexCoord2fARB(GL_TEXTURE0_ARB,SolidCubeData[5*i]     , SolidCubeData[5*i+1]);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB,SolidCubeData[5*i], SolidCubeData[5*i+1]);

GLfloat global_ambient[3] = {0.75, 0.75, 0.75};
GLfloat vert_position[3] = {5*i+2, 5*i+3, 5*i+4};
GLfloat vert_normal[3] = {0.0, 0.0, -1.0};
_peStaticLight->setupLighting(global_ambient, vert_position, vert_normal);
_peStaticLight->CalculateLighting(0, lightID, 10, 10, 10, 1, 1, 1, 0, 1.5, 0);
glColor3f(pe_sL.finalColor3f[1], pe_sL.finalColor3f[2], pe_sL.finalColor3f[3]);
glVertex3f(SolidCubeData[5*i+2], SolidCubeData[5*i+3], SolidCubeData[5*i+4]);
}
glEnd();```
I'm still pretty shakey on this, so please bear with me

thanx,
-psychopath

2. You are probably not clamping the light values to always be between 0.0f and 1.0f.

Code:
```//Get vector from light to object
D3DXVECTOR3 NrmToLight=LightSource-ObjectPosition;

//Normalize the vector
D3DXVec3Normalize(&NrmToLight,&NrmToLight);

//Calculate dot product of ToLightVector and SurfaceNormal for this tri
float LightCoef=D3DXVec3Dot(&NrmToLight,&SurfaceNormal);

//Prevent backlighting
if (LightCoef<=0.0f) LightCoef=0.0f;
if (LightCoef>=1.0f) LightCoef=1.0f;

...
...```

I havn't really been focused on much of anything lately so that could be the reason

Anyway, from what you posted, I think I can see what I left out.
I'll post again if I end up with further questions (if i remember )

-psychopath

4. Hmm, well, I didn't forget the thread this time, lol
Anyway, i'm seeing some signs of lighting, except theres still a problem. I only see "lighting" Whenever a vertex leaves the screen. When it does, I can see it start to turn dark and the dark "creeps over the quad" (sorry, thats the best I can describe it). I'm pretty sure its because i'm not converting to a matrix (projections, modelview, tangent, etc). Problem is, I don't know what to convert it to or how...I don't even know if 'convert' is the right word for it, lol.

-psychopath

5. You need to do some things before your light your vertices.

Transform them from model space to world space. Perform the lighting in world space

Your lighting is really only applicable to model space - essentially the light and your object are the only thing in the world at that time. But you transform to world space and then do the lighting. Then transform to clip space, view space, and project onto screen. If you perform lighting prior to transforming to world space, you will get some very odd results.

This is because every object originates at 0,0,0 in model space. So if you compute the vector to the light from your model, you will get strange numbers because both of them are at 0,0,0. When you transform to world space, or essentially position them in the world, now the math works out fine because the center of the object is not 0,0,0, but wherever the object is in the world. So the lighting will work.

From another post with lots of lighting information.

Diffuse lighting
X - denotes component-wise multiplication
N - surface normal
L - vector points towards light

Diffuse=(N dot L)*SourceDiffuse X MaterialDiffuse

So in Direct3D you would do this:

Code:
```struct RGBA
{
BYTE Blue;
BYTE Green;
BYTE Red;
BYTE Alpha;
};

void ComputeDiffuse(RGBA *outColor,D3DXVECTOR3 toLight,D3DXVECTOR3 Normal,RGBA SourceDiffuse,RGBA MaterialDiffuse)
{
//Normalize light vector
D3DXVECTOR3 nrmToLight=D3DXVec3Normalize(&nrmToLight,&toLight);

//Compute dot product
float dot=D3DXVec3Dot(&nrmToLight,&Normal);

//Prevent backlighting
if (dot<0.0f) dot=0.0f;
if (dot>1.0f) dot=1.0f;

*outColor.Red=SourceDiffuse.Red*MaterialDiffuse.Red;
*outColor.Green=SourceDiffuse.Green*MaterialDiffuse.Green;
*outColor.Blue=SourceDiffuse.Blue*MaterialDiffuse.Blue;
*outColor.Alpha=SourceDiffuse.Alpha*MaterialDiffuse.Alpha;

*outColor.Red*=dot;
*outColor.Green*=dot;
*outColor.Blue*=dot;
*outColor.Alpha*=dot;
}```
I would highly recommend doing this inside of a vertex shader. They support data swizzling which makes all of this much easier than using C.

6. hmm, ok, i'll do some more fixing, and see what I come up with.

-psychopath

7. Actually, I AM rendering the light in world space, via the ModelView matrix. OpenGL is essentially doing all of the matrix transformations in the background. What you described is only applicable to D3D (from what google told me anyway). So, i'm pretty much lost again, lol

-psychopath

8. What I posted is applicable to all 3D graphics. The functions from the D3DX library are, of course, proprietary to DirectX.
Code:
```...
D3DXVECTOR3 nrmToLight=D3DXVec3Normalize(&nrmToLight,&toLight);

//Compute dot product
float dot=D3DXVec3Dot(&nrmToLight,&Normal);```
Here is what the code for them might look like in a software renderer or a non-API renderer.
They would probably be a part of a vector class with operators much like D3DXVECTOR3, but I left all that out for clarity's sake.
Code:
```struct Vector3
{
float x,y,z;

Vector3(void):x(0.0f),y(0.0f),z(0.0f) {}
Vector3(float _x,float_y,float_z):x(_x),y(_y),z(_z) {}
};

void Vec3Normalize(Vector3 &out,const Vector3 &in)
{
float distx=in.x*in.x;
float disty=in.y*in.y;
float distz=in.z*in.z;
float totaldist=sqrt(distx+disty+distz);
out.x=in.x/totaldist;
out.y=in.y/totaldist;
out.z=in.z/totaldist;
}

float Vec3Dot(Vector3 &V1, Vector3 &V2)
{
return (V1.x*V2.x)+(V1.y*V2.y)+(V1.z*V2.z);
}```

9. ok, the lighting is working for the most part, but the normals are still messed up. Faces facing in the opposite direction of the light are still being the lit as much as all the other faces. I was looking at some sample code though, and I think its because the normals arn't being transformed in to eye coords, but i'm not really sure. Is this correct?

-psychopath

10. Yes could be. You must transform all of the vertex into the correct space, including the normals. And after transformation, you may have to re-normalize the normals.

11. Iv'e been looking through some sample code, but I still don't get how to transform normals into different spaces .