📄 t3dlib8.cpp
字号:
int _state, // state of light
int _attr, // type of light, and extra qualifiers
RGBAV1 _c_ambient, // ambient light intensity
RGBAV1 _c_diffuse, // diffuse light intensity
RGBAV1 _c_specular, // specular light intensity
POINT4D_PTR _pos, // position of light
VECTOR4D_PTR _dir, // direction of light
float _kc, // attenuation factors
float _kl,
float _kq,
float _spot_inner, // inner angle for spot light
float _spot_outer, // outer angle for spot light
float _pf) // power factor/falloff for spot lights
{
// this function initializes a light based on the flags sent in _attr, values that
// aren't needed are set to 0 by caller, nearly identical to version 1.0, however has
// new support for transformed light coordinates
// make sure light is in range
if (index < 0 || index >= MAX_LIGHTS)
return(0);
// all good, initialize the light (many fields may be dead)
lights[index].state = _state; // state of light
lights[index].id = index; // id of light
lights[index].attr = _attr; // type of light, and extra qualifiers
lights[index].c_ambient = _c_ambient; // ambient light intensity
lights[index].c_diffuse = _c_diffuse; // diffuse light intensity
lights[index].c_specular = _c_specular; // specular light intensity
lights[index].kc = _kc; // constant, linear, and quadratic attenuation factors
lights[index].kl = _kl;
lights[index].kq = _kq;
if (_pos)
{
VECTOR4D_COPY(&lights[index].pos, _pos); // position of light
VECTOR4D_COPY(&lights[index].tpos, _pos);
} // end if
if (_dir)
{
VECTOR4D_COPY(&lights[index].dir, _dir); // direction of light
// normalize it
VECTOR4D_Normalize(&lights[index].dir);
VECTOR4D_COPY(&lights[index].tdir, &lights[index].dir);
} // end if
lights[index].spot_inner = _spot_inner; // inner angle for spot light
lights[index].spot_outer = _spot_outer; // outer angle for spot light
lights[index].pf = _pf; // power factor/falloff for spot lights
// return light index as success
return(index);
} // end Create_Light_LIGHTV2
//////////////////////////////////////////////////////////////////////////////
int Reset_Lights_LIGHTV2(LIGHTV2_PTR lights, // light array to work with (new)
int max_lights) // number of lights in system
{
// this function simply resets all lights in the system
static int first_time = 1;
memset(lights, 0, max_lights*sizeof(LIGHTV2));
// reset number of lights global
num_lights = 0;
// reset first time
first_time = 0;
// return success
return(1);
} // end Reset_Lights_LIGHTV2
//////////////////////////////////////////////////////////////////////////////
int Light_OBJECT4DV2_World2_16(OBJECT4DV2_PTR obj, // object to process
CAM4DV1_PTR cam, // camera position
LIGHTV2_PTR lights, // light list (might have more than one)
int max_lights) // maximum lights in list
{
// {andre work in progress }
// 16-bit version of function
// function lights an object based on the sent lights and camera. the function supports
// constant/pure shading (emmisive), flat shading with ambient, infinite, point lights, and spot lights
// note that this lighting function is rather brute force and simply follows the math, however
// there are some clever integer operations that are used in scale 256 rather than going to floating
// point, but why? floating point and ints are the same speed, HOWEVER, the conversion to and from floating
// point can be cycle intensive, so if you can keep your calcs in ints then you can gain some speed
// also note, type 1 spot lights are simply point lights with direction, the "cone" is more of a function
// of the falloff due to attenuation, but they still look like spot lights
// type 2 spot lights are implemented with the intensity having a dot product relationship with the
// angle from the surface point to the light direction just like in the optimized model, but the pf term
// that is used for a concentration control must be 1,2,3,.... integral and non-fractional
unsigned int r_base, g_base, b_base, // base color being lit
r_sum, g_sum, b_sum, // sum of lighting process over all lights
r_sum0, g_sum0, b_sum0,
r_sum1, g_sum1, b_sum1,
r_sum2, g_sum2, b_sum2,
ri,gi,bi,
shaded_color; // final color
float dp, // dot product
dist, // distance from light to surface
dists,
i, // general intensities
nl, // length of normal
atten; // attenuation computations
VECTOR4D u, v, n, l, d, s; // used for cross product and light vector calculations
//Write_Error("\nEntering lighting function");
// test if the object is culled
if (!(obj->state & OBJECT4DV2_STATE_ACTIVE) ||
(obj->state & OBJECT4DV2_STATE_CULLED) ||
!(obj->state & OBJECT4DV2_STATE_VISIBLE))
return(0);
// for each valid poly, light it...
for (int poly=0; poly < obj->num_polys; poly++)
{
// acquire polygon
POLY4DV2_PTR curr_poly = &obj->plist[poly];
// light this polygon if and only if it's not clipped, not culled,
// active, and visible
if (!(curr_poly->state & POLY4DV2_STATE_ACTIVE) ||
(curr_poly->state & POLY4DV2_STATE_CLIPPED ) ||
(curr_poly->state & POLY4DV2_STATE_BACKFACE) )
continue; // move onto next poly
// set state of polygon to lit, so we don't light again in renderlist
// lighting system if it happens to get called
SET_BIT(curr_poly->state, POLY4DV2_STATE_LIT);
// extract vertex indices into master list, rember the polygons are
// NOT self contained, but based on the vertex list stored in the object
// itself
int vindex_0 = curr_poly->vert[0];
int vindex_1 = curr_poly->vert[1];
int vindex_2 = curr_poly->vert[2];
// we will use the transformed polygon vertex list since the backface removal
// only makes sense at the world coord stage further of the pipeline
//Write_Error("\npoly %d",poly);
// we will use the transformed polygon vertex list since the backface removal
// only makes sense at the world coord stage further of the pipeline
// test the lighting mode of the polygon (use flat for flat, gouraud))
if (curr_poly->attr & POLY4DV2_ATTR_SHADE_MODE_FLAT)
{
//Write_Error("\nEntering Flat Shader");
// step 1: extract the base color out in RGB mode, assume RGB 565
_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
r_sum = 0;
g_sum = 0;
b_sum = 0;
//Write_Error("\nsum color=%d,%d,%d", r_sum, g_sum, b_sum);
// 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
// set surface normal.z to FLT_MAX to flag it as non-computed
n.z = FLT_MAX;
// 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
r_sum+= ((lights[curr_light].c_ambient.r * r_base) / 256);
g_sum+= ((lights[curr_light].c_ambient.g * g_base) / 256);
b_sum+= ((lights[curr_light].c_ambient.b * b_base) / 256);
//Write_Error("\nambient sum=%d,%d,%d", r_sum, g_sum, b_sum);
// there better only be one ambient light!
} // 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
// 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;
// ok, recalling the lighting model for infinite lights
// I(d)dir = I0dir * Cldir
// 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)
{
i = 128*dp/nl;
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("\ninfinite sum=%d,%d,%d", r_sum, g_sum, b_sum);
} // end if infinite light
else
if (lights[curr_light].attr & LIGHTV2_ATTR_POINT) ///////////////////////////////////////
{
//Write_Error("\nEntering point light...");
// perform point light computations
// 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -