diff --git a/src/experimental/filament/compat/scene_decorator.cc b/src/experimental/filament/compat/scene_decorator.cc index b7bea6d3..04968afd 100644 --- a/src/experimental/filament/compat/scene_decorator.cc +++ b/src/experimental/filament/compat/scene_decorator.cc @@ -129,6 +129,7 @@ void SceneDecorator::Update(mjData* data, const mjvOption* vis_option, mjrf_removeRenderableFromScene(scene_, iter.get()); } decorations_.clear(); + meshes_.clear(); const mat4 clip_from_world = CalcClipFromWorld(model, data, *camera, viewport); @@ -143,12 +144,133 @@ void SceneDecorator::Update(mjData* data, const mjvOption* vis_option, draw_text_at_fn(geom.label, pos.x, pos.y, pos.z); } } - if (geom.category != mjCAT_DECOR) { + + const mjtGeom geom_type = (mjtGeom)geom.type; + + if (geom_type == mjGEOM_NONE || geom_type == mjGEOM_LABEL) { + continue; + } + if (geom.category != mjCAT_DECOR && geom.type != mjGEOM_FLEX) { continue; } - const mjtGeom geom_type = (mjtGeom)geom.type; - if (geom_type == mjGEOM_NONE || geom_type == mjGEOM_LABEL) { + if (geom.type == mjGEOM_FLEX) { + // Draw flexes "normally" with skins; no decor/debug rendering needed. + if (mjv_scene_.flexskinopt) { + continue; + } + + mjrfMaterial material; + mjrf_defaultMaterial(&material); + material.decor_ux = true; + material.color[0] = model->flex_rgba[4 * geom.objid + 0]; + material.color[1] = model->flex_rgba[4 * geom.objid + 1]; + material.color[2] = model->flex_rgba[4 * geom.objid + 2]; + material.color[3] = model->flex_rgba[4 * geom.objid + 3]; + + mjrfRenderableParams params; + mjrf_defaultRenderableParams(¶ms); + + const int vertadr = mjv_scene_.flexvertadr[geom.objid]; + const int vertnum = mjv_scene_.flexvertnum[geom.objid]; + const float radius = model->flex_radius[geom.objid]; + + if (mjv_scene_.flexvertopt) { + // Use small spheres to represent vertices. + const float rot[] = {1.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 1.f}; + const float size[] = {radius, radius, radius}; + for (int v = vertadr; v < vertadr + vertnum; ++v) { + auto vertex = CreateRenderable(ctx, params); + mjrf_setRenderableGeomMesh(vertex.get(), mjGEOM_SPHERE, 8, 8, 1); + mjrf_setRenderableMaterial(vertex.get(), &material); + mjrf_setRenderableSize(vertex.get(), size); + mjrf_setRenderableTransform(vertex.get(), mjv_scene_.flexvert + 3*v, rot); + mjrf_addRenderableToScene(scene_, vertex.get()); + decorations_.push_back(std::move(vertex)); + } + } + + if (mjv_scene_.flexedgeopt) { + const int edgeadr = mjv_scene_.flexedgeadr[geom.objid]; + const int edgenum = mjv_scene_.flexedgenum[geom.objid]; + + // Use small thin cylinders to represent the edges. + for (int e = edgeadr; e < edgeadr + edgenum; ++e) { + const float* v1 = mjv_scene_.flexvert + 3 * (vertadr + mjv_scene_.flexedge[2*e]); + const float* v2 = mjv_scene_.flexvert + 3 * (vertadr + mjv_scene_.flexedge[2*e+1]); + const mjtNum vec[3] = {v2[0] - v1[0], v2[1] - v1[1], v2[2] - v1[2]}; + + const float pos[3]{ + (v1[0] + v2[0]) * 0.5f, + (v1[1] + v2[1]) * 0.5f, + (v1[2] + v2[2]) * 0.5f, + }; + + mjtNum quat[4]; + mju_quatZ2Vec(quat, vec); + mjtNum edgemat[9]; + mju_quat2Mat(edgemat, quat); + const float rot[9] = { + static_cast(edgemat[0]), + static_cast(edgemat[1]), + static_cast(edgemat[2]), + static_cast(edgemat[3]), + static_cast(edgemat[4]), + static_cast(edgemat[5]), + static_cast(edgemat[6]), + static_cast(edgemat[7]), + static_cast(edgemat[8]), + }; + + const float len = static_cast(mju_norm3(vec)); + const float size[3] = {radius, radius, len * 0.5f}; + + auto vertex = CreateRenderable(ctx, params); + mjrf_setRenderableGeomMesh(vertex.get(), mjGEOM_CYLINDER, 1, 8, 1); + mjrf_setRenderableMaterial(vertex.get(), &material); + mjrf_setRenderableSize(vertex.get(), size); + mjrf_setRenderableTransform(vertex.get(), pos, rot); + mjrf_addRenderableToScene(scene_, vertex.get()); + decorations_.push_back(std::move(vertex)); + } + } + + if (mjv_scene_.flexfaceopt && mjv_scene_.flexfaceused[geom.objid]) { + const bool has_uvs = geom.texcoord && geom.matid >= 0; + const int addr = mjv_scene_.flexfaceadr[geom.objid]; + const float* positions = mjv_scene_.flexface + (9 * addr); + const float* normals = mjv_scene_.flexnormal + (9 * addr); + const float* uvs = + has_uvs ? mjv_scene_.flextexcoord + (6 * addr) : nullptr; + + mjrfMeshData data; + mjrf_defaultMeshData(&data); + data.num_attributes = has_uvs ? 3 : 2; + data.attributes[0].usage = mjVERTEX_ATTRIBUTE_USAGE_POSITION; + data.attributes[0].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT3; + data.attributes[0].bytes = positions; + data.attributes[1].usage = mjVERTEX_ATTRIBUTE_USAGE_NORMAL; + data.attributes[1].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT3; + data.attributes[1].bytes = normals; + data.attributes[2].usage = mjVERTEX_ATTRIBUTE_USAGE_UV; + data.attributes[2].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT2; + data.attributes[2].bytes = uvs; + data.num_vertices = 3 * mjv_scene_.flexfaceused[geom.objid]; + data.num_indices = 3 * mjv_scene_.flexfaceused[geom.objid]; + data.indices = nullptr; + data.index_type = mjINDEX_TYPE_U32; + data.primitive_type = mjMESH_PRIMITIVE_TYPE_TRIANGLES; + data.compute_bounds = true; + data.release = nullptr; + data.user_data = nullptr; + meshes_.push_back(CreateMesh(ctx, data)); + + auto renderable = CreateRenderable(ctx, params); + mjrf_setRenderableMesh(renderable.get(), meshes_.back().get(), 0, 0); + mjrf_setRenderableMaterial(renderable.get(), &material); + mjrf_addRenderableToScene(scene_, renderable.get()); + decorations_.push_back(std::move(renderable)); + } continue; } diff --git a/src/experimental/filament/compat/scene_decorator.h b/src/experimental/filament/compat/scene_decorator.h index 508700e5..c69ab1f1 100644 --- a/src/experimental/filament/compat/scene_decorator.h +++ b/src/experimental/filament/compat/scene_decorator.h @@ -50,10 +50,10 @@ class SceneDecorator { SceneDecorator& operator=(const SceneDecorator&) = delete; private: - mjrfContext* ctx_; mjrfScene* scene_; ModelObjects* model_objects_; mjvScene mjv_scene_; + std::vector> meshes_; std::vector> decorations_; }; diff --git a/src/render/filament/support/mesh_util.cc b/src/render/filament/support/mesh_util.cc index d72ac09a..fcc3a7b1 100644 --- a/src/render/filament/support/mesh_util.cc +++ b/src/render/filament/support/mesh_util.cc @@ -23,8 +23,8 @@ #include #include #include -#include #include +#include #include "engine/engine_vis_visualize.h" #include "render/filament/mjrfilament_cpp.h" #include "render/filament/support/filament_util.h" @@ -53,17 +53,16 @@ struct VertexWithUv { } // namespace - static void AccumulateNormal(float3* normals, const mjtNum* src_positions, - const int* indices, int i0, int i1, int i2) { - const int idx0 = indices[i0]; - const int idx1 = indices[i1]; - const int idx2 = indices[i2]; + const int* indices) { + const int idx0 = indices[0]; + const int idx1 = indices[1]; + const int idx2 = indices[2]; const float3 v0 = ReadFloat3(src_positions, idx0); const float3 v1 = ReadFloat3(src_positions, idx1); const float3 v2 = ReadFloat3(src_positions, idx2); - const float3 normal = cross(v1 - v0, v2 - v0); + const float3 normal = normalize(cross(v1 - v0, v2 - v0)); normals[idx0] += normal; normals[idx1] += normal; @@ -71,27 +70,10 @@ static void AccumulateNormal(float3* normals, const mjtNum* src_positions, } template -static void AddFlatFace(T* vertices, const mjtNum* src_positions, float radius, - const int* indices, int i0, int i1, int i2) { - const float3 v0 = ReadFloat3(src_positions, indices[i0]); - const float3 v1 = ReadFloat3(src_positions, indices[i1]); - const float3 v2 = ReadFloat3(src_positions, indices[i2]); - - const float3 normal = normalize(cross(v1 - v0, v2 - v0)); - vertices[0].position = v0 + (radius * normal); - vertices[1].position = v1 + (radius * normal); - vertices[2].position = v2 + (radius * normal); - - const float4 orientation = CalculateOrientation(normal); - vertices[0].orientation = orientation; - vertices[1].orientation = orientation; - vertices[2].orientation = orientation; -} - -template -static void AddSmoothFace(T* vertices, const mjtNum* src_positions, - const float3* src_normals, float radius, - const int* indices, int i0, int i1, int i2) { +static void AddFlexFace(T* vertices, const mjtNum* src_positions, + const float3* src_normals, float radius, + bool flatten_normals, const int* indices, int i0, + int i1, int i2) { const int idx0 = indices[i0]; const int idx1 = indices[i1]; const int idx2 = indices[i2]; @@ -104,13 +86,20 @@ static void AddSmoothFace(T* vertices, const mjtNum* src_positions, vertices[1].position = v1 + (radius * src_normals[idx1]); vertices[2].position = v2 + (radius * src_normals[idx2]); - const float sign = radius > 0 ? 1.f : -1.f; - vertices[0].orientation = CalculateOrientation(sign * src_normals[idx0]); - vertices[1].orientation = CalculateOrientation(sign * src_normals[idx1]); - vertices[2].orientation = CalculateOrientation(sign * src_normals[idx2]); + const float sign = radius >= 0 ? 1.f : -1.f; + if (flatten_normals) { + const float3 flat = normalize(cross(v1 - v0, v2 - v0)); + const float4 orientation = CalculateOrientation(sign * flat); + vertices[0].orientation = orientation; + vertices[1].orientation = orientation; + vertices[2].orientation = orientation; + } else { + vertices[0].orientation = CalculateOrientation(sign * src_normals[idx0]); + vertices[1].orientation = CalculateOrientation(sign * src_normals[idx1]); + vertices[2].orientation = CalculateOrientation(sign * src_normals[idx2]); + } } -// Assumes T::orientation is already set to the "smoothed" normal. template static void AddSideFace(T* vertices, const mjtNum* src_positions, const float3* src_normals, float radius, @@ -157,46 +146,15 @@ static void UpdateBounds(float3* min_pt, float3* max_pt, const T* vertices) { *max_pt = max(*max_pt, vertices[2].position); } -static int CalculateVertexCount(const mjModel* model, int flex_id, - int flex_layer, bool smooth_skinning) { - const int dim = model->flex_dim[flex_id]; - - int num_faces = 0; - if (dim == 1) { - // 1d flexes have no faces. - } else if (smooth_skinning) { - if (dim == 2) { - num_faces += (2 * model->flex_elemnum[flex_id]); - num_faces += (2 * model->flex_shellnum[flex_id]); - } else { - num_faces += model->flex_shellnum[flex_id]; - } - } else { - if (dim == 2) { - num_faces += (2 * model->flex_elemnum[flex_id]); - } else { - for (int e = 0; e < model->flex_elemnum[flex_id]; e++) { - if (model->flex_elemlayer[model->flex_elemadr[flex_id] + e] == - flex_layer) { - num_faces += 4; - } - } - } - } - return num_faces * 3; -} - template static void FillFlexVertices(T* vertices, const mjModel* model, const mjData* data, int flex_id, float3* min_pt, - float3* max_pt, int flex_layer, - bool smooth_skinning) { - *min_pt = float3(FLT_MAX); - *max_pt = float3(FLT_MIN); - - const int num_vertices = - CalculateVertexCount(model, flex_id, flex_layer, smooth_skinning); + float3* max_pt) { const int dim = model->flex_dim[flex_id]; + const int* edata = model->flex_elem + model->flex_elemdataadr[flex_id]; + const int* sdata = model->flex_shell + model->flex_shelldataadr[flex_id]; + const int* tdata = + model->flex_elemtexcoord + model->flex_elemdataadr[flex_id]; const float radius = (float)model->flex_radius[flex_id]; const bool flat_shading = (bool)model->flex_flatskin[flex_id]; @@ -208,133 +166,87 @@ static void FillFlexVertices(T* vertices, const mjModel* model, src_uvs = model->flex_texcoord + 2 * model->flex_texcoordadr[flex_id]; } - const int* edata = model->flex_elem + model->flex_elemdataadr[flex_id]; - const int* sdata = model->flex_shell + model->flex_shelldataadr[flex_id]; - const int* tdata = - model->flex_elemtexcoord + model->flex_elemdataadr[flex_id]; - - if (dim == 1) { - // 1D - don't render? - return; + // Determine the maximum vertex index. + int max_index = 0; + if (dim == 2) { + for (int e = 0; e < model->flex_elemnum[flex_id]; ++e) { + const int* subindices = edata + (e * 3); + max_index = mjMAX(max_index, subindices[0]); + max_index = mjMAX(max_index, subindices[1]); + max_index = mjMAX(max_index, subindices[2]); + } + } else { + for (int s = 0; s < model->flex_shellnum[flex_id]; ++s) { + const int* subindices = sdata + (s * 3); + max_index = mjMAX(max_index, subindices[0]); + max_index = mjMAX(max_index, subindices[1]); + max_index = mjMAX(max_index, subindices[2]); + } } - else if (smooth_skinning) { - // Accumulate normals in the `orientation` field. - std::vector normals(num_vertices, float3(0, 0, 0)); - if (dim == 2) { - for (int e = 0; e < model->flex_elemnum[flex_id]; ++e) { - const int* indices = edata + e * (dim + 1); - AccumulateNormal(normals.data(), src_positions, indices, 0, 1, 2); - } - } else { - for (int s = 0; s < model->flex_shellnum[flex_id]; ++s) { - const int* indices = sdata + s * dim; - AccumulateNormal(normals.data(), src_positions, indices, 0, 1, 2); - } + // Accumulate normals. + std::vector normals(max_index + 1, float3(0, 0, 0)); + if (dim == 2) { + for (int e = 0; e < model->flex_elemnum[flex_id]; ++e) { + const int* subindices = edata + (e * 3); + AccumulateNormal(normals.data(), src_positions, subindices); } + } else { + for (int s = 0; s < model->flex_shellnum[flex_id]; ++s) { + const int* subindices = sdata + (s * 3); + AccumulateNormal(normals.data(), src_positions, subindices); + } + } - // Normalize the accumulated normals. - for (float3& n : normals) { + // Normalize the accumulated normals. + for (float3& n : normals) { + if (length(n) > 1e-16f) { n = normalize(n); - } - - if (dim == 2) { - for (int e = 0; e < model->flex_elemnum[flex_id]; ++e) { - const int* indices = edata + (e * (dim + 1)); - const int* tex_indices = tdata + (e * (dim + 1)); - - if (flat_shading) { - AddFlatFace(vertices, src_positions, radius, indices, 0, 1, 2); - } else { - AddSmoothFace(vertices, src_positions, normals.data(), radius, - indices, 0, 1, 2); - } - AddFaceUvs(vertices, src_uvs, tex_indices, 0, 1, 2); - UpdateBounds(min_pt, max_pt, vertices); - vertices += 3; - - if (flat_shading) { - AddFlatFace(vertices, src_positions, -radius, indices, 0, 2, 1); - } else { - AddSmoothFace(vertices, src_positions, normals.data(), -radius, - indices, 0, 2, 1); - } - AddFaceUvs(vertices, src_uvs, tex_indices, 0, 2, 1); - UpdateBounds(min_pt, max_pt, vertices); - vertices += 3; - } - for (int s = 0; s < model->flex_shellnum[flex_id]; ++s) { - const int* indices = sdata + (s * dim); - - AddSideFace(vertices, src_positions, normals.data(), radius, indices, 0, - 1); - AddFaceUvs(vertices, src_uvs, indices, 0, 1, 1); - UpdateBounds(min_pt, max_pt, vertices); - vertices += 3; - - AddSideFace(vertices, src_positions, normals.data(), -radius, indices, - 1, 0); - AddFaceUvs(vertices, src_uvs, indices, 1, 0, 0); - UpdateBounds(min_pt, max_pt, vertices); - vertices += 3; - } } else { - for (int s = 0; s < model->flex_shellnum[flex_id]; ++s) { - const int* indices = sdata + s * dim; - if (flat_shading) { - AddFlatFace(vertices, src_positions, radius, indices, 0, 1, 2); - } else { - AddSmoothFace(vertices, src_positions, normals.data(), radius, - indices, 0, 1, 2); - } - AddFaceUvs(vertices, src_uvs, indices, 0, 1, 2); - UpdateBounds(min_pt, max_pt, vertices); - vertices += 3; - } + n = float3(1, 0, 0); } } - // 2D or 3D face: faces from elements, flat normals, texture - else { - for (int e = 0; e < model->flex_elemnum[flex_id]; e++) { - // in 3D, show only elements in selected layer - if (dim == 2 || model->flex_elemlayer[model->flex_elemadr[flex_id] + e] == - flex_layer) { - const int* edata2 = edata + e * (dim + 1); - const int* tdata2 = tdata + e * (dim + 1); + if (dim == 2) { + for (int e = 0; e < model->flex_elemnum[flex_id]; ++e) { + const int* indices = edata + (e * (dim + 1)); + const int* tex_indices = tdata + (e * (dim + 1)); - if (dim == 2) { - AddFlatFace(vertices, src_positions, radius, edata2, 0, 1, 2); - AddFaceUvs(vertices, src_uvs, tdata2, 0, 1, 2); - UpdateBounds(min_pt, max_pt, vertices); - vertices += 3; + AddFlexFace(vertices, src_positions, normals.data(), radius, + flat_shading, indices, 0, 1, 2); + AddFaceUvs(vertices, src_uvs, tex_indices, 0, 1, 2); + UpdateBounds(min_pt, max_pt, vertices); + vertices += 3; - AddFlatFace(vertices, src_positions, radius, edata2, 0, 2, 1); - AddFaceUvs(vertices, src_uvs, tdata2, 0, 2, 1); - UpdateBounds(min_pt, max_pt, vertices); - vertices += 3; - } else { - AddFlatFace(vertices, src_positions, radius, edata2, 0, 1, 2); - AddFaceUvs(vertices, src_uvs, tdata2, 0, 1, 2); - UpdateBounds(min_pt, max_pt, vertices); - vertices += 3; + AddFlexFace(vertices, src_positions, normals.data(), -radius, + flat_shading, indices, 0, 2, 1); + AddFaceUvs(vertices, src_uvs, tex_indices, 0, 2, 1); + UpdateBounds(min_pt, max_pt, vertices); + vertices += 3; + } + for (int s = 0; s < model->flex_shellnum[flex_id]; ++s) { + const int* indices = sdata + (s * dim); - AddFlatFace(vertices, src_positions, radius, edata2, 0, 2, 3); - AddFaceUvs(vertices, src_uvs, tdata2, 0, 2, 3); - UpdateBounds(min_pt, max_pt, vertices); - vertices += 3; + AddSideFace(vertices, src_positions, normals.data(), radius, indices, 0, + 1); + AddFaceUvs(vertices, src_uvs, indices, 0, 1, 1); + UpdateBounds(min_pt, max_pt, vertices); + vertices += 3; - AddFlatFace(vertices, src_positions, radius, edata2, 0, 3, 1); - AddFaceUvs(vertices, src_uvs, tdata2, 0, 3, 1); - UpdateBounds(min_pt, max_pt, vertices); - vertices += 3; - - AddFlatFace(vertices, src_positions, radius, edata2, 1, 3, 2); - AddFaceUvs(vertices, src_uvs, tdata2, 1, 3, 2); - UpdateBounds(min_pt, max_pt, vertices); - vertices += 3; - } - } + AddSideFace(vertices, src_positions, normals.data(), -radius, indices, 1, + 0); + AddFaceUvs(vertices, src_uvs, indices, 1, 0, 0); + UpdateBounds(min_pt, max_pt, vertices); + vertices += 3; + } + } else if (dim == 3) { + for (int s = 0; s < model->flex_shellnum[flex_id]; ++s) { + const int* indices = sdata + s * dim; + AddFlexFace(vertices, src_positions, normals.data(), radius, + flat_shading, indices, 0, 1, 2); + AddFaceUvs(vertices, src_uvs, indices, 0, 1, 2); + UpdateBounds(min_pt, max_pt, vertices); + vertices += 3; } } } @@ -500,13 +412,21 @@ static void SetBounds(mjrfMeshData* mesh_data, const float3& min_pt, } UniquePtr CreateFlexMesh(mjrfContext* ctx, const mjModel* model, - const mjData* data, int flex_id, - int flex_layer, bool smooth_skinning, - bool generate_edges, - bool generate_vertices) { - // TODO: generate edges and vertices if requested. - const int num_vertices = - CalculateVertexCount(model, flex_id, flex_layer, smooth_skinning); + const mjData* data, int flex_id) { + const int dim = model->flex_dim[flex_id]; + + int num_faces = 0; + if (dim == 2) { + num_faces += (2 * model->flex_elemnum[flex_id]); + num_faces += (2 * model->flex_shellnum[flex_id]); + } else if (dim == 3) { + num_faces += model->flex_shellnum[flex_id]; + } else { + // 1D flex objects should be rendered as a collection of capsules. + mju_error("Unsupported flex dimension: %d", dim); + } + + const int num_vertices = num_faces * 3; const bool has_uvs = model->flex_texcoordadr[flex_id] >= 0; mjrfMeshData mesh_data = PrepareMeshData(num_vertices, has_uvs); @@ -514,19 +434,17 @@ UniquePtr CreateFlexMesh(mjrfContext* ctx, const mjModel* model, float3 max_pt = float3(FLT_MIN); if (has_uvs) { VertexWithUv* vertices = (VertexWithUv*)(mesh_data.user_data); - FillFlexVertices(vertices, model, data, flex_id, &min_pt, &max_pt, - flex_layer, smooth_skinning); + FillFlexVertices(vertices, model, data, flex_id, &min_pt, &max_pt); } else { VertexNoUv* vertices = (VertexNoUv*)(mesh_data.user_data); - FillFlexVertices(vertices, model, data, flex_id, &min_pt, &max_pt, - flex_layer, smooth_skinning); + FillFlexVertices(vertices, model, data, flex_id, &min_pt, &max_pt); } SetBounds(&mesh_data, min_pt, max_pt); return CreateMesh(ctx, mesh_data); } UniquePtr CreateSkinMesh(mjrfContext* ctx, const mjModel* model, - const mjData* data, int skin_id) { + const mjData* data, int skin_id) { const int num_vertices = model->skin_vertnum[skin_id]; const bool has_uvs = model->skin_texcoordadr[skin_id] >= 0; mjrfMeshData mesh_data = PrepareMeshData(num_vertices, has_uvs); diff --git a/src/render/filament/support/mesh_util.h b/src/render/filament/support/mesh_util.h index baf97050..577db417 100644 --- a/src/render/filament/support/mesh_util.h +++ b/src/render/filament/support/mesh_util.h @@ -25,9 +25,7 @@ namespace mujoco { // Creates a mjrfMesh for the given flex object. UniquePtr CreateFlexMesh(mjrfContext* ctx, const mjModel* model, - const mjData* data, int flex_id, - int flex_layer, bool smooth_skinning, - bool generate_edges, bool generate_vertices); + const mjData* data, int flex_id); // Creates a mjrfMesh for the given skin object. UniquePtr CreateSkinMesh(mjrfContext* ctx, const mjModel* model, diff --git a/src/render/filament/support/renderable_manager.cc b/src/render/filament/support/renderable_manager.cc index b64b16bc..6827ef10 100644 --- a/src/render/filament/support/renderable_manager.cc +++ b/src/render/filament/support/renderable_manager.cc @@ -197,8 +197,10 @@ RenderableManager::~RenderableManager() { for (auto& renderable : sites_) { mjrf_removeRenderableFromScene(scene_, renderable.get()); } - for (auto& renderable : flexes_) { - mjrf_removeRenderableFromScene(scene_, renderable.get()); + for (auto& parts : flexes_) { + for (auto& renderable : parts) { + mjrf_removeRenderableFromScene(scene_, renderable.get()); + } } for (auto& renderable : skins_) { mjrf_removeRenderableFromScene(scene_, renderable.get()); @@ -231,15 +233,29 @@ void RenderableManager::Update(const mjData* data) { mjrf_setRenderableTransform(sites_[i].get(), pos.v, mat.asArray()); } - for (int i = 0; i < model->nflex; ++i) { - const int flex_layer = vopts_.flex_layer; - const bool smooth_skinning = vopts_.flags[mjVIS_FLEXSKIN]; - const bool edges = !smooth_skinning && vopts_.flags[mjVIS_FLEXEDGE]; - const bool vertices = !smooth_skinning && vopts_.flags[mjVIS_FLEXVERT]; - auto mesh = CreateFlexMesh(ctx, model, data, i, flex_layer, smooth_skinning, - edges, vertices); - mjrf_setRenderableMesh(flexes_[i].get(), mesh.get(), 0, 0); - flex_meshes_[i] = std::move(mesh); + if (vopts_.flags[mjVIS_FLEXSKIN]) { + for (int i = 0; i < model->nflex; ++i) { + const int dim = model->flex_dim[i]; + if (dim > 1) { + auto mesh = CreateFlexMesh(ctx, model, data, i); + mjrf_setRenderableMesh(flexes_[i][0].get(), mesh.get(), 0, 0); + flex_meshes_[i] = std::move(mesh); + } else { + const int vertadr = model->flex_vertadr[i]; + const int edgeadr = model->flex_edgeadr[i]; + const int edgenum = model->flex_edgenum[i]; + const float radius = model->flex_radius[i]; + auto& edges = flexes_[i]; + for (int j = 0; j < edgenum; ++j) { + const int e = j + edgeadr; + const int idx0 = model->flex_edge[2 * e]; + const int idx1 = model->flex_edge[2 * e + 1]; + const float3 v0 = ReadFloat3(data->flexvert_xpos, vertadr + idx0); + const float3 v1 = ReadFloat3(data->flexvert_xpos, vertadr + idx1); + Connect(edges[j].get(), v0, v1, radius); + } + } + } } for (int i = 0; i < model->nskin; ++i) { @@ -316,11 +332,13 @@ void RenderableManager::Update(const mjData* data) { island_id = model->tree_dofadr[tree]; } - mjrfMaterial material; - mjrf_getRenderableMaterial(flexes_[i].get(), &material); - material.island_id = island_id; - material.sleep_state = awake ? mjS_AWAKE : mjS_ASLEEP; - mjrf_setRenderableMaterial(flexes_[i].get(), &material); + for (auto& renderable : flexes_[i]) { + mjrfMaterial material; + mjrf_getRenderableMaterial(renderable.get(), &material); + material.island_id = island_id; + material.sleep_state = awake ? mjS_AWAKE : mjS_ASLEEP; + mjrf_setRenderableMaterial(renderable.get(), &material); + } } } } @@ -340,7 +358,10 @@ mjrfRenderable* RenderableManager::GetRenderable(mjtObj obj_type, int obj_index, break; case mjOBJ_FLEX: if (obj_index >= 0 && obj_index < flexes_.size()) { - return flexes_[obj_index].get(); + auto& parts = flexes_[obj_index]; + if (sub_index >= 0 && sub_index < parts.size()) { + return parts[sub_index].get(); + } } break; case mjOBJ_SKIN: @@ -449,18 +470,37 @@ void RenderableManager::AddFlexGeoms() { flexes_.reserve(model->nflex); flex_meshes_.reserve(model->nflex); for (int i = 0; i < model->nflex; ++i) { - mjrfRenderableParams params; - mjrf_defaultRenderableParams(¶ms); - auto renderable = CreateRenderable(ctx, params); + flex_meshes_.emplace_back(nullptr, nullptr); mjrfMaterial material = GetDefaultMaterial(mjOBJ_FLEX, i); - mjrf_setRenderableMaterial(renderable.get(), &material); + + mjrfRenderableParams params; + mjrf_defaultRenderableParams(¶ms); + + auto& parts = flexes_.emplace_back(); + + const int dim = model->flex_dim[i]; + if (dim == 1) { + const float radius = model->flex_radius[i]; + const float size[3] = {radius, radius, radius}; + for (int j = 0; j < model->flex_edgenum[i]; ++j) { + auto renderable = CreateRenderable(ctx, params); + mjrf_setRenderableGeomMesh(renderable.get(), mjGEOM_CAPSULE, 4, 8, 1); + mjrf_setRenderableSize(renderable.get(), size); + mjrf_setRenderableMaterial(renderable.get(), &material); + parts.push_back(std::move(renderable)); + } + } else { + auto renderable = CreateRenderable(ctx, params); + mjrf_setRenderableMaterial(renderable.get(), &material); + parts.push_back(std::move(renderable)); + } if (vopts_.flexgroup[model->flex_group[i]]) { - mjrf_addRenderableToScene(scene_, renderable.get()); + for (auto& renderable : parts) { + mjrf_addRenderableToScene(scene_, renderable.get()); + } } - flexes_.emplace_back(std::move(renderable)); - flex_meshes_.emplace_back(nullptr, nullptr); } } @@ -950,7 +990,7 @@ void RenderableManager::SetVisibility(mjtObj obj_type, int idx, bool visible) { case mjOBJ_FLEX: DetermineVisibilities(ops, vopts_.flexgroup, &vopts_.flags[mjVIS_FLEXSKIN], idx, visible); for (int i = 0; i < model->nflex; ++i) { - ApplyVisibility(ops, model->flex_group[i], scene_, {&flexes_[i], 1}); + ApplyVisibility(ops, model->flex_group[i], scene_, flexes_[i]); } break; case mjOBJ_SKIN: diff --git a/src/render/filament/support/renderable_manager.h b/src/render/filament/support/renderable_manager.h index 2958d559..1f170756 100644 --- a/src/render/filament/support/renderable_manager.h +++ b/src/render/filament/support/renderable_manager.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_RENDERABLE_MANAGER_H_ -#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_RENDERABLE_MANAGER_H_ +#ifndef MUJOCO_SRC_RENDER_FILAMENT_SUPPORT_RENDERABLE_MANAGER_H_ +#define MUJOCO_SRC_RENDER_FILAMENT_SUPPORT_RENDERABLE_MANAGER_H_ #include #include @@ -98,10 +98,10 @@ class RenderableManager { std::vector> geoms_; std::vector> sites_; - std::vector> flexes_; std::vector> skins_; - std::unordered_map, 2>> slider_cranks_; + std::vector>> flexes_; std::vector>> tendons_; + std::unordered_map, 2>> slider_cranks_; std::vector> flex_meshes_; std::vector> skin_meshes_; @@ -109,4 +109,4 @@ class RenderableManager { }; } // namespace mujoco -#endif // MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_RENDERABLE_MANAGER_H_ +#endif // MUJOCO_SRC_RENDER_FILAMENT_SUPPORT_RENDERABLE_MANAGER_H_