Files
Mujoco_WASM/src/experimental/filament/filament/geom_util.cc
T
Haroon Qureshi d4103939e4 Correctly compute bounding boxes for meshes.
Enable culling when bounding box is available.

PiperOrigin-RevId: 892289875
Change-Id: I124426b6e7e72f4d9a1486320d72d6eb032e0828
2026-03-31 05:58:11 -07:00

189 lines
6.8 KiB
C++

// 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.
#include "experimental/filament/filament/geom_util.h"
#include <cfloat>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <span>
#include <filament/Engine.h>
#include <filament/IndexBuffer.h>
#include <filament/VertexBuffer.h>
#include <math/vec3.h>
#include <mujoco/mujoco.h>
#include "experimental/filament/filament/buffer_util.h"
#include "experimental/filament/filament/math_util.h"
#include "experimental/filament/filament/vertex_util.h"
namespace mujoco {
using filament::math::float3;
static std::span<const float> GetPositions(const mjModel* model,
const mjvScene* scene,
const mjvGeom& geom) {
if (geom.type == mjGEOM_FLEX) {
const int num = 9 * scene->flexfaceused[geom.objid];
const int addr = scene->flexfaceadr[geom.objid];
const float* ptr = scene->flexface + (9 * addr);
return {ptr, static_cast<size_t>(num)};
} else {
const int num = 3 * scene->skinvertnum[geom.objid];
const int addr = scene->skinvertadr[geom.objid];
const float* ptr = scene->skinvert + (3 * addr);
return {ptr, static_cast<size_t>(num)};
}
}
static std::span<const float> GetNormals(const mjModel* model,
const mjvScene* scene,
const mjvGeom& geom) {
if (geom.type == mjGEOM_FLEX) {
const int num = 9 * scene->flexfaceused[geom.objid];
const int addr = scene->flexfaceadr[geom.objid];
const float* ptr = scene->flexnormal + (9 * addr);
return {ptr, static_cast<size_t>(num)};
} else {
const int num = 3 * scene->skinvertnum[geom.objid];
const int addr = scene->skinvertadr[geom.objid];
const float* ptr = scene->skinnormal + (3 * addr);
return {ptr, static_cast<size_t>(num)};
}
}
static std::span<const float> GetUvs(const mjModel* model,
const mjvScene* scene,
const mjvGeom& geom) {
if (geom.type == mjGEOM_FLEX) {
if (geom.texcoord && geom.matid >= 0) {
const int num = 6 * scene->flexfaceused[geom.objid];
const int addr = scene->flexfaceadr[geom.objid];
const float* ptr = scene->flextexcoord + (6 * addr);
return {ptr, static_cast<size_t>(num)};
} else {
const float* ptr = nullptr;
return {ptr, 0};
}
} else {
if (model->skin_texcoordadr[geom.objid] >= 0) {
const int num = 3 * scene->skinvertnum[geom.objid];
const int addr = model->skin_texcoordadr[geom.objid];
const float* ptr = model->skin_texcoord + (2 * addr);
return {ptr, static_cast<size_t>(num)};
} else {
const float* ptr = nullptr;
return {ptr, 0};
}
}
}
static std::span<const int> GetIndices(const mjModel* model,
const mjvScene* scene,
const mjvGeom& geom) {
if (geom.type == mjGEOM_FLEX) {
const int* ptr = nullptr;
return {ptr, 0};
} else {
const int num = 3 * model->skin_facenum[geom.objid];
const int* ptr = model->skin_face + 3 * model->skin_faceadr[geom.objid];
return {ptr, static_cast<size_t>(num)};
}
}
template <typename T>
static void FillVertices(std::byte* buffer, std::size_t len,
std::span<const float> positions,
std::span<const float> normals,
std::span<const float> uvs,
float3* vmin,
float3* vmax) {
const int num_vertices = len / sizeof(T);
T* ptr = reinterpret_cast<T*>(buffer);
for (int i = 0; i < num_vertices; ++i) {
ptr->position = ReadFloat3(positions.data(), i);
*vmin = min(*vmin, ptr->position);
*vmax = max(*vmax, ptr->position);
ptr->orientation = CalculateOrientation(ReadFloat3(normals.data(), i));
if constexpr (T::kHasUv) {
ptr->uv.x = uvs[i * 2];
ptr->uv.y = uvs[i * 2 + 1];
}
++ptr;
}
}
static filament::VertexBuffer* BuildVertexBuffer(
filament::Engine* engine, std::span<const float> positions,
std::span<const float> normals, std::span<const float> uvs, float3* vmin,
float3* vmax) {
const int num_vertices = positions.size() / 3;
if (uvs.data() != nullptr) {
using VertexType = VertexWithUv;
auto fill = [&](std::byte* buffer, std::size_t len) {
FillVertices<VertexType>(buffer, len, positions, normals, uvs, vmin,
vmax);
};
return CreateVertexBuffer<VertexType>(engine, num_vertices, fill);
} else {
using VertexType = VertexNoUv;
auto fill = [&](std::byte* buffer, std::size_t len) {
FillVertices<VertexType>(buffer, len, positions, normals, uvs, vmin,
vmax);
};
return CreateVertexBuffer<VertexType>(engine, num_vertices, fill);
}
}
static filament::IndexBuffer* BuildIndexBuffer(filament::Engine* engine,
std::span<const int> indices,
int num_indices) {
if (indices.data() == nullptr) {
auto fill_indices = FillSequence<uint32_t>;
return CreateIndexBuffer<uint32_t>(engine, num_indices, fill_indices);
} else {
auto fill_indices = [&](std::byte* buffer, std::size_t len) {
std::memcpy(buffer, indices.data(), len);
};
return CreateIndexBuffer<uint32_t>(engine, indices.size(), fill_indices);
}
}
FilamentBuffers CreateGeomBuffers(filament::Engine* engine,
const mjModel* model, const mjvScene* scene,
const mjvGeom& geom) {
auto positions = GetPositions(model, scene, geom);
auto normals = GetNormals(model, scene, geom);
auto uvs = GetUvs(model, scene, geom);
auto indices = GetIndices(model, scene, geom);
int num_indices = indices.size();
if (num_indices == 0 && geom.type == mjGEOM_FLEX) {
num_indices = 3 * scene->flexfaceused[geom.objid];
}
FilamentBuffers buffers;
float3 vmin = {FLT_MAX, FLT_MAX, FLT_MAX};
float3 vmax = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
buffers.vertex_buffer =
BuildVertexBuffer(engine, positions, normals, uvs, &vmin, &vmax);
buffers.index_buffer = BuildIndexBuffer(engine, indices, num_indices);
buffers.bounds.emplace().set(vmin, vmax);
return buffers;
}
} // namespace mujoco