Files
Mujoco_WASM/src/engine/engine_vis_init.c
T
Alessio Quaglino e1669b568b Change default values of flex visualization flags.
Deactivated vertices, edges, faces and activated skins. The skin is less precise but faster to render and more importantly when the wireframe is active it allows to look inside the body much more easily.

PiperOrigin-RevId: 585970250
Change-Id: Icb6c0ff6266e552cffce9b0c810f634f9a29a55e
2023-11-28 07:27:54 -08:00

484 lines
12 KiB
C

// Copyright 2021 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "engine/engine_vis_init.h"
#include <math.h>
#include <string.h>
#include <mujoco/mjmacro.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjvisualize.h>
#include "engine/engine_array_safety.h"
#include "engine/engine_util_errmem.h"
#include "engine/engine_util_misc.h"
#ifdef _MSC_VER
#pragma warning (disable: 4305) // disable MSVC warning: truncation from 'double' to 'float'
#endif
//--------------------------------- Strings --------------------------------------------------------
// label names
const char* mjLABELSTRING[mjNLABEL] = {
"None",
"Body",
"Joint",
"Geom",
"Site",
"Camera",
"Light",
"Tendon",
"Actuator",
"Constraint",
"Flex",
"Skin",
"Selection",
"SelPoint",
"Contact",
"ContactForce",
"Island"
};
// frame names
const char* mjFRAMESTRING[mjNFRAME] = {
"None",
"Body",
"Geom",
"Site",
"Camera",
"Light",
"Contact",
"World"
};
// visual options: {name, initial value, shortcut}
const char* mjVISSTRING[mjNVISFLAG][3] = {
{"Convex &Hull", "0", "H"},
{"Te&xture", "1", "X"},
{"&Joint", "0", "J"},
{"Camera", "0", "Q"},
{"Act&uator", "0", "U"},
{"Act&ivation", "0", ","},
{"Light", "0", "Z"},
{"Tendon", "1", "V"},
{"Range Finder", "1", "Y"},
{"Co&nstraint", "0", "E"},
{"&Inertia", "0", "I"},
{"Scale Inertia", "0", "'"},
{"Pertur&b Force", "0", "B"},
{"Perturb &Object", "1", "O"},
{"&Contact Point", "0", "C"},
{"Island", "1", ""}, // TODO(b/295296178): turn off after islands are on by default.
{"Contact &Force", "0", "F"},
{"Contact S&plit", "0", "P"},
{"&Transparent", "0", "T"},
{"&Auto Connect", "0", "A"},
{"Center of &Mass", "0", "M"},
{"S&elect Point", "0", ""},
{"Static Bo&dy", "1", "D"},
{"Skin", "1", ";"},
{"Flex Vert", "0", ""},
{"Flex Edge", "0", ""},
{"Flex Face", "0", ""},
{"Flex Skin", "1", ""},
{"Body Tree", "0", "`"},
{"Flex Tree", "0", ""},
{"Mesh Tree", "0", "\\"},
{"SDF iters", "0", ""}
};
// render options: {name, initial value, shortcut}
const char* mjRNDSTRING[mjNRNDFLAG][3] = {
{"Shadow", "1", "S"},
{"Wireframe", "0", "W"},
{"Reflection", "1", "R"},
{"Additive", "0", "L"},
{"Skybox", "1", "K"},
{"Fog", "0", "G"},
{"Haze", "1", "/"},
{"Segment", "0", ","},
{"Id Color", "0", ""},
{"Cull Face", "1", ""}
};
//--------------------------------- Implementation -------------------------------------------------
// allocate and init abstract scene
void mjv_makeScene(const mjModel* m, mjvScene* scn, int maxgeom) {
// free previous
mjv_freeScene(scn);
// allocate geom buffers
if (maxgeom > 0) {
// allocate
scn->maxgeom = maxgeom;
scn->geoms = (mjvGeom*) mju_malloc(maxgeom*sizeof(mjvGeom));
scn->geomorder = (int*) mju_malloc(maxgeom*sizeof(int));
// check allocation
if (!scn->geoms || !scn->geomorder) {
mjERROR("could not allocate geom buffers");
}
}
// set default OpenGL options
for (int i=0; i < mjNRNDFLAG; i++) {
scn->flags[i] = (mjRNDSTRING[i][1][0] == '1');
}
// set default model transformation
scn->scale = 1;
scn->rotate[0] = 1;
// set number of flexes
scn->nflex = m ? m->nflex : 0;
// allocate flex data
if (scn->nflex) {
int nflex = scn->nflex;
// allocate fixed
scn->flexedgeadr = (int*) mju_malloc(nflex*sizeof(int));
scn->flexedgenum = (int*) mju_malloc(nflex*sizeof(int));
scn->flexvertadr = (int*) mju_malloc(nflex*sizeof(int));
scn->flexvertnum = (int*) mju_malloc(nflex*sizeof(int));
scn->flexfaceadr = (int*) mju_malloc(nflex*sizeof(int));
scn->flexfacenum = (int*) mju_malloc(nflex*sizeof(int));
scn->flexfaceused= (int*) mju_malloc(nflex*sizeof(int));
scn->flexedge = (int*) mju_malloc(2*m->nflexedge*sizeof(int));
scn->flexvert = (float*) mju_malloc(3*m->nflexvert*sizeof(float));
// count max number of flex faces to be rendered (depending on vis options)
int nface = 0;
for (int f=0; f < nflex; f++) {
// 1D : 0
if (m->flex_dim[f] == 0) {
scn->flexfacenum[f] = 0;
}
// 2D: 2*fragments + 2*elements
else if (m->flex_dim[f] == 2) {
scn->flexfacenum[f] = 2*m->flex_shellnum[f] + 2*m->flex_elemnum[f];
}
// 3D: max(fragments, 4*maxlayer)
else {
// find number of elements in biggest layer
int maxlayer = 0, layer = 0, nlayer = 1;
while (nlayer) {
// count elements in this layer
nlayer = 0;
for (int e=0; e < m->flex_elemnum[f]; e++) {
if (m->flex_elemlayer[m->flex_elemadr[f]+e] == layer) {
nlayer++;
}
}
// accumulate max over layers, advance layer
maxlayer = mjMAX(maxlayer, nlayer);
layer++;
}
scn->flexfacenum[f] = mjMAX(m->flex_shellnum[f], 4*maxlayer);
}
// accumulate over flexes
nface += scn->flexfacenum[f];
}
// allocate face-related
scn->flexface = nface ? (float*) mju_malloc(9*nface*sizeof(float)) : NULL;
scn->flexnormal = nface ? (float*) mju_malloc(9*nface*sizeof(float)) : NULL;
scn->flextexcoord = nface ? (float*) mju_malloc(6*nface*sizeof(float)) : NULL;
// check allocation
if (!scn->flexedgeadr ||
!scn->flexedgenum ||
!scn->flexfaceadr ||
!scn->flexfacenum ||
!scn->flexfaceused||
!scn->flexvertadr ||
!scn->flexvertnum ||
!scn->flexedge ||
!scn->flexvert ||
(nface && !scn->flexface) ||
(nface && !scn->flexnormal) ||
(nface && !scn->flextexcoord)) {
mju_error("Could not allocate flex buffers");
}
// copy constant edge and vertex data
memcpy(scn->flexedgeadr, m->flex_edgeadr, nflex*sizeof(int));
memcpy(scn->flexedgenum, m->flex_edgenum, nflex*sizeof(int));
memcpy(scn->flexvertadr, m->flex_vertadr, nflex*sizeof(int));
memcpy(scn->flexvertnum, m->flex_vertnum, nflex*sizeof(int));
memcpy(scn->flexedge, m->flex_edge, 2*m->nflexedge*sizeof(int));
// compute flexfaceadr
for (int f=0; f < nflex; f++) {
scn->flexfaceadr[f] = f == 0 ? 0 : scn->flexfaceadr[f-1]+scn->flexfacenum[f-1];
}
}
// set number of skins
if (m) {
scn->nskin = m->nskin;
} else {
scn->nskin = 0;
}
// allocate skin data
if (scn->nskin) {
int nskin = m->nskin;
// allocate
scn->skinfacenum = (int*) mju_malloc(nskin*sizeof(int));
scn->skinvertadr = (int*) mju_malloc(nskin*sizeof(int));
scn->skinvertnum = (int*) mju_malloc(nskin*sizeof(int));
scn->skinvert = (float*) mju_malloc(3*m->nskinvert*sizeof(float));
scn->skinnormal = (float*) mju_malloc(3*m->nskinvert*sizeof(float));
// check allocation
if (!scn->skinfacenum ||
!scn->skinvertadr ||
!scn->skinvertnum ||
!scn->skinvert ||
!scn->skinnormal) {
mjERROR("could not allocate skin buffers");
}
// copy constant data
mju_copyInt(scn->skinfacenum, m->skin_facenum, nskin);
mju_copyInt(scn->skinvertadr, m->skin_vertadr, nskin);
mju_copyInt(scn->skinvertnum, m->skin_vertnum, nskin);
}
// mjvGeom, mjvLight, mjvGLCamera objects are invalid
}
// free abstract scene
void mjv_freeScene(mjvScene* scn) {
// free buffers allocated by mjv_makeScene
mju_free(scn->geoms);
mju_free(scn->geomorder);
mju_free(scn->flexedgeadr);
mju_free(scn->flexedgenum);
mju_free(scn->flexvertadr);
mju_free(scn->flexvertnum);
mju_free(scn->flexfaceadr);
mju_free(scn->flexfacenum);
mju_free(scn->flexfaceused);
mju_free(scn->flexedge);
mju_free(scn->flexvert);
mju_free(scn->flexface);
mju_free(scn->flexnormal);
mju_free(scn->flextexcoord);
mju_free(scn->skinfacenum);
mju_free(scn->skinvertadr);
mju_free(scn->skinvertnum);
mju_free(scn->skinvert);
mju_free(scn->skinnormal);
// clear data structure
mjv_defaultScene(scn);
}
// set default scene
void mjv_defaultScene(mjvScene* scn) {
memset(scn, 0, sizeof(mjvScene));
}
// set default visualization options
void mjv_defaultOption(mjvOption* vopt) {
vopt->label = mjLABEL_NONE;
vopt->frame = mjFRAME_NONE;
for (int i=0; i < mjNGROUP; i++) {
int state = (i < 3 ? 1 : 0);
vopt->geomgroup[i] = state;
vopt->sitegroup[i] = state;
vopt->jointgroup[i] = state;
vopt->tendongroup[i] = state;
vopt->actuatorgroup[i] = state;
vopt->flexgroup[i] = state;
vopt->skingroup[i] = state;
}
for (int i=0; i < mjNVISFLAG; i++) {
vopt->flags[i] = (mjVISSTRING[i][1][0] == '1');
}
vopt->bvh_depth = 1;
vopt->flex_layer = 0;
}
// set default camera
void mjv_defaultCamera(mjvCamera* cam) {
memset(cam, 0, sizeof(mjvCamera));
cam->type = mjCAMERA_FREE;
cam->fixedcamid = -1;
cam->trackbodyid = -1;
cam->distance = 2;
cam->azimuth = 90;
cam->elevation = -45;
}
// set default free camera
void mjv_defaultFreeCamera(const mjModel* m, mjvCamera* cam) {
memset(cam, 0, sizeof(mjvCamera));
cam->type = mjCAMERA_FREE;
cam->fixedcamid = -1;
cam->trackbodyid = -1;
cam->lookat[0] = m->stat.center[0];
cam->lookat[1] = m->stat.center[1];
cam->lookat[2] = m->stat.center[2];
cam->distance = 1.5 * m->stat.extent;
cam->azimuth = m->vis.global.azimuth;
cam->elevation = m->vis.global.elevation;
}
// set default perturbation
void mjv_defaultPerturb(mjvPerturb* pert) {
memset(pert, 0, sizeof(mjvPerturb));
pert->flexselect = -1;
pert->skinselect = -1;
pert->refquat[0] = 1;
pert->scale = 1;
}
// predefined line colors
static const float _linergb[8][3] = {
{1.0, 0.3, 0.3},
{0.1, 1.0, 0.1},
{0.3, 0.3, 1.0},
{0.1, 1.0, 1.0},
{1.0, 0.2, 1.0},
{1.0, 1.0, 0.1},
{1.0, 0.6, 0.2},
{0.6, 0.7, 0.4}
};
// set default figure
void mjv_defaultFigure(mjvFigure* fig) {
// set everything to zero
memset(fig, 0, sizeof(mjvFigure));
// disable highlight
fig->highlightid = -1;
// set enable flags
fig->flg_legend = 1;
fig->flg_ticklabel[0] = 1;
fig->flg_ticklabel[1] = 1;
fig->flg_extend = 1;
// set style
fig->linewidth = 3;
fig->gridwidth = 1;
fig->gridsize[0] = 2;
fig->gridsize[1] = 2;
fig->gridrgb[0] = 0.4f;
fig->gridrgb[1] = 0.4f;
fig->gridrgb[2] = 0.4f;
fig->figurergba[3] = 1;
fig->panergba[3] = 1;
fig->legendrgba[3] = 0.3f;
fig->textrgb[0] = 1;
fig->textrgb[1] = 1;
fig->textrgb[2] = 1;
fig->range[0][0] = 0;
fig->range[0][1] = 1;
fig->range[1][0] = 0;
fig->range[1][1] = 1;
mjSTRNCPY(fig->xformat, "%.0f");
mjSTRNCPY(fig->yformat, "%.2g");
mjSTRNCPY(fig->minwidth, "XXX");
// set line colors
for (int n=0; n < mjMAXLINE; n++) {
// predefined colors
if (n < 8) {
fig->linergb[n][0] = _linergb[n][0];
fig->linergb[n][1] = _linergb[n][1];
fig->linergb[n][2] = _linergb[n][2];
}
// automatically generated colors: Halton sequence
else {
fig->linergb[n][0] = 0.1f + 0.8f*mju_Halton(n, 2);
fig->linergb[n][1] = 0.1f + 0.8f*mju_Halton(n, 3);
fig->linergb[n][2] = 0.1f + 0.8f*mju_Halton(n, 5);
}
}
}
// compute rbound for mjvGeom
float mjv_rbound(const mjvGeom* geom) {
// model geom: return
if (geom->objtype == mjOBJ_GEOM) {
return geom->modelrbound;
}
// compute rbound according to type
const float* s = geom->size;
switch ((mjtMouse) geom->type) {
case mjGEOM_SPHERE:
return s[0];
case mjGEOM_CAPSULE:
return (s[0]+s[2]);
case mjGEOM_CYLINDER:
return sqrtf(s[0]*s[0] + s[2]*s[2]);
case mjGEOM_BOX:
return sqrtf(s[0]*s[0] + s[1]*s[1] + s[2]*s[2]);
break;
default: // not accurate for arrows, but they are not transparent
return mjMAX(s[0], mjMAX(s[1], s[2]));
}
}