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

📄 t3dlib8.cpp

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