/*! * \ingroup matrix */ void lib3ds_matrix_camera(Lib3dsMatrix matrix, Lib3dsVector pos, Lib3dsVector tgt, Lib3dsFloat roll) { Lib3dsMatrix M,R; Lib3dsVector x, y, z; lib3ds_vector_sub(y, tgt, pos); lib3ds_vector_normalize(y); z[0] = 0; z[1] = 0; z[2] = 1.0; lib3ds_vector_cross(x, y, z); lib3ds_vector_cross(z, x, y); lib3ds_vector_normalize(x); lib3ds_vector_normalize(y); lib3ds_matrix_identity(M); M[0][0] = x[0]; M[1][0] = x[1]; M[2][0] = x[2]; M[0][1] = y[0]; M[1][1] = y[1]; M[2][1] = y[2]; M[0][2] = z[0]; M[1][2] = z[1]; M[2][2] = z[2]; lib3ds_matrix_identity(R); lib3ds_matrix_rotate_y(R, roll); lib3ds_matrix_mul(matrix, R,M); lib3ds_matrix_translate_xyz(matrix, -pos[0],-pos[1],-pos[2]); }
/*! * Compute a vector normal to two line segments. * * Computes the normal vector to the lines b-a and b-c. * * \param n Returned normal vector. * \param a Endpoint of first line. * \param b Base point of both lines. * \param c Endpoint of second line. */ void lib3ds_vector_normal(float n[3], float a[3], float b[3], float c[3]) { float p[3], q[3]; lib3ds_vector_sub(p, c, b); lib3ds_vector_sub(q, a, b); lib3ds_vector_cross(n, p, q); lib3ds_vector_normalize(n); }
/*! * Compute a vector normal to two line segments. * * Computes the normal vector to the lines b-a and b-c. * * \param n Returned normal vector. * \param a Endpoint of first line. * \param b Base point of both lines. * \param c Endpoint of second line. * * \ingroup vector */ void lib3ds_vector_normal(Lib3dsVector n, Lib3dsVector a, Lib3dsVector b, Lib3dsVector c) { Lib3dsVector p,q; lib3ds_vector_sub(p,c,b); lib3ds_vector_sub(q,a,b); lib3ds_vector_cross(n,p,q); lib3ds_vector_normalize(n); }
/*! * Compute a camera matrix based on position, target and roll. * * Generates a translate/rotate matrix that maps world coordinates * to camera coordinates. Resulting matrix does not include perspective * transform. * * \param matrix Destination matrix. * \param pos Camera position * \param tgt Camera target * \param roll Roll angle * * \ingroup matrix */ void lib3ds_matrix_camera(Lib3dsMatrix matrix, Lib3dsVector pos, Lib3dsVector tgt, Lib3dsFloat roll) { Lib3dsMatrix M; Lib3dsVector x, y, z; lib3ds_vector_sub(y, tgt, pos); lib3ds_vector_normalize(y); if (y[0] != 0. || y[1] != 0) { z[0] = 0; z[1] = 0; z[2] = 1.0; } else { /* Special case: looking straight up or down z axis */ z[0] = -1.0; z[1] = 0; z[2] = 0; } lib3ds_vector_cross(x, y, z); lib3ds_vector_cross(z, x, y); lib3ds_vector_normalize(x); lib3ds_vector_normalize(z); lib3ds_matrix_identity(M); M[0][0] = x[0]; M[1][0] = x[1]; M[2][0] = x[2]; M[0][1] = y[0]; M[1][1] = y[1]; M[2][1] = y[2]; M[0][2] = z[0]; M[1][2] = z[1]; M[2][2] = z[2]; lib3ds_matrix_identity(matrix); lib3ds_matrix_rotate_y(matrix, roll); lib3ds_matrix_mult(matrix, M); lib3ds_matrix_translate_xyz(matrix, -pos[0],-pos[1],-pos[2]); }
/*! * Compute a camera matrix based on position, target and roll. * * Generates a translate/rotate matrix that maps world coordinates * to camera coordinates. Resulting matrix does not include perspective * transform. * * \param matrix Destination matrix. * \param pos Camera position * \param tgt Camera target * \param roll Roll angle */ void lib3ds_matrix_camera(float matrix[4][4], float pos[3], float tgt[3], float roll) { float M[4][4]; float x[3], y[3], z[3]; lib3ds_vector_sub(y, tgt, pos); lib3ds_vector_normalize(y); if (y[0] != 0. || y[1] != 0) { z[0] = 0; z[1] = 0; z[2] = 1.0; } else { /* Special case: looking straight up or down z axis */ z[0] = -1.0; z[1] = 0; z[2] = 0; } lib3ds_vector_cross(x, y, z); lib3ds_vector_cross(z, x, y); lib3ds_vector_normalize(x); lib3ds_vector_normalize(z); lib3ds_matrix_identity(M); M[0][0] = x[0]; M[1][0] = x[1]; M[2][0] = x[2]; M[0][1] = y[0]; M[1][1] = y[1]; M[2][1] = y[2]; M[0][2] = z[0]; M[1][2] = z[1]; M[2][2] = z[2]; lib3ds_matrix_identity(matrix); lib3ds_matrix_rotate(matrix, roll, 0, 1, 0); lib3ds_matrix_mult(matrix, matrix, M); lib3ds_matrix_translate(matrix, -pos[0], -pos[1], -pos[2]); }
/*! * 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); }