Improve wireframe rendering support in Filament renderer and Studio.
- Draw complete wireframes in the Filament renderer. - Bind the 'W' key to toggle the wireframe render flag in Studio. PiperOrigin-RevId: 957230911 Change-Id: Ib583c81ddcfa834686c7cf01d2b12842479993ea
This commit is contained in:
committed by
Copybara-Service
parent
6c78c98418
commit
e295b31c60
@@ -811,6 +811,8 @@ void App::HandleKeyboardEvents() {
|
|||||||
ToggleFlag(vis_options_.flags[mjVIS_COM]);
|
ToggleFlag(vis_options_.flags[mjVIS_COM]);
|
||||||
} else if (!is_freecam_wasd && ImGui_IsChordJustPressed(ImGuiKey_D)) {
|
} else if (!is_freecam_wasd && ImGui_IsChordJustPressed(ImGuiKey_D)) {
|
||||||
ToggleFlag(vis_options_.flags[mjVIS_STATIC]);
|
ToggleFlag(vis_options_.flags[mjVIS_STATIC]);
|
||||||
|
} else if (!is_freecam_wasd && ImGui_IsChordJustPressed(ImGuiKey_W)) {
|
||||||
|
ToggleFlag(renderer_->GetRenderFlags()[mjRND_WIREFRAME]);
|
||||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_Semicolon)) {
|
} else if (ImGui_IsChordJustPressed(ImGuiKey_Semicolon)) {
|
||||||
ToggleFlag(vis_options_.flags[mjVIS_SKIN]);
|
ToggleFlag(vis_options_.flags[mjVIS_SKIN]);
|
||||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_GraveAccent)) {
|
} else if (ImGui_IsChordJustPressed(ImGuiKey_GraveAccent)) {
|
||||||
@@ -2152,6 +2154,7 @@ void App::HelpGui() {
|
|||||||
ImGui::Text("Tendon");
|
ImGui::Text("Tendon");
|
||||||
ImGui::Text("Texture");
|
ImGui::Text("Texture");
|
||||||
ImGui::Text("Transparent");
|
ImGui::Text("Transparent");
|
||||||
|
ImGui::Text("Wireframe");
|
||||||
|
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
ImGui::Indent(indent);
|
ImGui::Indent(indent);
|
||||||
@@ -2181,6 +2184,7 @@ void App::HelpGui() {
|
|||||||
ImGui::Text("V");
|
ImGui::Text("V");
|
||||||
ImGui::Text("X");
|
ImGui::Text("X");
|
||||||
ImGui::Text("T");
|
ImGui::Text("T");
|
||||||
|
ImGui::Text("W");
|
||||||
|
|
||||||
ImGui::Columns();
|
ImGui::Columns();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,6 +146,9 @@ Mesh::~Mesh() {
|
|||||||
if (index_buffer_) {
|
if (index_buffer_) {
|
||||||
engine_->destroy(index_buffer_);
|
engine_->destroy(index_buffer_);
|
||||||
}
|
}
|
||||||
|
if (wireframe_index_buffer_) {
|
||||||
|
engine_->destroy(wireframe_index_buffer_);
|
||||||
|
}
|
||||||
if (vertex_buffer_) {
|
if (vertex_buffer_) {
|
||||||
engine_->destroy(vertex_buffer_);
|
engine_->destroy(vertex_buffer_);
|
||||||
}
|
}
|
||||||
@@ -308,6 +311,55 @@ void Mesh::UpdateIndexBuffer(const mjrfMeshData& data) {
|
|||||||
// callback for the vertex buffer will call release_callbacks_.
|
// callback for the vertex buffer will call release_callbacks_.
|
||||||
filament::backend::BufferDescriptor desc(indices, num_bytes);
|
filament::backend::BufferDescriptor desc(indices, num_bytes);
|
||||||
index_buffer_->setBuffer(*engine_, std::move(desc));
|
index_buffer_->setBuffer(*engine_, std::move(desc));
|
||||||
|
|
||||||
|
UpdateWireframeIndexBuffer(indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void FillWireframeIndices(const void* src, int num_indices, T* out) {
|
||||||
|
const T* in = static_cast<const T*>(src);
|
||||||
|
for (int i = 0; i < num_indices - 2; i += 3) {
|
||||||
|
*out++ = in[i + 0];
|
||||||
|
*out++ = in[i + 1];
|
||||||
|
*out++ = in[i + 1];
|
||||||
|
*out++ = in[i + 2];
|
||||||
|
*out++ = in[i + 2];
|
||||||
|
*out++ = in[i + 0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::UpdateWireframeIndexBuffer(const void* src_indices) {
|
||||||
|
// Line meshes are their own wireframe. Interior edges shared between two
|
||||||
|
// triangles are deliberately not deduplicated so that triangle index ranges
|
||||||
|
// map to line index ranges by doubling; see GetWireframeIndexBuffer().
|
||||||
|
if (config_.primitive_type != mjMESH_PRIMITIVE_TYPE_TRIANGLES) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int num_line_indices = 2 * config_.max_indices;
|
||||||
|
if (wireframe_index_buffer_ == nullptr) {
|
||||||
|
filament::IndexBuffer::Builder ib_builder;
|
||||||
|
ib_builder.indexCount(num_line_indices);
|
||||||
|
ib_builder.bufferType(config_.index_type == mjINDEX_TYPE_U16
|
||||||
|
? filament::IndexBuffer::IndexType::USHORT
|
||||||
|
: filament::IndexBuffer::IndexType::UINT);
|
||||||
|
wireframe_index_buffer_ = ib_builder.build(*engine_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int element_size = config_.index_type == mjINDEX_TYPE_U16
|
||||||
|
? sizeof(uint16_t)
|
||||||
|
: sizeof(uint32_t);
|
||||||
|
const int num_bytes = num_line_indices * element_size;
|
||||||
|
std::byte* lines = new std::byte[num_bytes];
|
||||||
|
shared_state_->callbacks.push_back([=]() { delete[] lines; });
|
||||||
|
if (config_.index_type == mjINDEX_TYPE_U16) {
|
||||||
|
FillWireframeIndices(src_indices, config_.max_indices,
|
||||||
|
reinterpret_cast<uint16_t*>(lines));
|
||||||
|
} else {
|
||||||
|
FillWireframeIndices(src_indices, config_.max_indices,
|
||||||
|
reinterpret_cast<uint32_t*>(lines));
|
||||||
|
}
|
||||||
|
filament::backend::BufferDescriptor desc(lines, num_bytes);
|
||||||
|
wireframe_index_buffer_->setBuffer(*engine_, std::move(desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mesh::UpdateBounds(const mjrfMeshData& data) {
|
void Mesh::UpdateBounds(const mjrfMeshData& data) {
|
||||||
@@ -361,6 +413,10 @@ filament::IndexBuffer* Mesh::GetFilamentIndexBuffer() const {
|
|||||||
return index_buffer_;
|
return index_buffer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filament::IndexBuffer* Mesh::GetWireframeIndexBuffer() const {
|
||||||
|
return wireframe_index_buffer_;
|
||||||
|
}
|
||||||
|
|
||||||
filament::VertexBuffer* Mesh::GetFilamentVertexBuffer() const {
|
filament::VertexBuffer* Mesh::GetFilamentVertexBuffer() const {
|
||||||
return vertex_buffer_;
|
return vertex_buffer_;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,12 @@ class Mesh : public mjrfMesh {
|
|||||||
// Returns the filament IndexBuffer for the mesh.
|
// Returns the filament IndexBuffer for the mesh.
|
||||||
filament::IndexBuffer* GetFilamentIndexBuffer() const;
|
filament::IndexBuffer* GetFilamentIndexBuffer() const;
|
||||||
|
|
||||||
|
// Returns the filament IndexBuffer of line indices for wireframe rendering,
|
||||||
|
// or nullptr for non-triangle meshes. Each triangle contributes its three
|
||||||
|
// edges, so a triangle index range [offset, count) maps to the line index
|
||||||
|
// range [2*offset, 2*count).
|
||||||
|
filament::IndexBuffer* GetWireframeIndexBuffer() const;
|
||||||
|
|
||||||
// Returns the filament VertexBuffer for the mesh.
|
// Returns the filament VertexBuffer for the mesh.
|
||||||
filament::VertexBuffer* GetFilamentVertexBuffer() const;
|
filament::VertexBuffer* GetFilamentVertexBuffer() const;
|
||||||
|
|
||||||
@@ -75,6 +81,7 @@ class Mesh : public mjrfMesh {
|
|||||||
|
|
||||||
void UpdateVertexBuffer(const mjrfMeshData& data);
|
void UpdateVertexBuffer(const mjrfMeshData& data);
|
||||||
void UpdateIndexBuffer(const mjrfMeshData& data);
|
void UpdateIndexBuffer(const mjrfMeshData& data);
|
||||||
|
void UpdateWireframeIndexBuffer(const void* indices);
|
||||||
void UpdateBounds(const mjrfMeshData& data);
|
void UpdateBounds(const mjrfMeshData& data);
|
||||||
|
|
||||||
filament::math::float4* BuildOrientationsFromNormals(int num_vertices,
|
filament::math::float4* BuildOrientationsFromNormals(int num_vertices,
|
||||||
@@ -86,6 +93,7 @@ class Mesh : public mjrfMesh {
|
|||||||
mjrfMeshConfig config_;
|
mjrfMeshConfig config_;
|
||||||
|
|
||||||
filament::IndexBuffer* index_buffer_ = nullptr;
|
filament::IndexBuffer* index_buffer_ = nullptr;
|
||||||
|
filament::IndexBuffer* wireframe_index_buffer_ = nullptr;
|
||||||
filament::VertexBuffer* vertex_buffer_ = nullptr;
|
filament::VertexBuffer* vertex_buffer_ = nullptr;
|
||||||
std::optional<filament::Box> bounds_;
|
std::optional<filament::Box> bounds_;
|
||||||
|
|
||||||
|
|||||||
@@ -461,11 +461,22 @@ void Renderable::SetWireframe(bool wireframe) {
|
|||||||
for (Part& part : parts_) {
|
for (Part& part : parts_) {
|
||||||
filament::VertexBuffer* vertex_buffer =
|
filament::VertexBuffer* vertex_buffer =
|
||||||
part.mesh->GetFilamentVertexBuffer();
|
part.mesh->GetFilamentVertexBuffer();
|
||||||
filament::IndexBuffer* index_buffer = part.mesh->GetFilamentIndexBuffer();
|
filament::IndexBuffer* wireframe_index_buffer =
|
||||||
rm.setGeometryAt(
|
part.mesh->GetWireframeIndexBuffer();
|
||||||
rm.getInstance(part.entity), 0,
|
if (wireframe && wireframe_index_buffer) {
|
||||||
wireframe ? kWireframeType : part.mesh->GetPrimitiveType(),
|
// Triangle meshes have a dedicated line index buffer enumerating the
|
||||||
vertex_buffer, index_buffer, part.elem_offset, part.elem_count);
|
// three edges of each triangle, addressed by doubling the range.
|
||||||
|
rm.setGeometryAt(rm.getInstance(part.entity), 0, kWireframeType,
|
||||||
|
vertex_buffer, wireframe_index_buffer,
|
||||||
|
2 * part.elem_offset, 2 * part.elem_count);
|
||||||
|
} else {
|
||||||
|
// Line meshes are drawn as-is in both modes.
|
||||||
|
rm.setGeometryAt(rm.getInstance(part.entity), 0,
|
||||||
|
wireframe ? kWireframeType
|
||||||
|
: part.mesh->GetPrimitiveType(),
|
||||||
|
vertex_buffer, part.mesh->GetFilamentIndexBuffer(),
|
||||||
|
part.elem_offset, part.elem_count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user