Add line and linebox geom primitives.

PiperOrigin-RevId: 818570050
Change-Id: If02873dd878a23b442368ce69bc024e0310e9d02
This commit is contained in:
Haroon Qureshi
2025-10-13 02:58:21 -07:00
committed by Copybara-Service
parent 66a1c22cae
commit 9b7e7e471d
8 changed files with 214 additions and 50 deletions
@@ -0,0 +1,29 @@
// Copyright 2025 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.
material {
name : unlit_segmentation,
shadingModel : unlit,
culling: none,
parameters : [
{ type : float4, name : BaseColorFactor }
]
}
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = materialParams.BaseColorFactor;
}
}
@@ -23,6 +23,7 @@
#include <filament/Box.h>
#include <filament/Engine.h>
#include <filament/IndexBuffer.h>
#include <filament/RenderableManager.h>
#include <filament/VertexBuffer.h>
// Functions for creating filament vertex and index buffers.
@@ -33,6 +34,8 @@ struct FilamentBuffers {
filament::IndexBuffer* index_buffer = nullptr;
filament::VertexBuffer* vertex_buffer = nullptr;
filament::Box bounds = {{-1, -1, -1}, {1, 1, 1}};
filament::RenderableManager::PrimitiveType type =
filament::RenderableManager::PrimitiveType::TRIANGLES;
};
// Function that fills in the given buffer with actual data.
+118 -1
View File
@@ -58,10 +58,45 @@ std::size_t NumIndicesPerSide(int num_quads_per_axis) {
return kNumIndicesPerQuad * num_quads_per_axis * num_quads_per_axis;
}
class LineBuilder {
public:
using VertexType = VertexNoUv;
using IndexType = uint16_t;
static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType =
filament::RenderableManager::PrimitiveType::LINES;
explicit LineBuilder() {}
std::size_t NumVertices() const {
return 2;
}
std::size_t NumIndices() const {
return 2;
}
void GenerateVertices(VertexType* ptr, size_t num) const {
constexpr float4 kOrientation = {0, 0, 0, 1}; // Unused for lines.
ptr[0] = VertexType({0, 0, 0}, kOrientation);
ptr[1] = VertexType({0, 0, 1}, kOrientation);
}
void GenerateIndices(IndexType* ptr, size_t num) const {
ptr[0] = 0;
ptr[1] = 1;
}
filament::Box GetBounds() const {
return {{-0.001, -0.001, 0}, {0.001, 0.001, 1}};
}
};
class PlaneBuilder {
public:
using VertexType = VertexNoUv;
using IndexType = uint16_t;
static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType =
filament::RenderableManager::PrimitiveType::TRIANGLES;
explicit PlaneBuilder(int num_quads_per_axis)
: num_quads_per_axis_(num_quads_per_axis),
@@ -109,10 +144,74 @@ class PlaneBuilder {
float4 orientation_;
};
class LineBoxBuilder {
public:
using VertexType = VertexNoUv;
using IndexType = uint16_t;
static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType =
filament::RenderableManager::PrimitiveType::LINES;
explicit LineBoxBuilder() {}
std::size_t NumVertices() const {
return 8;
}
std::size_t NumIndices() const {
return 24;
}
void GenerateVertices(VertexType* ptr, size_t num) const {
constexpr float4 kOrientation = {0, 0, 0, 1}; // Unused for lines.
ptr[0] = VertexType({-1.0f, -1.0f, -1.0f}, kOrientation);
ptr[1] = VertexType({ 1.0f, -1.0f, -1.0f}, kOrientation);
ptr[2] = VertexType({-1.0f, 1.0f, -1.0f}, kOrientation);
ptr[3] = VertexType({ 1.0f, 1.0f, -1.0f}, kOrientation);
ptr[4] = VertexType({-1.0f, -1.0f, 1.0f}, kOrientation);
ptr[5] = VertexType({ 1.0f, -1.0f, 1.0f}, kOrientation);
ptr[6] = VertexType({-1.0f, 1.0f, 1.0f}, kOrientation);
ptr[7] = VertexType({ 1.0f, 1.0f, 1.0f}, kOrientation);
}
void GenerateIndices(IndexType* ptr, size_t num) const {
// Bottom square (where z == -1).
ptr[0] = 0;
ptr[1] = 1;
ptr[2] = 1;
ptr[3] = 3;
ptr[4] = 3;
ptr[5] = 2;
ptr[6] = 2;
ptr[7] = 0;
// Top square (where z == 1).
ptr[8] = 4;
ptr[9] = 5;
ptr[10] = 5;
ptr[11] = 7;
ptr[12] = 7;
ptr[13] = 6;
ptr[14] = 6;
ptr[15] = 4;
// Connect edges from bottom to top.
ptr[16] = 2;
ptr[17] = 6;
ptr[18] = 3;
ptr[19] = 7;
ptr[20] = 0;
ptr[21] = 4;
ptr[22] = 1;
ptr[23] = 5;
}
filament::Box GetBounds() const { return {{-1, -1, -1}, {1, 1, 1}}; }
};
class BoxBuilder {
public:
using VertexType = VertexNoUv;
using IndexType = uint16_t;
static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType =
filament::RenderableManager::PrimitiveType::TRIANGLES;
static constexpr int kNumSides = 6;
@@ -196,6 +295,8 @@ class TubeBuilder {
public:
using VertexType = VertexNoUv;
using IndexType = uint16_t;
static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType =
filament::RenderableManager::PrimitiveType::TRIANGLES;
TubeBuilder(int num_stacks, int num_slices)
: num_stacks_(num_stacks), num_slices_(num_slices) {}
@@ -252,6 +353,8 @@ class ConeBuilder {
public:
using VertexType = VertexNoUv;
using IndexType = uint16_t;
static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType =
filament::RenderableManager::PrimitiveType::TRIANGLES;
ConeBuilder(int num_stacks, int num_slices)
: num_stacks_(num_stacks), num_slices_(num_slices) {}
@@ -341,6 +444,8 @@ class DiskBuilder {
public:
using VertexType = VertexNoUv;
using IndexType = uint16_t;
static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType =
filament::RenderableManager::PrimitiveType::TRIANGLES;
explicit DiskBuilder(int num_slices) : num_slices_(num_slices) {
orientation_ = CalculateOrientation({0, 0, 1});
@@ -388,6 +493,8 @@ class SphereBuilder {
public:
using VertexType = VertexNoUv;
using IndexType = uint16_t;
static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType =
filament::RenderableManager::PrimitiveType::TRIANGLES;
static constexpr IndexType kNorthPoleIndex = 0;
static constexpr IndexType kSouthPoleIndex = 1;
@@ -494,6 +601,8 @@ class DomeBuilder {
public:
using VertexType = VertexNoUv;
using IndexType = uint16_t;
static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType =
filament::RenderableManager::PrimitiveType::TRIANGLES;
static constexpr IndexType kPoleIndex = 0;
@@ -617,7 +726,11 @@ FilamentBuffers CreateFromBuilder(filament::Engine* engine, const T& builder) {
auto vb = CreateVertexBuffer<VertexType>(engine, num_vertices, vertices);
auto ib = CreateIndexBuffer<IndexType>(engine, num_indices, indices);
return {ib, vb, builder.GetBounds()};
return {ib, vb, builder.GetBounds(), T::kPrimitiveType};
}
FilamentBuffers CreateLine(filament::Engine* engine, const mjModel* model) {
return CreateFromBuilder(engine, LineBuilder());
}
FilamentBuffers CreatePlane(filament::Engine* engine, const mjModel* model) {
@@ -630,6 +743,10 @@ FilamentBuffers CreateBox(filament::Engine* engine, const mjModel* model) {
return CreateFromBuilder(engine, BoxBuilder(num_quads));
}
FilamentBuffers CreateLineBox(filament::Engine* engine, const mjModel* model) {
return CreateFromBuilder(engine, LineBoxBuilder());
}
FilamentBuffers CreateSphere(filament::Engine* engine, const mjModel* model) {
const int num_stacks = model->vis.quality.numstacks;
const int num_slices = model->vis.quality.numslices;
@@ -22,7 +22,9 @@
// Generates buffers for built-in shapes.
namespace mujoco {
FilamentBuffers CreateLine(filament::Engine* engine, const mjModel* model);
FilamentBuffers CreateBox(filament::Engine* engine, const mjModel* model);
FilamentBuffers CreateLineBox(filament::Engine* engine, const mjModel* model);
FilamentBuffers CreatePlane(filament::Engine* engine, const mjModel* model);
FilamentBuffers CreateSphere(filament::Engine* engine, const mjModel* model);
FilamentBuffers CreateTube(filament::Engine* engine, const mjModel* model);
+53 -45
View File
@@ -106,6 +106,10 @@ Drawable::Drawable(ObjectManager* object_mgr, const mjvGeom& geom)
AddShape(ObjectManager::kCone);
AddShape(ObjectManager::kDisk);
AddShape(ObjectManager::kDisk);
} else if (geom.type == mjGEOM_LINE) {
AddShape(ObjectManager::kLine);
} else if (geom.type == mjGEOM_LINEBOX) {
AddShape(ObjectManager::kLineBox);
} else if (geom.type == mjGEOM_FLEX || geom.type == mjGEOM_SKIN) {
// Flex and skin geometries are dynamically updated every frame.
} else {
@@ -298,53 +302,57 @@ void Drawable::UpdateMaterial(const mjvGeom& geom) {
textures.occlusion = object_mgr->GetTexture(geom.matid, mjTEXROLE_OCCLUSION);
}
if (geom.matid >= 0) {
if (textures.orm) {
material_.SetNormalMaterialType(ObjectManager::kPbrPacked);
} else if (textures.metallic) {
material_.SetNormalMaterialType(ObjectManager::kPbr);
} else if (textures.roughness) {
material_.SetNormalMaterialType(ObjectManager::kPbr);
} else if (model->mat_metallic[geom.matid] >= 0) {
material_.SetNormalMaterialType(ObjectManager::kPbr);
} else if (model->mat_roughness[geom.matid] >= 0) {
material_.SetNormalMaterialType(ObjectManager::kPbr);
}
}
// Check to see if we're dealing with a mesh with texture coordinates.
// `data_id` is the id of the mesh in model (i.e. the geom has mesh geometry)
// and `mesh_texcoordadr` stores the address of the mesh uvs if it has them.
bool has_texcoords = false;
if ((geom.type == mjGEOM_MESH || geom.type == mjGEOM_SDF) &&
geom.dataid >= 0 && model->mesh_texcoordadr[geom.dataid / 2] >= 0) {
has_texcoords = true;
}
if (textures.color == nullptr) {
if (geom.rgba[3] < 1.0f) {
material_.SetNormalMaterialType(ObjectManager::kPhongColorFade);
} else {
material_.SetNormalMaterialType(ObjectManager::kPhongColor);
}
} else if (textures.color->getTarget() ==
filament::Texture::Sampler::SAMPLER_CUBEMAP) {
if (geom.rgba[3] < 1.0f) {
material_.SetNormalMaterialType(ObjectManager::kPhongCubeFade);
} else {
material_.SetNormalMaterialType(ObjectManager::kPhongCube);
}
} else if (has_texcoords) {
if (geom.rgba[3] < 1.0f) {
material_.SetNormalMaterialType(ObjectManager::kPhong2dUvFade);
} else {
material_.SetNormalMaterialType(ObjectManager::kPhong2dUv);
}
if (geom.type == mjGEOM_LINE || geom.type == mjGEOM_LINEBOX) {
material_.SetNormalMaterialType(ObjectManager::kUnlitLine);
} else {
if (geom.rgba[3] < 1.0f) {
material_.SetNormalMaterialType(ObjectManager::kPhong2dFade);
if (geom.matid >= 0) {
if (textures.orm) {
material_.SetNormalMaterialType(ObjectManager::kPbrPacked);
} else if (textures.metallic) {
material_.SetNormalMaterialType(ObjectManager::kPbr);
} else if (textures.roughness) {
material_.SetNormalMaterialType(ObjectManager::kPbr);
} else if (model->mat_metallic[geom.matid] >= 0) {
material_.SetNormalMaterialType(ObjectManager::kPbr);
} else if (model->mat_roughness[geom.matid] >= 0) {
material_.SetNormalMaterialType(ObjectManager::kPbr);
}
}
// Check to see if we're dealing with a mesh with texture coordinates.
// `data_id` is the id of the mesh in model (i.e. the geom has mesh geometry)
// and `mesh_texcoordadr` stores the address of the mesh uvs if it has them.
bool has_texcoords = false;
if ((geom.type == mjGEOM_MESH || geom.type == mjGEOM_SDF) &&
geom.dataid >= 0 && model->mesh_texcoordadr[geom.dataid / 2] >= 0) {
has_texcoords = true;
}
if (textures.color == nullptr) {
if (geom.rgba[3] < 1.0f) {
material_.SetNormalMaterialType(ObjectManager::kPhongColorFade);
} else {
material_.SetNormalMaterialType(ObjectManager::kPhongColor);
}
} else if (textures.color->getTarget() ==
filament::Texture::Sampler::SAMPLER_CUBEMAP) {
if (geom.rgba[3] < 1.0f) {
material_.SetNormalMaterialType(ObjectManager::kPhongCubeFade);
} else {
material_.SetNormalMaterialType(ObjectManager::kPhongCube);
}
} else if (has_texcoords) {
if (geom.rgba[3] < 1.0f) {
material_.SetNormalMaterialType(ObjectManager::kPhong2dUvFade);
} else {
material_.SetNormalMaterialType(ObjectManager::kPhong2dUv);
}
} else {
material_.SetNormalMaterialType(ObjectManager::kPhong2d);
if (geom.rgba[3] < 1.0f) {
material_.SetNormalMaterialType(ObjectManager::kPhong2dFade);
} else {
material_.SetNormalMaterialType(ObjectManager::kPhong2d);
}
}
}
@@ -68,7 +68,9 @@ struct Asset {
ObjectManager::ObjectManager(const mjModel* model, filament::Engine* engine,
const mjrFilamentConfig* config)
: model_(model), engine_(engine), config_(config) {
shapes_[kLine] = CreateLine(engine_, model_);
shapes_[kBox] = CreateBox(engine_, model_);
shapes_[kLineBox] = CreateLineBox(engine_, model_);
shapes_[kCone] = CreateCone(engine_, model_);
shapes_[kDisk] = CreateDisk(engine_, model_);
shapes_[kDome] = CreateDome(engine_, model_);
@@ -94,6 +96,7 @@ ObjectManager::ObjectManager(const mjModel* model, filament::Engine* engine,
materials_[kPhongCube] = LoadMaterial("phong_cube.filamat");
materials_[kPhongCubeFade] = LoadMaterial("phong_cube_fade.filamat");
materials_[kUnlitSegmentation] = LoadMaterial("unlit_segmentation.filamat");
materials_[kUnlitLine] = LoadMaterial("unlit_line.filamat");
materials_[kUnlitDepth] = LoadMaterial("unlit_depth.filamat");
materials_[kUnlitUi] = LoadMaterial("unlit_ui.filamat");
@@ -51,11 +51,14 @@ class ObjectManager {
kPhongCubeFade,
kUnlitSegmentation,
kUnlitDepth,
kUnlitLine,
kUnlitUi,
kNumMaterials,
};
enum ShapeType {
kLine,
kLineBox,
kPlane,
kBox,
kSphere,
@@ -96,8 +96,8 @@ utils::Entity Renderables::CreateEntity(const FilamentBuffers& buffers) {
}
filament::RenderableManager::Builder builder(1);
builder.geometry(0, filament::RenderableManager::PrimitiveType::TRIANGLES,
buffers.vertex_buffer, buffers.index_buffer);
builder.geometry(0, buffers.type, buffers.vertex_buffer,
buffers.index_buffer);
if (material_instance_) {
builder.material(0, material_instance_);
}
@@ -124,8 +124,7 @@ void Renderables::UpdateEntity(utils::Entity entity,
mju_error("Invalid (null) index buffer.");
}
filament::RenderableManager& rm = engine_->getRenderableManager();
rm.setGeometryAt(rm.getInstance(entity), 0,
filament::RenderableManager::PrimitiveType::TRIANGLES,
rm.setGeometryAt(rm.getInstance(entity), 0, buffers.type,
buffers.vertex_buffer, buffers.index_buffer, 0,
buffers.index_buffer->getIndexCount());
}