Per Pixel Lighting

Started by
7 comments, last by OleKaiwalker 20 years, 8 months ago
Hey, I''m playing around with per pixel lighting through dot3 bump mapping, and I''d like to know, how to make specular lighting (like flashlights and pointlights). I can''t seem to figure it out, because the lighting is determinated by the vertices. On a quad with only 4 vertices it can''t be done... Am I right? My second question is: Is there another way to do per pixel lighting, that also does flashlights and so on... If yes, how is it done???
Advertisement
quote:Original post by OleKaiwalker
My second question is:
Is there another way to do per pixel lighting, that also does flashlights and so on... If yes, how is it done???

yes, it''s called arb_fragment_program or pixel shader. nvidia has some docs about that
our new version has many new and good features. sadly, the good ones are not new and the new ones are not good
Specular pixel lighting without ARB_fragment_program is quite difficult and slow. But is is possible. The problem here is the power-operation with the shininess. You can easily do dot3 operation in texture environments but no power operation. You have to multiply the dot-result until you reached the shininess. Using ARB_fragment_program can do that in only one pass but requires a new graphic card (GeForceFX, Radeon 9500 or newer).

Here my implementation of bump mapping with specular lighting using 4 texture units, maybe it might help you. (notice that only the specular power operation takes 5 passes when the shininess is 32!!)

glPushAttrib(GL_ALL_ATTRIB_BITS);	ToRender->SetArrays();	TheLight->BindPosition(GL_LIGHT0);	glPushAttrib(GL_ALL_ATTRIB_BITS);		glPolygonOffset(1.0f, 1.0f);		glEnable(GL_POLYGON_OFFSET_FILL);		VP_Pass1->Bind();		glActiveTextureARB(GL_TEXTURE0);		glEnable(GL_TEXTURE_CUBE_MAP);		HalfMap->Bind();		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);		glActiveTextureARB(GL_TEXTURE1);		glEnable(GL_TEXTURE_CUBE_MAP);		HalfMap->Bind();		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);		glActiveTextureARB(GL_TEXTURE2);			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);		for (unsigned int j = 0; j < ToRender->NumMeshes; j++)		{			ToRender->Meshes[j]->SetNormalMap();			ToRender->Meshes[j]->Render();		}	glPopAttrib();	glDepthFunc(GL_LEQUAL);	glDepthMask(GL_FALSE);	glEnable(GL_POLYGON_OFFSET_FILL);	glPolygonOffset(-0.01f, 0.0f);	glPushAttrib(GL_ALL_ATTRIB_BITS);		glDisable(GL_VERTEX_PROGRAM_ARB);		glEnable(GL_BLEND);				for (unsigned int j = 0; j < ToRender->NumMeshes; j++)		{			glBlendFunc(GL_ZERO, GL_DST_COLOR);			for (unsigned int i = 2; i <= ToRender->Meshes[j]->GetShininess(); i *= 2)			{				ToRender->Meshes[j]->Render();			}			ToRender->Meshes[j]->SetMaterialSpecAsColor();			glBlendFunc(GL_DST_COLOR, GL_ZERO);			ToRender->Meshes[j]->Render();		}			glPopAttrib();	VP_Pass2->Bind();	glEnable(GL_BLEND);	glBlendFunc(GL_ONE, GL_ONE);	glPushAttrib(GL_ALL_ATTRIB_BITS);		glActiveTextureARB(GL_TEXTURE0);		glEnable(GL_TEXTURE_CUBE_MAP);		NormCubeMap->Bind();		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE0);		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE1);		glActiveTextureARB(GL_TEXTURE1);				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);			for (unsigned int j = 0; j < ToRender->NumMeshes; j++)		{			ToRender->Meshes[j]->SetMaterialDiffAsColor();			glActiveTextureARB(GL_TEXTURE1);			ToRender->Meshes[j]->SetNormalMap();			glActiveTextureARB(GL_TEXTURE2);			ToRender->Meshes[j]->SetBase();			ToRender->Meshes[j]->Render();		}						glPopAttrib();	glBlendFunc(GL_DST_COLOR, GL_ZERO);	glDisable(GL_VERTEX_PROGRAM_ARB);	glPushAttrib(GL_ALL_ATTRIB_BITS);		for (unsigned int j = 0; j < ToRender->NumMeshes; j++)		{			TheLight->BindColorAsColor();			ToRender->Meshes[j]->Render();		}	glPopAttrib();	glBlendFunc(GL_ONE, GL_ONE);	glPushAttrib(GL_ALL_ATTRIB_BITS);		glActiveTextureARB(GL_TEXTURE0);		glEnable(GL_TEXTURE_2D);		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);		for (unsigned int j = 0; j < ToRender->NumMeshes; j++)		{			ToRender->Meshes[j]->SetMaterialAmbAsColor();			ToRender->Meshes[j]->SetBase();			ToRender->Meshes[j]->Render();		}						glPopAttrib();glPopAttrib();


VP_Pass1:

!!ARBvp1.0
# Vertex Program vor Diffuse & Specular Bump Mapping
# ARB2 Profile Pass 1

ATTRIB Position = vertex.position;
ATTRIB Normal = vertex.normal;
ATTRIB STangent = vertex.attrib[6];
ATTRIB TTangent = vertex.attrib[7];
ATTRIB TexCoord0 = vertex.texcoord[0];

OUTPUT oPosition = result.position;
OUTPUT oTexCoord0 = result.texcoord[0];
OUTPUT oTexCoord1 = result.texcoord[1];
OUTPUT oTexCoord2 = result.texcoord[2];

PARAM mview[] = { state.matrix.mvp };
PARAM light = state.light[0].position;
PARAM view = program.env[0];

TEMP LightVecObj; # Light Vector in Object Space
TEMP ViewVecObj; # View Vector in Object Space
TEMP H; # Half Vector
TEMP lng;

DP4 oPosition.x, mview[0], Position;
DP4 oPosition.y, mview[1], Position;
DP4 oPosition.z, mview[2], Position;
DP4 oPosition.w, mview[3], Position;

ADD LightVecObj, -Position, light;
ADD ViewVecObj, -Position, view;

DP3 lng, LightVecObj, LightVecObj;
RSQ lng, lng.x;
MUL LightVecObj, lng, LightVecObj;

DP3 lng, ViewVecObj, ViewVecObj;
RSQ lng, lng.x;
MUL ViewVecObj, lng, ViewVecObj;

ADD H, LightVecObj, ViewVecObj;

DP3 oTexCoord0.x, STangent, LightVecObj; #H;
DP3 oTexCoord0.y, TTangent, LightVecObj; #H;
DP3 oTexCoord0.z, Normal, LightVecObj; #H;

DP3 oTexCoord1.x, STangent, ViewVecObj; #H;
DP3 oTexCoord1.y, TTangent, ViewVecObj; #H;
DP3 oTexCoord1.z, Normal, ViewVecObj; #H;

MOV oTexCoord2, TexCoord0;

END

VP_Pass2:

!!ARBvp1.0
# Vertex Program vor Diffuse & Specular Bump Mapping
# ARB2 Profile Pass 2

ATTRIB Position = vertex.position;
ATTRIB Normal = vertex.normal;
ATTRIB STangent = vertex.attrib[6];
ATTRIB TTangent = vertex.attrib[7];
ATTRIB TexCoord0 = vertex.texcoord[0];
ATTRIB Color = vertex.color;

OUTPUT oPosition = result.position;
OUTPUT oTexCoord0 = result.texcoord[0];
OUTPUT oTexCoord1 = result.texcoord[1];
OUTPUT oTexCoord2 = result.texcoord[2];
OUTPUT oColor = result.color;

PARAM mview[] = { state.matrix.mvp };
PARAM light = state.light[0].position;

TEMP LightVecObj; # Light Vector in Object Space

DP4 oPosition.x, mview[0], Position;
DP4 oPosition.y, mview[1], Position;
DP4 oPosition.z, mview[2], Position;
DP4 oPosition.w, mview[3], Position;

ADD LightVecObj, -Position, light;

DP3 oTexCoord0.x, STangent, LightVecObj;
DP3 oTexCoord0.y, TTangent, LightVecObj;
DP3 oTexCoord0.z, Normal, LightVecObj;

MOV oTexCoord1, TexCoord0;
MOV oTexCoord2, TexCoord0;
MOV oColor, Color;

END

PS: The funniest thing I've noticed was that on a GeForce FX 5200 this implimentation is faster than the one-pass fragment program implimentation... :-)

--------------------------------------------------------

"If it looks good, it is good computer graphics"
"If it looks like computer graphics, it is bad computer graphics"

Corrail
corrail@gmx.at
ICQ#59184081

[edited by - Corrail on August 14, 2003 6:59:18 AM]
--------------------------------------------------------There is a theory which states that if ever anybody discovers exactly what the Universe is for and why it is here, it will instantly disappear and be replaced by something even more bizarre and inexplicable.There is another theory which states that this has already happened...
Real-Time Per-Pixel Point Lights and Spot Lights in OpenGL

There''s a few other, very nice, tutorials on that page.
How do I set my laser printer on stun?
quote:Original post by Wildfire
Real-Time Per-Pixel Point Lights and Spot Lights in OpenGL

There''s a few other, very nice, tutorials on that page.


The NV register combiners are evil. They only work with nvidia cards and they''re nowhere near as flexible as ARB_FP.

____________________________________________________________www.elf-stone.com | Automated GL Extension Loading: GLee 5.00 for Win32 and Linux

couldn''t you fake spot lights using projective texturing technique? (while rendering the geometry that is to be lit by the spot light from the cameras persepecitve)
quote:Original post by benjamin bunny
quote:Original post by Wildfire
Real-Time Per-Pixel Point Lights and Spot Lights in OpenGL

There''s a few other, very nice, tutorials on that page.


The NV register combiners are evil. They only work with nvidia cards and they''re nowhere near as flexible as ARB_FP.


So what else would you recommend using on a GF3/4?


Death of one is a tragedy, death of a million is just a statistic.
If at first you don't succeed, redefine success.
Well.... I learn VERY quick to use fragment_program and do PPL!
Were I learn? Go to humus Site and download the Phong OpenGL Example!

http://esprit.campus.luth.se/~humus/

download the vertex_program(you will not need it, but is same with fragment_program) tutorial from www.devmaster.net

download the ARB_Fragment_program pdf from ATI

also download the: Phong for dummies papper! And you are ready!

This is allo you need to start!
quote:Original post by python_regious
quote:Original post by benjamin bunny
quote:Original post by Wildfire
Real-Time Per-Pixel Point Lights and Spot Lights in OpenGL

There's a few other, very nice, tutorials on that page.


The NV register combiners are evil. They only work with nvidia cards and they're nowhere near as flexible as ARB_FP.


So what else would you recommend using on a GF3/4?


Death of one is a tragedy, death of a million is just a statistic.


GF3/4 supports nvidia's NV_VP1 and NV_FP1 extensions, which means you can write real shaders; there's no need to bother with the register combiners (which are pre-shader GF1 technology BTW).

Even better, write your shaders with Cg, and use the Cg runtime library to compile them on-the-fly, and you've got hardware independence, and porting to the OGLSL (when it's finally implemented on consumer hardware) should be easy.

[edited by - benjamin bunny on August 16, 2003 10:38:19 PM]

____________________________________________________________www.elf-stone.com | Automated GL Extension Loading: GLee 5.00 for Win32 and Linux

This topic is closed to new replies.

Advertisement