PDA

View Full Version : Attenuated PPL + ..... = ?



Freelancer
02-08-2004, 09:29 AM
Here is the code:

void SetPassThroughAttenStates()
{
static GLuint att_list = 0;

//Set up texture units
//Unit 0 - decal texture
glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex->GetId());

//Set up texture shader for unit 0:
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);

//unit 1 - pass through atten coords:
glActiveTextureARB(GL_TEXTURE1_ARB);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_PASS_THROUGH_NV);

//unit 2 - bump (normal) map - currently not in use
glActiveTextureARB(GL_TEXTURE2_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, bump->GetId());

//unit 3 - normalization cube map - currently not in use
glActiveTextureARB(GL_TEXTURE3_ARB);
glEnable(GL_TEXTURE_CUBE_MAP_ARB);
glBindTexture(GL_TEXTURE_CUBE_MAP, normal_cube_tex->GetId());

glActiveTextureARB(GL_TEXTURE0_ARB);

//Set up register combiners
//one general combiner
glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV , 1);
glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, light_diffuse);

// I've seen attenuated bump mapping examples without decal textures;
// I've seen ppl attenuation with flat textured surfaces...
// ...but never seen bump_map + decal + ppl_attenuation, with the
// exception of Ron Frazier's papers, which describe 6(!!!)-pass method.
//
// Furthermore, that method doesn't use any mid-end (GF3/GF4) features
// like vp's, more TMU's, more RC stages...
//
// The following code does only attenuated ppl with decal.
// How to *modify* it, so attenuated bump mapping WITH decal texture
// can be done in a single-pass? or, at least, 2 passes?
// Is that possible with GF3/GF4 hardware?

// Combiner 1 does: tex1 dot tex1 -> spare0
// Spare0 now holds the squared length of the vector in tex1.
glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE1_ARB,
GL_EXPAND_NORMAL_NV, GL_RGB);
glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_TEXTURE1_ARB,
GL_EXPAND_NORMAL_NV, GL_RGB);
glCombinerOutputNV(GL_COMBINER0_NV, GL_RGB, GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE);

// Set up final combiner to output: clampto01(1 - spare0) * col0 * tex0.

// First do (tex0 * col0) in the EF multiplier:
glFinalCombinerInputNV(GL_VARIABLE_E_NV, GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glFinalCombinerInputNV(GL_VARIABLE_F_NV, GL_CONSTANT_COLOR0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB);

// Now do rest:
glFinalCombinerInputNV(GL_VARIABLE_A_NV, GL_SPARE0_NV, GL_UNSIGNED_INVERT_NV, GL_RGB);
glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_E_TIMES_F_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glFinalCombinerInputNV(GL_VARIABLE_C_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glFinalCombinerInputNV(GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB);

glEnable(GL_REGISTER_COMBINERS_NV);

glEndList();

// Any ideas?
//
// Thanks for advance,
//
// Dmitry aka Freelancer.
}

Freelancer
02-08-2004, 09:31 AM
If anyone interested, here is the accompanying vertex program:

!!ARBvp1.0

#-------------------------------------------------------------------------#
# Attenuation Vertex Program - vp for per-vertex (attenuated) ppl setup #
#-------------------------------------------------------------------------#

# Parameters' definition:
# Matrices:
PARAM tm[4] = { state.matrix.texture[0] }; # texture matrix zero, contains atten. params
PARAM mvp[4] = { state.matrix.mvp }; # modelview-projection matrix

# Lighting:
PARAM lightPos = program.env[0]; #object space light position

# Per vertex inputs:
ATTRIB iPos = vertex.position; # position
ATTRIB iCol0 = vertex.color; # primary color
ATTRIB iTex0 = vertex.texcoord; # texture coord, unit 0
ATTRIB iNorm = vertex.normal; # normal
ATTRIB iTang = vertex.attrib[4]; # tangent
ATTRIB iBnrl = vertex.attrib[5]; # binormal

# Outputs:
OUTPUT oPos = result.position; # position
OUTPUT oCol0 = result.color; # color
OUTPUT oTex0 = result.texcoord; # texture coords for decal texture, unit 0
OUTPUT oTex1 = result.texcoord[1]; # texture coords for pp attenuation, unit 1
OUTPUT oTex2 = result.texcoord[2]; # texture coords for pp attenuation, unit 1
OUTPUT oTex3 = result.texcoord[3]; # tangent space light vector for ppl, unit 2

TEMP vertToLight;

# Transform vertex position to clip space:
DP4 oPos.x, mvp[0], iPos;
DP4 oPos.y, mvp[1], iPos;
DP4 oPos.z, mvp[2], iPos;
DP4 oPos.w, mvp[3], iPos;

# Just pass on texture coordinates:
MOV oTex0, iTex0;
MOV oTex2, iTex0;

# Transform position by texture matrix 0 to get 3d tex coords for attenuation;
# Put (s,t,r) -> (s1, t1, r1) for pass-through attenuation algorythm
# If you use it, be sure to rip out all the attenuation stuff,
# and use FP/RC for fragment processing.
DP4 oTex1.x, tm[0], iPos;
DP4 oTex1.y, tm[1], iPos;
DP4 oTex1.z, tm[2], iPos;

# light vector = (light position - vertex position)
ADD vertToLight, lightPos, -iPos;

# Convert light vector to tangent space
DP3 oTex3.x, vertToLight, iTang;
DP3 oTex3.y, vertToLight, iBnrl;
DP3 oTex3.z, vertToLight, iNorm;

# Pass on input color:
MOV oCol0, iCol0;

END

EDIT: texture matrix is set up the following way:

glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(0.5f, 0.5f, 0.5f);
glScalef(0.5f, 0.5f, 0.5f);
glScalef(1.0f / lightRadius, 1.0f / lightRadius, 1.0f / lightRadius);
glTranslatef(-light_position[0], -light_position[1], -light_position[2]);
glMatrixMode(GL_MODELVIEW);
...

[This message has been edited by Freelancer (edited 02-08-2004).]

jwatte
02-09-2004, 03:13 PM
I think most people don't find your question embedded in the middle of the code.

No, I don't know of a way for GeForce3/4 to do BOTH decal AND attennuation in a single pass.

If you can get attennuation in there, then you can accumulate lighting into the frame buffer, and then modulate decal when you're done. That'll tint specular, unless you accumulate specular seperately, though.

sqrt[-1]
02-09-2004, 09:29 PM
It is fairly easy to do bump + decal + pp_attenuation + pp_specular on Geforce 3 level hardware.

See this thread for attenuation: http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008916.html

So if your inputs are:
tex0 - Decal Texture
tex1 - Bump-map
tex2(cube) - Light Dir
tex3(cube) - Half angle

and the incomming color is the distance from the light to the fragment divided by the range. (don't worry about clamping as values outside this range are black)

With the above you can do simple 1-D^2 attenuation per-pixel with decal, bumpmapping and specular in one pass.

jwatte
02-10-2004, 08:47 AM
That's not per-pixel attennuation.

Consider:

B
/|
A D
\|
C

A, B and C are vertices; the light is at A. D is a point in the middle of the edge CB.

Suppose "B" and "D" are both further away from A than "range". However, "D" is closer than "range". No amount of per-vertex magic is going to give you an interpoland that will make the light affect D, but not C or B.

Michael Steinberg
02-10-2004, 09:27 PM
Maybe a bit of <code> something would do the magic? these ascii arts are a bit confusing if they dont come out the way intended to result....

Heeya, im back, hehehee!
Michael

sqrt[-1]
02-10-2004, 11:08 PM
Ok I stand corrected, there are some corner cases where what I said would not work accuratly (ie extremly poorly tessilated surfaces with lights that have a range less than the length of a polygon. (very rare in my work)).

So use this to handle jwattes' case:

So if your inputs are:
tex0 - Decal Texture
tex1 - Bump-map
tex2(cube) - Light Dir
tex3 - Light distance divided by range

will give you attenuation per-pixel with decal and bumpmapping in all cases. (if you want a crude pp specular you can hack it by using the secondary color to pass a half angle) But since your origional question did not ask for specular, this is ok.

Your move jwatte. http://www.opengl.org/discussion_boards/ubb/smile.gif

Freelancer
02-11-2004, 09:59 AM
Thank you guys, but...

1) I think FULL ammount of ppl goodies (diffuse+specular bump+attenuation) cannot be done on GF3/GF4 because of 4-textures-at once limitation. Thus, it can be done with Radeons (6 texturea-at-once).

2) For future: does anyone have a cool ARB_fragment_program that does if ALL in a single pass?

Guys, I really need it, SOS!!!

ScottManDeath
02-11-2004, 10:29 AM
It is inCG, I leave it as an exercise to compile it to ARBfp ;-)

It does the full (bumped) lighting with attenuation and gloss mapping.... not optimized and please don't mind my native languages comments.....
http://www.opengl.org/discussion_boards/ubb/wink.gif
vertex program



/************************************************** ****************************
*
* transformiert die L und V vektoren in den tangent space und gibt sie in
* textur koordinaten an den fragment shader für bumpmapping
*
*
*
*
*
*
************************************************** ****************************/
#define LIGHT0
//#define LIGHT1
//#define LIGHT2

// eintrittspunkt für das vertex programm
void main (

// attribute
in float4 position : ATTR0,
in float3 tangent : ATTR1,
in float3 binormal : ATTR2,
in float3 normal : ATTR3,
in float2 tex_coord : ATTR4,

//matrizen
uniform float4x4 model_view,
uniform float4x4 model_view_IT,
uniform float4x4 model_view_projection,
uniform float4x4 model_view_I,


uniform float4 l_position[3],

// für das fragment programm
out float4 o_position : POSITION,
out float2 o_tex_coord0 : TEXCOORD0,


out float3 o_view_vec : TEXCOORD1,
out float3 o_eye_position : TEXCOORD2,

out float3 o_light_vec0 : TEXCOORD3,
out float3 o_half_vec0 : TEXCOORD4,

out float3 o_light_vec1 : TEXCOORD5,
out float3 o_half_vec1 : TEXCOORD6,

out float3 o_light_vec2 : TEXCOORD7,
out float3 o_half_vec2 : COLOR0
)
{

// texturkoordinaten weiterschieben
o_tex_coord0 = tex_coord;

// vertex in clip space
o_position = mul(model_view_projection,position);

// und in eye space für attentuation im fragment shader
o_eye_position = mul ( model_view, position);


// matrix um vom objekt space in den tangen space zu kommen
// nur für richtungsvektoren !!
float3x3 obj_to_tan = float3x3(tangent,binormal, normal);

// view vektor in tangent space

// position des auges in object space
float4 obj_position_eye = mul(model_view_I, float4(0.0f,0.0f,1.0f,1.0f));
float3 obj_V = normalize((obj_position_eye - position).xyz );
o_view_vec = normalize(mul(obj_to_tan, obj_V));

#ifdef LIGHT0
// position der lichtquelle in object space
float4 obj_light_position0 = mul(model_view_I, l_position[0]);
// berechnung von L in objekt space
float3 obj_L0 = ((obj_light_position0 - position).xyz);
//und transformation von L in tangent space und ausgabe an den fragment shader
o_light_vec0 = (mul(obj_to_tan,obj_L0));
#endif

#ifdef LIGHT1
// position der lichtquelle in object space
float4 obj_light_position1 = mul(model_view_I, l_position[1]);
// berechnung von L in objekt space
float3 obj_L1 = normalize((obj_light_position1 - position).xyz);
//und transformation von L in tangent space und ausgabe an den fragment shader
o_light_vec1 = normalize(mul(obj_to_tan,obj_L1));
#endif

#ifdef LIGHT2
// position der lichtquelle in object space
float4 obj_light_position2 = mul(model_view_I, l_position[2]);
// berechnung von L in objekt space
float3 obj_L2 = normalize((obj_light_position2 - position).xyz);
//und transformation von L in tangent space und ausgabe an den fragment shader
o_light_vec2 = normalize(mul(obj_to_tan,obj_L2));
#endif


}

fragment program



/************************************************** ****************************
*
* bumpmapping, mit diffuse und specular licht
*
*
*
*
*
*
*
************************************************** ****************************/

// damit man beim compilieren eventuell einzelne lichter abschalten kann
#define LIGHT0
//#define LIGHT1
//#define LIGHT2

// funktion für point light
// man beachte das alle positionen / normalen im selben koordinatensystem sind
// addiert lichtintensität zur eingabe hinzu !!
void point_light (
// ein /ausgabe
inout float4 diffuse,
inout float4 specular,

in float3 light_vec,
in float3 half_vec,

in float3 normal,
in float3 light_attenuation,
in float distance,

// material
in float material_shininess,

// vormultiplizierte farben
in float4 k_ambient,
in float4 k_diffuse,
in float4 k_specular
)
{
// lichtberechnung
float4 dots = lit ( dot(normal,light_vec), dot(normal,half_vec),material_shininess);

float3 dist_vect = { 1.0f, distance, distance*distance };
float attenuation = 1.0f / dot(light_attenuation, dist_vect);


// ausgabe der farben
diffuse+= attenuation * (k_ambient + dots.y * k_diffuse);
specular+= attenuation * k_specular* dots.z;
}

float3 expand (float3 v)
{
return (v-0.5f)*2.0f;
}

// eintrittspunkt für das vertex programm

void main (
in float2 tex_coord : TEXCOORD0,

in float3 view_vec : TEXCOORD1,
in float3 eye_position : TEXCOORD2,

in float3 light_vec0 : TEXCOORD3,
in float3 half_vec0 : TEXCOORD4,

in float3 light_vec1 : TEXCOORD5,
in float3 half_vec1 : TEXCOORD6,

in float3 light_vec2 : TEXCOORD7,
in float3 half_vec2 : COLOR0,


// zum z-test, blending ...
out float4 o_color : COLOR,



//licht & material
uniform float3 l_attenuation[3],
uniform float4 l_position[3],


uniform float4 k_ambient[3],
uniform float4 k_diffuse[3],
uniform float4 k_specular[3],

uniform float m_shininess[3],

// texturen
uniform sampler2D tex_base,
uniform sampler2D tex_normal,
uniform sampler2D tex_height,
uniform sampler2D tex_gloss

)
{


float4 diffuse_sum = {0.0f,0.0f,0.0f,0.0f};
float4 specular_sum= {0.0f,0.0f,0.0f,0.0f};

float3 normal = normalize(expand( tex2D(tex_normal, tex_coord).xyz));


// lichtquelle 0
#ifdef LIGHT0
float3 L0 = normalize(light_vec0);
float3 H0 = normalize( L0 + normalize(view_vec) );

point_light ( diffuse_sum,
specular_sum,

L0,
H0,

normal,

l_attenuation[0],
distance(l_position[0].xyz,eye_position),
m_shininess[0],

k_ambient[0],
k_diffuse[0],
k_specular[0]
);
#endif

// lichtquelle 1
#ifdef LIGHT1
float3 L1 = normalize(light_vec1);
float3 H1 = normalize( L1 + normalize(view_vec) );

point_light ( diffuse_sum,
specular_sum,

L1,
H1,

normal,

l_attenuation[1],
distance(l_position[1].xyz,eye_position),
m_shininess[1],

k_ambient[1],
k_diffuse[1],
k_specular[1]
);
#endif

// lichtquelle 2
#ifdef LIGHT2
float3 L2 = normalize(light_vec2);
float3 H2 = normalize( L2 + normalize(view_vec) );

point_light ( diffuse_sum,
specular_sum,

L2,
H2,

normal,

l_attenuation[2],
distance(l_position[2].xyz,eye_position),
m_shininess[2],

k_ambient[2],
k_diffuse[2],
k_specular[2]
);
#endif

// ausgabe der farben
float4 base = tex2D(tex_base, tex_coord);
float4 gloss = tex2D(tex_gloss, tex_coord);
o_color.rgb = diffuse_sum.rgb * base.rgb + specular_sum.rgb * gloss.rgb;
o_color.a = base.a;

}

jwatte
02-11-2004, 03:24 PM
I have nothing to add; I think all I've said is exactly true.

Regarding per-pixel vs per-vertex lighting: those "special cases" are actually surprisingly common. And the light distance can be longer than the side of a triangle; all that's necessary is for one point on a edge to be closer to the light than the vertices at either end of the edge; that's pretty common (but with very high tesselation, it's usually less noticeable).

Both methods are valid and useful; I just answered exactly the question that was asked, not another question. (Although at times I find myself doing that, too :-)