⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 t3dlib8.cpp

📁 3D游戏编程大师技巧第十章的源代码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
                       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 + -