Hi
Recently I've started to carry on work on my engine,
I've decided to add bumpmap support to my class working
with Q3 Arena BSP map. I've had no experience with
bumpmapping before, although I loved it.
So somehow I've put it together and now - somehow -
it is showing levels with bumpmapping, but problem
I have is with lights. Particularly with finding best
light for some face. What is best light? I thought,that
it is closest one. No, it is not true. Then I thought
that face's normal must face light directly and be
closest one if posible. I've played around with few
posibilities, but I am still in beginning. I cannot
find best light source for bumpmapping. I should say,
that I am looking for one light source, because I don't
know how should I evaluate more lights for bumpmap purpose.
I will show you my problem on few examples:
In this one, the light is evaluated per whole face. I
will find light closest to whole face, then I compute
all vertices (bump shift - cubemap) to this perticular light.
(notice lightchange on the floor between hall and corridor)
Well, but what is problem - you can see on picture - that
on border of two faces, the light is different. From corridor
it is becoming dark, and from hall it is still light. So there
is awful light jump.
Code is about this:
void bspLevel::CalculateBumpVerticesLightShift ()
{
... some checks if light exist at all
// go throught all faces and find closest light
// do bump map shift according to this light
Vertex lightVector; // vector from vertices to light
Vertex stred; // middle point in face
for (int i=0;i<m_nFaces;i++)
{
bspFace *f = &m_pFaces;
// find middle point of face and make vector from it to light
// take first and third for ease
stred = m_pVertices[f->VertexIndex] + m_pVertices[f->VertexIndex + 2];
stred /= 2;
// find closest light and use face normal
Vertex light = ((CLight *)lt.FindClosestLight ( stred,f->m_vNormal ))->m_vPos;
for (int j=0;j<f->m_nVertices;j++)
{
int id = f->VertexIndex + j;
lightVector = light - m_pVertices[id];
m_pVertices[id].CubemapCoord.x = CMath::DotProduct (m_pVertices[id].STangent, lightVector);
m_pVertices[id].CubemapCoord.y = CMath::DotProduct (m_pVertices[id].TTangent, lightVector);
m_pVertices[id].CubemapCoord.z = CMath::DotProduct (f->m_vNormal, lightVector);
}
}
}
So .. I've decided to find closest light to every single vertex
in face, it's solved something, but not all problems. See image below:
You see the problem? Lights are not OK, because it makes weird
effect on walls, somewhere there is too much light, for me it
is random. Code was:
void bspLevel::CalculateBumpVerticesLightShift ()
{
... some checks if light exist at all
// go throught all faces and find closest light
// do bump map shift according to this light
Vertex lightVector; // vector from vertices to light
Vertex stred; // middle point in face
for (int i=0;i<m_nFaces;i++)
{
bspFace *f = &m_pFaces;
for (int j=0;j<f->m_nVertices;j++)
{
int id = f->VertexIndex + j;
Vertex light = ((CLight *)lt.FindClosestLight (m_pVertices[id],m_pVertices[id].m_vNormal ))->m_vPos;
lightVector = light - m_pVertices[id];
m_pVertices[id].CubemapCoord.x = CMath::DotProduct (m_pVertices[id].STangent, lightVector);
m_pVertices[id].CubemapCoord.y = CMath::DotProduct (m_pVertices[id].TTangent, lightVector);
m_pVertices[id].CubemapCoord.z = CMath::DotProduct (f->m_vNormal, lightVector);
}
}
}
Code for lightmanagers FindClosestLight, is not smartest one,
it goes trought all lights, find its closest two - one for really
closest and second for closest, which also faces light.
If there is no closest light which faces face, then use normal
closest.
Please take this function as temporary, not final, it is not
for optimalisation, but for understanding etc..
CLight *CLightManager::FindClosestLight (Vertex v, Vertex normal)
{
if (m_lLight.Count==0)
return NULL;
float vzdal = 99999; // for regarding normal
float vzdal2 = 99999; // without normal
float temp;
float uhel;
Vertex delta;
Vertex lightpos;
int id = 0; // id of light with normal
int id2 = 0; // id of light without normal
for (int i=0;i<m_lLight.Count;i++)
{
lightpos = m_lLight.m_vPos;
delta = lightpos - v;
temp = delta;
CMath::Normalize (δ);
uhel = CMath::DotProduct(delta, normal);
if (temp < vzdal && uhel>0)
{
vzdal = temp;
id = i;
}
if (temp < vzdal2)
{
vzdal2 = temp;
id2 = i;
}
}
// if there is not closest light with normal, then use closest without normal
if (vzdal == 99999)
{
id = id2;
}
// if vzdal1 light is too far, then use closest one
if (vzdal > 2 * vzdal2)
{
id = id2;
}
return &m_lLight[id];
}
So and now, what I need. Firstly I am not decided to continue with
only one light source per face, however I don't know how I should do
it for more lights. Is there any tutorial on it?
Well, let's say one light per face is enough. But how can I find
"good" light? How can I avoid this light jumps and light marks on
walls?
If you know some tutorial, which solves this - if in BSP it will be
great, let me know.
If you know some open source engine, which uses and solves this, also
let me know.
If you have better idea/procedure how to find best light, also let me know.
Any sugestions will be welcomed.
Thanks
Martin
[Edited by - martinhoge on December 5, 2005 8:54:50 AM]