📄 t3dlib8.cpp
字号:
} // end if
// at this point, we are almost ready, but we have to normalize the normal vector!
// this is a key optimization we can make later, we can pre-compute the length of all polygon
// normals, so this step can be optimized
// compute length of normal
//nl = VECTOR4D_Length_Fast2(&n);
nl = curr_poly->nlength;
// compute vector from surface to light
VECTOR4D_Build(&obj->vlist_trans[ vindex_0].v, &lights[curr_light].tpos, &l);
// compute distance and attenuation
dist = VECTOR4D_Length_Fast2(&l);
// and for the diffuse model
// Itotald = Rsdiffuse*Idiffuse * (n . l)
// so we basically need to multiple it all together
// notice the scaling by 128, I want to avoid floating point calculations, not because they
// are slower, but the conversion to and from cost cycles
dp = VECTOR4D_Dot(&n, &l);
// only add light if dp > 0
if (dp > 0)
{
atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
i = 128*dp / (nl * dist * atten );
r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
} // end if
//Write_Error("\npoint sum=%d,%d,%d",r_sum,g_sum,b_sum);
} // end if point
else
if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT1) ////////////////////////////////////
{
//Write_Error("\nentering spot light1...");
// perform spotlight/point computations simplified model that uses
// point light WITH a direction to simulate a spotlight
// light model for point light is once again:
// I0point * Clpoint
// I(d)point = ___________________
// kc + kl*d + kq*d2
//
// Where d = |p - s|
// thus it's almost identical to the infinite light, but attenuates as a function
// of distance from the point source to the surface point being lit
// test if we already computed poly normal in previous calculation
if (n.z==FLT_MAX)
{
// we need to compute the normal of this polygon face, and recall
// that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
// build u, v
VECTOR4D_Build(&obj->vlist_trans[ vindex_0].v, &obj->vlist_trans[ vindex_1].v, &u);
VECTOR4D_Build(&obj->vlist_trans[ vindex_0].v, &obj->vlist_trans[ vindex_2].v, &v);
// compute cross product
VECTOR4D_Cross(&u, &v, &n);
} // end if
// at this point, we are almost ready, but we have to normalize the normal vector!
// this is a key optimization we can make later, we can pre-compute the length of all polygon
// normals, so this step can be optimized
// compute length of normal
//nl = VECTOR4D_Length_Fast2(&n);
nl = curr_poly->nlength;
// compute vector from surface to light
VECTOR4D_Build(&obj->vlist_trans[ vindex_0].v, &lights[curr_light].tpos, &l);
// compute distance and attenuation
dist = VECTOR4D_Length_Fast2(&l);
// and for the diffuse model
// Itotald = Rsdiffuse*Idiffuse * (n . l)
// so we basically need to multiple it all together
// notice the scaling by 128, I want to avoid floating point calculations, not because they
// are slower, but the conversion to and from cost cycles
// note that I use the direction of the light here rather than a the vector to the light
// thus we are taking orientation into account which is similar to the spotlight model
dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
// only add light if dp > 0
if (dp > 0)
{
atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
i = 128*dp / (nl * atten );
r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
} // end if
//Write_Error("\nspotlight sum=%d,%d,%d",r_sum, g_sum, b_sum);
} // end if spotlight1
else
if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT2) // simple version ////////////////////
{
//Write_Error("\nEntering spotlight2 ...");
// perform spot light computations
// light model for spot light simple version is once again:
// I0spotlight * Clspotlight * MAX( (l . s), 0)^pf
// I(d)spotlight = __________________________________________
// kc + kl*d + kq*d2
// Where d = |p - s|, and pf = power factor
// thus it's almost identical to the point, but has the extra term in the numerator
// relating the angle between the light source and the point on the surface
// test if we already computed poly normal in previous calculation
if (n.z==FLT_MAX)
{
// we need to compute the normal of this polygon face, and recall
// that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
// build u, v
VECTOR4D_Build(&obj->vlist_trans[ vindex_0].v, &obj->vlist_trans[ vindex_1].v, &u);
VECTOR4D_Build(&obj->vlist_trans[ vindex_0].v, &obj->vlist_trans[ vindex_2].v, &v);
// compute cross product
VECTOR4D_Cross(&u, &v, &n);
} // end if
// at this point, we are almost ready, but we have to normalize the normal vector!
// this is a key optimization we can make later, we can pre-compute the length of all polygon
// normals, so this step can be optimized
// compute length of normal
//nl = VECTOR4D_Length_Fast2(&n);
nl = curr_poly->nlength;
// and for the diffuse model
// Itotald = Rsdiffuse*Idiffuse * (n . l)
// so we basically need to multiple it all together
// notice the scaling by 128, I want to avoid floating point calculations, not because they
// are slower, but the conversion to and from cost cycles
dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
// only add light if dp > 0
if (dp > 0)
{
// compute vector from light to surface (different from l which IS the light dir)
VECTOR4D_Build( &lights[curr_light].tpos, &obj->vlist_trans[ vindex_0].v, &s);
// compute length of s (distance to light source) to normalize s for lighting calc
dists = VECTOR4D_Length_Fast2(&s);
// compute spot light term (s . l)
float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
// proceed only if term is positive
if (dpsl > 0)
{
// compute attenuation
atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);
// for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
// must be integral
float dpsl_exp = dpsl;
// exponentiate for positive integral powers
for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
dpsl_exp*=dpsl;
// now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf
i = 128*dp * dpsl_exp / (nl * atten );
r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
} // end if
} // end if
//Write_Error("\nSpotlight sum=%d,%d,%d",r_sum, g_sum, b_sum);
} // end if spot light
} // end for light
// make sure colors aren't out of range
if (r_sum > 255) r_sum = 255;
if (g_sum > 255) g_sum = 255;
if (b_sum > 255) b_sum = 255;
//Write_Error("\nWriting final values to polygon %d = %d,%d,%d", poly, r_sum, g_sum, b_sum);
// write the color over current color
curr_poly->lit_color[0] = RGB16Bit(r_sum, g_sum, b_sum);
} // end if
else
if (curr_poly->attr & POLY4DV2_ATTR_SHADE_MODE_GOURAUD) /////////////////////////////////
{
// gouraud shade, unfortunetly at this point in the pipeline, we have lost the original
// mesh, and only have triangles, thus, many triangles will share the same vertices and
// they will get lit 2x since we don't have any way to tell this, alas, performing lighting
// at the object level is a better idea when gouraud shading is performed since the
// commonality of vertices is still intact, in any case, lighting here is similar to polygon
// flat shaded, but we do it 3 times, once for each vertex, additionally there are lots
// of opportunities for optimization, but I am going to lay off them for now, so the code
// is intelligible, later we will optimize
//Write_Error("\nEntering gouraud shader...");
// step 1: extract the base color out in RGB mode
// assume 565 format
_RGB565FROM16BIT(curr_poly->color, &r_base, &g_base, &b_base);
// scale to 8 bit
r_base <<= 3;
g_base <<= 2;
b_base <<= 3;
//Write_Error("\nBase color=%d, %d, %d", r_base, g_base, b_base);
// initialize color sum(s) for vertices
r_sum0 = 0;
g_sum0 = 0;
b_sum0 = 0;
r_sum1 = 0;
g_sum1 = 0;
b_sum1 = 0;
r_sum2 = 0;
g_sum2 = 0;
b_sum2 = 0;
//Write_Error("\nColor sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
// new optimization:
// when there are multiple lights in the system we will end up performing numerous
// redundant calculations to minimize this my strategy is to set key variables to
// to MAX values on each loop, then during the lighting calcs to test the vars for
// the max value, if they are the max value then the first light that needs the math
// will do it, and then save the information into the variable (causing it to change state
// from an invalid number) then any other lights that need the math can use the previously
// computed value
// loop thru lights
for (int curr_light = 0; curr_light < max_lights; curr_light++)
{
// is this light active
if (lights[curr_light].state==LIGHTV2_STATE_OFF)
continue;
//Write_Error("\nprocessing light %d", curr_light);
// what kind of light are we dealing with
if (lights[curr_light].attr & LIGHTV2_ATTR_AMBIENT) ///////////////////////////////
{
//Write_Error("\nEntering ambient light....");
// simply multiply each channel against the color of the
// polygon then divide by 256 to scale back to 0..255
// use a shift in real life!!! >> 8
ri = ((lights[curr_light].c_ambient.r * r_base) / 256);
gi = ((lights[curr_light].c_ambient.g * g_base) / 256);
bi = ((lights[curr_light].c_ambient.b * b_base) / 256);
// ambient light has the same affect on each vertex
r_sum0+=ri;
g_sum0+=gi;
b_sum0+=bi;
r_sum1+=ri;
g_sum1+=gi;
b_sum1+=bi;
r_sum2+=ri;
g_sum2+=gi;
b_sum2+=bi;
// there better only be one ambient light!
//Write_Error("\nexiting ambient ,sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
} // end if
else
if (lights[curr_light].attr & LIGHTV2_ATTR_INFINITE) /////////////////////////////////
{
//Write_Error("\nentering infinite light...");
// infinite lighting, we need the surface normal, and the direction
// of the light source
// no longer need to compute no
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -