Esempio n. 1
0
/*!
 * Calculates the vertex normals corresponding to the smoothing group
 * settings for each face of a mesh.
 *
 * \param mesh      A pointer to the mesh to calculate the normals for.
 * \param normals   A pointer to a buffer to store the calculated
 *                  normals. The buffer must have the size:
 *                  3*3*sizeof(float)*mesh->nfaces.
 *
 * To allocate the normal buffer do for example the following:
 * \code
 *  Lib3dsVector *normals = malloc(3*3*sizeof(float)*mesh->nfaces);
 * \endcode
 *
 * To access the normal of the i-th vertex of the j-th face do the
 * following:
 * \code
 *   normals[3*j+i]
 * \endcode
 */
void
lib3ds_mesh_calculate_vertex_normals(Lib3dsMesh *mesh, float (*normals)[3]) {
    Lib3dsFaces **fl;
    Lib3dsFaces *fa;
    int i, j;

    if (!mesh->nfaces) {
        return;
    }

    fl = (Lib3dsFaces**)calloc(sizeof(Lib3dsFaces*), mesh->nvertices);
    fa = (Lib3dsFaces*)malloc(sizeof(Lib3dsFaces) * 3 * mesh->nfaces);

    for (i = 0; i < mesh->nfaces; ++i) {
        for (j = 0; j < 3; ++j) {
            Lib3dsFaces* l = &fa[3*i+j];
            float p[3], q[3], n[3];
            float len, weight;

            l->index = i;
            l->next = fl[mesh->faces[i].index[j]];
            fl[mesh->faces[i].index[j]] = l;

            lib3ds_vector_sub(p, mesh->vertices[mesh->faces[i].index[j<2? j + 1 : 0]], mesh->vertices[mesh->faces[i].index[j]]);
            lib3ds_vector_sub(q, mesh->vertices[mesh->faces[i].index[j>0? j - 1 : 2]], mesh->vertices[mesh->faces[i].index[j]]);
            lib3ds_vector_cross(n, p, q);
            len = lib3ds_vector_length(n);
            if (len > 0) {
                weight = (float)atan2(len, lib3ds_vector_dot(p, q));
                lib3ds_vector_scalar_mul(l->normal, n, weight / len);
            } else {
                lib3ds_vector_zero(l->normal);
            }
        }
    }

    for (i = 0; i < mesh->nfaces; ++i) {
        Lib3dsFace *f = &mesh->faces[i];
        for (j = 0; j < 3; ++j) {
            float n[3];
            Lib3dsFaces *p;
            Lib3dsFace *pf;

            assert(mesh->faces[i].index[j] < mesh->nvertices);

            if (f->smoothing_group) {
                unsigned smoothing_group = f->smoothing_group;

                lib3ds_vector_zero(n);
                for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) {
                    pf = &mesh->faces[p->index];
                    if (pf->smoothing_group & f->smoothing_group)
                        smoothing_group |= pf->smoothing_group;
                }

                for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) {
                    pf = &mesh->faces[p->index];
                    if (smoothing_group & pf->smoothing_group) {
                        lib3ds_vector_add(n, n, p->normal);
                    }
                }
            } else {
                lib3ds_vector_copy(n, fa[3*i+j].normal);
            }

            lib3ds_vector_normalize(n);
            lib3ds_vector_copy(normals[3*i+j], n);
        }
    }

    free(fa);
    free(fl);
}
Esempio n. 2
0
/*!
 * Calculates the vertex normals corresponding to the smoothing group
 * settings for each face of a mesh.
 *
 * \param mesh      A pointer to the mesh to calculate the normals for.
 * \param normalL   A pointer to a buffer to store the calculated
 *                  normals. The buffer must have the size:
 *                  3*sizeof(Lib3dsVector)*mesh->faces. 
 *
 * To allocate the normal buffer do for example the following:
 * \code
 *  Lib3dsVector *normalL = malloc(3*sizeof(Lib3dsVector)*mesh->faces);
 * \endcode
 *
 * To access the normal of the i-th vertex of the j-th face do the 
 * following:
 * \code
 *   normalL[3*j+i]
 * \endcode
 *
 * \ingroup mesh
 */
void
lib3ds_mesh_calculate_normals(Lib3dsMesh *mesh, Lib3dsVector *normalL)
{
  Lib3dsFaces **fl; 
  Lib3dsFaces *fa; 
  unsigned i,j,k;

  if (!mesh->faces) {
    return;
  }

  fl=calloc(sizeof(Lib3dsFaces*),mesh->points);
  ASSERT(fl);
  fa=calloc(sizeof(Lib3dsFaces),3*mesh->faces);
  ASSERT(fa);
  k=0;
  for (i=0; i<mesh->faces; ++i) {
    Lib3dsFace *f=&mesh->faceL[i];
    for (j=0; j<3; ++j) {
      Lib3dsFaces* l=&fa[k++];
      ASSERT(f->points[j]<mesh->points);
      l->face=f;
      l->next=fl[f->points[j]];
      fl[f->points[j]]=l;
    }
  }
  
  for (i=0; i<mesh->faces; ++i) {
    Lib3dsFace *f=&mesh->faceL[i];
    for (j=0; j<3; ++j) {
      // FIXME: static array needs at least check!!
      Lib3dsVector n,N[128];
      Lib3dsFaces *p;
      int k,l;
      int found;

      ASSERT(f->points[j]<mesh->points);

      if (f->smoothing) {
        lib3ds_vector_zero(n);
        k=0;
        for (p=fl[f->points[j]]; p; p=p->next) {
          found=0;
          for (l=0; l<k; ++l) {
	    if( l >= 128 )
	      printf("array N overflow: i=%d, j=%d, k=%d\n", i,j,k);
            if (fabs(lib3ds_vector_dot(N[l], p->face->normal)-1.0)<1e-5) {
              found=1;
              break;
            }
          }
          if (!found) {
            if (f->smoothing & p->face->smoothing) {
              lib3ds_vector_add(n,n, p->face->normal);
              lib3ds_vector_copy(N[k], p->face->normal);
              ++k;
            }
          }
        }
      } 
      else {
        lib3ds_vector_copy(n, f->normal);
      }
      lib3ds_vector_normalize(n);

      lib3ds_vector_copy(normalL[3*i+j], n);
    }
  }

  free(fa);
  free(fl);
}