Read normals and textures from OBJ, do not duplicate vertices.
PiperOrigin-RevId: 510461549 Change-Id: I19245d691e722a8371e61153383f275f599353d6
This commit is contained in:
committed by
Copybara-Service
parent
35967a30d9
commit
9756ed0d80
Vendored
+1
-1
@@ -14,7 +14,7 @@ nlight 1
|
|||||||
nmesh 0
|
nmesh 0
|
||||||
nmeshvert 0
|
nmeshvert 0
|
||||||
nmeshface 0
|
nmeshface 0
|
||||||
nmeshtexvert 0
|
nmeshtexcoord 0
|
||||||
nmeshgraph 0
|
nmeshgraph 0
|
||||||
nskin 0
|
nskin 0
|
||||||
nskinvert 0
|
nskinvert 0
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ General
|
|||||||
|
|
||||||
- The ``mjd_transitionFD`` function no longer triggers sensor calculation unless explicitly requested.
|
- The ``mjd_transitionFD`` function no longer triggers sensor calculation unless explicitly requested.
|
||||||
- Corrected the spelling of the ``inteval`` attribute to ``interval`` in the ``mjLROpt`` struct.
|
- Corrected the spelling of the ``inteval`` attribute to ``interval`` in the ``mjLROpt`` struct.
|
||||||
|
- Mesh texture and normal mappings are now 3-per-triangle rather than 1-per-vertex. Mesh vertices are no longer
|
||||||
|
duplicated in order to circumvent this limitation as they previously were.
|
||||||
|
|
||||||
Python bindings
|
Python bindings
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|||||||
@@ -746,7 +746,8 @@ struct mjModel_ {
|
|||||||
int nlight; // number of lights
|
int nlight; // number of lights
|
||||||
int nmesh; // number of meshes
|
int nmesh; // number of meshes
|
||||||
int nmeshvert; // number of vertices in all meshes
|
int nmeshvert; // number of vertices in all meshes
|
||||||
int nmeshtexvert; // number of vertices with texcoords in all meshes
|
int nmeshnormal; // number of normals in all meshes
|
||||||
|
int nmeshtexcoord; // number of texcoords in all meshes
|
||||||
int nmeshface; // number of triangular faces in all meshes
|
int nmeshface; // number of triangular faces in all meshes
|
||||||
int nmeshgraph; // number of ints in mesh auxiliary data
|
int nmeshgraph; // number of ints in mesh auxiliary data
|
||||||
int nskin; // number of skins
|
int nskin; // number of skins
|
||||||
@@ -942,14 +943,19 @@ struct mjModel_ {
|
|||||||
// meshes
|
// meshes
|
||||||
int* mesh_vertadr; // first vertex address (nmesh x 1)
|
int* mesh_vertadr; // first vertex address (nmesh x 1)
|
||||||
int* mesh_vertnum; // number of vertices (nmesh x 1)
|
int* mesh_vertnum; // number of vertices (nmesh x 1)
|
||||||
int* mesh_texcoordadr; // texcoord data address; -1: no texcoord (nmesh x 1)
|
|
||||||
int* mesh_faceadr; // first face address (nmesh x 1)
|
int* mesh_faceadr; // first face address (nmesh x 1)
|
||||||
int* mesh_facenum; // number of faces (nmesh x 1)
|
int* mesh_facenum; // number of faces (nmesh x 1)
|
||||||
|
int* mesh_normaladr; // first normal address (nmesh x 1)
|
||||||
|
int* mesh_normalnum; // number of normals (nmesh x 1)
|
||||||
|
int* mesh_texcoordadr; // texcoord data address; -1: no texcoord (nmesh x 1)
|
||||||
|
int* mesh_texcoordnum; // number of texcoord (nmesh x 1)
|
||||||
int* mesh_graphadr; // graph data address; -1: no graph (nmesh x 1)
|
int* mesh_graphadr; // graph data address; -1: no graph (nmesh x 1)
|
||||||
float* mesh_vert; // vertex positions for all meshes (nmeshvert x 3)
|
float* mesh_vert; // vertex positions for all meshes (nmeshvert x 3)
|
||||||
float* mesh_normal; // vertex normals for all meshes (nmeshvert x 3)
|
float* mesh_normal; // normals for all meshes (nmeshnormal x 3)
|
||||||
float* mesh_texcoord; // vertex texcoords for all meshes (nmeshtexvert x 2)
|
float* mesh_texcoord; // vertex texcoords for all meshes (nmeshtexcoord x 2)
|
||||||
int* mesh_face; // triangle face data (nmeshface x 3)
|
int* mesh_face; // vertex face data (nmeshface x 3)
|
||||||
|
int* mesh_facenormal; // normal face data (nmeshface x 3)
|
||||||
|
int* mesh_facetexcoord; // texture face data (nmeshface x 3)
|
||||||
int* mesh_graph; // convex graph data (nmeshgraph x 1)
|
int* mesh_graph; // convex graph data (nmeshgraph x 1)
|
||||||
|
|
||||||
// skins
|
// skins
|
||||||
|
|||||||
@@ -542,7 +542,8 @@ struct mjModel_ {
|
|||||||
int nlight; // number of lights
|
int nlight; // number of lights
|
||||||
int nmesh; // number of meshes
|
int nmesh; // number of meshes
|
||||||
int nmeshvert; // number of vertices in all meshes
|
int nmeshvert; // number of vertices in all meshes
|
||||||
int nmeshtexvert; // number of vertices with texcoords in all meshes
|
int nmeshnormal; // number of normals in all meshes
|
||||||
|
int nmeshtexcoord; // number of texcoords in all meshes
|
||||||
int nmeshface; // number of triangular faces in all meshes
|
int nmeshface; // number of triangular faces in all meshes
|
||||||
int nmeshgraph; // number of ints in mesh auxiliary data
|
int nmeshgraph; // number of ints in mesh auxiliary data
|
||||||
int nskin; // number of skins
|
int nskin; // number of skins
|
||||||
@@ -738,14 +739,19 @@ struct mjModel_ {
|
|||||||
// meshes
|
// meshes
|
||||||
int* mesh_vertadr; // first vertex address (nmesh x 1)
|
int* mesh_vertadr; // first vertex address (nmesh x 1)
|
||||||
int* mesh_vertnum; // number of vertices (nmesh x 1)
|
int* mesh_vertnum; // number of vertices (nmesh x 1)
|
||||||
int* mesh_texcoordadr; // texcoord data address; -1: no texcoord (nmesh x 1)
|
|
||||||
int* mesh_faceadr; // first face address (nmesh x 1)
|
int* mesh_faceadr; // first face address (nmesh x 1)
|
||||||
int* mesh_facenum; // number of faces (nmesh x 1)
|
int* mesh_facenum; // number of faces (nmesh x 1)
|
||||||
|
int* mesh_normaladr; // first normal address (nmesh x 1)
|
||||||
|
int* mesh_normalnum; // number of normals (nmesh x 1)
|
||||||
|
int* mesh_texcoordadr; // texcoord data address; -1: no texcoord (nmesh x 1)
|
||||||
|
int* mesh_texcoordnum; // number of texcoord (nmesh x 1)
|
||||||
int* mesh_graphadr; // graph data address; -1: no graph (nmesh x 1)
|
int* mesh_graphadr; // graph data address; -1: no graph (nmesh x 1)
|
||||||
float* mesh_vert; // vertex positions for all meshes (nmeshvert x 3)
|
float* mesh_vert; // vertex positions for all meshes (nmeshvert x 3)
|
||||||
float* mesh_normal; // vertex normals for all meshes (nmeshvert x 3)
|
float* mesh_normal; // normals for all meshes (nmeshnormal x 3)
|
||||||
float* mesh_texcoord; // vertex texcoords for all meshes (nmeshtexvert x 2)
|
float* mesh_texcoord; // vertex texcoords for all meshes (nmeshtexcoord x 2)
|
||||||
int* mesh_face; // triangle face data (nmeshface x 3)
|
int* mesh_face; // vertex face data (nmeshface x 3)
|
||||||
|
int* mesh_facenormal; // normal face data (nmeshface x 3)
|
||||||
|
int* mesh_facetexcoord; // texture face data (nmeshface x 3)
|
||||||
int* mesh_graph; // convex graph data (nmeshgraph x 1)
|
int* mesh_graph; // convex graph data (nmeshgraph x 1)
|
||||||
|
|
||||||
// skins
|
// skins
|
||||||
|
|||||||
@@ -74,7 +74,8 @@
|
|||||||
X( nlight ) \
|
X( nlight ) \
|
||||||
X( nmesh ) \
|
X( nmesh ) \
|
||||||
X( nmeshvert ) \
|
X( nmeshvert ) \
|
||||||
X( nmeshtexvert ) \
|
X( nmeshnormal ) \
|
||||||
|
X( nmeshtexcoord ) \
|
||||||
X( nmeshface ) \
|
X( nmeshface ) \
|
||||||
X( nmeshgraph ) \
|
X( nmeshgraph ) \
|
||||||
X( nskin ) \
|
X( nskin ) \
|
||||||
@@ -263,14 +264,19 @@
|
|||||||
X( float, light_specular, nlight, 3 ) \
|
X( float, light_specular, nlight, 3 ) \
|
||||||
X( int, mesh_vertadr, nmesh, 1 ) \
|
X( int, mesh_vertadr, nmesh, 1 ) \
|
||||||
X( int, mesh_vertnum, nmesh, 1 ) \
|
X( int, mesh_vertnum, nmesh, 1 ) \
|
||||||
|
X( int, mesh_normaladr, nmesh, 1 ) \
|
||||||
|
X( int, mesh_normalnum, nmesh, 1 ) \
|
||||||
X( int, mesh_texcoordadr, nmesh, 1 ) \
|
X( int, mesh_texcoordadr, nmesh, 1 ) \
|
||||||
|
X( int, mesh_texcoordnum, nmesh, 1 ) \
|
||||||
X( int, mesh_faceadr, nmesh, 1 ) \
|
X( int, mesh_faceadr, nmesh, 1 ) \
|
||||||
X( int, mesh_facenum, nmesh, 1 ) \
|
X( int, mesh_facenum, nmesh, 1 ) \
|
||||||
X( int, mesh_graphadr, nmesh, 1 ) \
|
X( int, mesh_graphadr, nmesh, 1 ) \
|
||||||
X( float, mesh_vert, nmeshvert, 3 ) \
|
X( float, mesh_vert, nmeshvert, 3 ) \
|
||||||
X( float, mesh_normal, nmeshvert, 3 ) \
|
X( float, mesh_normal, nmeshnormal, 3 ) \
|
||||||
X( float, mesh_texcoord, nmeshtexvert, 2 ) \
|
X( float, mesh_texcoord, nmeshtexcoord, 2 ) \
|
||||||
X( int, mesh_face, nmeshface, 3 ) \
|
X( int, mesh_face, nmeshface, 3 ) \
|
||||||
|
X( int, mesh_facenormal, nmeshface, 3 ) \
|
||||||
|
X( int, mesh_facetexcoord, nmeshface, 3 ) \
|
||||||
X( int, mesh_graph, nmeshgraph, 1 ) \
|
X( int, mesh_graph, nmeshgraph, 1 ) \
|
||||||
X( int, skin_matid, nskin, 1 ) \
|
X( int, skin_matid, nskin, 1 ) \
|
||||||
X( int, skin_group, nskin, 1 ) \
|
X( int, skin_group, nskin, 1 ) \
|
||||||
|
|||||||
@@ -367,8 +367,8 @@ static int safeAddToBufferSize(intptr_t* offset, int* nbuffer, size_t type_size,
|
|||||||
// allocate and initialize mjModel structure
|
// allocate and initialize mjModel structure
|
||||||
mjModel* mj_makeModel(int nq, int nv, int nu, int na, int nbody, int njnt,
|
mjModel* mj_makeModel(int nq, int nv, int nu, int na, int nbody, int njnt,
|
||||||
int ngeom, int nsite, int ncam, int nlight,
|
int ngeom, int nsite, int ncam, int nlight,
|
||||||
int nmesh, int nmeshvert, int nmeshtexvert, int nmeshface, int nmeshgraph,
|
int nmesh, int nmeshvert, int nmeshnormal, int nmeshtexcoord, int nmeshface,
|
||||||
int nskin, int nskinvert, int nskintexvert, int nskinface,
|
int nmeshgraph, int nskin, int nskinvert, int nskintexvert, int nskinface,
|
||||||
int nskinbone, int nskinbonevert, int nhfield, int nhfielddata,
|
int nskinbone, int nskinbonevert, int nhfield, int nhfielddata,
|
||||||
int ntex, int ntexdata, int nmat, int npair, int nexclude,
|
int ntex, int ntexdata, int nmat, int npair, int nexclude,
|
||||||
int neq, int ntendon, int nwrap, int nsensor,
|
int neq, int ntendon, int nwrap, int nsensor,
|
||||||
@@ -399,7 +399,8 @@ mjModel* mj_makeModel(int nq, int nv, int nu, int na, int nbody, int njnt,
|
|||||||
m->nlight = nlight;
|
m->nlight = nlight;
|
||||||
m->nmesh = nmesh;
|
m->nmesh = nmesh;
|
||||||
m->nmeshvert = nmeshvert;
|
m->nmeshvert = nmeshvert;
|
||||||
m->nmeshtexvert = nmeshtexvert;
|
m->nmeshnormal = nmeshnormal;
|
||||||
|
m->nmeshtexcoord = nmeshtexcoord;
|
||||||
m->nmeshface = nmeshface;
|
m->nmeshface = nmeshface;
|
||||||
m->nmeshgraph = nmeshgraph;
|
m->nmeshgraph = nmeshgraph;
|
||||||
m->nskin = nskin;
|
m->nskin = nskin;
|
||||||
@@ -512,7 +513,7 @@ mjModel* mj_copyModel(mjModel* dest, const mjModel* src) {
|
|||||||
if (!dest) {
|
if (!dest) {
|
||||||
dest = mj_makeModel(src->nq, src->nv, src->nu, src->na, src->nbody, src->njnt,
|
dest = mj_makeModel(src->nq, src->nv, src->nu, src->na, src->nbody, src->njnt,
|
||||||
src->ngeom, src->nsite, src->ncam, src->nlight, src->nmesh, src->nmeshvert,
|
src->ngeom, src->nsite, src->ncam, src->nlight, src->nmesh, src->nmeshvert,
|
||||||
src->nmeshtexvert, src->nmeshface, src->nmeshgraph,
|
src->nmeshnormal, src->nmeshtexcoord, src->nmeshface, src->nmeshgraph,
|
||||||
src->nskin, src->nskinvert, src->nskintexvert, src->nskinface,
|
src->nskin, src->nskinvert, src->nskintexvert, src->nskinface,
|
||||||
src->nskinbone, src->nskinbonevert, src->nhfield, src->nhfielddata,
|
src->nskinbone, src->nskinbonevert, src->nhfield, src->nhfielddata,
|
||||||
src->ntex, src->ntexdata, src->nmat, src->npair, src->nexclude,
|
src->ntex, src->ntexdata, src->nmat, src->npair, src->nexclude,
|
||||||
@@ -691,7 +692,7 @@ mjModel* mj_loadModel(const char* filename, const mjVFS* vfs) {
|
|||||||
info[28], info[29], info[30], info[31], info[32], info[33], info[34],
|
info[28], info[29], info[30], info[31], info[32], info[33], info[34],
|
||||||
info[35], info[36], info[37], info[38], info[39], info[40], info[41],
|
info[35], info[36], info[37], info[38], info[39], info[40], info[41],
|
||||||
info[42], info[43], info[44], info[45], info[46], info[47], info[48],
|
info[42], info[43], info[44], info[45], info[46], info[47], info[48],
|
||||||
info[49], info[50]);
|
info[49], info[50], info[51]);
|
||||||
if (!m || m->nbuffer!=info[getnint()-1]) {
|
if (!m || m->nbuffer!=info[getnint()-1]) {
|
||||||
if (fp) {
|
if (fp) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@@ -1361,7 +1362,8 @@ const char* mj_validateReferences(const mjModel* m) {
|
|||||||
X(light_bodyid, nlight, nbody , 0 ) \
|
X(light_bodyid, nlight, nbody , 0 ) \
|
||||||
X(light_targetbodyid, nlight, nbody , 0 ) \
|
X(light_targetbodyid, nlight, nbody , 0 ) \
|
||||||
X(mesh_vertadr, nmesh, nmeshvert , m->mesh_vertnum ) \
|
X(mesh_vertadr, nmesh, nmeshvert , m->mesh_vertnum ) \
|
||||||
X(mesh_texcoordadr, nmesh, nmeshtexvert , 0 ) \
|
X(mesh_normaladr, nmesh, nmeshnormal , m->mesh_normalnum ) \
|
||||||
|
X(mesh_texcoordadr, nmesh, nmeshtexcoord, m->mesh_texcoordnum ) \
|
||||||
X(mesh_faceadr, nmesh, nmeshface , m->mesh_facenum ) \
|
X(mesh_faceadr, nmesh, nmeshface , m->mesh_facenum ) \
|
||||||
X(mesh_graphadr, nmesh, nmeshgraph , 0 ) \
|
X(mesh_graphadr, nmesh, nmeshgraph , 0 ) \
|
||||||
X(skin_matid, nskin, nmat , 0 ) \
|
X(skin_matid, nskin, nmat , 0 ) \
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ void mj_defaultStatistic(mjStatistic* stat);
|
|||||||
// allocate mjModel
|
// allocate mjModel
|
||||||
mjModel* mj_makeModel(int nq, int nv, int nu, int na, int nbody, int njnt,
|
mjModel* mj_makeModel(int nq, int nv, int nu, int na, int nbody, int njnt,
|
||||||
int ngeom, int nsite, int ncam, int nlight,
|
int ngeom, int nsite, int ncam, int nlight,
|
||||||
int nmesh, int nmeshvert, int nmeshtexvert, int nmeshface, int nmeshgraph,
|
int nmesh, int nmeshvert, int nmeshnormal, int nmeshtexcoord, int nmeshface,
|
||||||
int nskin, int nskinvert, int nskintexvert, int nskinface,
|
int nmeshgraph, int nskin, int nskinvert, int nskintexvert, int nskinface,
|
||||||
int nskinbone, int nskinbonevert, int nhfield, int nhfielddata,
|
int nskinbone, int nskinbonevert, int nhfield, int nhfielddata,
|
||||||
int ntex, int ntexdata, int nmat, int npair, int nexclude,
|
int ntex, int ntexdata, int nmat, int npair, int nexclude,
|
||||||
int neq, int ntendon, int nwrap, int nsensor,
|
int neq, int ntendon, int nwrap, int nsensor,
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ static void makeMesh(const mjModel* m, mjrContext* con) {
|
|||||||
|
|
||||||
// (re) upload mesh to GPU
|
// (re) upload mesh to GPU
|
||||||
void mjr_uploadMesh(const mjModel* m, const mjrContext* con, int meshid) {
|
void mjr_uploadMesh(const mjModel* m, const mjrContext* con, int meshid) {
|
||||||
int vertadr, numvert, numface, texcoordadr;
|
int vertadr, numvert, normaladr, numface, texcoordadr;
|
||||||
float normal[3], *v1, *v2, *v3, *n1, *n2, *n3, *t1, *t2, *t3;
|
float normal[3], *v1, *v2, *v3, *n1, *n2, *n3, *t1, *t2, *t3;
|
||||||
|
|
||||||
// check index
|
// check index
|
||||||
@@ -220,6 +220,7 @@ void mjr_uploadMesh(const mjModel* m, const mjrContext* con, int meshid) {
|
|||||||
|
|
||||||
// get vertex and texcoord address for this mesh
|
// get vertex and texcoord address for this mesh
|
||||||
vertadr = m->mesh_vertadr[meshid];
|
vertadr = m->mesh_vertadr[meshid];
|
||||||
|
normaladr = m->mesh_normaladr[meshid];
|
||||||
texcoordadr = m->mesh_texcoordadr[meshid];
|
texcoordadr = m->mesh_texcoordadr[meshid];
|
||||||
|
|
||||||
// render original mesh
|
// render original mesh
|
||||||
@@ -234,15 +235,15 @@ void mjr_uploadMesh(const mjModel* m, const mjrContext* con, int meshid) {
|
|||||||
v3 = m->mesh_vert + 3*(m->mesh_face[3*face+2] + vertadr);
|
v3 = m->mesh_vert + 3*(m->mesh_face[3*face+2] + vertadr);
|
||||||
|
|
||||||
// compute normal addresses
|
// compute normal addresses
|
||||||
n1 = m->mesh_normal + 3*(m->mesh_face[3*face] + vertadr);
|
n1 = m->mesh_normal + 3*(m->mesh_facenormal[3*face] + normaladr);
|
||||||
n2 = m->mesh_normal + 3*(m->mesh_face[3*face+1] + vertadr);
|
n2 = m->mesh_normal + 3*(m->mesh_facenormal[3*face+1] + normaladr);
|
||||||
n3 = m->mesh_normal + 3*(m->mesh_face[3*face+2] + vertadr);
|
n3 = m->mesh_normal + 3*(m->mesh_facenormal[3*face+2] + normaladr);
|
||||||
|
|
||||||
// compute texcoord addresses
|
// compute texcoord addresses
|
||||||
if (texcoordadr>=0) {
|
if (texcoordadr>=0) {
|
||||||
t1 = m->mesh_texcoord + 2*(m->mesh_face[3*face] + texcoordadr);
|
t1 = m->mesh_texcoord + 2*(m->mesh_facetexcoord[3*face] + texcoordadr);
|
||||||
t2 = m->mesh_texcoord + 2*(m->mesh_face[3*face+1] + texcoordadr);
|
t2 = m->mesh_texcoord + 2*(m->mesh_facetexcoord[3*face+1] + texcoordadr);
|
||||||
t3 = m->mesh_texcoord + 2*(m->mesh_face[3*face+2] + texcoordadr);
|
t3 = m->mesh_texcoord + 2*(m->mesh_facetexcoord[3*face+2] + texcoordadr);
|
||||||
} else {
|
} else {
|
||||||
t1 = t2 = t3 = NULL;
|
t1 = t2 = t3 = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
+146
-124
@@ -95,6 +95,8 @@ mjCMesh::mjCMesh(mjCModel* _model, mjCDef* _def) {
|
|||||||
usernormal.clear();
|
usernormal.clear();
|
||||||
usertexcoord.clear();
|
usertexcoord.clear();
|
||||||
userface.clear();
|
userface.clear();
|
||||||
|
userfacenormal.clear();
|
||||||
|
userfacetexcoord.clear();
|
||||||
useredge.clear();
|
useredge.clear();
|
||||||
|
|
||||||
// clear internal variables
|
// clear internal variables
|
||||||
@@ -106,12 +108,16 @@ mjCMesh::mjCMesh(mjCModel* _model, mjCDef* _def) {
|
|||||||
mjuu_setvec(boxsz_volume, 0, 0, 0);
|
mjuu_setvec(boxsz_volume, 0, 0, 0);
|
||||||
mjuu_setvec(aabb, 0, 0, 0);
|
mjuu_setvec(aabb, 0, 0, 0);
|
||||||
nvert = 0;
|
nvert = 0;
|
||||||
|
nnormal = 0;
|
||||||
|
ntexcoord = 0;
|
||||||
nface = 0;
|
nface = 0;
|
||||||
szgraph = 0;
|
szgraph = 0;
|
||||||
vert = NULL;
|
vert = NULL;
|
||||||
normal = NULL;
|
normal = NULL;
|
||||||
texcoord = NULL;
|
texcoord = NULL;
|
||||||
face = NULL;
|
face = NULL;
|
||||||
|
facenormal = NULL;
|
||||||
|
facetexcoord = NULL;
|
||||||
graph = NULL;
|
graph = NULL;
|
||||||
needhull = false;
|
needhull = false;
|
||||||
invalidorientation.first = -1;
|
invalidorientation.first = -1;
|
||||||
@@ -141,17 +147,37 @@ mjCMesh::~mjCMesh() {
|
|||||||
usernormal.clear();
|
usernormal.clear();
|
||||||
usertexcoord.clear();
|
usertexcoord.clear();
|
||||||
userface.clear();
|
userface.clear();
|
||||||
|
userfacenormal.clear();
|
||||||
|
userfacetexcoord.clear();
|
||||||
useredge.clear();
|
useredge.clear();
|
||||||
|
|
||||||
if (vert) mju_free(vert);
|
if (vert) mju_free(vert);
|
||||||
if (normal) mju_free(normal);
|
if (normal) mju_free(normal);
|
||||||
if (texcoord) mju_free(texcoord);
|
if (texcoord) mju_free(texcoord);
|
||||||
if (face) mju_free(face);
|
if (face) mju_free(face);
|
||||||
|
if (facenormal) mju_free(facenormal);
|
||||||
|
if (facetexcoord) mju_free(facetexcoord);
|
||||||
if (graph) mju_free(graph);
|
if (graph) mju_free(graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T> static T* VecToArray(std::vector<T>& vector, bool clear = true){
|
||||||
|
if (vector.empty())
|
||||||
|
return nullptr;
|
||||||
|
else {
|
||||||
|
int n = (int)vector.size();
|
||||||
|
T* cvec = (T*) mju_malloc(n*sizeof(T));
|
||||||
|
memcpy(cvec, vector.data(), n*sizeof(T));
|
||||||
|
if (clear) {
|
||||||
|
vector.clear();
|
||||||
|
}
|
||||||
|
return cvec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// compiler
|
// compiler
|
||||||
void mjCMesh::Compile(const mjVFS* vfs) {
|
void mjCMesh::Compile(const mjVFS* vfs) {
|
||||||
// load file
|
// load file
|
||||||
@@ -191,8 +217,7 @@ void mjCMesh::Compile(const mjVFS* vfs) {
|
|||||||
|
|
||||||
// copy from user
|
// copy from user
|
||||||
nvert = (int)uservert.size()/3;
|
nvert = (int)uservert.size()/3;
|
||||||
vert = (float*) mju_malloc(3*nvert*sizeof(float));
|
vert = VecToArray(uservert, !file.empty());
|
||||||
memcpy(vert, uservert.data(), 3*nvert*sizeof(float));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy user normal
|
// copy user normal
|
||||||
@@ -203,13 +228,13 @@ void mjCMesh::Compile(const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check size
|
// check size
|
||||||
if (usernormal.size()!=3*nvert) {
|
if (usernormal.size()%3) {
|
||||||
throw mjCError(this, "vertex and normal data incompatible size");
|
throw mjCError(this, "normal data must be a multiple of 3");
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy from user
|
// copy from user
|
||||||
normal = (float*) mju_malloc(3*nvert*sizeof(float));
|
nnormal = (int)usernormal.size()/3;
|
||||||
memcpy(normal, usernormal.data(), 3*nvert*sizeof(float));
|
normal = VecToArray(usernormal, !file.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy user texcoord
|
// copy user texcoord
|
||||||
@@ -220,13 +245,13 @@ void mjCMesh::Compile(const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check size
|
// check size
|
||||||
if (usertexcoord.size()!=2*nvert) {
|
if (usertexcoord.size()%2) {
|
||||||
throw mjCError(this, "vertex and texcoord data incompatible size");
|
throw mjCError(this, "texcoord must be a multiple of 2");
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy from user
|
// copy from user
|
||||||
texcoord = (float*) mju_malloc(2*nvert*sizeof(float));
|
ntexcoord = (int)usertexcoord.size()/2;
|
||||||
memcpy(texcoord, usertexcoord.data(), 2*nvert*sizeof(float));
|
texcoord = VecToArray(usertexcoord, !file.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy user face
|
// copy user face
|
||||||
@@ -243,8 +268,7 @@ void mjCMesh::Compile(const mjVFS* vfs) {
|
|||||||
|
|
||||||
// copy from user
|
// copy from user
|
||||||
nface = (int)userface.size()/3;
|
nface = (int)userface.size()/3;
|
||||||
face = (int*) mju_malloc(3*nface*sizeof(int));
|
face = VecToArray(userface, !file.empty());
|
||||||
memcpy(face, userface.data(), 3*nface*sizeof(int));
|
|
||||||
|
|
||||||
// check vertices exist
|
// check vertices exist
|
||||||
for (auto vertex_index : userface) {
|
for (auto vertex_index : userface) {
|
||||||
@@ -301,6 +325,36 @@ void mjCMesh::Compile(const mjVFS* vfs) {
|
|||||||
MakeNormal();
|
MakeNormal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy user normal indices
|
||||||
|
if (!userfacenormal.empty()) {
|
||||||
|
// check repeated
|
||||||
|
if (facenormal) {
|
||||||
|
throw mjCError(this, "repeated facenormal specification");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userfacenormal.size()!=3*nface) {
|
||||||
|
throw mjCError(this, "face data must have the same size as face normal data");
|
||||||
|
}
|
||||||
|
|
||||||
|
facenormal = VecToArray(userfacenormal, !file.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy user texcoord
|
||||||
|
if (!userfacetexcoord.empty()) {
|
||||||
|
// check repeated
|
||||||
|
if (facetexcoord) {
|
||||||
|
throw mjCError(this, "repeated facetexcoord specification");
|
||||||
|
}
|
||||||
|
|
||||||
|
facetexcoord = VecToArray(userfacetexcoord, !file.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
// facenormal might not exist if usernormal was specified
|
||||||
|
if (!facenormal) {
|
||||||
|
facenormal = (int*) mju_malloc(3*nface*sizeof(int));
|
||||||
|
memcpy(facenormal, face, 3*nface*sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
// scale, center, orient, compute mass and inertia
|
// scale, center, orient, compute mass and inertia
|
||||||
Process();
|
Process();
|
||||||
processed = true;
|
processed = true;
|
||||||
@@ -543,19 +597,6 @@ void mjCMesh::RemoveRepeated() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T> static T* VecToArray(std::vector<T>& vector){
|
|
||||||
if (vector.empty())
|
|
||||||
return nullptr;
|
|
||||||
else {
|
|
||||||
int n = (int)vector.size();
|
|
||||||
T* cvec = (T*) mju_malloc(n*sizeof(T));
|
|
||||||
memcpy(cvec, vector.data(), n*sizeof(T));
|
|
||||||
vector.clear();
|
|
||||||
return cvec;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// load OBJ mesh
|
// load OBJ mesh
|
||||||
void mjCMesh::LoadOBJ(const mjVFS* vfs) {
|
void mjCMesh::LoadOBJ(const mjVFS* vfs) {
|
||||||
|
|
||||||
@@ -587,105 +628,73 @@ void mjCMesh::LoadOBJ(const mjVFS* vfs) {
|
|||||||
throw mjCError(this, "%s", msg.str().c_str());
|
throw mjCError(this, "%s", msg.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto attrib = objReader.GetAttrib();
|
const auto& attrib = objReader.GetAttrib();
|
||||||
|
uservert = attrib.vertices; // copy from one std::vector to another
|
||||||
|
usernormal = attrib.normals;
|
||||||
|
usertexcoord = attrib.texcoords;
|
||||||
|
|
||||||
if (objReader.GetShapes().empty()) {
|
if (!objReader.GetShapes().empty()) {
|
||||||
uservert = attrib.vertices; // copy from one std::vector to another
|
const auto& mesh = objReader.GetShapes()[0].mesh;
|
||||||
usernormal = attrib.normals;
|
|
||||||
usertexcoord = attrib.texcoords;
|
|
||||||
} else {
|
|
||||||
auto mesh = objReader.GetShapes()[0].mesh;
|
|
||||||
bool has_normals = !attrib.normals.empty();
|
|
||||||
bool has_texcoords = !attrib.texcoords.empty();
|
|
||||||
bool righthand = (scale[0]*scale[1]*scale[2] > 0);
|
bool righthand = (scale[0]*scale[1]*scale[2] > 0);
|
||||||
|
|
||||||
// iterate over mesh faces
|
// iterate over mesh faces
|
||||||
int index_in_mesh_indices = 0;
|
std::vector<tinyobj::index_t> face_indices;
|
||||||
for (int face = 0; face < mesh.num_face_vertices.size(); face++) {
|
for (int face = 0, idx = 0; idx < mesh.indices.size();) {
|
||||||
if (mesh.num_face_vertices[face] > 4) {
|
int nfacevert = mesh.num_face_vertices[face];
|
||||||
|
if (nfacevert < 3 || nfacevert > 4) {
|
||||||
throw mjCError(
|
throw mjCError(
|
||||||
this, "only tri or quad meshes are supported for OBJ (file '%s')",
|
this, "only tri or quad meshes are supported for OBJ (file '%s')",
|
||||||
filename.c_str());
|
filename.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// add face
|
face_indices.push_back(mesh.indices[idx]);
|
||||||
std::vector<std::array<tinyobj::index_t, 3>> faces;
|
face_indices.push_back(mesh.indices[idx + (righthand==1 ? 1 : 2)]);
|
||||||
tinyobj::index_t v0 = mesh.indices[index_in_mesh_indices];
|
face_indices.push_back(mesh.indices[idx + (righthand==1 ? 2 : 1)]);
|
||||||
tinyobj::index_t v1 = mesh.indices[index_in_mesh_indices+1];
|
|
||||||
tinyobj::index_t v2 = mesh.indices[index_in_mesh_indices+2];
|
|
||||||
std::array<tinyobj::index_t, 3> face1 = {v0, v1, v2};
|
|
||||||
faces.push_back(face1);
|
|
||||||
|
|
||||||
// handle quad: add second triangle with 4th vertex
|
if (nfacevert == 4) {
|
||||||
if (mesh.num_face_vertices[face] == 4) {
|
face_indices.push_back(mesh.indices[idx]);
|
||||||
tinyobj::index_t v3 = mesh.indices[index_in_mesh_indices+3];
|
face_indices.push_back(mesh.indices[idx + (righthand==1 ? 2 : 3)]);
|
||||||
std::array<tinyobj::index_t, 3> face2 = {v0, v2, v3};
|
face_indices.push_back(mesh.indices[idx + (righthand==1 ? 3 : 2)]);
|
||||||
faces.push_back(face2);
|
|
||||||
}
|
}
|
||||||
for (const auto& face_indices : faces) {
|
idx += nfacevert;
|
||||||
int index_of_first_vertex = uservert.size()/3;
|
++face;
|
||||||
for (auto tinyobj_index : face_indices) {
|
}
|
||||||
// add vertices to uservert
|
|
||||||
uservert.insert(
|
|
||||||
uservert.end(),
|
|
||||||
attrib.vertices.begin() + 3*tinyobj_index.vertex_index,
|
|
||||||
attrib.vertices.begin() + 3*tinyobj_index.vertex_index + 3);
|
|
||||||
|
|
||||||
// for each vertex, add its normal
|
// for each vertex, store index, normal, and texcoord
|
||||||
if (has_normals) {
|
for (const auto& mesh_index : face_indices) {
|
||||||
usernormal.insert(
|
userface.push_back(mesh_index.vertex_index);
|
||||||
usernormal.end(),
|
|
||||||
attrib.normals.begin() + 3*tinyobj_index.normal_index,
|
|
||||||
attrib.normals.begin() + 3*tinyobj_index.normal_index + 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
// for each vertex, add two entries to usertexcoord
|
if (!usernormal.empty()) {
|
||||||
if (has_texcoords) {
|
userfacenormal.push_back(mesh_index.normal_index);
|
||||||
usertexcoord.push_back(
|
}
|
||||||
attrib.texcoords[2*tinyobj_index.texcoord_index]);
|
|
||||||
usertexcoord.push_back( // flip the v coordinate
|
if (!usertexcoord.empty()) {
|
||||||
1-attrib.texcoords[2*tinyobj_index.texcoord_index + 1]);
|
userfacetexcoord.push_back(mesh_index.texcoord_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int i0 = index_of_first_vertex;
|
|
||||||
int i1 = index_of_first_vertex+1;
|
for (int i = 0; i < face_indices.size(); i += 3) {
|
||||||
int i2 = index_of_first_vertex+2;
|
// add edges
|
||||||
|
const float *v0 = uservert.data() + 3*face_indices[i+0].vertex_index;
|
||||||
// add edges
|
const float *v1 = uservert.data() + 3*face_indices[i+1].vertex_index;
|
||||||
const float *v0 = uservert.data() + 3*i0;
|
const float *v2 = uservert.data() + 3*face_indices[i+2].vertex_index;
|
||||||
const float *v1 = uservert.data() + 3*i1;
|
|
||||||
const float *v2 = uservert.data() + 3*i2;
|
// only consider edges if the face contribution is significant
|
||||||
mjtNum normal[3];
|
mjtNum normal[3];
|
||||||
|
if (_triangle(normal, nullptr, v0, v1, v2)>sqrt(mjMINVAL)) {
|
||||||
// only consider edges if the face contribution is significant
|
useredge.push_back(std::pair(face_indices[i+0].vertex_index, face_indices[i+1].vertex_index));
|
||||||
if (_triangle(normal, nullptr, v0, v1, v2)>sqrt(mjMINVAL)) {
|
useredge.push_back(std::pair(face_indices[i+1].vertex_index, face_indices[i+2].vertex_index));
|
||||||
useredge.push_back(std::pair(face_indices[0].vertex_index, face_indices[1].vertex_index));
|
useredge.push_back(std::pair(face_indices[i+2].vertex_index, face_indices[i+0].vertex_index));
|
||||||
useredge.push_back(std::pair(face_indices[1].vertex_index, face_indices[2].vertex_index));
|
} else {
|
||||||
useredge.push_back(std::pair(face_indices[2].vertex_index, face_indices[0].vertex_index));
|
// TODO(b/255525326)
|
||||||
} else {
|
|
||||||
// TODO(b/255525326)
|
|
||||||
}
|
|
||||||
|
|
||||||
// add vertex indices (in uservert) to userface
|
|
||||||
userface.push_back(i0);
|
|
||||||
if (righthand) {
|
|
||||||
userface.push_back(i1);
|
|
||||||
userface.push_back(i2);
|
|
||||||
} else {
|
|
||||||
userface.push_back(i2);
|
|
||||||
userface.push_back(i1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
index_in_mesh_indices += mesh.num_face_vertices[face];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nvert = (int)uservert.size()/3;
|
// flip the second texcoord
|
||||||
nface = (int)userface.size()/3;
|
for (int i=1; i<usertexcoord.size()/2; i++) {
|
||||||
vert = VecToArray(uservert);
|
usertexcoord[2*i+1] = 1-usertexcoord[2*i+1];
|
||||||
face = VecToArray(userface);
|
}
|
||||||
normal = VecToArray(usernormal);
|
|
||||||
texcoord = VecToArray(usertexcoord);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -857,8 +866,8 @@ void mjCMesh::LoadMSH(const mjVFS* vfs) {
|
|||||||
|
|
||||||
// get sizes from header
|
// get sizes from header
|
||||||
nvert = ((int*)buffer)[0];
|
nvert = ((int*)buffer)[0];
|
||||||
int nnormal = ((int*)buffer)[1];
|
nnormal = ((int*)buffer)[1];
|
||||||
int ntexcoord = ((int*)buffer)[2];
|
ntexcoord = ((int*)buffer)[2];
|
||||||
nface = ((int*)buffer)[3];
|
nface = ((int*)buffer)[3];
|
||||||
|
|
||||||
// check sizes
|
// check sizes
|
||||||
@@ -899,7 +908,13 @@ void mjCMesh::LoadMSH(const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
if (nface) {
|
if (nface) {
|
||||||
face = (int*) mju_malloc(3*nface*sizeof(int));
|
face = (int*) mju_malloc(3*nface*sizeof(int));
|
||||||
|
facenormal = (int*) mju_malloc(3*nface*sizeof(int));
|
||||||
memcpy(face, fdata, 3*nface*sizeof(int));
|
memcpy(face, fdata, 3*nface*sizeof(int));
|
||||||
|
memcpy(facenormal, fdata, 3*nface*sizeof(int));
|
||||||
|
}
|
||||||
|
if (nface && texcoord) {
|
||||||
|
facetexcoord = (int*) mju_malloc(3*nface*sizeof(int));
|
||||||
|
memcpy(facetexcoord, fdata, 3*nface*sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
// rearange face data if left-handed scaling
|
// rearange face data if left-handed scaling
|
||||||
@@ -940,12 +955,9 @@ void mjCMesh::Process() {
|
|||||||
|
|
||||||
// process vertices
|
// process vertices
|
||||||
for (i=0; i<nvert; i++) {
|
for (i=0; i<nvert; i++) {
|
||||||
// positions
|
|
||||||
vert[3*i] -= rp[0];
|
vert[3*i] -= rp[0];
|
||||||
vert[3*i+1] -= rp[1];
|
vert[3*i+1] -= rp[1];
|
||||||
vert[3*i+2] -= rp[2];
|
vert[3*i+2] -= rp[2];
|
||||||
|
|
||||||
// normals not affected by translation
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -959,14 +971,15 @@ void mjCMesh::Process() {
|
|||||||
|
|
||||||
// process vertices
|
// process vertices
|
||||||
for (i=0; i<nvert; i++) {
|
for (i=0; i<nvert; i++) {
|
||||||
// positions
|
|
||||||
mjtNum p1[3], p0[3] = {vert[3*i], vert[3*i+1], vert[3*i+2]};
|
mjtNum p1[3], p0[3] = {vert[3*i], vert[3*i+1], vert[3*i+2]};
|
||||||
mju_rotVecMatT(p1, p0, mat);
|
mju_rotVecMatT(p1, p0, mat);
|
||||||
vert[3*i] = (float) p1[0];
|
vert[3*i] = (float) p1[0];
|
||||||
vert[3*i+1] = (float) p1[1];
|
vert[3*i+1] = (float) p1[1];
|
||||||
vert[3*i+2] = (float) p1[2];
|
vert[3*i+2] = (float) p1[2];
|
||||||
|
}
|
||||||
|
|
||||||
// normals
|
// process normals
|
||||||
|
for (i=0; i<nnormal; i++) {
|
||||||
mjtNum n1[3], n0[3] = {normal[3*i], normal[3*i+1], normal[3*i+2]};
|
mjtNum n1[3], n0[3] = {normal[3*i], normal[3*i+1], normal[3*i+2]};
|
||||||
mju_rotVecMatT(n1, n0, mat);
|
mju_rotVecMatT(n1, n0, mat);
|
||||||
normal[3*i] = (float) n1[0];
|
normal[3*i] = (float) n1[0];
|
||||||
@@ -978,12 +991,12 @@ void mjCMesh::Process() {
|
|||||||
// scale
|
// scale
|
||||||
if (scale[0]!=1 || scale[1]!=1 || scale[2]!=1) {
|
if (scale[0]!=1 || scale[1]!=1 || scale[2]!=1) {
|
||||||
for (i=0; i<nvert; i++) {
|
for (i=0; i<nvert; i++) {
|
||||||
// positions
|
|
||||||
vert[3*i] *= scale[0];
|
vert[3*i] *= scale[0];
|
||||||
vert[3*i+1] *= scale[1];
|
vert[3*i+1] *= scale[1];
|
||||||
vert[3*i+2] *= scale[2];
|
vert[3*i+2] *= scale[2];
|
||||||
|
}
|
||||||
|
|
||||||
// normals
|
for (i=0; i<nnormal; i++) {
|
||||||
normal[3*i] *= scale[0];
|
normal[3*i] *= scale[0];
|
||||||
normal[3*i+1] *= scale[1];
|
normal[3*i+1] *= scale[1];
|
||||||
normal[3*i+2] *= scale[2];
|
normal[3*i+2] *= scale[2];
|
||||||
@@ -991,7 +1004,7 @@ void mjCMesh::Process() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// normalize normals
|
// normalize normals
|
||||||
for (i=0; i<nvert; i++) {
|
for (i=0; i<nnormal; i++) {
|
||||||
// compute length
|
// compute length
|
||||||
float len = normal[3*i]*normal[3*i] + normal[3*i+1]*normal[3*i+1] + normal[3*i+2]*normal[3*i+2];
|
float len = normal[3*i]*normal[3*i] + normal[3*i+1]*normal[3*i+1] + normal[3*i+2]*normal[3*i+2];
|
||||||
|
|
||||||
@@ -1168,9 +1181,11 @@ void mjCMesh::Process() {
|
|||||||
for (j=0; j<3; j++) {
|
for (j=0; j<3; j++) {
|
||||||
vert[3*i+j] = (float) res[j];
|
vert[3*i+j] = (float) res[j];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
for (i=0; i<nnormal; i++) {
|
||||||
// normals
|
// normals
|
||||||
const double nrm[3] = {normal[3*i], normal[3*i+1], normal[3*i+2]};
|
const double nrm[3] = {normal[3*i], normal[3*i+1], normal[3*i+2]};
|
||||||
|
double res[3];
|
||||||
mjuu_mulvecmat(res, nrm, mat);
|
mjuu_mulvecmat(res, nrm, mat);
|
||||||
for (j=0; j<3; j++) {
|
for (j=0; j<3; j++) {
|
||||||
normal[3*i+j] = (float) res[j];
|
normal[3*i+j] = (float) res[j];
|
||||||
@@ -1452,8 +1467,14 @@ void mjCMesh::MakeNormal(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// allocate and clear normals
|
// allocate and clear normals
|
||||||
normal = (float*) mju_malloc(3*nvert*sizeof(float));
|
nnormal = nvert;
|
||||||
memset(normal, 0, 3*nvert*sizeof(float));
|
normal = (float*) mju_malloc(3*nnormal*sizeof(float));
|
||||||
|
memset(normal, 0, 3*nnormal*sizeof(float));
|
||||||
|
|
||||||
|
if (!facenormal) {
|
||||||
|
facenormal = (int*) mju_malloc(3*nface*sizeof(int));
|
||||||
|
memset(facenormal, 0, 3*nface*sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
// loop over faces, accumulate vertex normals
|
// loop over faces, accumulate vertex normals
|
||||||
for (i=0; i<nface; i++) {
|
for (i=0; i<nface; i++) {
|
||||||
@@ -1480,14 +1501,15 @@ void mjCMesh::MakeNormal(void) {
|
|||||||
for (k=0; k<3; k++) {
|
for (k=0; k<3; k++) {
|
||||||
normal[3*vertid[j]+k] += nrm[k]*area;
|
normal[3*vertid[j]+k] += nrm[k]*area;
|
||||||
}
|
}
|
||||||
|
facenormal[3*i+j] = vertid[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove large-angle faces
|
// remove large-angle faces
|
||||||
if (!smoothnormal) {
|
if (!smoothnormal) {
|
||||||
// allocate removal and clear
|
// allocate removal and clear
|
||||||
float* nremove = (float*) mju_malloc(3*nvert*sizeof(float));
|
float* nremove = (float*) mju_malloc(3*nnormal*sizeof(float));
|
||||||
memset(nremove, 0, 3*nvert*sizeof(float));
|
memset(nremove, 0, 3*nnormal*sizeof(float));
|
||||||
|
|
||||||
// remove contributions from faces at large angles with vertex normal
|
// remove contributions from faces at large angles with vertex normal
|
||||||
for (i=0; i<nface; i++) {
|
for (i=0; i<nface; i++) {
|
||||||
@@ -1525,14 +1547,14 @@ void mjCMesh::MakeNormal(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply removal, free nremove
|
// apply removal, free nremove
|
||||||
for (i=0; i<3*nvert; i++) {
|
for (i=0; i<3*nnormal; i++) {
|
||||||
normal[i] -= nremove[i];
|
normal[i] -= nremove[i];
|
||||||
}
|
}
|
||||||
mju_free(nremove);
|
mju_free(nremove);
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalize normals
|
// normalize normals
|
||||||
for (i=0; i<nvert; i++) {
|
for (i=0; i<nnormal; i++) {
|
||||||
// compute length
|
// compute length
|
||||||
float len = sqrtf(normal[3*i]*normal[3*i] +
|
float len = sqrtf(normal[3*i]*normal[3*i] +
|
||||||
normal[3*i+1]*normal[3*i+1] +
|
normal[3*i+1]*normal[3*i+1] +
|
||||||
|
|||||||
+19
-8
@@ -258,7 +258,8 @@ void mjCModel::Clear(void) {
|
|||||||
nu = 0;
|
nu = 0;
|
||||||
na = 0;
|
na = 0;
|
||||||
nmeshvert = 0;
|
nmeshvert = 0;
|
||||||
nmeshtexvert = 0;
|
nmeshnormal = 0;
|
||||||
|
nmeshtexcoord = 0;
|
||||||
nmeshface = 0;
|
nmeshface = 0;
|
||||||
nmeshgraph = 0;
|
nmeshgraph = 0;
|
||||||
nskinvert = 0;
|
nskinvert = 0;
|
||||||
@@ -933,11 +934,12 @@ void mjCModel::SetSizes(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// nmeshvert, nmeshface, nmeshtexvert, nmeshgraph
|
// nmeshvert, nmeshface, nmeshtexcoord, nmeshgraph
|
||||||
for (i=0; i<nmesh; i++) {
|
for (i=0; i<nmesh; i++) {
|
||||||
nmeshvert += meshes[i]->nvert;
|
nmeshvert += meshes[i]->nvert;
|
||||||
|
nmeshnormal += meshes[i]->nnormal;
|
||||||
nmeshface += meshes[i]->nface;
|
nmeshface += meshes[i]->nface;
|
||||||
nmeshtexvert += (meshes[i]->texcoord ? meshes[i]->nvert : 0);
|
nmeshtexcoord += (meshes[i]->texcoord ? meshes[i]->ntexcoord : 0);
|
||||||
nmeshgraph += meshes[i]->szgraph;
|
nmeshgraph += meshes[i]->szgraph;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1645,7 +1647,7 @@ void mjCModel::CopyTree(mjModel* m) {
|
|||||||
|
|
||||||
// copy objects outside kinematic tree
|
// copy objects outside kinematic tree
|
||||||
void mjCModel::CopyObjects(mjModel* m) {
|
void mjCModel::CopyObjects(mjModel* m) {
|
||||||
int i, j, adr, bone_adr, vert_adr, face_adr, texcoord_adr;
|
int i, j, adr, bone_adr, vert_adr, normal_adr, face_adr, texcoord_adr;
|
||||||
int bonevert_adr, graph_adr, data_adr;
|
int bonevert_adr, graph_adr, data_adr;
|
||||||
|
|
||||||
// sizes outside call to mj_makeModel
|
// sizes outside call to mj_makeModel
|
||||||
@@ -1657,6 +1659,7 @@ void mjCModel::CopyObjects(mjModel* m) {
|
|||||||
|
|
||||||
// meshes
|
// meshes
|
||||||
vert_adr = 0;
|
vert_adr = 0;
|
||||||
|
normal_adr = 0;
|
||||||
texcoord_adr = 0;
|
texcoord_adr = 0;
|
||||||
face_adr = 0;
|
face_adr = 0;
|
||||||
graph_adr = 0;
|
graph_adr = 0;
|
||||||
@@ -1667,17 +1670,24 @@ void mjCModel::CopyObjects(mjModel* m) {
|
|||||||
// set fields
|
// set fields
|
||||||
m->mesh_vertadr[i] = vert_adr;
|
m->mesh_vertadr[i] = vert_adr;
|
||||||
m->mesh_vertnum[i] = pme->nvert;
|
m->mesh_vertnum[i] = pme->nvert;
|
||||||
|
m->mesh_normaladr[i] = normal_adr;
|
||||||
|
m->mesh_normalnum[i] = pme->nnormal;
|
||||||
m->mesh_texcoordadr[i] = (pme->texcoord ? texcoord_adr : -1);
|
m->mesh_texcoordadr[i] = (pme->texcoord ? texcoord_adr : -1);
|
||||||
|
m->mesh_texcoordnum[i] = pme->ntexcoord;
|
||||||
m->mesh_faceadr[i] = face_adr;
|
m->mesh_faceadr[i] = face_adr;
|
||||||
m->mesh_facenum[i] = pme->nface;
|
m->mesh_facenum[i] = pme->nface;
|
||||||
m->mesh_graphadr[i] = (pme->szgraph ? graph_adr : -1);
|
m->mesh_graphadr[i] = (pme->szgraph ? graph_adr : -1);
|
||||||
|
|
||||||
// copy vertices, normals, faces, texcoords, aux data
|
// copy vertices, normals, faces, texcoords, aux data
|
||||||
memcpy(m->mesh_vert + 3*vert_adr, pme->vert, 3*pme->nvert*sizeof(float));
|
memcpy(m->mesh_vert + 3*vert_adr, pme->vert, 3*pme->nvert*sizeof(float));
|
||||||
memcpy(m->mesh_normal + 3*vert_adr, pme->normal, 3*pme->nvert*sizeof(float));
|
memcpy(m->mesh_normal + 3*normal_adr, pme->normal, 3*pme->nnormal*sizeof(float));
|
||||||
memcpy(m->mesh_face + 3*face_adr, pme->face, 3*pme->nface*sizeof(float));
|
memcpy(m->mesh_face + 3*face_adr, pme->face, 3*pme->nface*sizeof(float));
|
||||||
|
memcpy(m->mesh_facenormal + 3*face_adr, pme->facenormal, 3*pme->nface*sizeof(int));
|
||||||
if (pme->texcoord) {
|
if (pme->texcoord) {
|
||||||
memcpy(m->mesh_texcoord + 2*texcoord_adr, pme->texcoord, 2*pme->nvert*sizeof(float));
|
memcpy(m->mesh_texcoord + 2*texcoord_adr, pme->texcoord, 2*pme->ntexcoord*sizeof(float));
|
||||||
|
memcpy(m->mesh_facetexcoord + 3*face_adr, pme->facetexcoord, 3*pme->nface*sizeof(int));
|
||||||
|
} else {
|
||||||
|
memset(m->mesh_facetexcoord + 3*face_adr, 0, 3*pme->nface*sizeof(int));
|
||||||
}
|
}
|
||||||
if (pme->szgraph) {
|
if (pme->szgraph) {
|
||||||
memcpy(m->mesh_graph + graph_adr, pme->graph, pme->szgraph*sizeof(int));
|
memcpy(m->mesh_graph + graph_adr, pme->graph, pme->szgraph*sizeof(int));
|
||||||
@@ -1685,7 +1695,8 @@ void mjCModel::CopyObjects(mjModel* m) {
|
|||||||
|
|
||||||
// advance counters
|
// advance counters
|
||||||
vert_adr += pme->nvert;
|
vert_adr += pme->nvert;
|
||||||
texcoord_adr += (pme->texcoord ? pme->nvert : 0);
|
normal_adr += pme->nnormal;
|
||||||
|
texcoord_adr += (pme->texcoord ? pme->ntexcoord : 0);
|
||||||
face_adr += pme->nface;
|
face_adr += pme->nface;
|
||||||
graph_adr += pme->szgraph;
|
graph_adr += pme->szgraph;
|
||||||
}
|
}
|
||||||
@@ -2619,7 +2630,7 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
|
|||||||
|
|
||||||
// create low-level model
|
// create low-level model
|
||||||
m = mj_makeModel(nq, nv, nu, na, nbody, njnt, ngeom, nsite, ncam, nlight,
|
m = mj_makeModel(nq, nv, nu, na, nbody, njnt, ngeom, nsite, ncam, nlight,
|
||||||
nmesh, nmeshvert, nmeshtexvert, nmeshface, nmeshgraph,
|
nmesh, nmeshvert, nmeshnormal, nmeshtexcoord, nmeshface, nmeshgraph,
|
||||||
nskin, nskinvert, nskintexvert, nskinface, nskinbone, nskinbonevert,
|
nskin, nskinvert, nskintexvert, nskinface, nskinbone, nskinbonevert,
|
||||||
nhfield, nhfielddata, ntex, ntexdata, nmat, npair, nexclude,
|
nhfield, nhfielddata, ntex, ntexdata, nmat, npair, nexclude,
|
||||||
neq, ntendon, nwrap, nsensor,
|
neq, ntendon, nwrap, nsensor,
|
||||||
|
|||||||
@@ -216,7 +216,8 @@ class mjCModel {
|
|||||||
int nu; // number of actuators/controls
|
int nu; // number of actuators/controls
|
||||||
int na; // number of activation variables
|
int na; // number of activation variables
|
||||||
int nmeshvert; // number of vertices in all meshes
|
int nmeshvert; // number of vertices in all meshes
|
||||||
int nmeshtexvert; // number of texture coordinates in all meshes
|
int nmeshnormal; // number of normals in all meshes
|
||||||
|
int nmeshtexcoord; // number of texture coordinates in all meshes
|
||||||
int nmeshface; // number of triangular faces in all meshes
|
int nmeshface; // number of triangular faces in all meshes
|
||||||
int nmeshgraph; // number of shorts in mesh auxiliary data
|
int nmeshgraph; // number of shorts in mesh auxiliary data
|
||||||
int nskinvert; // number of vertices in all skins
|
int nskinvert; // number of vertices in all skins
|
||||||
|
|||||||
@@ -476,7 +476,9 @@ class mjCMesh: public mjCBase {
|
|||||||
std::vector<float> uservert; // user vertex data
|
std::vector<float> uservert; // user vertex data
|
||||||
std::vector<float> usernormal; // user normal data
|
std::vector<float> usernormal; // user normal data
|
||||||
std::vector<float> usertexcoord; // user texcoord data
|
std::vector<float> usertexcoord; // user texcoord data
|
||||||
std::vector<int> userface; // user face data
|
std::vector<int> userface; // user vertex indices
|
||||||
|
std::vector<int> userfacenormal; // user normal indices
|
||||||
|
std::vector<int> userfacetexcoord; // user texcoord indices
|
||||||
std::vector< std::pair<int, int> > useredge; // user half-edge data
|
std::vector< std::pair<int, int> > useredge; // user half-edge data
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -514,12 +516,16 @@ class mjCMesh: public mjCBase {
|
|||||||
|
|
||||||
// mesh data to be copied into mjModel
|
// mesh data to be copied into mjModel
|
||||||
int nvert; // number of vertices
|
int nvert; // number of vertices
|
||||||
|
int nnormal; // number of normals
|
||||||
|
int ntexcoord; // number of texcoords
|
||||||
int nface; // number of faces
|
int nface; // number of faces
|
||||||
int szgraph; // size of graph data in ints
|
int szgraph; // size of graph data in ints
|
||||||
float* vert; // vertex data (3*nvert), relative to (pos, quat)
|
float* vert; // vertex data (3*nvert), relative to (pos, quat)
|
||||||
float* normal; // vertex normal data (3*nvert)
|
float* normal; // vertex normal data (3*nnormal)
|
||||||
float* texcoord; // vertex texcoord data (2*nvert, or NULL)
|
float* texcoord; // vertex texcoord data (2*ntexcoord or NULL)
|
||||||
int* face; // face vertex indices (3*nface)
|
int* face; // face vertex indices (3*nface)
|
||||||
|
int* facenormal; // face normal indices (3*nface)
|
||||||
|
int* facetexcoord; // face texcoord indices (3*nface)
|
||||||
int* graph; // convex graph data
|
int* graph; // convex graph data
|
||||||
|
|
||||||
bool needhull; // needs convex hull for collisions
|
bool needhull; // needs convex hull for collisions
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<mujoco>
|
||||||
|
<asset>
|
||||||
|
<mesh file="cube.msh"/>
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<geom type="mesh" mesh="cube"/>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
@@ -32,6 +32,8 @@ namespace {
|
|||||||
|
|
||||||
using MjCMeshTest = MujocoTest;
|
using MjCMeshTest = MujocoTest;
|
||||||
|
|
||||||
|
static const char* const kMeshPath =
|
||||||
|
"user/testdata/mesh.xml";
|
||||||
static const char* const kDuplicateVerticesPath =
|
static const char* const kDuplicateVerticesPath =
|
||||||
"user/testdata/duplicate_vertices.xml";
|
"user/testdata/duplicate_vertices.xml";
|
||||||
static const char* const kCubePath =
|
static const char* const kCubePath =
|
||||||
@@ -100,6 +102,17 @@ TEST_F(MjCMeshTest, DeDuplicateSTLVertices) {
|
|||||||
mj_deleteModel(model);
|
mj_deleteModel(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------- test Mesh loading (MSH) ------------------------------
|
||||||
|
TEST_F(MjCMeshTest, LoadMSH) {
|
||||||
|
const std::string xml_path = GetTestDataFilePath(kMeshPath);
|
||||||
|
char error[1024];
|
||||||
|
size_t error_sz = 1024;
|
||||||
|
mjModel* model = mj_loadXML(xml_path.c_str(), 0, error, error_sz);
|
||||||
|
ASSERT_THAT(model, testing::NotNull()) << error;
|
||||||
|
ASSERT_EQ(model->nmeshvert, 36);
|
||||||
|
mj_deleteModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
// ------------- test OBJ loading ----------------------------------------------
|
// ------------- test OBJ loading ----------------------------------------------
|
||||||
|
|
||||||
using MjCMeshTest = MujocoTest;
|
using MjCMeshTest = MujocoTest;
|
||||||
@@ -109,6 +122,7 @@ TEST_F(MjCMeshTest, LoadCube) {
|
|||||||
mjModel* model = mj_loadXML(xml_path.c_str(), 0, nullptr, 0);
|
mjModel* model = mj_loadXML(xml_path.c_str(), 0, nullptr, 0);
|
||||||
ASSERT_GT(model->ngeom, 0);
|
ASSERT_GT(model->ngeom, 0);
|
||||||
ASSERT_EQ(model->nmeshvert, 8);
|
ASSERT_EQ(model->nmeshvert, 8);
|
||||||
|
ASSERT_EQ(model->nmeshface, 12);
|
||||||
mj_deleteModel(model);
|
mj_deleteModel(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +160,7 @@ TEST_F(MjCMeshTest, KeepDuplicateOBJVertices) {
|
|||||||
char error[1024];
|
char error[1024];
|
||||||
size_t error_sz = 1024;
|
size_t error_sz = 1024;
|
||||||
mjModel* model = mj_loadXML(xml_path.c_str(), 0, error, error_sz);
|
mjModel* model = mj_loadXML(xml_path.c_str(), 0, error, error_sz);
|
||||||
ASSERT_EQ(model->nmeshvert, 12);
|
ASSERT_EQ(model->nmeshvert, 16);
|
||||||
mj_deleteModel(model);
|
mj_deleteModel(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +189,26 @@ TEST_F(MjCMeshTest, TinyMeshLoads) {
|
|||||||
mj_deleteModel(model);
|
mj_deleteModel(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------- test inline loading ------------------------------------------
|
||||||
|
TEST_F(MjCMeshTest, FaceNormalAutogenerated) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<asset>
|
||||||
|
<mesh name="example_mesh"
|
||||||
|
vertex="0 0 0 1 0 0 0 1 0 0 0 1"
|
||||||
|
normal="1 0 0 0 1 0 0 0 1 0.707 0 0.707"
|
||||||
|
face="0 2 1 0 3 2" />
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<geom type="mesh" mesh="example_mesh"/>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
mjModel* model = LoadModelFromString(xml, 0, 0);
|
||||||
|
ASSERT_THAT(model, testing::NotNull());
|
||||||
|
mj_deleteModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
// ------------- test inertia -------------------------------------------------
|
// ------------- test inertia -------------------------------------------------
|
||||||
|
|
||||||
TEST_F(MjCMeshTest, SmallInertiaLoads) {
|
TEST_F(MjCMeshTest, SmallInertiaLoads) {
|
||||||
|
|||||||
@@ -1874,7 +1874,8 @@ public unsafe struct mjModel_ {
|
|||||||
public int nlight;
|
public int nlight;
|
||||||
public int nmesh;
|
public int nmesh;
|
||||||
public int nmeshvert;
|
public int nmeshvert;
|
||||||
public int nmeshtexvert;
|
public int nmeshnormal;
|
||||||
|
public int nmeshtexcoord;
|
||||||
public int nmeshface;
|
public int nmeshface;
|
||||||
public int nmeshgraph;
|
public int nmeshgraph;
|
||||||
public int nskin;
|
public int nskin;
|
||||||
@@ -2042,14 +2043,19 @@ public unsafe struct mjModel_ {
|
|||||||
public float* light_specular;
|
public float* light_specular;
|
||||||
public int* mesh_vertadr;
|
public int* mesh_vertadr;
|
||||||
public int* mesh_vertnum;
|
public int* mesh_vertnum;
|
||||||
public int* mesh_texcoordadr;
|
|
||||||
public int* mesh_faceadr;
|
public int* mesh_faceadr;
|
||||||
public int* mesh_facenum;
|
public int* mesh_facenum;
|
||||||
|
public int* mesh_normaladr;
|
||||||
|
public int* mesh_normalnum;
|
||||||
|
public int* mesh_texcoordadr;
|
||||||
|
public int* mesh_texcoordnum;
|
||||||
public int* mesh_graphadr;
|
public int* mesh_graphadr;
|
||||||
public float* mesh_vert;
|
public float* mesh_vert;
|
||||||
public float* mesh_normal;
|
public float* mesh_normal;
|
||||||
public float* mesh_texcoord;
|
public float* mesh_texcoord;
|
||||||
public int* mesh_face;
|
public int* mesh_face;
|
||||||
|
public int* mesh_facenormal;
|
||||||
|
public int* mesh_facetexcoord;
|
||||||
public int* mesh_graph;
|
public int* mesh_graph;
|
||||||
public int* skin_matid;
|
public int* skin_matid;
|
||||||
public int* skin_group;
|
public int* skin_group;
|
||||||
|
|||||||
Reference in New Issue
Block a user