Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Infinite Stencil Shadow Volume

Iniciado por Haddd, 27 de Mayo de 2005, 09:28:55 AM

« anterior - próximo »

Haddd

 Bueno, estoy intentando implementar esta técnica. Se basa en modificar la matriz de forma que al extrusionar el vértice para crear la proyección, se proyecte siempre sober el farplane, evitando así el problema de que la extrusión supere al farplane de la cámara y pasen cosas raras.


Esta es la matriz de la cámara modificada:

// Infinite projection matrix, that forces geometries at infinity to render
// at 1.0-epsilon depth
// This matrix is used if the silhouette edges are to be extruded to infinity
float epsilon = 0.0001f;
projection.M33 = 1.0f - epsilon;
projection.M43 = nearPlane * (epsilon - 1.0f);
projection.M34 = 1.0f;


Después hacemos lo siguiente al renderizar :



Matrix mLightClip, mLight, mInvLight, mWorldInvLight;

Vector3 position = posLuz;

mLight = Matrix.Translation(position);
mInvLight = Matrix.Translation(-position);

Matrix proj = Haddd.Scene.Camera.Projection;


mLightClip = mLight * Haddd.Scene.Camera.View*proj;

mWorldInvLight =  mInvLight;




Y este es el shader. Como podeis ver, los vértices los tengo en WorldSpace y si es < que un cierto nº significa que es un vértice a extrusionar.

VS_OUTPUT VShaderVolume(VS_INPUT vin)
{
VS_OUTPUT vout;
 
  float4 pos=vin.position;
 
  if(pos.z<=-5000.0f)
  {
   pos.z+=10000.0f;
   
   
  // Transform vertex to WorldLight space
  pos = mul( pos, mWorldInvLight );

   pos.w=0;
   
  // Multiple the vertex with vMask, transform to clip space and output
  vout.position = mul( pos , mLightClip );
  }
  else
 vout.position = mul(pos,WorldViewProjection);

return vout;
}


Pues bien, me sale...más o menos. Es decir, veo que realmente se proeycta al final en el far clip, pero al moverme me aparecen jaggies y errores.

Me he basado en el libro ShaderX2, pero creo que el problema está en que el LightSpace sólo tiene en cuenta la posición, no la rotación.

¿alguien ha implementado esto? ¿otra técnica?

Pogacha

 Lo he implementado en OpenGL ...

El problema del volumen infinito se soluciona con esto:http://www.gamedev.net/columns/hardcore/sh...olume/page4.asp
El tutorial te explica todo el proceso.
Solo debes tener paciencia, ahora en DX ni idea, lo que has escrito es mandarin para mi!

Saludos

Haddd

 Sí, tengo el libro donde "semi explica" todo este tema. El problema es que no entiendo porque sólo utiliza la posición para pasar de World a Light. Yo creo que ahí está el problema...

¿tu utilizas Depth Clamping? Si es así no hay nada que hablar, porque es automático, pero por desgracia en DX no existe este parámetro  (nooo)

¿puedes poner el código donde pasas el vértice a LightSpace ?

Muchas gracias

raistlin

 a continuacion copio un extracto del codigo del engine que programe para usar en proyectos de mi empresa, aqui tienes la parte que CREO tienes dudas


struct Vertex {
   float x, y, z; // worldspace coords
   float u, v;    // texture coords
   //
   float i, j, k; // lightspace coords
   //
   Vector normal; // vertex normal
};



void ShadowObject(Matrix *m_object, Matrix *m_camera, Object *p_object)
{
   Face *cur_face, face;
   int n_material_id;
   float tx, ty, tz;
   float x, y, z;
   Polygon poly;
   Vertex v[3];
   int i, j;

   face.vertex[0] = &v[0];
   face.vertex[1] = &v[1];
   face.vertex[2] = &v[2];
   // temporary face vertices

   Matrix_Inverse(m_camera, &m);
   Matrix_Multiply(&m, m_object, &m);
   Matrix_Inverse(&m, &im);
   // calc transformation matrices

   for(i = 0; i < p_object->n_face_num; i ++){
       if((p_object->face[i].normal.c * im[3][2] +
          p_object->face[i].normal.a * im[3][0] +
          p_object->face[i].normal.b * im[3][1] +
          p_object->face[i].normal.d) > 0.1)
           continue;
       // backface culling

       cur_face = &p_object->face[i];
       n_material_id = cur_face->n_material;
       for(j = 0; j < 3; j ++){
           x = cur_face->vertex[j]->x;
           y = cur_face->vertex[j]->y;
           z = cur_face->vertex[j]->z;
           //
           tx = x * m[0][0] + y * m[1][0] +
                z * m[2][0] +     m[3][0];
           ty = x * m[0][1] + y * m[1][1] +
                z * m[2][1] +     m[3][1];
           tz = x * m[0][2] + y * m[1][2] +
                z * m[2][2] +     m[3][2];
           //
           face.vertex[j]->x = tx;
           face.vertex[j]->y = ty;
           face.vertex[j]->z = tz;

           cur_face->vertex[j]->i = tx;
           cur_face->vertex[j]->j = ty;
           cur_face->vertex[j]->k = tz;
           // store lightspace coords back to face
       }

       poly = Clip_Face(&face, &pyramid);
       // cull face with pyramid

       if(poly.n_vertex_num) { // non-zero for visible faces
           for(j = 0; j < poly.n_vertex_num; j ++) {
               if(poly.vertex[j].z < 0.1) {
                   poly.n_vertex_num = 0;
                   break;
               }
               // in case z - coord is too small, skip this poly

               poly.vertex[j].x = (n_Width / 2) + (poly.vertex[j].x *
                   z_delta) / poly.vertex[j].z;
               poly.vertex[j].y = (n_Height / 2) + (poly.vertex[j].y *
                   z_delta) / poly.vertex[j].z;
               // perspective correction
           }

           ShadowPolygon(&poly, cur_face->n_id);
           // draw polygon to shadow-buffer
       }
   }
}




int Compute_Interpolation_Consts(Polygon *pp, int nWidth, int nHeight)
{
   float x[3], y[3], z[3];
   float i[3], j[3], k[3];
   float u[3], v[3];
   float c;
   int l;

   for(l = 0; l < 3; l ++) {    
       z[l] = 1 / pp->vertex[l].z;
       u[l] = pp->vertex[l].u * z[l] * nWidth;
       v[l] = pp->vertex[l].v * z[l] * nHeight;
       x[l] = pp->vertex[l].x;
       y[l] = pp->vertex[l].y;
       //
       k[l] = pp->vertex[l].k * z[l];
       i[l] = pp->vertex[l].i * z[l];
       j[l] = pp->vertex[l].j * z[l];
   }
   .
   .



void Draw_Segment(int c, int l, float z, float u, float v,
   float i, float j, float k, unsigned __int32 *video)
{
   int xs = (n_Width >> 1) * 0x10000;
   int ys = (n_Height >> 1) * 0x10000;
   int du, u1, u2;
   int dv, v1, v2;
   int di, i1, i2;
   int dj, j1, j2;
   float z1, zs;

   z1 = (0x10000 / z);
   // back to linear to 16:16 fp

   u1 = (int)(u * z1);
   v1 = (int)(v * z1);
   // treat u and v bit different

   zs = (0x10000 * z_delta) / k;
   i1 = xs + (int)(i * zs);
   j1 = ys + (int)(j * zs);
   // lightspace coords

   while(c >= 16) {
       z += dzdx * 16;
       u += dudx * 16;
       v += dvdx * 16;
       //
       i += didx * 16;
       j += djdx * 16;
       k += dkdx * 16;
       // for speed purposes recompute at every 16-th pixel only

       z1 = (0x10000 / z);
       // next linear z
       
       u2 = (int)(u * z1);
       v2 = (int)(v * z1);
       // treat u and v bit different

       zs = (0x10000 * z_delta) / k;
       i2 = xs + (int)(i * zs);
       j2 = ys + (int)(j * zs);
       // lightspace coords

       du = (u2 - u1) / 16;
       dv = (v2 - v1) / 16;
       di = (i2 - i1) / 16;
       dj = (j2 - j1) / 16;
       // calc deltas

       Interpolate_Segment(u1, du, v1, dv, i1, di, j1, dj, video, video + 16);
       // call texturing loop

       c -= 16;
       // reduce count of pixel to draw
       
       video += 16;
       // move next

       u1 = u2;
       v1 = v2;
       i1 = i2;
       j1 = j2;
       // use previous values
   }

   if(c > 0) { // draw the rest of scanline (less than 16 pixels)
   .
   .



static void _fastcall Interpolate_Segment_Bilerp(int u1, int du, int v1, int dv,
   int i1, int di, int j1, int dj, unsigned __int32 *video, unsigned __int32 *v2)
{
   unsigned __int32 texel;
   int frac, tex;
   int i, j;

   do {
       tex = ((u1 >> 16) & A_1) + ((v1 >> B_1) & A_2);
       // texel address

       frac = ((u1 >> 10) & 0x3f) + ((v1 >> 4) & 0xfc0);
       // fractional part (6 bits of V + 6 bits of U)

       texel = _palette[(_texture[tex] << 6) + multab[0][frac]] +
               _palette[(_texture[(tex + 1) & A_3] << 6) + multab[1][frac]] +
               _palette[(_texture[(tex + W_0) & A_3] << 6) + multab[2][frac]] +
               _palette[(_texture[(tex + W_1) & A_3] << 6) + multab[3][frac]];
       // bilinear interpolation

       i = i1 >> 16;
       j = j1 >> 16;
       if(i > 1 && i < Width - 1 && j > 1 && j < Height - 1) {
           if(_sh_buffer[i + 1 + Width * (j + 1)] != _cur_id &&
              _sh_buffer[i + 1 + Width * (j - 1)] != _cur_id &&
              _sh_buffer[i + 1 + Width * j] != _cur_id &&
              _sh_buffer[i + Width * j] != _cur_id &&
              _sh_buffer[i - 1 + Width * (j + 1)] != _cur_id &&
              _sh_buffer[i - 1 + Width * (j - 1)] != _cur_id &&
              _sh_buffer[i - 1 + Width * j] != _cur_id &&
              _sh_buffer[i + Width * (j + 1)] != _cur_id &&
              _sh_buffer[i + Width * (j - 1)] != _cur_id) {
               texel = ((((texel & 0xff00ff) * n_ambient) & 0xff00ff00) |
                        (((texel & 0x00ff00) * n_ambient) & 0x00ff0000)) >> 8;
   // pixel is occluded by some else polygon
           }
       } else {
           texel = ((((texel & 0xff00ff) * n_ambient) & 0xff00ff00) |
                    (((texel & 0x00ff00) * n_ambient) & 0x00ff0000)) >> 8;
  // pixel is outside of light cone
       }
       // modulate pixel color with shadow (ambient) color

       *video ++ = texel;
       // new position

       u1 += du;
       v1 += dv;
       i1 += di;
       j1 += dj;
       // coord interpolation
   } while(video < v2);
}


Intento que los novatos entiendan como funciona el mundo.

Haddd

 Ufff Raist, gracias, pero... :blink:

Leyendo el código que os he enviado..¿no veis algún error?

Pogacha

 La verdad es que no entiendo nada del codigo original ...
Yo lo que hago es tener una sola matriz modelview que es de alcance infinito, y la uzo para pintar todo ... o sea todos los polis pasan por ella ... luego ( cuando uso las sombras ) hago la extrujacion hasta el infinito con un shader parecido al del doom3.
Todos los ejemplos que tengo son en OpenGL.
Si te sirve el Octagon engine tiene todo lo necesario como para hacer un doom3.
Saludos.






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.