From 5e50a8f2edb421d295ec4a033eddc2835dc254b5 Mon Sep 17 00:00:00 2001 From: brunojezek Date: Thu, 13 Apr 2023 14:21:49 +0200 Subject: [PATCH 01/24] Add skinning and morphing samples to check functionality hellomorphing.cpp - morph target (blendshapes) animation helloskinning.cpp - bone skinning animation helloskinningbuffer.cpp - bone skinning animation of two renderables with common skinning buffer Bone skinning is limited to four bones per vertex --- samples/CMakeLists.txt | 3 + samples/hellomorphing.cpp | 194 +++++++++++++++++++++++++ samples/helloskinning.cpp | 176 +++++++++++++++++++++++ samples/helloskinningbuffer.cpp | 241 ++++++++++++++++++++++++++++++++ 4 files changed, 614 insertions(+) create mode 100644 samples/hellomorphing.cpp create mode 100644 samples/helloskinning.cpp create mode 100644 samples/helloskinningbuffer.cpp diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 340cd02a087..dbe09bf7686 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -231,8 +231,11 @@ if (NOT ANDROID) add_demo(gltf_viewer) add_demo(gltf_instances) add_demo(heightfield) + add_demo(hellomorphing) add_demo(hellopbr) add_demo(hellotriangle) + add_demo(helloskinning) + add_demo(helloskinningbuffer) add_demo(image_viewer) add_demo(lightbulb) add_demo(material_sandbox) diff --git a/samples/hellomorphing.cpp b/samples/hellomorphing.cpp new file mode 100644 index 00000000000..815e0089544 --- /dev/null +++ b/samples/hellomorphing.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include "generated/resources/resources.h" + +using namespace filament; +using utils::Entity; +using utils::EntityManager; +using namespace filament::math; + +struct App { + VertexBuffer* vb; + IndexBuffer* ib; + Material* mat; + Camera* cam; + Entity camera; + Skybox* skybox; + Entity renderable; + MorphTargetBuffer *mt1; + MorphTargetBuffer *mt2; +}; + +struct Vertex { + float2 position; + uint32_t color; +}; + +static const Vertex TRIANGLE_VERTICES[3] = { + {{1, 0}, 0xffff0000u}, //blue one (ABGR) + {{cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ff00u}, //green one + {{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu}, //red one +}; + +static const float3 targets_pos1[9] = { + {-2, 0, 0},{0, 2, 0},{1, 0, 0}, //1st position for 1st, 2nd and 3rd point of the first primitive + {1, 1, 0},{-1, 0, 0},{-1, 0, 0}, //2nd ... + {0, 0, 0},{0, 0, 0},{0, 0, 0} //no position change +}; + +static const float3 targets_pos2[9] = { + {0, 2, 0},{-2, 0, 0},{1, 0, 0}, //1st position for 1st, 2nd and 3rd point of the second primitive + {-1, 0, 0},{1, 1, 0},{-1, 0, 0}, //position of th 3rd point is same for both morph targets + {0, 0, 0},{0, 0, 0}, {0, 0, 0} +}; + +static const short4 targets_tan[9] = { + {0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}, + {0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}, + {0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0} +}; + +static constexpr uint16_t TRIANGLE_INDICES[3] = { 0, 1, 2 }; + +int main(int argc, char** argv) { + Config config; + config.title = "helloMorphing"; + + App app; + auto setup = [&app](Engine* engine, View* view, Scene* scene) { + app.skybox = Skybox::Builder().color({0.1, 0.125, 0.25, 1.0}).build(*engine); + + scene->setSkybox(app.skybox); + view->setPostProcessingEnabled(false); + static_assert(sizeof(Vertex) == 12, "Strange vertex size."); + app.vb = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .build(*engine); + app.vb->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr)); + app.ib = IndexBuffer::Builder() + .indexCount(3) + .bufferType(IndexBuffer::IndexType::USHORT) + .build(*engine); + app.ib->setBuffer(*engine, + IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 6, nullptr)); + app.mat = Material::Builder() + .package(RESOURCES_BAKEDCOLOR_DATA, RESOURCES_BAKEDCOLOR_SIZE) + .build(*engine); + + app.mt1 = MorphTargetBuffer::Builder() + .vertexCount(9) + .count(3) + .build( *engine); + + app.mt2 = MorphTargetBuffer::Builder() + .vertexCount(9) + .count(3) + .build( *engine); + + app.mt1->setPositionsAt(*engine,0, targets_pos1, 3, 0); + app.mt1->setPositionsAt(*engine,1, targets_pos1+3, 3, 0); + app.mt1->setPositionsAt(*engine,2, targets_pos1+6, 3, 0); + app.mt1->setTangentsAt(*engine,0, targets_tan, 3, 0); + app.mt1->setTangentsAt(*engine,1, targets_tan+3, 3, 0); + app.mt1->setTangentsAt(*engine,2, targets_tan+6, 3, 0); + + app.mt2->setPositionsAt(*engine,0, targets_pos2, 3, 0); + app.mt2->setPositionsAt(*engine,1, targets_pos2+3, 3, 0); + app.mt2->setPositionsAt(*engine,2, targets_pos2+6, 3, 0); + app.mt2->setTangentsAt(*engine,0, targets_tan, 3, 0); + app.mt2->setTangentsAt(*engine,1, targets_tan+3, 3, 0); + app.mt2->setTangentsAt(*engine,2, targets_tan+6, 3, 0); + + app.renderable = EntityManager::get().create(); + + RenderableManager::Builder(2) + .boundingBox({{ -1, -1, -1 }, { 1, 1, 1 }}) + .material(0, app.mat->getDefaultInstance()) + .material(1, app.mat->getDefaultInstance()) + .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.vb, app.ib, 0, 3) + .geometry(1, RenderableManager::PrimitiveType::TRIANGLES, app.vb, app.ib, 0, 3) + .culling(false) + .receiveShadows(false) + .castShadows(false) + .morphing(3) + .morphing(0,0,app.mt1) + .morphing(0,1,app.mt2) + .build(*engine, app.renderable); + + scene->addEntity(app.renderable); + app.camera = utils::EntityManager::get().create(); + app.cam = engine->createCamera(app.camera); + view->setCamera(app.cam); + }; + + auto cleanup = [&app](Engine* engine, View*, Scene*) { + engine->destroy(app.skybox); + engine->destroy(app.renderable); + engine->destroy(app.mat); + engine->destroy(app.vb); + engine->destroy(app.ib); + engine->destroy(app.mt1); + engine->destroy(app.mt2); + engine->destroyCameraComponent(app.camera); + utils::EntityManager::get().destroy(app.camera); + }; + + FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { + constexpr float ZOOM = 1.5f; + const uint32_t w = view->getViewport().width; + const uint32_t h = view->getViewport().height; + const float aspect = (float) w / h; + app.cam->setProjection(Camera::Projection::ORTHO, + -aspect * ZOOM, aspect * ZOOM, + -ZOOM, ZOOM, 0, 1); + + auto& rm = engine->getRenderableManager(); + //morphTarget/blendshapes animation defined for all primitives + float z = (float)(sin(now)/2.f + 0.5f); + float weights[] = {1 - z, z/2, z/2}; + //set global weights of all morph targets + rm.setMorphWeights(rm.getInstance(app.renderable), weights, 3, 0); + }); + + FilamentApp::get().run(config, setup, cleanup); + + return 0; +} diff --git a/samples/helloskinning.cpp b/samples/helloskinning.cpp new file mode 100644 index 00000000000..222cdd2b332 --- /dev/null +++ b/samples/helloskinning.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include "generated/resources/resources.h" + +using namespace filament; +using utils::Entity; +using utils::EntityManager; +using namespace filament::math; + +struct App { + VertexBuffer* vb; + VertexBuffer* vb2; + IndexBuffer* ib; + Material* mat; + Camera* cam; + Entity camera; + Skybox* skybox; + Entity renderable; +}; + +struct VertexWithBones { + float2 position; + uint32_t color; + filament::math::ushort4 joints; + filament::math::float4 weighs; +}; + +static const VertexWithBones TRIANGLE_VERTICES_WITHBONES[6] = { + {{1, 0}, 0xffff0000u, {0,1,0,0}, {1.0f,0.f,0.f,0.f}}, + {{cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ff00u, {0,1,0,0}, {0.f,1.f,0.f,0.f}}, + {{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu,{0,1,0,0}, {0.5f,0.5f,0.f,0.f}}, + {{1, -1}, 0xffffff00u, {0,2,0,0}, {0.0f,1.f,0.f,0.f}}, + {{-cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ffffu, {0,1,0,0}, {0.f,1.f,0.f,0.f}}, + {{-cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xffff00ffu,{0,1,0,0}, {0.f,0.f,0.5f,0.5f}}, +}; + +static constexpr uint16_t TRIANGLE_INDICES[6] = { 0, 1, 2, 3}; + +mat4f transforms[] = {mat4f(1), + mat4f::translation(float3(1, 0, 0)), + mat4f::translation(float3(1, 1, 0)), + mat4f::translation(float3(0, 1, 0))}; + +int main(int argc, char** argv) { + Config config; + config.title = "hello skinning"; + + App app; + auto setup = [&app](Engine* engine, View* view, Scene* scene) { + app.skybox = Skybox::Builder().color({0.1, 0.125, 0.25, 1.0}).build(*engine); + + scene->setSkybox(app.skybox); + view->setPostProcessingEnabled(false); + static_assert(sizeof(VertexWithBones) == 36, "Strange vertex size."); + app.vb = VertexBuffer::Builder() + .vertexCount(4) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 36) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 36) + .normalized(VertexAttribute::COLOR) + .attribute(VertexAttribute::BONE_INDICES, 0, VertexBuffer::AttributeType::USHORT4, 12, 36) + .attribute(VertexAttribute::BONE_WEIGHTS, 0, VertexBuffer::AttributeType::FLOAT4, 20, 36) + .build(*engine); + app.vb2 = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 36) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 36) + .normalized(VertexAttribute::COLOR) + .attribute(VertexAttribute::BONE_INDICES, 0, VertexBuffer::AttributeType::USHORT4, 12, 36) + .attribute(VertexAttribute::BONE_WEIGHTS, 0, VertexBuffer::AttributeType::FLOAT4, 20, 36) + .build(*engine); + app.vb->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES_WITHBONES, 154, nullptr)); + app.vb2->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES_WITHBONES + 3, 108, nullptr)); + app.ib = IndexBuffer::Builder() + .indexCount(6) + .bufferType(IndexBuffer::IndexType::USHORT) + .build(*engine); + app.ib->setBuffer(*engine, + IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 8, nullptr)); + app.mat = Material::Builder() + .package(RESOURCES_BAKEDCOLOR_DATA, RESOURCES_BAKEDCOLOR_SIZE) + .build(*engine); + + app.renderable = EntityManager::get().create(); + + RenderableManager::Builder(2) + .boundingBox({{ -1, -1, -1 }, { 1, 1, 1 }}) + .material(0, app.mat->getDefaultInstance()) + .material(1, app.mat->getDefaultInstance()) + .geometry(0, RenderableManager::PrimitiveType::TRIANGLE_STRIP, app.vb, app.ib, 0, 4) + .geometry(1, RenderableManager::PrimitiveType::TRIANGLES, app.vb2, app.ib, 0, 3) + .culling(false) + .receiveShadows(false) + .castShadows(false) + .skinning(4, transforms) + .enableSkinningBuffers(false) + .build(*engine, app.renderable); + + scene->addEntity(app.renderable); + app.camera = utils::EntityManager::get().create(); + app.cam = engine->createCamera(app.camera); + view->setCamera(app.cam); + }; + + auto cleanup = [&app](Engine* engine, View*, Scene*) { + engine->destroy(app.skybox); + engine->destroy(app.renderable); + engine->destroy(app.mat); + engine->destroy(app.vb); + engine->destroy(app.vb2); + engine->destroy(app.ib); + engine->destroyCameraComponent(app.camera); + utils::EntityManager::get().destroy(app.camera); + }; + + FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { + constexpr float ZOOM = 1.5f; + const uint32_t w = view->getViewport().width; + const uint32_t h = view->getViewport().height; + const float aspect = (float) w / h; + app.cam->setProjection(Camera::Projection::ORTHO, + -aspect * ZOOM, aspect * ZOOM, + -ZOOM, ZOOM, 0, 1); + + auto& rm = engine->getRenderableManager(); + + //skinning/bones animation + float tr = (float)(sin(now)); + mat4f trans[] = {filament::math::mat4f::translation(filament::math::float3{tr, 0, 0}), + filament::math::mat4f::translation(filament::math::float3{-1, tr, 0}), + filament::math::mat4f(1.f)}; + rm.setBones(rm.getInstance(app.renderable), trans,3, 0); + + + }); + + FilamentApp::get().run(config, setup, cleanup); + + return 0; +} diff --git a/samples/helloskinningbuffer.cpp b/samples/helloskinningbuffer.cpp new file mode 100644 index 00000000000..b5c57950dba --- /dev/null +++ b/samples/helloskinningbuffer.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include "generated/resources/resources.h" + +using namespace filament; +using utils::Entity; +using utils::EntityManager; +using namespace filament::math; + +struct App { + VertexBuffer *vb, *vb2; + IndexBuffer* ib; + Material* mat; + Camera* cam; + Entity camera; + Skybox* skybox; + Entity renderable1; + Entity renderable2; + SkinningBuffer *sb; +}; + +struct Vertex { + float2 position; + uint32_t color; +}; + +static const Vertex TRIANGLE_VERTICES[3] = { + {{1, 0}, 0xffff0000u}, + {{cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ff00u}, + {{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu}, +}; + +static const ushort skinJoints[] = {0,1,2,3, + 0,1,2,3, + 0,1,2,3 +}; + +static const float skinWeights[] = {0.25f,0.25f,0.25f,0.25f, + 0.25f,0.25f,0.25f,0.25f, + 0.25f,0.25f,0.25f,0.25f +}; + +static constexpr uint16_t TRIANGLE_INDICES[] = { 0, 1, 2, 3 }; + +mat4f transforms[] = {math::mat4f(1.f), + mat4f::translation(float3(1, 0, 0)), + mat4f::translation(float3(1, 1, 0)), + mat4f::translation(float3(0, 1, 0)), + mat4f::translation(float3(-1, 1, 0)), + mat4f::translation(float3(-1, 0, 0)), + mat4f::translation(float3(-1, -1, 0)), + mat4f::translation(float3(0, -1, 0)), + mat4f::translation(float3(1, -1, 0))}; + + + +int main(int argc, char** argv) { + Config config; + config.title = "skinning buffer common for two renderables"; + + App app; + auto setup = [&app](Engine* engine, View* view, Scene* scene) { + app.skybox = Skybox::Builder().color({0.1, 0.125, 0.25, 1.0}).build(*engine); + + scene->setSkybox(app.skybox); + view->setPostProcessingEnabled(false); + static_assert(sizeof(Vertex) == 12, "Strange vertex size."); + app.vb = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(3) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .attribute(VertexAttribute::BONE_INDICES, 1, VertexBuffer::AttributeType::USHORT4, 0, 8) + .attribute(VertexAttribute::BONE_WEIGHTS, 2, VertexBuffer::AttributeType::FLOAT4, 0, 16) + .build(*engine); + app.vb->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr)); + app.vb->setBufferAt(*engine, 1, + VertexBuffer::BufferDescriptor(skinJoints, 24, nullptr)); + app.vb->setBufferAt(*engine, 2, + VertexBuffer::BufferDescriptor(skinWeights, 48, nullptr)); + + app.vb2 = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .build(*engine); + app.vb2->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr)); + app.ib = IndexBuffer::Builder() + .indexCount(3) + .bufferType(IndexBuffer::IndexType::USHORT) + .build(*engine); + app.ib->setBuffer(*engine, + IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 6, nullptr)); + app.mat = Material::Builder() + .package(RESOURCES_BAKEDCOLOR_DATA, RESOURCES_BAKEDCOLOR_SIZE) + .build(*engine); + + app.sb = SkinningBuffer::Builder() + .boneCount(9) + .initialize() + .build(*engine); + app.sb->setBones(*engine, transforms,9,0); + + app.renderable1 = EntityManager::get().create(); + app.renderable2 = EntityManager::get().create(); + + RenderableManager::Builder(1) + .boundingBox({{ -1, -1, -1 }, { 1, 1, 1 }}) + .material(0, app.mat->getDefaultInstance()) + .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.vb, app.ib, 0, 3) + .culling(false) + .receiveShadows(false) + .castShadows(false) + .enableSkinningBuffers(true) + .skinning(app.sb, 9, 0) + .build(*engine, app.renderable1); + + RenderableManager::Builder(2) + .boundingBox({{ -1, -1, -1 }, { 1, 1, 1 }}) + .material(0, app.mat->getDefaultInstance()) + .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.vb, app.ib, 0, 3) + .geometry(1, RenderableManager::PrimitiveType::TRIANGLES, app.vb2, app.ib, 0, 3) + .culling(false) + .receiveShadows(false) + .castShadows(false) + .enableSkinningBuffers(true) + .skinning(app.sb, 9, 0) + .build(*engine, app.renderable2); + + scene->addEntity(app.renderable1); + scene->addEntity(app.renderable2); + app.camera = utils::EntityManager::get().create(); + app.cam = engine->createCamera(app.camera); + view->setCamera(app.cam); + }; + + auto cleanup = [&app](Engine* engine, View*, Scene*) { + engine->destroy(app.skybox); + engine->destroy(app.renderable1); + engine->destroy(app.renderable2); + engine->destroy(app.mat); + engine->destroy(app.vb); + engine->destroy(app.vb2); + engine->destroy(app.ib); + engine->destroy(app.sb); + engine->destroyCameraComponent(app.camera); + utils::EntityManager::get().destroy(app.camera); + }; + + FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { + constexpr float ZOOM = 1.5f; + const uint32_t w = view->getViewport().width; + const uint32_t h = view->getViewport().height; + const float aspect = (float) w / h; + app.cam->setProjection(Camera::Projection::ORTHO, + -aspect * ZOOM, aspect * ZOOM, + -ZOOM, ZOOM, 0, 1); + auto& tcm = engine->getTransformManager(); + + //transformation of both renderables + tcm.setTransform(tcm.getInstance(app.renderable1), + filament::math::mat4f::translation(filament::math::float3{ 0.5, 0, 0 })); + tcm.setTransform(tcm.getInstance(app.renderable2), + filament::math::mat4f::translation(filament::math::float3{ 0, 0.5, 0 })); + + auto& rm = engine->getRenderableManager(); + + //skinning/bones animation + float t = (float)(now - (int)now); + float s = sin(t * f::PI * 2.f); + float c = cos(t * f::PI * 2.f); + + mat4f translate[] = {mat4f::translation(float3(s, c, 0))}; + + mat4f trans1of8[9] = {}; + for(uint i = 0; i<9; i++){ + trans1of8[i] = filament::math::mat4f(1); + } + s *= 5; + mat4f transA[] = { + mat4f::translation(float3(s, 0, 0)), + mat4f::translation(float3(s, s, 0)), + mat4f::translation(float3(0, s, 0)), + mat4f::translation(float3(-s, s, 0)), + mat4f::translation(float3(-s, 0, 0)), + mat4f::translation(float3(-s, -s, 0)), + mat4f::translation(float3(0, -s, 0)), + mat4f::translation(float3(s, -s, 0)), + filament::math::mat4f(1)}; + uint offset = ((uint)now) % 8; + trans1of8[offset] = transA[offset]; + + //set transformation of the first bone + app.sb->setBones(*engine, translate, 1, 0); + + //set transformation of the other bones, only 3 of them can be used, do to limitation + app.sb->setBones(*engine,trans1of8, 8, 1); + }); + + FilamentApp::get().run(config, setup, cleanup); + + return 0; +} From 9f01fab379ac09e392b3c6738cd282527073364c Mon Sep 17 00:00:00 2001 From: brunojezek Date: Thu, 13 Apr 2023 19:19:44 +0200 Subject: [PATCH 02/24] Implement skinning for more than four bones pair vertex The API allows defining an unlimited number of bone indices and weights of primitives. Date is defined ind building process of the renderable manager. Backward compatibility with the original solution. Skinning of vertices is calculated on GPU, data is transferred to the vertex shader in the texture. samples: helloskinningbuffer_morebones.cpp - extended version of helloskinningbuffer.cpp sample suzanneskinning.cpp - skinning of a complex model skinningtest.cpp - different variants of skinning for more primitives and renderables --- filament/include/filament/RenderableManager.h | 74 +++ filament/src/RenderPass.cpp | 13 +- filament/src/RenderPass.h | 7 +- filament/src/components/RenderableManager.cpp | 213 ++++++++- filament/src/components/RenderableManager.h | 7 +- filament/src/details/Scene.h | 2 +- filament/src/details/SkinningBuffer.cpp | 98 ++++ filament/src/details/SkinningBuffer.h | 14 + filament/src/details/VertexBuffer.cpp | 107 ++++- filament/src/details/VertexBuffer.h | 6 + .../include/private/filament/EngineEnums.h | 3 +- .../include/private/filament/SibStructs.h | 6 + libs/filamat/src/shaders/ShaderGenerator.cpp | 4 +- libs/filamat/src/shaders/SibGenerator.cpp | 19 +- libs/filamat/src/shaders/SibGenerator.h | 1 + samples/CMakeLists.txt | 4 + samples/helloskinningbuffer_morebones.cpp | 244 ++++++++++ samples/skinningtest.cpp | 452 ++++++++++++++++++ samples/suzanneskinning.cpp | 287 +++++++++++ shaders/src/getters.vs | 84 +++- shaders/src/main.vs | 5 +- 21 files changed, 1622 insertions(+), 28 deletions(-) create mode 100644 samples/helloskinningbuffer_morebones.cpp create mode 100644 samples/skinningtest.cpp create mode 100644 samples/suzanneskinning.cpp diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index 868375bac04..498c34823d6 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -30,6 +30,7 @@ #include #include +#include namespace utils { class Entity; @@ -349,6 +350,74 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { Builder& skinning(size_t boneCount, Bone const* bones) noexcept; //!< \overload Builder& skinning(size_t boneCount) noexcept; //!< \overload + /** + * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the + * second value is the bone weight. The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS + * defined in the VertexBuffer. Both ways of indices and weights definition must not be combined in one primitive. + * Number of pairs is not limited to 4 bones per vertex. + * All bone weights of one vertex should sum to one. Otherwise they will be normalized. + * Data must be rectangular and number of pairs must be same for all vertices of this primitive. + * The data is arranged sequentially, all bone pairs for the first vertex, then for the second vertex, and so on. + * + * @param primitiveIndex zero-based index of the primitive, must be less than the primitive count passed to Builder constructor + * @param indicesAndWeights pairs of bone index and bone weight for all vertices sequentially, + * @param count number of all pairs, must be a multiple of vertexCount of the primitive + * @param offset specifies where in the indicesAndWeights buffer to start reading (expressed as a number of pairs) + * + * @return Builder reference for chaining calls. + */ + Builder& boneIndicesAndWeights(size_t primitiveIndex,math::float2 const* indicesAndWeights, size_t count, size_t offset = 0); + + /** + * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the + * second value is the bone weight. The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS + * defined in the VertexBuffer. Both ways of indices and weights definition must not be combined in one primitive. + * Number of pairs is not limited to 4 bones per vertex. + * All bone weights of one vertex should sum to one. Otherwise they will be normalized. + * Data must be rectangular and number of pairs must be same for all vertices and all primitives of renderable. + * The data is arranged sequentially, all bone pairs for the first vertex of the first primitive, then for the second vertex of + * the first primitive, ..., all bone pairs for the first vertex of the second primitive, ..., and so on. + * + * @param indicesAndWeightsArray pairs of bone index and bone weight for all vertices and primitives sequentially + * @param count number of all pairs, must be a multiple of vertexCount by primitiveCount + * @param offset specifies where in the indicesAndWeights buffer to start reading (expressed as a number of pairs) + * + * @return Builder reference for chaining calls. + */ + Builder& boneIndicesAndWeights(math::float2 const* indicesAndWeightsArray, size_t count, size_t offset = 0); + + /** + * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the + * second value is the bone weight. The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS + * defined in the VertexBuffer. Both ways of indices and weights definition must not be combined in one primitive. + * Number of pairs is not limited to 4 bones per vertex. + * All bone weights of one vertex should sum to one. Otherwise they will be normalized. + * Data doesn't have to be rectangular and number of pairs per vertices of primitive can be variable. + * The vector of the vertices contains the vectors of the pairs + * + * @param primitiveIndex zero-based index of the primitive, must be less than the primitive count passed to Builder constructor + * @param indicesAndWeightsVectors pairs of bone index and bone weight for all vertices of the primitive sequentially + * + * @return Builder reference for chaining calls. + */ + Builder& boneIndicesAndWeights(size_t primitiveIndex, + std::vector> const &indicesAndWeightsVector); + /** + * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the + * second value is the bone weight. The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS + * defined in the VertexBuffer. Both ways of indices and weights definition must not be combined in one primitive. + * Number of pairs is not limited to 4 bones per vertex. + * All bone weights of one vertex should sum to one. Otherwise they will be normalized. + * Data doesn't have to be rectangular and number of pairs per vertices and primitives can be variable. + * The vector of the primitives contains the vectors of the vertices with the vectors of the pairs + * + * @param indicesAndWeightsVectors pairs of bone index and bone weight for all vertices and primitives sequentially + * + * @return Builder reference for chaining calls. + */ + Builder& boneIndicesAndWeights( + std::vector>> const &indicesAndWeightsVectors) noexcept; + /** * Controls if the renderable has vertex morphing targets, zero by default. This is * required to enable GPU morphing. @@ -498,7 +567,12 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { size_t offset = 0; size_t count = 0; } morphing; + struct { + bool bonePairsSet = false; + std::vector> bonePairs; //bone indices and weights for each entry(primitive) + } skinning; }; + void processBoneIndicesAndWights(Engine& engine, utils::Entity entity); }; /** diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp index 56425c8fbb4..c7d5492c911 100644 --- a/filament/src/RenderPass.cpp +++ b/filament/src/RenderPass.cpp @@ -241,7 +241,8 @@ void RenderPass::instanceify(FEngine& engine) noexcept { lhs.primitive.skinningHandle == rhs.primitive.skinningHandle && lhs.primitive.skinningOffset == rhs.primitive.skinningOffset && lhs.primitive.morphWeightBuffer == rhs.primitive.morphWeightBuffer && - lhs.primitive.morphTargetBuffer == rhs.primitive.morphTargetBuffer; + lhs.primitive.morphTargetBuffer == rhs.primitive.morphTargetBuffer && + lhs.primitive.skinningTexture == rhs.primitive.skinningTexture ; }); uint32_t const instanceCount = e - curr; @@ -585,6 +586,8 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, cmdColor.primitive.skinningHandle = skinning.handle; cmdColor.primitive.skinningOffset = skinning.offset; + cmdColor.primitive.skinningTexture = skinning.handleSampler; + cmdColor.primitive.morphWeightBuffer = morphing.handle; cmdColor.primitive.morphTargetBuffer = morphTargets.buffer->getHwHandle(); @@ -689,6 +692,8 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, cmdDepth.primitive.skinningHandle = skinning.handle; cmdDepth.primitive.skinningOffset = skinning.offset; + cmdDepth.primitive.skinningTexture = skinning.handleSampler; + cmdDepth.primitive.morphWeightBuffer = morphing.handle; cmdDepth.primitive.morphTargetBuffer = morphTargets.buffer->getHwHandle(); @@ -873,7 +878,11 @@ void RenderPass::Executor::execute(backend::DriverApi& driver, // note: even if only skinning is enabled, binding morphTargetBuffer is needed. driver.bindSamplers(+SamplerBindingPoints::PER_RENDERABLE_MORPHING, info.morphTargetBuffer); - } + + if (UTILS_UNLIKELY(info.skinningTexture)) + driver.bindSamplers(+SamplerBindingPoints::PER_RENDERABLE_SKINNING, + info.skinningTexture); + } if (UTILS_UNLIKELY(info.morphWeightBuffer)) { // Instead of using a UBO per primitive, we could also have a single UBO for all diff --git a/filament/src/RenderPass.h b/filament/src/RenderPass.h index 92c7b06c0c6..953164ae66a 100644 --- a/filament/src/RenderPass.h +++ b/filament/src/RenderPass.h @@ -224,7 +224,7 @@ class RenderPass { return boolish ? value : uint64_t(0); } - struct PrimitiveInfo { // 48 bytes + struct PrimitiveInfo { // 56 bytes union { FMaterialInstance const* mi; uint64_t padding = {}; // ensures mi is 8 bytes on all archs @@ -232,6 +232,7 @@ class RenderPass { backend::RasterState rasterState; // 4 bytes backend::Handle primitiveHandle; // 4 bytes backend::Handle skinningHandle; // 4 bytes + backend::Handle skinningTexture; // 4 bytes backend::Handle morphWeightBuffer; // 4 bytes backend::Handle morphTargetBuffer; // 4 bytes backend::Handle instanceBufferHandle; // 4 bytes @@ -239,7 +240,7 @@ class RenderPass { uint32_t skinningOffset = 0; // 4 bytes uint16_t instanceCount; // 2 bytes [MSb: user] Variant materialVariant; // 1 byte - uint8_t reserved[4] = {}; // 4 bytes + uint8_t reserved[0] = {}; // 1 byte static const uint16_t USER_INSTANCE_MASK = 0x8000u; static const uint16_t INSTANCE_COUNT_MASK = 0x7fffu; @@ -249,7 +250,7 @@ class RenderPass { struct alignas(8) Command { // 64 bytes CommandKey key = 0; // 8 bytes PrimitiveInfo primitive; // 48 bytes - uint64_t reserved[1] = {}; // 8 bytes + uint64_t reserved[2] = {}; // 16 bytes bool operator < (Command const& rhs) const noexcept { return key < rhs.key; } // placement new declared as "throw" to avoid the compiler's null-check inline void* operator new (std::size_t, void* ptr) { diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 513c1267854..3160556ec01 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -68,6 +68,8 @@ struct RenderableManager::BuilderDetails { FSkinningBuffer* mSkinningBuffer = nullptr; FInstanceBuffer* mInstanceBuffer = nullptr; uint32_t mSkinningBufferOffset = 0; + float2* mBoneIndicesAndWeight = nullptr; + size_t mBoneIndicesAndWeightsCount = 0; explicit BuilderDetails(size_t count) : mEntries(count), mCulling(true), mCastShadows(false), mReceiveShadows(true), @@ -205,6 +207,88 @@ RenderableManager::Builder& RenderableManager::Builder::enableSkinningBuffers(bo return *this; } +RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(size_t primitiveIndex, + math::float2 const* indicesAndWeights, size_t count, size_t offset) { + std::vector& entries = mImpl->mEntries; + + ASSERT_PRECONDITION(primitiveIndex < entries.size() && primitiveIndex >= 0, + "[primitive @ %u] index is out of size (%u)", primitiveIndex, entries.size()); + auto vertexCount = entries[primitiveIndex].vertices->getVertexCount(); + ASSERT_PRECONDITION(vertexCount > 0, + "[primitive @ %u] no defined vertices (%u)", primitiveIndex, vertexCount); + auto pairsPerVertexCount = count / vertexCount; + ASSERT_PRECONDITION(pairsPerVertexCount > 0 && count % vertexCount == 0, + "[primitive @ %u] bone indices and weights pairs count (%u) must be a multiple of vertex count (%u)", + primitiveIndex, count, vertexCount); + + std::vector> bonePairs; + for( size_t iVertex = 0; iVertex < vertexCount; iVertex++){ + std::vector vertexData(pairsPerVertexCount); + std::memcpy(&vertexData[0], &indicesAndWeights[offset + iVertex * pairsPerVertexCount], + pairsPerVertexCount * sizeof(float2)); + bonePairs.push_back(vertexData); + } + return boneIndicesAndWeights(primitiveIndex, bonePairs); +} + +RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights( + math::float2 const* indicesAndWeightsArray, size_t count, size_t offset){ + std::vector& entries = mImpl->mEntries; + size_t primitiveCount = entries.size(); + size_t allVerticesCount = 0; + // number off all vertices of all primitives calculation + for (size_t iEntry = 0; iEntry < primitiveCount; iEntry++){ + allVerticesCount += entries[iEntry].vertices->getVertexCount(); + } + size_t pairsPerAllVerticesCount = count / allVerticesCount; + ASSERT_PRECONDITION(pairsPerAllVerticesCount > 0 && count % allVerticesCount == 0, + "bone indices and weights pairs count (%u) must be a multiple of vertex counts of all primitives (%u)", + count, allVerticesCount); + size_t pairSkipped = offset; + for (size_t iEntry = 0; iEntry < primitiveCount; iEntry++){ + size_t pairsPerPrimitiveCount = pairsPerAllVerticesCount * entries[iEntry].vertices->getVertexCount(); + boneIndicesAndWeights(iEntry, + indicesAndWeightsArray + pairSkipped, + pairsPerPrimitiveCount); + pairSkipped += pairsPerAllVerticesCount; + } + return *this; +} + +RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(size_t primitiveIndex, + const std::vector> &indicesAndWeightsVector) { + auto count = indicesAndWeightsVector.size(); + if (!count) { + // skip if no skinning data + //mImpl->mEntries[primitiveIndex].skinning.bonePairsSet = true; + return *this; + } + std::vector& entries = mImpl->mEntries; + ASSERT_PRECONDITION(primitiveIndex < entries.size() && primitiveIndex >= 0, + "[primitive @ %u] index is out of size (%u)", primitiveIndex, entries.size()); + auto vertexCount = entries[primitiveIndex].vertices->getVertexCount(); + ASSERT_PRECONDITION(vertexCount > 0, + "[primitive @ %u] no defined vertices (%u)", primitiveIndex, vertexCount); + auto pairsPerVertexCount = count / vertexCount; + ASSERT_PRECONDITION(pairsPerVertexCount > 0 && count % vertexCount == 0, + "[primitive @ %u] bone indices and weights pairs count (%u) must be a multiple of vertex count (%u)", + primitiveIndex, count, vertexCount); + auto& skinning = entries[primitiveIndex].skinning; + ASSERT_PRECONDITION(skinning.bonePairs.empty(), + "[primitive @ %u] bone indices and weights data already exists", primitiveIndex); + skinning.bonePairs = indicesAndWeightsVector; //copy + skinning.bonePairsSet = true; + + return *this; +} + +RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights( + const std::vector>> &indicesAndWeightsVectors) noexcept{ + for (size_t iEntry = 0, c = min(mImpl->mEntries.size(), indicesAndWeightsVectors.size()); iEntry < c; iEntry++) + boneIndicesAndWeights(iEntry, indicesAndWeightsVectors[iEntry]); + return *this; +} + RenderableManager::Builder& RenderableManager::Builder::fog(bool enabled) noexcept { mImpl->mFogEnabled = enabled; return *this; @@ -243,6 +327,109 @@ RenderableManager::Builder& RenderableManager::Builder::globalBlendOrderEnabled( return *this; } +void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Entity entity){ + size_t maxPairsCount = 0; + size_t maxPairsCountPerPrimitive = 0; + + for (size_t iEntry = 0, c = mImpl->mEntries.size(); iEntry < c; iEntry++) { + auto& entry = mImpl->mEntries[iEntry]; + if (entry.skinning.bonePairs.size()) { + auto const& declaredAttributes = downcast(entry.vertices)->getDeclaredAttributes(); + ASSERT_PRECONDITION(!declaredAttributes[VertexAttribute::BONE_INDICES], + "[entity=%u, primitive @ %u] vertex attribute for skinning BONE_INDICES are already defined", + entity.getId(), iEntry); + ASSERT_PRECONDITION(!declaredAttributes[VertexAttribute::BONE_WEIGHTS], + "[entity=%u, primitive @ %u] vertex attribute BONE_WEIGHTS for skinning are already defined", + entity.getId(), iEntry); + for (size_t iVertex = 0, vertexCount = entry.skinning.bonePairs.size(); iVertex < vertexCount; iVertex++){ + auto pairCountPerVertex = entry.skinning.bonePairs[iVertex].size(); + maxPairsCount += pairCountPerVertex; + maxPairsCountPerPrimitive = max(pairCountPerVertex, maxPairsCountPerPrimitive); + } + } + } + size_t pairsCount = 0; //counting of number of pairs stored in texture + float2* tempPairs; //temporary indices and weights for one vertex + if (maxPairsCount) { //at least one primitive has bone indices and weights + mImpl->mBoneIndicesAndWeight = (float2*) malloc( + maxPairsCount * 2 * 4); //final texture data, indices and weights + tempPairs = (float2*) malloc(maxPairsCountPerPrimitive * 2 + * 4); //temporary indices and weights for one vertex + } + for (size_t iEntry = 0, entriesCount = mImpl->mEntries.size(); iEntry < entriesCount; iEntry++) { + auto& entry = mImpl->mEntries[iEntry]; + //bone data are defined boneIndicesAndWeights() + if (entry.skinning.bonePairsSet) { + if (entry.skinning.bonePairs.size()){ + size_t vertexCount = entry.vertices->getVertexCount(); + auto skinJoints = (ushort*) malloc(vertexCount * 4 * 2); + auto skinWeights = (float*) malloc(vertexCount * 4 * 4); + for(size_t iVertex = 0; iVertex < vertexCount; iVertex++) { + size_t pairsPerVertexCount = entry.skinning.bonePairs[iVertex].size(); + //if (!pairsPerVertexCount) continue; + size_t tempPairCount = 0; + float boneWeightsSum = 0; + for (size_t k = 0; k < pairsPerVertexCount; k++){ + auto boneWeight = entry.skinning.bonePairs[iVertex][k][1]; + auto boneIndex= entry.skinning.bonePairs[iVertex][k][0]; + ASSERT_PRECONDITION(boneWeight >= 0, + "[entity=%u, primitive @ %u] bone weight (%f) of vertex=%u is negative ", + entity.getId(), iEntry, boneWeight, iVertex); + if (boneWeight){ + ASSERT_PRECONDITION(boneIndex >= 0, + "[entity=%u, primitive @ %u] bone index (%i) of vertex=%u is negative ", + entity.getId(), iEntry, (int) boneIndex, iVertex); + ASSERT_PRECONDITION(boneIndex < mImpl->mSkinningBoneCount, + "[entity=%u, primitive @ %u] bone index (%i) of vertex=%u is bigger then bone count (%u) ", + entity.getId(), iEntry, (int) boneIndex, iVertex, mImpl->mSkinningBoneCount); + boneWeightsSum += boneWeight; + tempPairs[tempPairCount][0] = boneIndex; + tempPairs[tempPairCount][1] = boneWeight; + tempPairCount++; + } + } + + ASSERT_PRECONDITION(boneWeightsSum > 0, + "[entity=%u, primitive @ %u] sum of bone weights of vertex=%u is %f, it should be positive.", + entity.getId(), iEntry, iVertex, boneWeightsSum); + if (abs(boneWeightsSum - 1.f) > std::numeric_limits::epsilon()) + utils::slog.w << "Warning of skinning: [entity=%" << entity.getId() <<", primitive @ %" << iEntry + << "] sum of bone weights of vertex=" << iVertex << " is " << boneWeightsSum + << ", it should be one. Weights will be normalized." << utils::io::endl; + + //prepare data for vertex attributes + auto offset = iVertex * 4; + //set attributes, indices and weights, for <= 4 pairs + for (size_t j = 0, c = min(tempPairCount, 4ul); j < c; j++) { + skinJoints[j + offset] = tempPairs[j][0]; + skinWeights[j + offset] = tempPairs[j][1] / boneWeightsSum; + } + //reset rest weights + for (size_t j = tempPairCount; j < 4; j++) + skinWeights[j + offset] = 0; + //prepare data for texture + if (tempPairCount > 4) + { //set attributes, indices and weights, for > 4 pairs + skinWeights[3 + offset] = -(float) (pairsCount + 1); //negative offset to texture 0..-1, 1..-2 + skinJoints[3 + offset] = (ushort) tempPairCount; //number pairs per vertex in texture + for (size_t j = 3; j < tempPairCount; j++) { + mImpl->mBoneIndicesAndWeight[pairsCount][0] = tempPairs[j][0]; + mImpl->mBoneIndicesAndWeight[pairsCount][1] = tempPairs[j][1] / boneWeightsSum; + pairsCount++; + } + } + } //for all vertices per primitive + + downcast(mImpl->mEntries[iEntry].vertices) + ->updateBoneIndicesAndWeights(downcast(engine), skinJoints, skinWeights); + + } + } + }//for all primitives + mImpl->mBoneIndicesAndWeightsCount = pairsCount; + +} + RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& engine, Entity entity) { bool isEmpty = true; @@ -262,6 +449,11 @@ RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& eng mImpl->mInstanceCount, bufferInstanceCount); } + if (mImpl->mSkinningBoneCount > 0 || mImpl->mSkinningBufferMode) { + processBoneIndicesAndWights(engine, entity); + } + + for (size_t i = 0, c = mImpl->mEntries.size(); i < c; i++) { auto& entry = mImpl->mEntries[i]; @@ -287,12 +479,12 @@ RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& eng // reject invalid geometry parameters ASSERT_PRECONDITION(entry.offset + entry.count <= entry.indices->getIndexCount(), "[entity=%u, primitive @ %u] offset (%u) + count (%u) > indexCount (%u)", - i, entity.getId(), + entity.getId(), i, entry.offset, entry.count, entry.indices->getIndexCount()); ASSERT_PRECONDITION(entry.minIndex <= entry.maxIndex, "[entity=%u, primitive @ %u] minIndex (%u) > maxIndex (%u)", - i, entity.getId(), + entity.getId(), i, entry.minIndex, entry.maxIndex); // this can't be an error because (1) those values are not immutable, so the caller @@ -460,6 +652,19 @@ void FRenderableManager::create( } } + if (UTILS_UNLIKELY(boneCount > 0) && (builder->mBoneIndicesAndWeightsCount > 0)){ + //create and set texture for bone indices and weights + Bones& bones = manager[ci].bones; + FSkinningBuffer::HandleIndicesAndWeights handle = downcast(builder->mSkinningBuffer)-> + createIndicesAndWeightsHandle(downcast(engine), builder->mBoneIndicesAndWeightsCount); + bones.handleSamplerGroup = handle.sampler; + bones.handleTexture = handle.texture; + + downcast(builder->mSkinningBuffer)-> + setIndicesAndWeightsData(downcast(engine), handle.texture, + builder->mBoneIndicesAndWeight, builder->mBoneIndicesAndWeightsCount); + } + // Create and initialize all needed MorphTargets. // It's required to avoid branches in hot loops. MorphTargets* morphTargets = new MorphTargets[entryCount]; @@ -549,6 +754,10 @@ void FRenderableManager::destroyComponent(Instance ci) noexcept { if (bones.handle && !bones.skinningBufferMode) { driver.destroyBufferObject(bones.handle); } + if (bones.handleSamplerGroup){ + driver.destroySamplerGroup(bones.handleSamplerGroup); + driver.destroyTexture(bones.handleTexture); + } // destroy the weights structures if any MorphWeights const& morphWeights = manager[ci].morphWeights; diff --git a/filament/src/components/RenderableManager.h b/filament/src/components/RenderableManager.h index 648ccdaeb58..d79d2ca3eeb 100644 --- a/filament/src/components/RenderableManager.h +++ b/filament/src/components/RenderableManager.h @@ -151,6 +151,7 @@ class FRenderableManager : public RenderableManager { struct SkinningBindingInfo { backend::Handle handle; uint32_t offset; + backend::Handle handleSampler; }; inline SkinningBindingInfo getSkinningBufferInfo(Instance instance) const noexcept; @@ -208,8 +209,10 @@ class FRenderableManager : public RenderableManager { uint16_t count = 0; uint16_t offset = 0; bool skinningBufferMode = false; + backend::Handle handleSamplerGroup; + backend::Handle handleTexture; }; - static_assert(sizeof(Bones) == 12); + static_assert(sizeof(Bones) == 20); struct MorphWeights { backend::Handle handle; @@ -410,7 +413,7 @@ Box const& FRenderableManager::getAABB(Instance instance) const noexcept { FRenderableManager::SkinningBindingInfo FRenderableManager::getSkinningBufferInfo(Instance instance) const noexcept { Bones const& bones = mManager[instance].bones; - return { bones.handle, bones.offset }; + return { bones.handle, bones.offset, bones.handleSamplerGroup }; } inline uint32_t FRenderableManager::getBoneCount(Instance instance) const noexcept { diff --git a/filament/src/details/Scene.h b/filament/src/details/Scene.h index a17d30386f5..d7adc8d3c80 100644 --- a/filament/src/details/Scene.h +++ b/filament/src/details/Scene.h @@ -92,7 +92,7 @@ class FScene : public Scene { RENDERABLE_INSTANCE, // 4 | instance of the Renderable component WORLD_TRANSFORM, // 16 | instance of the Transform component VISIBILITY_STATE, // 2 | visibility data of the component - SKINNING_BUFFER, // 8 | bones uniform buffer handle, offset + SKINNING_BUFFER, // 8 | bones uniform buffer handle, offset, indices and weights MORPHING_BUFFER, // 16 | weights uniform buffer handle, count, morph targets INSTANCES, // 16 | instancing info for this Renderable WORLD_AABB_CENTER, // 12 | world-space bounding box center of the renderable diff --git a/filament/src/details/SkinningBuffer.cpp b/filament/src/details/SkinningBuffer.cpp index 9fd859a2645..dd8544a56e7 100644 --- a/filament/src/details/SkinningBuffer.cpp +++ b/filament/src/details/SkinningBuffer.cpp @@ -18,6 +18,8 @@ #include "components/RenderableManager.h" +#include "private/filament/SibStructs.h" + #include "details/Engine.h" #include "FilamentAPI-impl.h" @@ -162,5 +164,101 @@ void FSkinningBuffer::setBones(FEngine& engine, Handle offset * sizeof(PerRenderableBoneUib::BoneData)); } +// This value is limited by ES3.0, ES3.0 only guarantees 2048. +// When you change this value, you must change MAX_SKINNING_BUFFER_WIDTH at getters.vs +constexpr size_t MAX_SKINNING_BUFFER_WIDTH = 2048; + +static inline size_t getWidth(size_t pairCount) noexcept { + return std::min(pairCount, MAX_SKINNING_BUFFER_WIDTH); +} + +static inline size_t getHeight(size_t pairCount) noexcept { + return (pairCount + MAX_SKINNING_BUFFER_WIDTH) / MAX_SKINNING_BUFFER_WIDTH; +} + +inline size_t getSize(size_t pairCount) noexcept { + const size_t stride = getWidth(pairCount); + const size_t height = getHeight(pairCount); + return Texture::PixelBufferDescriptor::computeDataSize( + Texture::PixelBufferDescriptor::PixelDataFormat::RG, + Texture::PixelBufferDescriptor::PixelDataType::FLOAT, + stride, height, 1); +} + +UTILS_NOINLINE +void updateDataAt(backend::DriverApi& driver, + Handle handle, PixelDataFormat format, PixelDataType type, + const char* out, size_t elementSize, + size_t count, size_t size) { + + size_t const textureWidth = getWidth( count);//size); + size_t const lineCount = count / textureWidth; + size_t const lastLineCount = count % textureWidth; + + // 'out' buffer is going to be used up to 2 times, so for simplicity we use a shared_buffer + // to manage its lifetime. One side effect of this is that the callbacks below will allocate + // a small object on the heap. (inspired by MorphTargetBuffered) + std::shared_ptr allocation((void*)out, ::free); + + if (lineCount) { + // update the full-width lines if any + driver.update3DImage(handle, 0, 0, 0, 0, + textureWidth, lineCount, 1, PixelBufferDescriptor::make( + out, (textureWidth * lineCount) * elementSize, + format, type,[allocation](void const*, size_t) {} + )); + out += (lineCount * textureWidth) * elementSize; + } + + if (lastLineCount) { + // update the last partial line if any + driver.update3DImage(handle, 0, 0, lineCount, 0, + lastLineCount, 1, 1, PixelBufferDescriptor::make( + out, lastLineCount * elementSize, + format, type,[allocation](void const*, size_t) {} + )); + } +} + +FSkinningBuffer::HandleIndicesAndWeights FSkinningBuffer::createIndicesAndWeightsHandle(FEngine& engine, size_t count) { + backend::Handle samplerHandle; + backend::Handle textureHandle; //bone indices and weights + + FEngine::DriverApi& driver = engine.getDriverApi(); + auto size = getSize(count); + // create a texture for skinning pairs data (bone index and weight) + size = getSize(count); + + textureHandle = driver.createTexture(SamplerType::SAMPLER_2D, 1, + TextureFormat::RG32F, 1, + getWidth(size), getHeight(size), 1, + TextureUsage::DEFAULT); + samplerHandle = driver.createSamplerGroup(PerRenderPrimitiveSkinningSib::SAMPLER_COUNT); + SamplerGroup samplerGroup(PerRenderPrimitiveSkinningSib::SAMPLER_COUNT); + samplerGroup.setSampler(PerRenderPrimitiveSkinningSib::BONE_IaW, + {textureHandle, {}}); + driver.updateSamplerGroup(samplerHandle, + samplerGroup.toBufferDescriptor(driver)); + return { + .sampler = samplerHandle, + .texture = textureHandle + }; +} + +void FSkinningBuffer::setIndicesAndWeightsData(FEngine& engine, + backend::Handle textureHandle, math::float2 const* pairs, size_t count) { + + FEngine::DriverApi& driver = engine.getDriverApi(); + auto size = getSize(count); + auto* out = (float2*) malloc(size); + std::transform(pairs, pairs + count, out, + [](const float2& p) { return float2(p); }); + + updateDataAt(driver, textureHandle, + Texture::Format::RG, Texture::Type::FLOAT, + (char const*)out, sizeof(float2), + count, size); +} + } // namespace filament diff --git a/filament/src/details/SkinningBuffer.h b/filament/src/details/SkinningBuffer.h index 8fd1cddd410..bfc1884fe70 100644 --- a/filament/src/details/SkinningBuffer.h +++ b/filament/src/details/SkinningBuffer.h @@ -23,6 +23,8 @@ #include "private/filament/EngineEnums.h" #include "private/filament/UibStructs.h" +#include "backend/DriverApiForward.h" + #include #include @@ -52,6 +54,9 @@ class FSkinningBuffer : public SkinningBuffer { return (count + CONFIG_MAX_BONE_COUNT - 1) & ~(CONFIG_MAX_BONE_COUNT - 1); } + backend::Handle setIndicesAndWeights(FEngine& engine, + math::float2 const* pairs, size_t count); + private: friend class ::FilamentTest_Bones_Test; friend class SkinningBuffer; @@ -69,6 +74,15 @@ class FSkinningBuffer : public SkinningBuffer { return mHandle; } + struct HandleIndicesAndWeights{ + backend::Handle sampler; + backend::Handle texture; + }; + HandleIndicesAndWeights createIndicesAndWeightsHandle(FEngine& engine, + size_t count); + void setIndicesAndWeightsData(FEngine& engine, + backend::Handle textureHandle, math::float2 const* pairs, size_t count); + backend::Handle mHandle; uint32_t mBoneCount; }; diff --git a/filament/src/details/VertexBuffer.cpp b/filament/src/details/VertexBuffer.cpp index 859f1dbc1c8..0ee1bd1aae3 100644 --- a/filament/src/details/VertexBuffer.cpp +++ b/filament/src/details/VertexBuffer.cpp @@ -206,7 +206,11 @@ void FVertexBuffer::terminate(FEngine& engine) { driver.destroyBufferObject(bo); } } - driver.destroyVertexBuffer(mHandle); + if (mBoneBufferObjectsUsed){ + driver.destroyBufferObject(mBoJointsHandle); + driver.destroyBufferObject(mBoWeightsHandle); + } + driver.destroyVertexBuffer(mHandle); } size_t FVertexBuffer::getVertexCount() const noexcept { @@ -233,9 +237,108 @@ void FVertexBuffer::setBufferObjectAt(FEngine& engine, uint8_t bufferIndex, if (bufferIndex < mBufferCount) { auto hwBufferObject = bufferObject->getHwHandle(); engine.getDriverApi().setVertexBufferObject(mHandle, bufferIndex, hwBufferObject); - } else { + //store handle to recreate VertexBuffer in the case extra bone indices and weights definition + //used only in buffer object mode + mBufferObjects[bufferIndex] = hwBufferObject; + } else { ASSERT_PRECONDITION(bufferIndex < mBufferCount, "bufferIndex must be < bufferCount"); } } +void FVertexBuffer::updateBoneIndicesAndWeights(FEngine& engine, + ushort* skinJoints, float* skinWeights) { + AttributeArray attributeArray; + + static_assert(attributeArray.size() == MAX_VERTEX_ATTRIBUTE_COUNT, + "Attribute and Builder::Attribute arrays must match"); + + static_assert(sizeof(Attribute) == sizeof(AttributeData), + "Attribute and Builder::Attribute must match"); + + ASSERT_PRECONDITION(!mDeclaredAttributes[VertexAttribute::BONE_INDICES], + "Vertex buffer attribute BONE_INDICES is already defined"); + ASSERT_PRECONDITION(!mDeclaredAttributes[VertexAttribute::BONE_WEIGHTS], + "Vertex buffer attribute BONE_WEIGHTS is already defined"); + ASSERT_PRECONDITION(mBufferCount < (MAX_VERTEX_BUFFER_COUNT - 2), + "Vertex buffer uses to many buffers (%u)", mBufferCount); + + size_t bufferSizes[MAX_VERTEX_BUFFER_COUNT] = {}; + auto slotIndicesOld = mAttributes[VertexAttribute::BONE_INDICES].buffer; + mDeclaredAttributes.set(VertexAttribute::BONE_INDICES); + mAttributes[VertexAttribute::BONE_INDICES].offset = 0; + mAttributes[VertexAttribute::BONE_INDICES].stride = 8; + mAttributes[VertexAttribute::BONE_INDICES].buffer = mBufferCount; + mAttributes[VertexAttribute::BONE_INDICES].type = VertexBuffer::AttributeType::USHORT4; + mAttributes[VertexAttribute::BONE_INDICES].flags = Attribute::FLAG_INTEGER_TARGET; + auto slotWeightsOld = mAttributes[VertexAttribute::BONE_INDICES].buffer; + mDeclaredAttributes.set(VertexAttribute::BONE_WEIGHTS); + mAttributes[VertexAttribute::BONE_WEIGHTS].offset = 0; + mAttributes[VertexAttribute::BONE_WEIGHTS].stride = 16; + mAttributes[VertexAttribute::BONE_WEIGHTS].buffer = mBufferCount + 1; + mAttributes[VertexAttribute::BONE_WEIGHTS].type = VertexBuffer::AttributeType::FLOAT4; + mAttributes[VertexAttribute::BONE_WEIGHTS].flags = 0; + + auto const& declaredAttributes = mDeclaredAttributes; + auto const& attributes = mAttributes; + + uint8_t attributeCount = (uint8_t) mDeclaredAttributes.count(); + #pragma nounroll + for (size_t i = 0, n = attributeArray.size(); i < n; ++i) { + if (declaredAttributes[i]) { + const uint32_t offset = attributes[i].offset; + const uint8_t stride = attributes[i].stride; + const uint8_t slot = attributes[i].buffer; + + attributeArray[i].offset = offset; + attributeArray[i].stride = stride; + attributeArray[i].buffer = slot; + attributeArray[i].type = attributes[i].type; + attributeArray[i].flags = attributes[i].flags; + + const size_t end = offset + mVertexCount * stride; + bufferSizes[slot] = math::max(bufferSizes[slot], end); + } + } + FEngine::DriverApi& driver = engine.getDriverApi(); + //destroy old bone buffer objects if any + if (!mBufferObjectsEnabled) { + if (slotIndicesOld != Attribute::BUFFER_UNUSED) + driver.destroyBufferObject(mBufferObjects[slotIndicesOld]); + if (slotIndicesOld != Attribute::BUFFER_UNUSED) + driver.destroyBufferObject(mBufferObjects[slotWeightsOld]); + } + + //destroy old and create new vertex buffer + auto oldHandle = mHandle; + mHandle = driver.createVertexBuffer(mBufferCount + 2, attributeCount, mVertexCount, attributeArray); + driver.destroyVertexBuffer(oldHandle); + #pragma nounroll + for (size_t i = 0; i < mBufferCount; ++i) + if (bufferSizes[i] > 0) + driver.setVertexBufferObject(mHandle, i, mBufferObjects[i]); + //add new bone buffer objects + mBufferCount++; + auto boJointsHandle = driver.createBufferObject(bufferSizes[mBufferCount - 1], + backend::BufferObjectBinding::VERTEX, backend::BufferUsage::STATIC); + driver.setVertexBufferObject(mHandle, mBufferCount - 1, boJointsHandle); + auto bdJoints = BufferDescriptor( + skinJoints, bufferSizes[mBufferCount - 1], nullptr); + driver.updateBufferObject(boJointsHandle,std::move(bdJoints), 0); + mBufferCount++; + auto boWeightsHandle = driver.createBufferObject(bufferSizes[mBufferCount - 1], + backend::BufferObjectBinding::VERTEX, backend::BufferUsage::STATIC); + driver.setVertexBufferObject(mHandle, mBufferCount - 1, boWeightsHandle); + auto bdWeights = BufferDescriptor( + skinWeights, bufferSizes[mBufferCount - 1], nullptr); + driver.updateBufferObject(boWeightsHandle,std::move(bdWeights), 0); + if (!mBufferObjectsEnabled) { + mBufferObjects[mBufferCount - 2] = boJointsHandle; + mBufferObjects[mBufferCount - 1] = boWeightsHandle; + }else{ + //for correct destroy bone buffer object + mBoneBufferObjectsUsed = true; + mBoJointsHandle = boJointsHandle; + mBoWeightsHandle = boWeightsHandle; + } +} } // namespace filament diff --git a/filament/src/details/VertexBuffer.h b/filament/src/details/VertexBuffer.h index d8455bfe4d2..b70e90744ab 100644 --- a/filament/src/details/VertexBuffer.h +++ b/filament/src/details/VertexBuffer.h @@ -41,6 +41,7 @@ class FVertexBuffer : public VertexBuffer { using BufferObjectHandle = backend::BufferObjectHandle; FVertexBuffer(FEngine& engine, const Builder& builder); + FVertexBuffer(FEngine& engine, FVertexBuffer* buffer); // frees driver resources, object becomes invalid void terminate(FEngine& engine); @@ -60,6 +61,8 @@ class FVertexBuffer : public VertexBuffer { void setBufferObjectAt(FEngine& engine, uint8_t bufferIndex, FBufferObject const * bufferObject); + void updateBoneIndicesAndWeights(FEngine& engine, ushort* skinJoints, float* skinWeights); + private: friend class VertexBuffer; @@ -74,6 +77,9 @@ class FVertexBuffer : public VertexBuffer { uint32_t mVertexCount = 0; uint8_t mBufferCount = 0; bool mBufferObjectsEnabled = false; + bool mBoneBufferObjectsUsed = false; //mBoJointsHandle and mBoWeightsHandle are used, only in buffer object mode + BufferObjectHandle mBoJointsHandle; //handle for extra bone indices BufferObject + BufferObjectHandle mBoWeightsHandle; //handle for extra bone weights BufferObject }; FILAMENT_DOWNCAST(VertexBuffer) diff --git a/libs/filabridge/include/private/filament/EngineEnums.h b/libs/filabridge/include/private/filament/EngineEnums.h index 7475d9f61ab..f72c2ac66ab 100644 --- a/libs/filabridge/include/private/filament/EngineEnums.h +++ b/libs/filabridge/include/private/filament/EngineEnums.h @@ -52,6 +52,7 @@ enum class SamplerBindingPoints : uint8_t { PER_VIEW = 0, // samplers updated per view PER_RENDERABLE_MORPHING = 1, // morphing sampler updated per render primitive PER_MATERIAL_INSTANCE = 2, // samplers updates per material + PER_RENDERABLE_SKINNING = 3, // bone indices and weights sampler updated per render primitive // Update utils::Enum::count<>() below when adding values here // These are limited by CONFIG_SAMPLER_BINDING_COUNT (currently 4) }; @@ -132,7 +133,7 @@ struct utils::EnableIntegerOperators template<> inline constexpr size_t utils::Enum::count() { return 9; } template<> -inline constexpr size_t utils::Enum::count() { return 3; } +inline constexpr size_t utils::Enum::count() { return 4; } static_assert(utils::Enum::count() <= filament::backend::CONFIG_UNIFORM_BINDING_COUNT); static_assert(utils::Enum::count() <= filament::backend::CONFIG_SAMPLER_BINDING_COUNT); diff --git a/libs/filabridge/include/private/filament/SibStructs.h b/libs/filabridge/include/private/filament/SibStructs.h index 0fb56891a4a..c6262508beb 100644 --- a/libs/filabridge/include/private/filament/SibStructs.h +++ b/libs/filabridge/include/private/filament/SibStructs.h @@ -42,6 +42,12 @@ struct PerRenderPrimitiveMorphingSib { static constexpr size_t SAMPLER_COUNT = 2; }; +struct PerRenderPrimitiveSkinningSib { + static constexpr size_t BONE_IaW = 0; //bone indices and weights + + static constexpr size_t SAMPLER_COUNT = 1; +}; + } // namespace filament #endif //TNT_FILABRIDGE_SIBSTRUCTS_H diff --git a/libs/filamat/src/shaders/ShaderGenerator.cpp b/libs/filamat/src/shaders/ShaderGenerator.cpp index 4f11b4b69e8..2f76bbd7459 100644 --- a/libs/filamat/src/shaders/ShaderGenerator.cpp +++ b/libs/filamat/src/shaders/ShaderGenerator.cpp @@ -439,7 +439,9 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel, cg.generateUniforms(vs, ShaderStage::VERTEX, UniformBindingPoints::PER_RENDERABLE_BONES, UibGenerator::getPerRenderableBonesUib()); - + cg.generateSamplers(vs, SamplerBindingPoints::PER_RENDERABLE_SKINNING, + material.samplerBindings.getBlockOffset(SamplerBindingPoints::PER_RENDERABLE_SKINNING), + SibGenerator::getPerRenderPrimitiveBonesSib(variant)); cg.generateUniforms(vs, ShaderStage::VERTEX, UniformBindingPoints::PER_RENDERABLE_MORPHING, UibGenerator::getPerRenderableMorphingUib()); diff --git a/libs/filamat/src/shaders/SibGenerator.cpp b/libs/filamat/src/shaders/SibGenerator.cpp index eb1a5b0f0a8..c6b774f16f8 100644 --- a/libs/filamat/src/shaders/SibGenerator.cpp +++ b/libs/filamat/src/shaders/SibGenerator.cpp @@ -107,13 +107,28 @@ SamplerInterfaceBlock const& SibGenerator::getPerRenderPrimitiveMorphingSib(Vari return sib; } -SamplerInterfaceBlock const* SibGenerator::getSib( - SamplerBindingPoints bindingPoint, Variant variant) noexcept { +SamplerInterfaceBlock const& SibGenerator::getPerRenderPrimitiveBonesSib(Variant variant) noexcept { + using Type = SamplerInterfaceBlock::Type; + using Format = SamplerInterfaceBlock::Format; + using Precision = SamplerInterfaceBlock::Precision; + + static SamplerInterfaceBlock sib = SamplerInterfaceBlock::Builder() + .name("BonesBuffer") + .stageFlags(backend::ShaderStageFlags::VERTEX) + .add({ { "indicesAndWeights", Type::SAMPLER_2D, Format::FLOAT, Precision::HIGH }}) + .build(); + + return sib; +} + +SamplerInterfaceBlock const* SibGenerator::getSib(SamplerBindingPoints bindingPoint, Variant variant) noexcept { switch (bindingPoint) { case SamplerBindingPoints::PER_VIEW: return &getPerViewSib(variant); case SamplerBindingPoints::PER_RENDERABLE_MORPHING: return &getPerRenderPrimitiveMorphingSib(variant); + case SamplerBindingPoints::PER_RENDERABLE_SKINNING: + return &getPerRenderPrimitiveBonesSib(variant); default: return nullptr; } diff --git a/libs/filamat/src/shaders/SibGenerator.h b/libs/filamat/src/shaders/SibGenerator.h index 18ae7bb9f24..eb874653c50 100644 --- a/libs/filamat/src/shaders/SibGenerator.h +++ b/libs/filamat/src/shaders/SibGenerator.h @@ -31,6 +31,7 @@ class SibGenerator { public: static SamplerInterfaceBlock const& getPerViewSib(Variant variant) noexcept; static SamplerInterfaceBlock const& getPerRenderPrimitiveMorphingSib(Variant variant) noexcept; + static SamplerInterfaceBlock const& getPerRenderPrimitiveBonesSib(Variant variant) noexcept; static SamplerInterfaceBlock const* getSib(filament::SamplerBindingPoints bindingPoint, Variant variant) noexcept; // When adding a sampler block here, make sure to also update // FMaterial::getSurfaceProgramSlow and FMaterial::getPostProcessProgramSlow if needed diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index dbe09bf7686..a50e5475826 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -236,6 +236,7 @@ if (NOT ANDROID) add_demo(hellotriangle) add_demo(helloskinning) add_demo(helloskinningbuffer) + add_demo(helloskinningbuffer_morebones) add_demo(image_viewer) add_demo(lightbulb) add_demo(material_sandbox) @@ -246,8 +247,10 @@ if (NOT ANDROID) add_demo(sample_full_pbr) add_demo(sample_normal_map) add_demo(shadowtest) + add_demo(skinningtest) add_demo(strobecolor) add_demo(suzanne) + add_demo(suzanneskinning) add_demo(texturedquad) add_demo(vbotest) add_demo(viewtest) @@ -263,6 +266,7 @@ if (NOT ANDROID) target_link_libraries(sample_cloth PRIVATE filameshio) target_link_libraries(sample_normal_map PRIVATE filameshio) target_link_libraries(suzanne PRIVATE filameshio suzanne-resources) + target_link_libraries(suzanneskinning PRIVATE filameshio suzanne-resources) if (FILAMENT_DISABLE_MATOPT) add_definitions(-DFILAMENT_DISABLE_MATOPT=1) diff --git a/samples/helloskinningbuffer_morebones.cpp b/samples/helloskinningbuffer_morebones.cpp new file mode 100644 index 00000000000..04ea527192c --- /dev/null +++ b/samples/helloskinningbuffer_morebones.cpp @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include "generated/resources/resources.h" + +using namespace filament; +using utils::Entity; +using utils::EntityManager; +using namespace filament::math; + +struct App { + VertexBuffer *vb1, *vb2; + IndexBuffer *ib1, *ib2; + Material* mat; + Camera* cam; + Entity camera; + Skybox* skybox; + Entity renderable1, renderable2; + SkinningBuffer *sb; +}; + +struct Vertex { + float2 position; + uint32_t color; +}; + +static const Vertex TRIANGLE_VERTICES[3] = { + {{1, 0}, 0xffff0000u}, + {{cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ff00u}, + {{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu}, +}; + +static constexpr uint16_t TRIANGLE_INDICES[] = { 0, 1, 2, 3 }; + +mat4f transforms[] = {math::mat4f(1.f), + mat4f::translation(float3(1, 0, 0)), + mat4f::translation(float3(1, 1, 0)), + mat4f::translation(float3(0, 1, 0)), + mat4f::translation(float3(-1, 1, 0)), + mat4f::translation(float3(-1, 0, 0)), + mat4f::translation(float3(-1, -1, 0)), + mat4f::translation(float3(0, -1, 0)), + mat4f::translation(float3(1, -1, 0))}; + + +std::vector> boneDataPerPrimitive; + +int main(int argc, char** argv) { + Config config; + config.title = "skinning buffer common for two renderables"; + auto offset = 0; + std::vector boneDataPerVertex; + float w = 1/9.f; + for (uint i = 0; i < 9; i++) + boneDataPerVertex.push_back(float2 (i, w)); + boneDataPerPrimitive.push_back(boneDataPerVertex); + boneDataPerPrimitive.push_back(boneDataPerVertex); + boneDataPerPrimitive.push_back(boneDataPerVertex); + + App app; + auto setup = [&app](Engine* engine, View* view, Scene* scene) { + app.skybox = Skybox::Builder().color({0.1, 0.125, 0.25, 1.0}).build(*engine); + + scene->setSkybox(app.skybox); + view->setPostProcessingEnabled(false); + static_assert(sizeof(Vertex) == 12, "Strange vertex size."); + app.vb1 = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .build(*engine); + app.vb1->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr)); + app.vb2 = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .build(*engine); + app.vb2->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr)); + + app.ib1 = IndexBuffer::Builder() + .indexCount(3) + .bufferType(IndexBuffer::IndexType::USHORT) + .build(*engine); + app.ib2 = IndexBuffer::Builder() + .indexCount(3) + .bufferType(IndexBuffer::IndexType::USHORT) + .build(*engine); + app.ib1->setBuffer(*engine, + IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 6, nullptr)); + app.ib2->setBuffer(*engine, + IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 6, nullptr)); + app.mat = Material::Builder() + .package(RESOURCES_BAKEDCOLOR_DATA, RESOURCES_BAKEDCOLOR_SIZE) + .build(*engine); + + app.sb = SkinningBuffer::Builder() + .boneCount(256) + .initialize() + .build(*engine); + app.sb->setBones(*engine, transforms,9,0); + + app.renderable1 = EntityManager::get().create(); + app.renderable2 = EntityManager::get().create(); + + RenderableManager::Builder(1) + .boundingBox({{ -1, -1, -1 }, { 1, 1, 1 }}) + .material(0, app.mat->getDefaultInstance()) + .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.vb1, app.ib1, 0, 3) + .culling(false) + .receiveShadows(false) + .castShadows(false) + .enableSkinningBuffers(true) + .skinning(app.sb, 9, 0) + //set bone indices and weight for 3 vertices, 9 bones per vertx + .boneIndicesAndWeights(0, boneDataPerPrimitive) + .build(*engine, app.renderable1); + + RenderableManager::Builder(1) + .boundingBox({{ -1, -1, -1 }, { 1, 1, 1 }}) + .material(0, app.mat->getDefaultInstance()) + .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.vb2, app.ib2, 0, 3) + .culling(false) + .receiveShadows(false) + .castShadows(false) + .enableSkinningBuffers(true) + .skinning(app.sb, 9, 0) + //set bone indices and weight for 3 vertices, 9 bones per vertx + .boneIndicesAndWeights(0, boneDataPerPrimitive) + .build(*engine, app.renderable2); + + scene->addEntity(app.renderable1); + scene->addEntity(app.renderable2); + app.camera = utils::EntityManager::get().create(); + app.cam = engine->createCamera(app.camera); + view->setCamera(app.cam); + }; + + auto cleanup = [&app](Engine* engine, View*, Scene*) { + engine->destroy(app.skybox); + engine->destroy(app.renderable1); + engine->destroy(app.renderable2); + engine->destroy(app.mat); + engine->destroy(app.vb1); + engine->destroy(app.ib1); + engine->destroy(app.vb2); + engine->destroy(app.ib2); + engine->destroy(app.sb); + engine->destroyCameraComponent(app.camera); + utils::EntityManager::get().destroy(app.camera); + }; + + FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { + constexpr float ZOOM = 1.5f; + const uint32_t w = view->getViewport().width; + const uint32_t h = view->getViewport().height; + const float aspect = (float) w / h; + app.cam->setProjection(Camera::Projection::ORTHO, + -aspect * ZOOM, aspect * ZOOM, + -ZOOM, ZOOM, 0, 1); + auto& tcm = engine->getTransformManager(); + + //transformation of both renderables + tcm.setTransform(tcm.getInstance(app.renderable1), + filament::math::mat4f::translation(filament::math::float3{ 0.5, 0, 0 })); + tcm.setTransform(tcm.getInstance(app.renderable2), + filament::math::mat4f::translation(filament::math::float3{ 0, 0.5, 0 })); + + auto& rm = engine->getRenderableManager(); + + //skinning/bones animation + float t = (float)(now - (int)now); + float s = sin(t * f::PI * 2.f); + float c = cos(t * f::PI * 2.f); + + mat4f translate[] = {mat4f::translation(float3(s, c, 0))}; + + mat4f trans[9] = {}; + for(uint i = 0; i < 9; i++){ + trans[i] = filament::math::mat4f(1);//transforms[0]; + } + s *= 5; + mat4f transA[] = { + mat4f::translation(float3(s, 0, 0)), + mat4f::translation(float3(s, s, 0)), + mat4f::translation(float3(0, s, 0)), + mat4f::translation(float3(-s, s, 0)), + mat4f::translation(float3(-s, 0, 0)), + mat4f::translation(float3(-s, -s, 0)), + mat4f::translation(float3(0, -s, 0)), + mat4f::translation(float3(s, -s, 0)), + filament::math::mat4f(1)}; + uint offset = ((uint)now) % 8; + trans[offset] = transA[offset]; + + //set transformation of the first bone + app.sb->setBones(*engine, translate, 1, 0); + + //set transformation of the others bones + app.sb->setBones(*engine,trans, 8, 1); + + }); + + FilamentApp::get().run(config, setup, cleanup); + + return 0; +} diff --git a/samples/skinningtest.cpp b/samples/skinningtest.cpp new file mode 100644 index 00000000000..9ce6e3e4a64 --- /dev/null +++ b/samples/skinningtest.cpp @@ -0,0 +1,452 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include "generated/resources/resources.h" + +using namespace filament; +using utils::Entity; +using utils::EntityManager; +using namespace filament::math; + +struct App { + VertexBuffer *vb0, *vb1, *vb2, *vb3, *vb4, *vb5, *vb6; + IndexBuffer* ib, *ib2; + Material* mat; + Camera* cam; + Entity camera; + Skybox* skybox; + Entity renderable1, renderable2, renderable3; + SkinningBuffer *sb, *sb2; + MorphTargetBuffer *mt; + BufferObject *boTriangle, *boVertices, *boJoints, *boWeights; +}; + +struct Vertex { + float2 position; + uint32_t color; +}; + +static const Vertex TRIANGLE_VERTICES[6] = { + {{1, 0}, 0xffff0000u}, + {{cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ff00u}, + {{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu}, + {{0, 1}, 0xffffff00u}, + {{-cos(M_PI * 2 / 3), -sin(M_PI * 2 / 3)}, 0xff00ffffu}, + {{-cos(M_PI * 4 / 3), -sin(M_PI * 4 / 3)}, 0xffff00ffu}, +}; + +static const float3 targets_pos[9] = { + {-2, 0, 0},{0, 2, 0},{1, 0, 0}, + {1, 1, 0},{-1, 0, 0},{-1, 0, 0}, + {0, 0, 0},{0, 0, 0},{0, 0, 0} +}; + +static const short4 targets_tan[9] = { + {0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}, + {0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}, + {0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0} +}; + +static const ushort skinJoints[] = {0,1,2,5, + 0,2,3,5, + 0,3,1,5 +}; + +static const float skinWeights[] = {0.5f,0.0f,0.0f,0.5f, + 0.5f,0.0f,0.f,0.5f, + 0.5f,0.0f,0.f,0.5f, +}; + +static float2 boneDataArray[48] = {}; //index and weight for 3 vertices X 8 bones + +static constexpr uint16_t TRIANGLE_INDICES[6] = { 0, 1, 2, 3, 4, 5 }; + +mat4f transforms[] = {math::mat4f(1), + mat4f::translation(float3(1, 0, 0)), + mat4f::translation(float3(1, 1, 0)), + mat4f::translation(float3(0, 1, 0)), + mat4f::translation(float3(-1, 1, 0)), + mat4f::translation(float3(-1, 0, 0)), + mat4f::translation(float3(-1, -1, 0)), + mat4f::translation(float3(0, -1, 0)), + mat4f::translation(float3(1, -1, 0))}; + +std::vector> boneDataPerPrimitive, boneDataPerPrimitive2; +std::vector>> boneDataPerRenderable; + +int main(int argc, char** argv) { + Config config; + config.title = "skinning test with more than 4 bones per vertex"; + + std::vector boneDataPerVertex; + float w = 1 / 8.f; + for (uint i = 0; i < 8; i++){ + boneDataArray[i] = float2 (i, w); + boneDataArray[i + 8] = float2 (i, w); + boneDataArray[i + 16] = float2 (i, w); + boneDataPerVertex.push_back(float2 (i, w)); + } + std::vector boneDataPerVertex2; + w = 1 / 3.f; + for (uint i = 0; i < 3; i++){ + boneDataPerVertex2.push_back(float2 (i, w)); + } + + std::vector emptyBoneDataPerVertex(0); + std::vector> emptyBoneDataPerPrimitive(0); + boneDataPerPrimitive.push_back(boneDataPerVertex); + boneDataPerPrimitive.push_back(boneDataPerVertex); + boneDataPerPrimitive.push_back(boneDataPerVertex); + + boneDataPerPrimitive2.push_back(boneDataPerVertex); + boneDataPerPrimitive2.push_back(boneDataPerVertex2); + boneDataPerPrimitive2.push_back(boneDataPerVertex); + boneDataPerPrimitive2.push_back(boneDataPerVertex); + boneDataPerPrimitive2.push_back(boneDataPerVertex2); + boneDataPerPrimitive2.push_back(boneDataPerVertex); +// boneDataPerPrimitive.push_back(emptyBoneDataPerVertex); + + boneDataPerRenderable.push_back(boneDataPerPrimitive); + boneDataPerRenderable.push_back(boneDataPerPrimitive); + boneDataPerRenderable.push_back(emptyBoneDataPerPrimitive); + + App app; + auto setup = [&app](Engine* engine, View* view, Scene* scene) { + app.skybox = Skybox::Builder().color({0.1, 0.125, 0.25, 1.0}).build(*engine); + + scene->setSkybox(app.skybox); + view->setPostProcessingEnabled(false); + static_assert(sizeof(Vertex) == 12, "Strange vertex size."); + //primitive 0, triangle without skinning vertex attributes + app.vb0 = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .build(*engine); + + //primitive 1, triangle without skinning vertex attributes + app.vb1 = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .build(*engine); + + //primitive 2, triangle with skinning vertex attributes, buffer object disabled + app.vb2 = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(3) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .attribute(VertexAttribute::BONE_INDICES, 1, VertexBuffer::AttributeType::USHORT4, 0, 8) + .attribute(VertexAttribute::BONE_WEIGHTS, 2, VertexBuffer::AttributeType::FLOAT4, 0, 16) + //.enableBufferObjects() + .build(*engine); + + //primitive 3, triangle without skinning vertex attributes, buffer object enabled + app.vb3 = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .enableBufferObjects() + .build(*engine); + + //primitive 4, triangle without skinning vertex attributes + app.vb4 = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .build(*engine); + + //primitive 5, two triangles without skinning vertex attributes + app.vb5 = VertexBuffer::Builder() + .vertexCount(6) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .build(*engine); + + //primitive 6, triangle without skinning vertex attributes + app.vb6 = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .build(*engine); +//--------data for primitive 0 + app.vb0->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr)); +//--------data for primitive 1 + app.vb1->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 3, 36, nullptr)); + app.vb2->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 3, 36, nullptr)); + +//--------data for primitive 2 + app.vb2->setBufferAt(*engine, 1, + VertexBuffer::BufferDescriptor(skinJoints, 24, nullptr)); + app.vb2->setBufferAt(*engine, 2, + VertexBuffer::BufferDescriptor(skinWeights, 48, nullptr)); + +//--------data for primitive 3 + app.boTriangle = BufferObject::Builder() + .size(3 * 4 * sizeof(Vertex)) + .build(*engine); + app.boTriangle->setBuffer(*engine, BufferObject::BufferDescriptor( + TRIANGLE_VERTICES + 2, app.boTriangle->getByteCount(), nullptr)); + app.vb3->setBufferObjectAt(*engine, 0,app.boTriangle); + +//--------data for primitive 4 + app.vb4->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 1, 36, nullptr),0); +//--------data for primitive 5 + app.vb5->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 0, 72, nullptr),0); +//--------data for primitive 6 + app.vb6->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 0, 36, nullptr),0); +//index buffer data + app.ib = IndexBuffer::Builder() + .indexCount(3) + .bufferType(IndexBuffer::IndexType::USHORT) + .build(*engine); + app.ib->setBuffer(*engine, + IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 6, nullptr)); + + app.ib2 = IndexBuffer::Builder() + .indexCount(6) + .bufferType(IndexBuffer::IndexType::USHORT) + .build(*engine); + app.ib2->setBuffer(*engine, + IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 12, nullptr)); + + app.mat = Material::Builder() + .package(RESOURCES_BAKEDCOLOR_DATA, RESOURCES_BAKEDCOLOR_SIZE) + .build(*engine); + +//skinning buffer for renderable 1 + app.sb = SkinningBuffer::Builder() + .boneCount(9) + .initialize(true) + .build(*engine); + +//skinning buffer common for renderable 2 and 3 + app.sb2 = SkinningBuffer::Builder() + .boneCount(9) + .initialize(true) + .build(*engine); + + app.sb->setBones(*engine, transforms,9,0); + +//morph target definition to check combination bone skinning and blend shapes + app.mt = MorphTargetBuffer::Builder() + .vertexCount(9) + .count(3) + .build( *engine); + + app.mt->setPositionsAt(*engine,0, targets_pos, 3, 0); + app.mt->setPositionsAt(*engine,1, targets_pos+3, 3, 0); + app.mt->setPositionsAt(*engine,2, targets_pos+6, 3, 0); + app.mt->setTangentsAt(*engine,0, targets_tan, 9, 0); + app.mt->setTangentsAt(*engine,1, targets_tan, 9, 0); + app.mt->setTangentsAt(*engine,2, targets_tan, 9, 0); + +//renderable 1: +//primitive 0 = skinned triangle, bone data defined as vector per primitive, +//primitive 1 = skinned triangle, bone data defined as array per primitive, +//primitive 2 = triangle without skinning and with morphing, bone data defined as vertex attributes + app.renderable1 = EntityManager::get().create(); + RenderableManager::Builder(3) + .boundingBox({{-1, -1, -1}, {1, 1, 1}}) + .material(0, app.mat->getDefaultInstance()) + .material(1, app.mat->getDefaultInstance()) + .material(2, app.mat->getDefaultInstance()) + .geometry(0,RenderableManager::PrimitiveType::TRIANGLES, + app.vb0,app.ib,0,3) + .geometry(1,RenderableManager::PrimitiveType::TRIANGLES, + app.vb3,app.ib,0,3) + .geometry(2,RenderableManager::PrimitiveType::TRIANGLES, + app.vb2,app.ib,0,3) + .culling(false) + .receiveShadows(false) + .castShadows(false) + .enableSkinningBuffers(true) + .skinning(app.sb, 9, 0) + + .boneIndicesAndWeights(0, boneDataPerPrimitive) + .boneIndicesAndWeights(1, boneDataArray, 24) + .morphing(3) + .morphing(0,2,app.mt) + .build(*engine, app.renderable1); + +//renderable 2: +//primitive 0 = skinning and morphing triangle, bone data defined as vector for all primitives of renderable, +//primitive 1 = skinning triangle, bone data defined as vector for all primitives of renderable, + app.renderable2 = EntityManager::get().create(); + RenderableManager::Builder(2) + .boundingBox({{-1, -1, -1}, {1, 1, 1}}) + .material(0, app.mat->getDefaultInstance()) + .material(1, app.mat->getDefaultInstance()) + .geometry(0,RenderableManager::PrimitiveType::TRIANGLES, + app.vb1,app.ib,0,3) + .geometry(1,RenderableManager::PrimitiveType::TRIANGLES, + app.vb6,app.ib,0,3) + .culling(false) + .receiveShadows(false) + .castShadows(false) + .enableSkinningBuffers(true) + .skinning(app.sb2, 9, 0) + .boneIndicesAndWeights(boneDataPerRenderable) + .morphing(3) + .morphing(0,0,app.mt) + .build(*engine, app.renderable2); + +//renderable 3: +//primitive 0 = skinning of two triangles, bone data defined as vector with various number of bones per vertex, +//primitive 1 = skinning triangle, bone data defined as vector with various number of bones per vertex, + app.renderable3 = EntityManager::get().create(); + RenderableManager::Builder(2) + .boundingBox({{-1, -1, -1}, {1, 1, 1}}) + .material(0, app.mat->getDefaultInstance()) + .material(1, app.mat->getDefaultInstance()) + .geometry(0,RenderableManager::PrimitiveType::TRIANGLES, + app.vb5,app.ib2,0,6) + .geometry(1,RenderableManager::PrimitiveType::TRIANGLES, + app.vb4,app.ib,0,3) + .culling(false) + .receiveShadows(false) + .castShadows(false) + .enableSkinningBuffers(true) + .skinning(app.sb2, 9, 0) + + .boneIndicesAndWeights( 1, boneDataPerPrimitive) + .boneIndicesAndWeights( 0, boneDataPerPrimitive2) + .build(*engine, app.renderable3); + + scene->addEntity(app.renderable1); + scene->addEntity(app.renderable2); + scene->addEntity(app.renderable3); + app.camera = utils::EntityManager::get().create(); + app.cam = engine->createCamera(app.camera); + view->setCamera(app.cam); + }; + + auto cleanup = [&app](Engine* engine, View*, Scene*) { + engine->destroy(app.skybox); + engine->destroy(app.renderable1); + engine->destroy(app.renderable2); + engine->destroy(app.renderable3); + engine->destroy(app.mat); + engine->destroy(app.vb0); + engine->destroy(app.vb1); + engine->destroy(app.vb2); + engine->destroy(app.vb3); + engine->destroy(app.vb4); + engine->destroy(app.vb5); + engine->destroy(app.vb6); + engine->destroy(app.ib); + engine->destroy(app.ib2); + engine->destroy(app.sb); + engine->destroy(app.sb2); + engine->destroy(app.mt); + engine->destroy(app.boTriangle); + engine->destroyCameraComponent(app.camera); + utils::EntityManager::get().destroy(app.camera); + }; + + FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { + constexpr float ZOOM = 1.5f; + const uint32_t w = view->getViewport().width; + const uint32_t h = view->getViewport().height; + const float aspect = (float) w / h; + app.cam->setProjection(Camera::Projection::ORTHO, + -aspect * ZOOM, aspect * ZOOM, + -ZOOM, ZOOM, 0, 1); + + auto& rm = engine->getRenderableManager(); + + //skinning/bone animation for more than four bones per vertex + float t = (float)(now - (int)now); + uint offset = ((uint)now) % 9; + float s = sin(t * f::PI * 2.f) * 10; + mat4f trans[9] = {}; + for(uint i = 0; i < 9; i++){ + trans[i] = filament::math::mat4f(1);//transforms[0]; + } + mat4f trans2[9] = {}; + for(uint i = 0; i < 9; i++){ + trans2[i] = filament::math::mat4f(1);//transforms[0]; + } + mat4f transA[] = { + mat4f::scaling(float3(s / 10.f,s / 10.f, 1)), + //filament::math::mat4f(1), + mat4f::translation(float3(s, 0, 0)), + mat4f::translation(float3(s, s, 0)), + mat4f::translation(float3(0, s, 0)), + mat4f::translation(float3(-s, s, 0)), + mat4f::translation(float3(-s, 0, 0)), + mat4f::translation(float3(-s, -s, 0)), + mat4f::translation(float3(0, -s, 0)), + mat4f::translation(float3(s, -s, 0)), + filament::math::mat4f(1)}; + trans[offset] = transA[offset]; + trans2[offset] = transA[(offset + 0) % 9]; + + app.sb->setBones(*engine,trans,9,0); + app.sb2->setBones(*engine,trans2,9,0); + + //morphTarget/blendshapes animation + float z = (float)(sin(now)/2.f + 0.5f); + float weights[] = {1 - z, 0, z}; + rm.setMorphWeights(rm.getInstance(app.renderable1), weights, 3, 0); + rm.setMorphWeights(rm.getInstance(app.renderable2), weights, 3, 0); + + }); + + FilamentApp::get().run(config, setup, cleanup); + + return 0; +} diff --git a/samples/suzanneskinning.cpp b/samples/suzanneskinning.cpp new file mode 100644 index 00000000000..e3b7a0ff55a --- /dev/null +++ b/samples/suzanneskinning.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +#include + +#include + +#include + +#include + +#include "generated/resources/resources.h" +#include "generated/resources/monkey.h" + +using namespace filament; +using namespace ktxreader; +using utils::Entity; +using utils::EntityManager; +using namespace filament::math; + +struct App { + Material* material; + MaterialInstance* materialInstance; + filamesh::MeshReader::Mesh mesh; + mat4f transform; + Texture* albedo; + Texture* normal; + Texture* roughness; + Texture* metallic; + Texture* ao; + Entity renderable; + SkinningBuffer *sb; +}; + +mat4f transforms[] = {math::mat4f(1), + mat4f::translation(float3(1, 0, 0)), + mat4f::translation(float3(1, 1, 0)), + mat4f::translation(float3(0, 1, 0)), + mat4f::translation(float3(-1, 1, 0)), + mat4f::translation(float3(-1, 0, 0)), + mat4f::translation(float3(-1, -1, 0)), + mat4f::translation(float3(0, -1, 0)), + mat4f::translation(float3(1, -1, 0))}; + +std::vector> boneDataPerPrimitive(17785); //number of vertices +static const char* IBL_FOLDER = "assets/ibl/lightroom_14b"; + +static void printUsage(char* name) { + std::string exec_name(utils::Path(name).getName()); + std::string usage( + "SHOWCASE renders a Suzanne model with compressed textures.\n" + "Usage:\n" + " SHOWCASE [options]\n" + "Options:\n" + " --help, -h\n" + " Prints this message\n\n" + " --api, -a\n" + " Specify the backend API: opengl (default), vulkan, or metal\n" + ); + const std::string from("SHOWCASE"); + for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) { + usage.replace(pos, from.length(), exec_name); + } + std::cout << usage; +} + +static int handleCommandLineArguments(int argc, char* argv[], Config* config) { + static constexpr const char* OPTSTR = "ha:"; + static const struct option OPTIONS[] = { + { "help", no_argument, nullptr, 'h' }, + { "api", required_argument, nullptr, 'a' }, + { nullptr, 0, nullptr, 0 } + }; + int opt; + int option_index = 0; + while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) { + std::string arg(optarg ? optarg : ""); + switch (opt) { + default: + case 'h': + printUsage(argv[0]); + exit(0); + case 'a': + if (arg == "opengl") { + config->backend = Engine::Backend::OPENGL; + } else if (arg == "vulkan") { + config->backend = Engine::Backend::VULKAN; + } else if (arg == "metal") { + config->backend = Engine::Backend::METAL; + } else { + std::cerr << "Unrecognized backend. Must be 'opengl'|'vulkan'|'metal'.\n"; + } + break; + } + } + return optind; +} + +static Texture* loadNormalMap(Engine* engine, const uint8_t* normals, size_t nbytes) { + int w, h, n; + unsigned char* data = stbi_load_from_memory(normals, nbytes, &w, &h, &n, 3); + Texture* normalMap = Texture::Builder() + .width(uint32_t(w)) + .height(uint32_t(h)) + .levels(0xff) + .format(Texture::InternalFormat::RGB8) + .build(*engine); + Texture::PixelBufferDescriptor buffer(data, size_t(w * h * 3), + Texture::Format::RGB, Texture::Type::UBYTE, + (Texture::PixelBufferDescriptor::Callback) &stbi_image_free); + normalMap->setImage(*engine, 0, std::move(buffer)); + normalMap->generateMipmaps(*engine); + return normalMap; +} + +int main(int argc, char** argv) { + int boneCount = 9; + std::vector boneDataPerVertex; + for (uint i = 0; i < boneCount; i++) + boneDataPerVertex.push_back(float2(i, 1/(float) boneCount)); //index and weight for one vertex + for (uint i = 0; i < boneDataPerPrimitive.size(); i++){ + boneDataPerPrimitive[i] = boneDataPerVertex; + } + + Config config; + config.title = "Suzanne model with unlimited bone skinning, example with 9 bones per vertex (#17785)"; + config.iblDirectory = FilamentApp::getRootAssetsPath() + IBL_FOLDER; + + handleCommandLineArguments(argc, argv, &config); + + App app; + auto setup = [config, &app](Engine* engine, View* view, Scene* scene) { + auto& tcm = engine->getTransformManager(); + auto& rcm = engine->getRenderableManager(); + auto& em = utils::EntityManager::get(); + + Ktx2Reader reader(*engine); + + reader.requestFormat(Texture::InternalFormat::DXT3_SRGBA); + reader.requestFormat(Texture::InternalFormat::DXT3_RGBA); + + // Uncompressed formats are lower priority, so they get added last. + reader.requestFormat(Texture::InternalFormat::SRGB8_A8); + reader.requestFormat(Texture::InternalFormat::RGBA8); + + constexpr auto sRGB = Ktx2Reader::TransferFunction::sRGB; + constexpr auto LINEAR = Ktx2Reader::TransferFunction::LINEAR; + + app.albedo = reader.load(MONKEY_ALBEDO_DATA, MONKEY_ALBEDO_SIZE, sRGB); + app.ao = reader.load(MONKEY_AO_DATA, MONKEY_AO_SIZE, LINEAR); + app.metallic = reader.load(MONKEY_METALLIC_DATA, MONKEY_METALLIC_SIZE, LINEAR); + app.roughness = reader.load(MONKEY_ROUGHNESS_DATA, MONKEY_ROUGHNESS_SIZE, LINEAR); + +#if !defined(NDEBUG) + using namespace utils; + slog.i << "Resolved format for albedo: " << app.albedo->getFormat() << io::endl; + slog.i << "Resolved format for ambient occlusion: " << app.ao->getFormat() << io::endl; + slog.i << "Resolved format for metallic: " << app.metallic->getFormat() << io::endl; + slog.i << "Resolved format for roughness: " << app.roughness->getFormat() << io::endl; +#endif + + app.normal = loadNormalMap(engine, MONKEY_NORMAL_DATA, MONKEY_NORMAL_SIZE); + TextureSampler sampler(TextureSampler::MinFilter::LINEAR_MIPMAP_LINEAR, + TextureSampler::MagFilter::LINEAR); + + // Instantiate material. + app.material = Material::Builder() + .package(RESOURCES_TEXTUREDLIT_DATA, RESOURCES_TEXTUREDLIT_SIZE).build(*engine); + app.materialInstance = app.material->createInstance(); + app.materialInstance->setParameter("albedo", app.albedo, sampler); + app.materialInstance->setParameter("ao", app.ao, sampler); + app.materialInstance->setParameter("metallic", app.metallic, sampler); + app.materialInstance->setParameter("normal", app.normal, sampler); + app.materialInstance->setParameter("roughness", app.roughness, sampler); + + auto ibl = FilamentApp::get().getIBL()->getIndirectLight(); + ibl->setIntensity(100000); + ibl->setRotation(mat3f::rotation(0.5f, float3{ 0, 1, 0 })); + + // Add geometry into the scene. + app.mesh = filamesh::MeshReader::loadMeshFromBuffer(engine, MONKEY_SUZANNE_DATA, nullptr, + nullptr, app.materialInstance); + auto ti = tcm.getInstance(app.mesh.renderable); + app.transform = mat4f{ mat3f(1), float3(0, 0, 0) } * tcm.getWorldTransform(ti); + + app.sb = SkinningBuffer::Builder() + .boneCount(256) + .initialize(true) + .build(*engine); + app.sb->setBones(*engine, transforms,9,0); + + app.renderable = EntityManager::get().create(); + RenderableManager::Builder(1) + .boundingBox({{ -2, -2, -2 }, { 2, 2, 2 }}) + .material(0, app.materialInstance) + .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.mesh.vertexBuffer, app.mesh.indexBuffer) + .receiveShadows(true) + .castShadows(false) + .enableSkinningBuffers(true) + .skinning(app.sb, 9, 0) + .boneIndicesAndWeights(0, boneDataPerPrimitive) + .build(*engine, app.renderable); + fprintf(stdout,"RenderableManager built done \n"); + + scene->addEntity(app.renderable); + tcm.setTransform(ti, app.transform); + }; + + auto cleanup = [&app](Engine* engine, View*, Scene*) { + engine->destroy(app.materialInstance); + engine->destroy(app.mesh.renderable); + engine->destroy(app.material); + engine->destroy(app.albedo); + engine->destroy(app.normal); + engine->destroy(app.roughness); + engine->destroy(app.metallic); + engine->destroy(app.ao); + engine->destroy(app.renderable); + engine->destroy(app.sb); + engine->destroy(app.mesh.vertexBuffer); + engine->destroy(app.mesh.indexBuffer); + }; + +FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { + + //skinning/bone animation for more than four bones per vertex + float t = now / 10.f; + float s1 = sin(t * f::PI * 4.f) * 10; + float s2 = sin(t * f::PI * 6.f) * 10; + float s3 = sin(t * f::PI * 8.f) * 10; + + //create bone transformations + mat4f trans[] = { + mat4f::scaling(float3(s1 + 10, 1.f, 1.f)), + mat4f::scaling(float3(1.f, s2 + 10, 1.f)), + mat4f::scaling(float3(1.f, 1.f, s3 + 10)), + mat4f::rotation(t * f::PI * 16.f, float3(1, 0, 0)), + mat4f::rotation(t * f::PI * 4.f, float3(0, 1, 0)), + mat4f::rotation(t * f::PI * 8.f, float3(0, 0, 1)), + mat4f::translation(float3(s1, 0, 0)), + mat4f::translation(float3(0, s2, 0)), + mat4f::translation(float3(0, 0, s3)), +// mat4f::translation(float3(0, 0, 20))*mat4f::rotation(t * f::PI * 2.f, float3(1, 0, 0))*mat4f::translation(float3(0, 0, -20)) + }; + + app.sb->setBones(*engine,trans,9,0); + }); + + FilamentApp::get().run(config, setup, cleanup); + + return 0; +} diff --git a/shaders/src/getters.vs b/shaders/src/getters.vs index cc06a19f5c3..be835831980 100644 --- a/shaders/src/getters.vs +++ b/shaders/src/getters.vs @@ -33,6 +33,7 @@ int getVertexIndex() { #endif #if defined(VARIANT_HAS_SKINNING_OR_MORPHING) +#define MAX_SKINNING_BUFFER_WIDTH 2048u vec3 mulBoneNormal(vec3 n, uint i) { highp mat3 cof; @@ -62,18 +63,83 @@ vec3 mulBoneVertex(vec3 v, uint i) { return v.x * m[0].xyz + (v.y * m[1].xyz + (v.z * m[2].xyz + m[3].xyz)); } +void skinPosition(inout vec3 p, const uvec4 ids, const vec4 weights) { + //standard skinning for 4 weights, some of them could be zero + if (weights.w >= 0.0){ + p = weights.x * mulBoneVertex(p, uint(ids.x)) + + weights.y * mulBoneVertex(p, uint(ids.y)) + + weights.z * mulBoneVertex(p, uint(ids.z)) + + weights.w * mulBoneVertex(p, uint(ids.w)); + return; + } + //skinning for >4 weights + vec3 posSum = weights.x * mulBoneVertex(p, uint(ids.x)); + posSum += weights.y * mulBoneVertex(p, uint(ids.y)); + posSum += weights.z * mulBoneVertex(p, uint(ids.z));uint pairIndex = -uint(weights.w + 1.); + uint pairStop = pairIndex + uint(ids.w - 3u); + for (uint i = pairIndex; i < pairStop; i = i + 1u) { + ivec2 texcoord = ivec2(i % MAX_SKINNING_BUFFER_WIDTH, i / MAX_SKINNING_BUFFER_WIDTH); + vec2 indexWeight = texelFetch(bonesBuffer_indicesAndWeights, texcoord, 0).rg; + posSum += mulBoneVertex(p, uint(indexWeight.r)) * indexWeight.g; + } + p = posSum; +} + void skinNormal(inout vec3 n, const uvec4 ids, const vec4 weights) { - n = mulBoneNormal(n, ids.x) * weights.x - + mulBoneNormal(n, ids.y) * weights.y - + mulBoneNormal(n, ids.z) * weights.z - + mulBoneNormal(n, ids.w) * weights.w; + //standard skinning for 4 weights, some of them could be zero + if (weights.w >= 0.0){ + n = weights.x * mulBoneVertex(n, uint(ids.x)) + + weights.y * mulBoneVertex(n, uint(ids.y)) + + weights.z * mulBoneVertex(n, uint(ids.z)) + + weights.w * mulBoneVertex(n, uint(ids.w)); + return; + } + //skinning for >4 weights + vec3 normSum = weights.x * mulBoneNormal(n, uint(ids.x)); + normSum += weights.y * mulBoneNormal(n, uint(ids.y)); + normSum += weights.z * mulBoneNormal(n, uint(ids.z)); + uint pairIndex = -uint(weights.w + 1.); + uint pairStop = pairIndex + uint(ids.w - 3u); + for (uint i = pairIndex; i < pairStop; i = i + 1u) { + ivec2 texcoord = ivec2(i % MAX_SKINNING_BUFFER_WIDTH, i / MAX_SKINNING_BUFFER_WIDTH); + vec2 indexWeight = texelFetch(bonesBuffer_indicesAndWeights, texcoord, 0).rg; + + normSum += mulBoneNormal(n, uint(indexWeight.r)) * indexWeight.g; + } + n = normSum; } -void skinPosition(inout vec3 p, const uvec4 ids, const vec4 weights) { - p = mulBoneVertex(p, ids.x) * weights.x - + mulBoneVertex(p, ids.y) * weights.y - + mulBoneVertex(p, ids.z) * weights.z - + mulBoneVertex(p, ids.w) * weights.w; +void skinTwoVectors(inout vec3 n, inout vec3 t, const uvec4 ids, const vec4 weights) { + ///standard skinning for 4 weights, some of them could be zero + if (weights.w >= 0.0){ + n = weights.x * mulBoneVertex(n, uint(ids.x)) + + weights.y * mulBoneVertex(n, uint(ids.y)) + + weights.z * mulBoneVertex(n, uint(ids.z)) + + weights.w * mulBoneVertex(n, uint(ids.w)); + t = weights.x * mulBoneVertex(t, uint(ids.x)) + + weights.y * mulBoneVertex(t, uint(ids.y)) + + weights.z * mulBoneVertex(t, uint(ids.z)) + + weights.w * mulBoneVertex(t, uint(ids.w)); + return; + } + //skinning for >4 weights + vec3 normSum = weights.x * mulBoneNormal(n, uint(ids.x)); + normSum += weights.y * mulBoneNormal(n, uint(ids.y)) ; + normSum += weights.z * mulBoneNormal(n, uint(ids.z)); + vec3 tangSum = weights.x * mulBoneNormal(t, uint(ids.x)); + tangSum += weights.y * mulBoneNormal(t, uint(ids.y)); + tangSum += weights.z * mulBoneNormal(t, uint(ids.z)); + uint pairIndex = -uint(weights.w + 1.); + uint pairStop = pairIndex + uint(ids.w - 3u); + for (uint i = pairIndex; i < pairStop; i = i + 1u) { + ivec2 texcoord = ivec2(i % MAX_SKINNING_BUFFER_WIDTH, i / MAX_SKINNING_BUFFER_WIDTH); + vec2 indexWeight = texelFetch(bonesBuffer_indicesAndWeights, texcoord, 0).rg; + + normSum += mulBoneNormal(n, uint(indexWeight.r)) * indexWeight.g; + tangSum += mulBoneNormal(t, uint(indexWeight.r)) * indexWeight.g; + } + n = normSum; + t = tangSum; } #define MAX_MORPH_TARGET_BUFFER_WIDTH 2048 diff --git a/shaders/src/main.vs b/shaders/src/main.vs index 8183b235196..37bbc123a9b 100644 --- a/shaders/src/main.vs +++ b/shaders/src/main.vs @@ -80,9 +80,8 @@ void main() { #endif } - if ((object_uniforms_flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0) { - skinNormal(material.worldNormal, mesh_bone_indices, mesh_bone_weights); - skinNormal(vertex_worldTangent.xyz, mesh_bone_indices, mesh_bone_weights); + if ((object_uniforms.flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) { + skinTwoVectors(material.worldNormal, vertex_worldTangent.xyz, mesh_bone_indices, mesh_bone_weights); } #endif From 3afccd4ea990b45f6cd7888d059133c5ec53b5c9 Mon Sep 17 00:00:00 2001 From: brunojezek Date: Wed, 26 Apr 2023 14:43:03 +0200 Subject: [PATCH 03/24] Change std::vector to utils::FixedCapacityVector To avoid using stl in public API std::vectors were changed to utils::FixedCapacityVector --- filament/include/filament/RenderableManager.h | 7 +-- filament/src/components/RenderableManager.cpp | 14 +++--- samples/helloskinningbuffer_morebones.cpp | 15 +++--- samples/skinningtest.cpp | 48 ++++++++++--------- samples/suzanneskinning.cpp | 10 ++-- 5 files changed, 49 insertions(+), 45 deletions(-) diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index 498c34823d6..26c837dd709 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -26,6 +26,7 @@ #include #include +#include #include @@ -401,7 +402,7 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * @return Builder reference for chaining calls. */ Builder& boneIndicesAndWeights(size_t primitiveIndex, - std::vector> const &indicesAndWeightsVector); + utils::FixedCapacityVector> const &indicesAndWeightsVector); /** * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the * second value is the bone weight. The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS @@ -416,7 +417,7 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * @return Builder reference for chaining calls. */ Builder& boneIndicesAndWeights( - std::vector>> const &indicesAndWeightsVectors) noexcept; + utils::FixedCapacityVector< utils::FixedCapacityVector< utils::FixedCapacityVector>> const &indicesAndWeightsVectors) noexcept; /** * Controls if the renderable has vertex morphing targets, zero by default. This is @@ -569,7 +570,7 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { } morphing; struct { bool bonePairsSet = false; - std::vector> bonePairs; //bone indices and weights for each entry(primitive) + utils::FixedCapacityVector> bonePairs; //bone indices and weights for each entry(primitive) } skinning; }; void processBoneIndicesAndWights(Engine& engine, utils::Entity entity); diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 3160556ec01..ee26b05cdd7 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -221,12 +221,12 @@ RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(si "[primitive @ %u] bone indices and weights pairs count (%u) must be a multiple of vertex count (%u)", primitiveIndex, count, vertexCount); - std::vector> bonePairs; + utils::FixedCapacityVector> bonePairs(vertexCount); for( size_t iVertex = 0; iVertex < vertexCount; iVertex++){ - std::vector vertexData(pairsPerVertexCount); + utils::FixedCapacityVector vertexData(pairsPerVertexCount); std::memcpy(&vertexData[0], &indicesAndWeights[offset + iVertex * pairsPerVertexCount], pairsPerVertexCount * sizeof(float2)); - bonePairs.push_back(vertexData); + bonePairs[iVertex] = vertexData; } return boneIndicesAndWeights(primitiveIndex, bonePairs); } @@ -256,7 +256,7 @@ RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights( } RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(size_t primitiveIndex, - const std::vector> &indicesAndWeightsVector) { + const utils::FixedCapacityVector< utils::FixedCapacityVector> &indicesAndWeightsVector) { auto count = indicesAndWeightsVector.size(); if (!count) { // skip if no skinning data @@ -283,8 +283,8 @@ RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(si } RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights( - const std::vector>> &indicesAndWeightsVectors) noexcept{ - for (size_t iEntry = 0, c = min(mImpl->mEntries.size(), indicesAndWeightsVectors.size()); iEntry < c; iEntry++) + const utils::FixedCapacityVector>> &indicesAndWeightsVectors) noexcept{ + for (size_t iEntry = 0, c = min((uint)mImpl->mEntries.size(), indicesAndWeightsVectors.size()); iEntry < c; iEntry++) boneIndicesAndWeights(iEntry, indicesAndWeightsVectors[iEntry]); return *this; } @@ -344,7 +344,7 @@ void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Ent for (size_t iVertex = 0, vertexCount = entry.skinning.bonePairs.size(); iVertex < vertexCount; iVertex++){ auto pairCountPerVertex = entry.skinning.bonePairs[iVertex].size(); maxPairsCount += pairCountPerVertex; - maxPairsCountPerPrimitive = max(pairCountPerVertex, maxPairsCountPerPrimitive); + maxPairsCountPerPrimitive = max(pairCountPerVertex, (uint)maxPairsCountPerPrimitive); } } } diff --git a/samples/helloskinningbuffer_morebones.cpp b/samples/helloskinningbuffer_morebones.cpp index 04ea527192c..71c9c220f4a 100644 --- a/samples/helloskinningbuffer_morebones.cpp +++ b/samples/helloskinningbuffer_morebones.cpp @@ -75,19 +75,20 @@ mat4f transforms[] = {math::mat4f(1.f), mat4f::translation(float3(1, -1, 0))}; -std::vector> boneDataPerPrimitive; +utils::FixedCapacityVector> boneDataPerPrimitive(3); int main(int argc, char** argv) { Config config; config.title = "skinning buffer common for two renderables"; auto offset = 0; - std::vector boneDataPerVertex; + utils::FixedCapacityVector boneDataPerVertex(9); float w = 1/9.f; - for (uint i = 0; i < 9; i++) - boneDataPerVertex.push_back(float2 (i, w)); - boneDataPerPrimitive.push_back(boneDataPerVertex); - boneDataPerPrimitive.push_back(boneDataPerVertex); - boneDataPerPrimitive.push_back(boneDataPerVertex); + for (size_t i = 0; i < 9; i++) + boneDataPerVertex[i] = float2 (i, w); + auto i = 0; + boneDataPerPrimitive[i++] = boneDataPerVertex; + boneDataPerPrimitive[i++] = boneDataPerVertex; + boneDataPerPrimitive[i++] = boneDataPerVertex; App app; auto setup = [&app](Engine* engine, View* view, Scene* scene) { diff --git a/samples/skinningtest.cpp b/samples/skinningtest.cpp index 9ce6e3e4a64..71e43ec19fd 100644 --- a/samples/skinningtest.cpp +++ b/samples/skinningtest.cpp @@ -104,44 +104,46 @@ mat4f transforms[] = {math::mat4f(1), mat4f::translation(float3(0, -1, 0)), mat4f::translation(float3(1, -1, 0))}; -std::vector> boneDataPerPrimitive, boneDataPerPrimitive2; -std::vector>> boneDataPerRenderable; +utils::FixedCapacityVector> boneDataPerPrimitive(3), boneDataPerPrimitive2(6); +utils::FixedCapacityVector>> boneDataPerRenderable(3); int main(int argc, char** argv) { Config config; config.title = "skinning test with more than 4 bones per vertex"; - std::vector boneDataPerVertex; + utils::FixedCapacityVector boneDataPerVertex(8); float w = 1 / 8.f; for (uint i = 0; i < 8; i++){ boneDataArray[i] = float2 (i, w); boneDataArray[i + 8] = float2 (i, w); boneDataArray[i + 16] = float2 (i, w); - boneDataPerVertex.push_back(float2 (i, w)); + boneDataPerVertex[i] = float2 (i, w); } - std::vector boneDataPerVertex2; + utils::FixedCapacityVector boneDataPerVertex2(3); w = 1 / 3.f; for (uint i = 0; i < 3; i++){ - boneDataPerVertex2.push_back(float2 (i, w)); + boneDataPerVertex2[i] = float2 (i, w); } - std::vector emptyBoneDataPerVertex(0); - std::vector> emptyBoneDataPerPrimitive(0); - boneDataPerPrimitive.push_back(boneDataPerVertex); - boneDataPerPrimitive.push_back(boneDataPerVertex); - boneDataPerPrimitive.push_back(boneDataPerVertex); - - boneDataPerPrimitive2.push_back(boneDataPerVertex); - boneDataPerPrimitive2.push_back(boneDataPerVertex2); - boneDataPerPrimitive2.push_back(boneDataPerVertex); - boneDataPerPrimitive2.push_back(boneDataPerVertex); - boneDataPerPrimitive2.push_back(boneDataPerVertex2); - boneDataPerPrimitive2.push_back(boneDataPerVertex); -// boneDataPerPrimitive.push_back(emptyBoneDataPerVertex); - - boneDataPerRenderable.push_back(boneDataPerPrimitive); - boneDataPerRenderable.push_back(boneDataPerPrimitive); - boneDataPerRenderable.push_back(emptyBoneDataPerPrimitive); + utils::FixedCapacityVector emptyBoneDataPerVertex(0); + utils::FixedCapacityVector> emptyBoneDataPerPrimitive(0); + auto i = 0; + boneDataPerPrimitive[i++] = boneDataPerVertex; + boneDataPerPrimitive[i++] = boneDataPerVertex; + boneDataPerPrimitive[i++] = boneDataPerVertex; + + i = 0; + boneDataPerPrimitive2[i++] = boneDataPerVertex; + boneDataPerPrimitive2[i++] = boneDataPerVertex2; + boneDataPerPrimitive2[i++] = boneDataPerVertex; + boneDataPerPrimitive2[i++] = boneDataPerVertex; + boneDataPerPrimitive2[i++] = boneDataPerVertex2; + boneDataPerPrimitive2[i++] = boneDataPerVertex; + + i = 0; + boneDataPerRenderable[i++] = boneDataPerPrimitive; + boneDataPerRenderable[i++] = boneDataPerPrimitive; + boneDataPerRenderable[i++] = emptyBoneDataPerPrimitive; App app; auto setup = [&app](Engine* engine, View* view, Scene* scene) { diff --git a/samples/suzanneskinning.cpp b/samples/suzanneskinning.cpp index e3b7a0ff55a..bfd08e5df0a 100644 --- a/samples/suzanneskinning.cpp +++ b/samples/suzanneskinning.cpp @@ -77,7 +77,7 @@ mat4f transforms[] = {math::mat4f(1), mat4f::translation(float3(0, -1, 0)), mat4f::translation(float3(1, -1, 0))}; -std::vector> boneDataPerPrimitive(17785); //number of vertices +utils::FixedCapacityVector> boneDataPerPrimitive(17785); //number of vertices static const char* IBL_FOLDER = "assets/ibl/lightroom_14b"; static void printUsage(char* name) { @@ -150,10 +150,10 @@ static Texture* loadNormalMap(Engine* engine, const uint8_t* normals, size_t nby int main(int argc, char** argv) { int boneCount = 9; - std::vector boneDataPerVertex; - for (uint i = 0; i < boneCount; i++) - boneDataPerVertex.push_back(float2(i, 1/(float) boneCount)); //index and weight for one vertex - for (uint i = 0; i < boneDataPerPrimitive.size(); i++){ + utils::FixedCapacityVector boneDataPerVertex(boneCount); + for (size_t i = 0; i < boneCount; i++) + boneDataPerVertex[i] = float2(i, 1/(float) boneCount); //index and weight for one vertex + for (size_t i = 0; i < boneDataPerPrimitive.size(); i++){ boneDataPerPrimitive[i] = boneDataPerVertex; } From 7a54399bb70c372bf932ba1c78be786b05f77530 Mon Sep 17 00:00:00 2001 From: brunojezek Date: Thu, 27 Apr 2023 14:39:55 +0200 Subject: [PATCH 04/24] Minor changes according to the PR revision process remove offset parameter of boneIndicesAndWeights methods rename variables format comments --- filament/include/filament/RenderableManager.h | 13 +- filament/src/RenderPass.h | 2 +- filament/src/components/RenderableManager.cpp | 49 +++---- filament/src/details/SkinningBuffer.cpp | 24 ++-- filament/src/details/VertexBuffer.cpp | 30 ++--- filament/src/details/VertexBuffer.h | 6 +- .../include/private/filament/SibStructs.h | 2 +- samples/hellomorphing.cpp | 20 +-- samples/helloskinning.cpp | 2 +- samples/helloskinningbuffer.cpp | 8 +- samples/helloskinningbuffer_morebones.cpp | 29 +++-- samples/skinningtest.cpp | 121 +++++++++--------- samples/suzanneskinning.cpp | 13 +- shaders/src/getters.vs | 12 +- 14 files changed, 168 insertions(+), 163 deletions(-) diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index 26c837dd709..8066f33347a 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -363,11 +363,10 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * @param primitiveIndex zero-based index of the primitive, must be less than the primitive count passed to Builder constructor * @param indicesAndWeights pairs of bone index and bone weight for all vertices sequentially, * @param count number of all pairs, must be a multiple of vertexCount of the primitive - * @param offset specifies where in the indicesAndWeights buffer to start reading (expressed as a number of pairs) * * @return Builder reference for chaining calls. */ - Builder& boneIndicesAndWeights(size_t primitiveIndex,math::float2 const* indicesAndWeights, size_t count, size_t offset = 0); + Builder& boneIndicesAndWeights(size_t primitiveIndex,math::float2 const* indicesAndWeights, size_t count); /** * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the @@ -381,11 +380,10 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * * @param indicesAndWeightsArray pairs of bone index and bone weight for all vertices and primitives sequentially * @param count number of all pairs, must be a multiple of vertexCount by primitiveCount - * @param offset specifies where in the indicesAndWeights buffer to start reading (expressed as a number of pairs) * * @return Builder reference for chaining calls. */ - Builder& boneIndicesAndWeights(math::float2 const* indicesAndWeightsArray, size_t count, size_t offset = 0); + Builder& boneIndicesAndWeights(math::float2 const* indicesAndWeightsArray, size_t count); /** * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the @@ -402,7 +400,8 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * @return Builder reference for chaining calls. */ Builder& boneIndicesAndWeights(size_t primitiveIndex, - utils::FixedCapacityVector> const &indicesAndWeightsVector); + utils::FixedCapacityVector< + utils::FixedCapacityVector> const &indicesAndWeightsVector); /** * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the * second value is the bone weight. The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS @@ -417,7 +416,9 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * @return Builder reference for chaining calls. */ Builder& boneIndicesAndWeights( - utils::FixedCapacityVector< utils::FixedCapacityVector< utils::FixedCapacityVector>> const &indicesAndWeightsVectors) noexcept; + utils::FixedCapacityVector< + utils::FixedCapacityVector< + utils::FixedCapacityVector>> const &indicesAndWeightsVectors) noexcept; /** * Controls if the renderable has vertex morphing targets, zero by default. This is diff --git a/filament/src/RenderPass.h b/filament/src/RenderPass.h index 953164ae66a..6e1254b4e77 100644 --- a/filament/src/RenderPass.h +++ b/filament/src/RenderPass.h @@ -250,7 +250,7 @@ class RenderPass { struct alignas(8) Command { // 64 bytes CommandKey key = 0; // 8 bytes PrimitiveInfo primitive; // 48 bytes - uint64_t reserved[2] = {}; // 16 bytes + uint64_t reserved[1] = {}; // 8 bytes bool operator < (Command const& rhs) const noexcept { return key < rhs.key; } // placement new declared as "throw" to avoid the compiler's null-check inline void* operator new (std::size_t, void* ptr) { diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index ee26b05cdd7..055c7f5824c 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -208,7 +208,7 @@ RenderableManager::Builder& RenderableManager::Builder::enableSkinningBuffers(bo } RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(size_t primitiveIndex, - math::float2 const* indicesAndWeights, size_t count, size_t offset) { + math::float2 const* indicesAndWeights, size_t count) { std::vector& entries = mImpl->mEntries; ASSERT_PRECONDITION(primitiveIndex < entries.size() && primitiveIndex >= 0, @@ -224,7 +224,7 @@ RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(si utils::FixedCapacityVector> bonePairs(vertexCount); for( size_t iVertex = 0; iVertex < vertexCount; iVertex++){ utils::FixedCapacityVector vertexData(pairsPerVertexCount); - std::memcpy(&vertexData[0], &indicesAndWeights[offset + iVertex * pairsPerVertexCount], + std::memcpy(&vertexData[0], &indicesAndWeights[iVertex * pairsPerVertexCount], pairsPerVertexCount * sizeof(float2)); bonePairs[iVertex] = vertexData; } @@ -232,7 +232,7 @@ RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(si } RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights( - math::float2 const* indicesAndWeightsArray, size_t count, size_t offset){ + math::float2 const* indicesAndWeightsArray, size_t count){ std::vector& entries = mImpl->mEntries; size_t primitiveCount = entries.size(); size_t allVerticesCount = 0; @@ -244,7 +244,7 @@ RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights( ASSERT_PRECONDITION(pairsPerAllVerticesCount > 0 && count % allVerticesCount == 0, "bone indices and weights pairs count (%u) must be a multiple of vertex counts of all primitives (%u)", count, allVerticesCount); - size_t pairSkipped = offset; + size_t pairSkipped = 0; for (size_t iEntry = 0; iEntry < primitiveCount; iEntry++){ size_t pairsPerPrimitiveCount = pairsPerAllVerticesCount * entries[iEntry].vertices->getVertexCount(); boneIndicesAndWeights(iEntry, @@ -260,7 +260,7 @@ RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(si auto count = indicesAndWeightsVector.size(); if (!count) { // skip if no skinning data - //mImpl->mEntries[primitiveIndex].skinning.bonePairsSet = true; + // mImpl->mEntries[primitiveIndex].skinning.bonePairsSet = true; return *this; } std::vector& entries = mImpl->mEntries; @@ -276,7 +276,7 @@ RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(si auto& skinning = entries[primitiveIndex].skinning; ASSERT_PRECONDITION(skinning.bonePairs.empty(), "[primitive @ %u] bone indices and weights data already exists", primitiveIndex); - skinning.bonePairs = indicesAndWeightsVector; //copy + skinning.bonePairs = indicesAndWeightsVector; // copy skinning.bonePairsSet = true; return *this; @@ -327,6 +327,7 @@ RenderableManager::Builder& RenderableManager::Builder::globalBlendOrderEnabled( return *this; } +UTILS_NOINLINE void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Entity entity){ size_t maxPairsCount = 0; size_t maxPairsCountPerPrimitive = 0; @@ -348,17 +349,17 @@ void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Ent } } } - size_t pairsCount = 0; //counting of number of pairs stored in texture - float2* tempPairs; //temporary indices and weights for one vertex - if (maxPairsCount) { //at least one primitive has bone indices and weights + size_t pairsCount = 0; // counting of number of pairs stored in texture + float2* tempPairs; // temporary indices and weights for one vertex + if (maxPairsCount) { // at least one primitive has bone indices and weights mImpl->mBoneIndicesAndWeight = (float2*) malloc( - maxPairsCount * 2 * 4); //final texture data, indices and weights + maxPairsCount * 2 * 4); // final texture data, indices and weights tempPairs = (float2*) malloc(maxPairsCountPerPrimitive * 2 - * 4); //temporary indices and weights for one vertex + * 4); // temporary indices and weights for one vertex } for (size_t iEntry = 0, entriesCount = mImpl->mEntries.size(); iEntry < entriesCount; iEntry++) { auto& entry = mImpl->mEntries[iEntry]; - //bone data are defined boneIndicesAndWeights() + // bone data are defined boneIndicesAndWeights() if (entry.skinning.bonePairsSet) { if (entry.skinning.bonePairs.size()){ size_t vertexCount = entry.vertices->getVertexCount(); @@ -366,7 +367,7 @@ void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Ent auto skinWeights = (float*) malloc(vertexCount * 4 * 4); for(size_t iVertex = 0; iVertex < vertexCount; iVertex++) { size_t pairsPerVertexCount = entry.skinning.bonePairs[iVertex].size(); - //if (!pairsPerVertexCount) continue; + // if (!pairsPerVertexCount) continue; size_t tempPairCount = 0; float boneWeightsSum = 0; for (size_t k = 0; k < pairsPerVertexCount; k++){ @@ -397,35 +398,35 @@ void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Ent << "] sum of bone weights of vertex=" << iVertex << " is " << boneWeightsSum << ", it should be one. Weights will be normalized." << utils::io::endl; - //prepare data for vertex attributes + // prepare data for vertex attributes auto offset = iVertex * 4; - //set attributes, indices and weights, for <= 4 pairs + // set attributes, indices and weights, for <= 4 pairs for (size_t j = 0, c = min(tempPairCount, 4ul); j < c; j++) { skinJoints[j + offset] = tempPairs[j][0]; skinWeights[j + offset] = tempPairs[j][1] / boneWeightsSum; } - //reset rest weights + // reset rest weights for (size_t j = tempPairCount; j < 4; j++) skinWeights[j + offset] = 0; - //prepare data for texture + // prepare data for texture if (tempPairCount > 4) - { //set attributes, indices and weights, for > 4 pairs - skinWeights[3 + offset] = -(float) (pairsCount + 1); //negative offset to texture 0..-1, 1..-2 - skinJoints[3 + offset] = (ushort) tempPairCount; //number pairs per vertex in texture + { // set attributes, indices and weights, for > 4 pairs + skinWeights[3 + offset] = -(float) (pairsCount + 1); // negative offset to texture 0..-1, 1..-2 + skinJoints[3 + offset] = (ushort) tempPairCount; // number pairs per vertex in texture for (size_t j = 3; j < tempPairCount; j++) { mImpl->mBoneIndicesAndWeight[pairsCount][0] = tempPairs[j][0]; mImpl->mBoneIndicesAndWeight[pairsCount][1] = tempPairs[j][1] / boneWeightsSum; pairsCount++; } } - } //for all vertices per primitive + } // for all vertices per primitive downcast(mImpl->mEntries[iEntry].vertices) ->updateBoneIndicesAndWeights(downcast(engine), skinJoints, skinWeights); } } - }//for all primitives + }// for all primitives mImpl->mBoneIndicesAndWeightsCount = pairsCount; } @@ -449,7 +450,7 @@ RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& eng mImpl->mInstanceCount, bufferInstanceCount); } - if (mImpl->mSkinningBoneCount > 0 || mImpl->mSkinningBufferMode) { + if (UTILS_LIKELY(mImpl->mSkinningBoneCount) || UTILS_LIKELY(mImpl->mSkinningBufferMode)) { processBoneIndicesAndWights(engine, entity); } @@ -653,7 +654,7 @@ void FRenderableManager::create( } if (UTILS_UNLIKELY(boneCount > 0) && (builder->mBoneIndicesAndWeightsCount > 0)){ - //create and set texture for bone indices and weights + // create and set texture for bone indices and weights Bones& bones = manager[ci].bones; FSkinningBuffer::HandleIndicesAndWeights handle = downcast(builder->mSkinningBuffer)-> createIndicesAndWeightsHandle(downcast(engine), builder->mBoneIndicesAndWeightsCount); diff --git a/filament/src/details/SkinningBuffer.cpp b/filament/src/details/SkinningBuffer.cpp index dd8544a56e7..e03585870bc 100644 --- a/filament/src/details/SkinningBuffer.cpp +++ b/filament/src/details/SkinningBuffer.cpp @@ -168,17 +168,17 @@ void FSkinningBuffer::setBones(FEngine& engine, Handle // When you change this value, you must change MAX_SKINNING_BUFFER_WIDTH at getters.vs constexpr size_t MAX_SKINNING_BUFFER_WIDTH = 2048; -static inline size_t getWidth(size_t pairCount) noexcept { +static inline size_t getSkinningBufferWidth(size_t pairCount) noexcept { return std::min(pairCount, MAX_SKINNING_BUFFER_WIDTH); } -static inline size_t getHeight(size_t pairCount) noexcept { +static inline size_t getSkinningBufferHeight(size_t pairCount) noexcept { return (pairCount + MAX_SKINNING_BUFFER_WIDTH) / MAX_SKINNING_BUFFER_WIDTH; } -inline size_t getSize(size_t pairCount) noexcept { - const size_t stride = getWidth(pairCount); - const size_t height = getHeight(pairCount); +inline size_t getSkinningBufferSize(size_t pairCount) noexcept { + const size_t stride = getSkinningBufferWidth(pairCount); + const size_t height = getSkinningBufferHeight(pairCount); return Texture::PixelBufferDescriptor::computeDataSize( Texture::PixelBufferDescriptor::PixelDataFormat::RG, Texture::PixelBufferDescriptor::PixelDataType::FLOAT, @@ -191,7 +191,7 @@ void updateDataAt(backend::DriverApi& driver, const char* out, size_t elementSize, size_t count, size_t size) { - size_t const textureWidth = getWidth( count);//size); + size_t const textureWidth = getSkinningBufferWidth( count);//size); size_t const lineCount = count / textureWidth; size_t const lastLineCount = count % textureWidth; @@ -222,20 +222,20 @@ void updateDataAt(backend::DriverApi& driver, FSkinningBuffer::HandleIndicesAndWeights FSkinningBuffer::createIndicesAndWeightsHandle(FEngine& engine, size_t count) { backend::Handle samplerHandle; - backend::Handle textureHandle; //bone indices and weights + backend::Handle textureHandle; // bone indices and weights FEngine::DriverApi& driver = engine.getDriverApi(); - auto size = getSize(count); + auto size = getSkinningBufferSize(count); // create a texture for skinning pairs data (bone index and weight) - size = getSize(count); + size = getSkinningBufferSize(count); textureHandle = driver.createTexture(SamplerType::SAMPLER_2D, 1, TextureFormat::RG32F, 1, - getWidth(size), getHeight(size), 1, + getSkinningBufferWidth(size), getSkinningBufferHeight(size), 1, TextureUsage::DEFAULT); samplerHandle = driver.createSamplerGroup(PerRenderPrimitiveSkinningSib::SAMPLER_COUNT); SamplerGroup samplerGroup(PerRenderPrimitiveSkinningSib::SAMPLER_COUNT); - samplerGroup.setSampler(PerRenderPrimitiveSkinningSib::BONE_IaW, + samplerGroup.setSampler(PerRenderPrimitiveSkinningSib::BONE_INDICES_AND_WEIGHTS, {textureHandle, {}}); driver.updateSamplerGroup(samplerHandle, samplerGroup.toBufferDescriptor(driver)); @@ -249,7 +249,7 @@ void FSkinningBuffer::setIndicesAndWeightsData(FEngine& engine, backend::Handle textureHandle, math::float2 const* pairs, size_t count) { FEngine::DriverApi& driver = engine.getDriverApi(); - auto size = getSize(count); + auto size = getSkinningBufferSize(count); auto* out = (float2*) malloc(size); std::transform(pairs, pairs + count, out, [](const float2& p) { return float2(p); }); diff --git a/filament/src/details/VertexBuffer.cpp b/filament/src/details/VertexBuffer.cpp index 0ee1bd1aae3..e8744cc7d74 100644 --- a/filament/src/details/VertexBuffer.cpp +++ b/filament/src/details/VertexBuffer.cpp @@ -207,8 +207,8 @@ void FVertexBuffer::terminate(FEngine& engine) { } } if (mBoneBufferObjectsUsed){ - driver.destroyBufferObject(mBoJointsHandle); - driver.destroyBufferObject(mBoWeightsHandle); + driver.destroyBufferObject(mBoneJointsHandle); + driver.destroyBufferObject(mBoneWeightsHandle); } driver.destroyVertexBuffer(mHandle); } @@ -237,8 +237,8 @@ void FVertexBuffer::setBufferObjectAt(FEngine& engine, uint8_t bufferIndex, if (bufferIndex < mBufferCount) { auto hwBufferObject = bufferObject->getHwHandle(); engine.getDriverApi().setVertexBufferObject(mHandle, bufferIndex, hwBufferObject); - //store handle to recreate VertexBuffer in the case extra bone indices and weights definition - //used only in buffer object mode + // store handle to recreate VertexBuffer in the case extra bone indices and weights definition + // used only in buffer object mode mBufferObjects[bufferIndex] = hwBufferObject; } else { ASSERT_PRECONDITION(bufferIndex < mBufferCount, "bufferIndex must be < bufferCount"); @@ -316,29 +316,29 @@ void FVertexBuffer::updateBoneIndicesAndWeights(FEngine& engine, for (size_t i = 0; i < mBufferCount; ++i) if (bufferSizes[i] > 0) driver.setVertexBufferObject(mHandle, i, mBufferObjects[i]); - //add new bone buffer objects + // add new bone buffer objects mBufferCount++; - auto boJointsHandle = driver.createBufferObject(bufferSizes[mBufferCount - 1], + auto boneJointsHandle = driver.createBufferObject(bufferSizes[mBufferCount - 1], backend::BufferObjectBinding::VERTEX, backend::BufferUsage::STATIC); - driver.setVertexBufferObject(mHandle, mBufferCount - 1, boJointsHandle); + driver.setVertexBufferObject(mHandle, mBufferCount - 1, boneJointsHandle); auto bdJoints = BufferDescriptor( skinJoints, bufferSizes[mBufferCount - 1], nullptr); - driver.updateBufferObject(boJointsHandle,std::move(bdJoints), 0); + driver.updateBufferObject(boneJointsHandle,std::move(bdJoints), 0); mBufferCount++; - auto boWeightsHandle = driver.createBufferObject(bufferSizes[mBufferCount - 1], + auto boneWeightsHandle = driver.createBufferObject(bufferSizes[mBufferCount - 1], backend::BufferObjectBinding::VERTEX, backend::BufferUsage::STATIC); - driver.setVertexBufferObject(mHandle, mBufferCount - 1, boWeightsHandle); + driver.setVertexBufferObject(mHandle, mBufferCount - 1, boneWeightsHandle); auto bdWeights = BufferDescriptor( skinWeights, bufferSizes[mBufferCount - 1], nullptr); - driver.updateBufferObject(boWeightsHandle,std::move(bdWeights), 0); + driver.updateBufferObject(boneWeightsHandle,std::move(bdWeights), 0); if (!mBufferObjectsEnabled) { - mBufferObjects[mBufferCount - 2] = boJointsHandle; - mBufferObjects[mBufferCount - 1] = boWeightsHandle; + mBufferObjects[mBufferCount - 2] = boneJointsHandle; + mBufferObjects[mBufferCount - 1] = boneWeightsHandle; }else{ //for correct destroy bone buffer object mBoneBufferObjectsUsed = true; - mBoJointsHandle = boJointsHandle; - mBoWeightsHandle = boWeightsHandle; + mBoneJointsHandle = boneJointsHandle; + mBoneWeightsHandle = boneWeightsHandle; } } } // namespace filament diff --git a/filament/src/details/VertexBuffer.h b/filament/src/details/VertexBuffer.h index b70e90744ab..040d411e0cd 100644 --- a/filament/src/details/VertexBuffer.h +++ b/filament/src/details/VertexBuffer.h @@ -77,9 +77,9 @@ class FVertexBuffer : public VertexBuffer { uint32_t mVertexCount = 0; uint8_t mBufferCount = 0; bool mBufferObjectsEnabled = false; - bool mBoneBufferObjectsUsed = false; //mBoJointsHandle and mBoWeightsHandle are used, only in buffer object mode - BufferObjectHandle mBoJointsHandle; //handle for extra bone indices BufferObject - BufferObjectHandle mBoWeightsHandle; //handle for extra bone weights BufferObject + bool mBoneBufferObjectsUsed = false; // mBoJointsHandle and mBoWeightsHandle are used, only in buffer object mode + BufferObjectHandle mBoneJointsHandle; // handle for extra bone indices BufferObject + BufferObjectHandle mBoneWeightsHandle; // handle for extra bone weights BufferObject }; FILAMENT_DOWNCAST(VertexBuffer) diff --git a/libs/filabridge/include/private/filament/SibStructs.h b/libs/filabridge/include/private/filament/SibStructs.h index c6262508beb..94bdb2b276d 100644 --- a/libs/filabridge/include/private/filament/SibStructs.h +++ b/libs/filabridge/include/private/filament/SibStructs.h @@ -43,7 +43,7 @@ struct PerRenderPrimitiveMorphingSib { }; struct PerRenderPrimitiveSkinningSib { - static constexpr size_t BONE_IaW = 0; //bone indices and weights + static constexpr size_t BONE_INDICES_AND_WEIGHTS = 0; //bone indices and weights static constexpr size_t SAMPLER_COUNT = 1; }; diff --git a/samples/hellomorphing.cpp b/samples/hellomorphing.cpp index 815e0089544..1eee2e63269 100644 --- a/samples/hellomorphing.cpp +++ b/samples/hellomorphing.cpp @@ -58,20 +58,20 @@ struct Vertex { }; static const Vertex TRIANGLE_VERTICES[3] = { - {{1, 0}, 0xffff0000u}, //blue one (ABGR) - {{cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ff00u}, //green one - {{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu}, //red one + {{1, 0}, 0xffff0000u}, // blue one (ABGR) + {{cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ff00u}, // green one + {{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu}, // red one }; static const float3 targets_pos1[9] = { - {-2, 0, 0},{0, 2, 0},{1, 0, 0}, //1st position for 1st, 2nd and 3rd point of the first primitive - {1, 1, 0},{-1, 0, 0},{-1, 0, 0}, //2nd ... - {0, 0, 0},{0, 0, 0},{0, 0, 0} //no position change + {-2, 0, 0},{0, 2, 0},{1, 0, 0}, // 1st position for 1st, 2nd and 3rd point of the first primitive + {1, 1, 0},{-1, 0, 0},{-1, 0, 0}, // 2nd ... + {0, 0, 0},{0, 0, 0},{0, 0, 0} // no position change }; static const float3 targets_pos2[9] = { - {0, 2, 0},{-2, 0, 0},{1, 0, 0}, //1st position for 1st, 2nd and 3rd point of the second primitive - {-1, 0, 0},{1, 1, 0},{-1, 0, 0}, //position of th 3rd point is same for both morph targets + {0, 2, 0},{-2, 0, 0},{1, 0, 0}, // 1st position for 1st, 2nd and 3rd point of the second primitive + {-1, 0, 0},{1, 1, 0},{-1, 0, 0}, // position of th 3rd point is same for both morph targets {0, 0, 0},{0, 0, 0}, {0, 0, 0} }; @@ -181,10 +181,10 @@ int main(int argc, char** argv) { -ZOOM, ZOOM, 0, 1); auto& rm = engine->getRenderableManager(); - //morphTarget/blendshapes animation defined for all primitives + // morphTarget/blendshapes animation defined for all primitives float z = (float)(sin(now)/2.f + 0.5f); float weights[] = {1 - z, z/2, z/2}; - //set global weights of all morph targets + // set global weights of all morph targets rm.setMorphWeights(rm.getInstance(app.renderable), weights, 3, 0); }); diff --git a/samples/helloskinning.cpp b/samples/helloskinning.cpp index 222cdd2b332..71a152c7b10 100644 --- a/samples/helloskinning.cpp +++ b/samples/helloskinning.cpp @@ -160,7 +160,7 @@ int main(int argc, char** argv) { auto& rm = engine->getRenderableManager(); - //skinning/bones animation + // Bone skinning animation float tr = (float)(sin(now)); mat4f trans[] = {filament::math::mat4f::translation(filament::math::float3{tr, 0, 0}), filament::math::mat4f::translation(filament::math::float3{-1, tr, 0}), diff --git a/samples/helloskinningbuffer.cpp b/samples/helloskinningbuffer.cpp index b5c57950dba..bec7daf8618 100644 --- a/samples/helloskinningbuffer.cpp +++ b/samples/helloskinningbuffer.cpp @@ -195,7 +195,7 @@ int main(int argc, char** argv) { -ZOOM, ZOOM, 0, 1); auto& tcm = engine->getTransformManager(); - //transformation of both renderables + // Transformation of both renderables tcm.setTransform(tcm.getInstance(app.renderable1), filament::math::mat4f::translation(filament::math::float3{ 0.5, 0, 0 })); tcm.setTransform(tcm.getInstance(app.renderable2), @@ -203,7 +203,7 @@ int main(int argc, char** argv) { auto& rm = engine->getRenderableManager(); - //skinning/bones animation + // Bone skinning animation float t = (float)(now - (int)now); float s = sin(t * f::PI * 2.f); float c = cos(t * f::PI * 2.f); @@ -228,10 +228,10 @@ int main(int argc, char** argv) { uint offset = ((uint)now) % 8; trans1of8[offset] = transA[offset]; - //set transformation of the first bone + // Set transformation of the first bone app.sb->setBones(*engine, translate, 1, 0); - //set transformation of the other bones, only 3 of them can be used, do to limitation + // Set transformation of the other bones, only 3 of them can be used, do to limitation app.sb->setBones(*engine,trans1of8, 8, 1); }); diff --git a/samples/helloskinningbuffer_morebones.cpp b/samples/helloskinningbuffer_morebones.cpp index 71c9c220f4a..fa00c82dcfa 100644 --- a/samples/helloskinningbuffer_morebones.cpp +++ b/samples/helloskinningbuffer_morebones.cpp @@ -81,14 +81,15 @@ int main(int argc, char** argv) { Config config; config.title = "skinning buffer common for two renderables"; auto offset = 0; + size_t boneCount = 9; utils::FixedCapacityVector boneDataPerVertex(9); - float w = 1/9.f; - for (size_t i = 0; i < 9; i++) - boneDataPerVertex[i] = float2 (i, w); - auto i = 0; - boneDataPerPrimitive[i++] = boneDataPerVertex; - boneDataPerPrimitive[i++] = boneDataPerVertex; - boneDataPerPrimitive[i++] = boneDataPerVertex; + float weight = 1.f / boneCount; + for (size_t idx = 0; idx < boneCount; idx++) + boneDataPerVertex[idx] = float2(idx, weight); + auto idx = 0; + boneDataPerPrimitive[idx++] = boneDataPerVertex; + boneDataPerPrimitive[idx++] = boneDataPerVertex; + boneDataPerPrimitive[idx++] = boneDataPerVertex; App app; auto setup = [&app](Engine* engine, View* view, Scene* scene) { @@ -150,7 +151,7 @@ int main(int argc, char** argv) { .castShadows(false) .enableSkinningBuffers(true) .skinning(app.sb, 9, 0) - //set bone indices and weight for 3 vertices, 9 bones per vertx + // Set bone indices and weight for 3 vertices, 9 bones per vertx .boneIndicesAndWeights(0, boneDataPerPrimitive) .build(*engine, app.renderable1); @@ -163,7 +164,7 @@ int main(int argc, char** argv) { .castShadows(false) .enableSkinningBuffers(true) .skinning(app.sb, 9, 0) - //set bone indices and weight for 3 vertices, 9 bones per vertx + // Set bone indices and weight for 3 vertices, 9 bones per vertx .boneIndicesAndWeights(0, boneDataPerPrimitive) .build(*engine, app.renderable2); @@ -198,7 +199,7 @@ int main(int argc, char** argv) { -ZOOM, ZOOM, 0, 1); auto& tcm = engine->getTransformManager(); - //transformation of both renderables + // Transformation of both renderables tcm.setTransform(tcm.getInstance(app.renderable1), filament::math::mat4f::translation(filament::math::float3{ 0.5, 0, 0 })); tcm.setTransform(tcm.getInstance(app.renderable2), @@ -206,7 +207,7 @@ int main(int argc, char** argv) { auto& rm = engine->getRenderableManager(); - //skinning/bones animation + // Bone skinning animation float t = (float)(now - (int)now); float s = sin(t * f::PI * 2.f); float c = cos(t * f::PI * 2.f); @@ -215,7 +216,7 @@ int main(int argc, char** argv) { mat4f trans[9] = {}; for(uint i = 0; i < 9; i++){ - trans[i] = filament::math::mat4f(1);//transforms[0]; + trans[i] = filament::math::mat4f(1); } s *= 5; mat4f transA[] = { @@ -231,10 +232,10 @@ int main(int argc, char** argv) { uint offset = ((uint)now) % 8; trans[offset] = transA[offset]; - //set transformation of the first bone + // Set transformation of the first bone app.sb->setBones(*engine, translate, 1, 0); - //set transformation of the others bones + // Set transformation of the others bones app.sb->setBones(*engine,trans, 8, 1); }); diff --git a/samples/skinningtest.cpp b/samples/skinningtest.cpp index 71e43ec19fd..3c2681dd397 100644 --- a/samples/skinningtest.cpp +++ b/samples/skinningtest.cpp @@ -111,39 +111,41 @@ int main(int argc, char** argv) { Config config; config.title = "skinning test with more than 4 bones per vertex"; - utils::FixedCapacityVector boneDataPerVertex(8); - float w = 1 / 8.f; - for (uint i = 0; i < 8; i++){ - boneDataArray[i] = float2 (i, w); - boneDataArray[i + 8] = float2 (i, w); - boneDataArray[i + 16] = float2 (i, w); - boneDataPerVertex[i] = float2 (i, w); + size_t boneCount = 8; + utils::FixedCapacityVector boneDataPerVertex(boneCount); + float weight = 1.f / boneCount; + for (uint idx = 0; idx < boneCount; idx++){ + boneDataArray[idx] = float2(idx, weight); + boneDataArray[idx + boneCount] = float2(idx, weight); + boneDataArray[idx + 2*boneCount] = float2(idx, weight); + boneDataPerVertex[idx] = float2(idx, weight); } utils::FixedCapacityVector boneDataPerVertex2(3); - w = 1 / 3.f; - for (uint i = 0; i < 3; i++){ - boneDataPerVertex2[i] = float2 (i, w); + boneCount = 3; + weight = 1.f / boneCount; + for (uint idx = 0; idx < boneCount; idx++){ + boneDataPerVertex2[idx] = float2(idx, weight); } utils::FixedCapacityVector emptyBoneDataPerVertex(0); utils::FixedCapacityVector> emptyBoneDataPerPrimitive(0); - auto i = 0; - boneDataPerPrimitive[i++] = boneDataPerVertex; - boneDataPerPrimitive[i++] = boneDataPerVertex; - boneDataPerPrimitive[i++] = boneDataPerVertex; - - i = 0; - boneDataPerPrimitive2[i++] = boneDataPerVertex; - boneDataPerPrimitive2[i++] = boneDataPerVertex2; - boneDataPerPrimitive2[i++] = boneDataPerVertex; - boneDataPerPrimitive2[i++] = boneDataPerVertex; - boneDataPerPrimitive2[i++] = boneDataPerVertex2; - boneDataPerPrimitive2[i++] = boneDataPerVertex; - - i = 0; - boneDataPerRenderable[i++] = boneDataPerPrimitive; - boneDataPerRenderable[i++] = boneDataPerPrimitive; - boneDataPerRenderable[i++] = emptyBoneDataPerPrimitive; + auto idx = 0; + boneDataPerPrimitive[idx++] = boneDataPerVertex; + boneDataPerPrimitive[idx++] = boneDataPerVertex; + boneDataPerPrimitive[idx++] = boneDataPerVertex; + + idx = 0; + boneDataPerPrimitive2[idx++] = boneDataPerVertex; + boneDataPerPrimitive2[idx++] = boneDataPerVertex2; + boneDataPerPrimitive2[idx++] = boneDataPerVertex; + boneDataPerPrimitive2[idx++] = boneDataPerVertex; + boneDataPerPrimitive2[idx++] = boneDataPerVertex2; + boneDataPerPrimitive2[idx++] = boneDataPerVertex; + + idx = 0; + boneDataPerRenderable[idx++] = boneDataPerPrimitive; + boneDataPerRenderable[idx++] = boneDataPerPrimitive; + boneDataPerRenderable[idx++] = emptyBoneDataPerPrimitive; App app; auto setup = [&app](Engine* engine, View* view, Scene* scene) { @@ -152,7 +154,7 @@ int main(int argc, char** argv) { scene->setSkybox(app.skybox); view->setPostProcessingEnabled(false); static_assert(sizeof(Vertex) == 12, "Strange vertex size."); - //primitive 0, triangle without skinning vertex attributes + // primitive 0, triangle without skinning vertex attributes app.vb0 = VertexBuffer::Builder() .vertexCount(3) .bufferCount(1) @@ -161,7 +163,7 @@ int main(int argc, char** argv) { .normalized(VertexAttribute::COLOR) .build(*engine); - //primitive 1, triangle without skinning vertex attributes + // primitive 1, triangle without skinning vertex attributes app.vb1 = VertexBuffer::Builder() .vertexCount(3) .bufferCount(1) @@ -170,7 +172,7 @@ int main(int argc, char** argv) { .normalized(VertexAttribute::COLOR) .build(*engine); - //primitive 2, triangle with skinning vertex attributes, buffer object disabled + // primitive 2, triangle with skinning vertex attributes, buffer object disabled app.vb2 = VertexBuffer::Builder() .vertexCount(3) .bufferCount(3) @@ -179,10 +181,9 @@ int main(int argc, char** argv) { .normalized(VertexAttribute::COLOR) .attribute(VertexAttribute::BONE_INDICES, 1, VertexBuffer::AttributeType::USHORT4, 0, 8) .attribute(VertexAttribute::BONE_WEIGHTS, 2, VertexBuffer::AttributeType::FLOAT4, 0, 16) - //.enableBufferObjects() .build(*engine); - //primitive 3, triangle without skinning vertex attributes, buffer object enabled + // primitive 3, triangle without skinning vertex attributes, buffer object enabled app.vb3 = VertexBuffer::Builder() .vertexCount(3) .bufferCount(1) @@ -192,7 +193,7 @@ int main(int argc, char** argv) { .enableBufferObjects() .build(*engine); - //primitive 4, triangle without skinning vertex attributes + // primitive 4, triangle without skinning vertex attributes app.vb4 = VertexBuffer::Builder() .vertexCount(3) .bufferCount(1) @@ -201,7 +202,7 @@ int main(int argc, char** argv) { .normalized(VertexAttribute::COLOR) .build(*engine); - //primitive 5, two triangles without skinning vertex attributes + // primitive 5, two triangles without skinning vertex attributes app.vb5 = VertexBuffer::Builder() .vertexCount(6) .bufferCount(1) @@ -210,7 +211,7 @@ int main(int argc, char** argv) { .normalized(VertexAttribute::COLOR) .build(*engine); - //primitive 6, triangle without skinning vertex attributes + // primitive 6, triangle without skinning vertex attributes app.vb6 = VertexBuffer::Builder() .vertexCount(3) .bufferCount(1) @@ -218,22 +219,22 @@ int main(int argc, char** argv) { .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) .build(*engine); -//--------data for primitive 0 +// --------data for primitive 0 app.vb0->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr)); -//--------data for primitive 1 +// --------data for primitive 1 app.vb1->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 3, 36, nullptr)); app.vb2->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 3, 36, nullptr)); -//--------data for primitive 2 +// --------data for primitive 2 app.vb2->setBufferAt(*engine, 1, VertexBuffer::BufferDescriptor(skinJoints, 24, nullptr)); app.vb2->setBufferAt(*engine, 2, VertexBuffer::BufferDescriptor(skinWeights, 48, nullptr)); -//--------data for primitive 3 +// --------data for primitive 3 app.boTriangle = BufferObject::Builder() .size(3 * 4 * sizeof(Vertex)) .build(*engine); @@ -241,16 +242,16 @@ int main(int argc, char** argv) { TRIANGLE_VERTICES + 2, app.boTriangle->getByteCount(), nullptr)); app.vb3->setBufferObjectAt(*engine, 0,app.boTriangle); -//--------data for primitive 4 +// --------data for primitive 4 app.vb4->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 1, 36, nullptr),0); -//--------data for primitive 5 +// --------data for primitive 5 app.vb5->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 0, 72, nullptr),0); -//--------data for primitive 6 +// --------data for primitive 6 app.vb6->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 0, 36, nullptr),0); -//index buffer data +// index buffer data app.ib = IndexBuffer::Builder() .indexCount(3) .bufferType(IndexBuffer::IndexType::USHORT) @@ -269,13 +270,13 @@ int main(int argc, char** argv) { .package(RESOURCES_BAKEDCOLOR_DATA, RESOURCES_BAKEDCOLOR_SIZE) .build(*engine); -//skinning buffer for renderable 1 +// Skinning buffer for renderable 1 app.sb = SkinningBuffer::Builder() .boneCount(9) .initialize(true) .build(*engine); -//skinning buffer common for renderable 2 and 3 +// Skinning buffer common for renderable 2 and 3 app.sb2 = SkinningBuffer::Builder() .boneCount(9) .initialize(true) @@ -283,7 +284,7 @@ int main(int argc, char** argv) { app.sb->setBones(*engine, transforms,9,0); -//morph target definition to check combination bone skinning and blend shapes +// Morph target definition to check combination bone skinning and blend shapes app.mt = MorphTargetBuffer::Builder() .vertexCount(9) .count(3) @@ -296,10 +297,10 @@ int main(int argc, char** argv) { app.mt->setTangentsAt(*engine,1, targets_tan, 9, 0); app.mt->setTangentsAt(*engine,2, targets_tan, 9, 0); -//renderable 1: -//primitive 0 = skinned triangle, bone data defined as vector per primitive, -//primitive 1 = skinned triangle, bone data defined as array per primitive, -//primitive 2 = triangle without skinning and with morphing, bone data defined as vertex attributes +// renderable 1: +// primitive 0 = skinned triangle, bone data defined as vector per primitive, +// primitive 1 = skinned triangle, bone data defined as array per primitive, +// primitive 2 = triangle without skinning and with morphing, bone data defined as vertex attributes app.renderable1 = EntityManager::get().create(); RenderableManager::Builder(3) .boundingBox({{-1, -1, -1}, {1, 1, 1}}) @@ -324,9 +325,9 @@ int main(int argc, char** argv) { .morphing(0,2,app.mt) .build(*engine, app.renderable1); -//renderable 2: -//primitive 0 = skinning and morphing triangle, bone data defined as vector for all primitives of renderable, -//primitive 1 = skinning triangle, bone data defined as vector for all primitives of renderable, +// renderable 2: +// primitive 0 = skinning and morphing triangle, bone data defined as vector for all primitives of renderable, +// primitive 1 = skinning triangle, bone data defined as vector for all primitives of renderable, app.renderable2 = EntityManager::get().create(); RenderableManager::Builder(2) .boundingBox({{-1, -1, -1}, {1, 1, 1}}) @@ -346,9 +347,9 @@ int main(int argc, char** argv) { .morphing(0,0,app.mt) .build(*engine, app.renderable2); -//renderable 3: -//primitive 0 = skinning of two triangles, bone data defined as vector with various number of bones per vertex, -//primitive 1 = skinning triangle, bone data defined as vector with various number of bones per vertex, +// renderable 3: +// primitive 0 = skinning of two triangles, bone data defined as vector with various number of bones per vertex, +// primitive 1 = skinning triangle, bone data defined as vector with various number of bones per vertex, app.renderable3 = EntityManager::get().create(); RenderableManager::Builder(2) .boundingBox({{-1, -1, -1}, {1, 1, 1}}) @@ -410,17 +411,17 @@ int main(int argc, char** argv) { auto& rm = engine->getRenderableManager(); - //skinning/bone animation for more than four bones per vertex + // Bone skinning animation for more than four bones per vertex float t = (float)(now - (int)now); uint offset = ((uint)now) % 9; float s = sin(t * f::PI * 2.f) * 10; mat4f trans[9] = {}; for(uint i = 0; i < 9; i++){ - trans[i] = filament::math::mat4f(1);//transforms[0]; + trans[i] = filament::math::mat4f(1); } mat4f trans2[9] = {}; for(uint i = 0; i < 9; i++){ - trans2[i] = filament::math::mat4f(1);//transforms[0]; + trans2[i] = filament::math::mat4f(1); } mat4f transA[] = { mat4f::scaling(float3(s / 10.f,s / 10.f, 1)), @@ -440,7 +441,7 @@ int main(int argc, char** argv) { app.sb->setBones(*engine,trans,9,0); app.sb2->setBones(*engine,trans2,9,0); - //morphTarget/blendshapes animation + // Morph targets (blendshapes) animation float z = (float)(sin(now)/2.f + 0.5f); float weights[] = {1 - z, 0, z}; rm.setMorphWeights(rm.getInstance(app.renderable1), weights, 3, 0); diff --git a/samples/suzanneskinning.cpp b/samples/suzanneskinning.cpp index bfd08e5df0a..1d835c9fd63 100644 --- a/samples/suzanneskinning.cpp +++ b/samples/suzanneskinning.cpp @@ -151,10 +151,11 @@ static Texture* loadNormalMap(Engine* engine, const uint8_t* normals, size_t nby int main(int argc, char** argv) { int boneCount = 9; utils::FixedCapacityVector boneDataPerVertex(boneCount); - for (size_t i = 0; i < boneCount; i++) - boneDataPerVertex[i] = float2(i, 1/(float) boneCount); //index and weight for one vertex - for (size_t i = 0; i < boneDataPerPrimitive.size(); i++){ - boneDataPerPrimitive[i] = boneDataPerVertex; + // index and weight for one vertex + for (size_t idx = 0; idx < boneCount; idx++) + boneDataPerVertex[idx] = float2(idx, 1.f / boneCount); + for (size_t idx = 0; idx < boneDataPerPrimitive.size(); idx++){ + boneDataPerPrimitive[idx] = boneDataPerVertex; } Config config; @@ -258,13 +259,13 @@ int main(int argc, char** argv) { FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { - //skinning/bone animation for more than four bones per vertex + // Bone skinning animation for more than four bones per vertex float t = now / 10.f; float s1 = sin(t * f::PI * 4.f) * 10; float s2 = sin(t * f::PI * 6.f) * 10; float s3 = sin(t * f::PI * 8.f) * 10; - //create bone transformations + // Create bone transformations mat4f trans[] = { mat4f::scaling(float3(s1 + 10, 1.f, 1.f)), mat4f::scaling(float3(1.f, s2 + 10, 1.f)), diff --git a/shaders/src/getters.vs b/shaders/src/getters.vs index be835831980..ee1e33d3dc9 100644 --- a/shaders/src/getters.vs +++ b/shaders/src/getters.vs @@ -64,7 +64,7 @@ vec3 mulBoneVertex(vec3 v, uint i) { } void skinPosition(inout vec3 p, const uvec4 ids, const vec4 weights) { - //standard skinning for 4 weights, some of them could be zero + // standard skinning for 4 weights, some of them could be zero if (weights.w >= 0.0){ p = weights.x * mulBoneVertex(p, uint(ids.x)) + weights.y * mulBoneVertex(p, uint(ids.y)) @@ -72,7 +72,7 @@ void skinPosition(inout vec3 p, const uvec4 ids, const vec4 weights) { + weights.w * mulBoneVertex(p, uint(ids.w)); return; } - //skinning for >4 weights + // skinning for >4 weights vec3 posSum = weights.x * mulBoneVertex(p, uint(ids.x)); posSum += weights.y * mulBoneVertex(p, uint(ids.y)); posSum += weights.z * mulBoneVertex(p, uint(ids.z));uint pairIndex = -uint(weights.w + 1.); @@ -86,7 +86,7 @@ void skinPosition(inout vec3 p, const uvec4 ids, const vec4 weights) { } void skinNormal(inout vec3 n, const uvec4 ids, const vec4 weights) { - //standard skinning for 4 weights, some of them could be zero + // standard skinning for 4 weights, some of them could be zero if (weights.w >= 0.0){ n = weights.x * mulBoneVertex(n, uint(ids.x)) + weights.y * mulBoneVertex(n, uint(ids.y)) @@ -94,7 +94,7 @@ void skinNormal(inout vec3 n, const uvec4 ids, const vec4 weights) { + weights.w * mulBoneVertex(n, uint(ids.w)); return; } - //skinning for >4 weights + // skinning for >4 weights vec3 normSum = weights.x * mulBoneNormal(n, uint(ids.x)); normSum += weights.y * mulBoneNormal(n, uint(ids.y)); normSum += weights.z * mulBoneNormal(n, uint(ids.z)); @@ -110,7 +110,7 @@ void skinNormal(inout vec3 n, const uvec4 ids, const vec4 weights) { } void skinTwoVectors(inout vec3 n, inout vec3 t, const uvec4 ids, const vec4 weights) { - ///standard skinning for 4 weights, some of them could be zero + // standard skinning for 4 weights, some of them could be zero if (weights.w >= 0.0){ n = weights.x * mulBoneVertex(n, uint(ids.x)) + weights.y * mulBoneVertex(n, uint(ids.y)) @@ -122,7 +122,7 @@ void skinTwoVectors(inout vec3 n, inout vec3 t, const uvec4 ids, const vec4 weig + weights.w * mulBoneVertex(t, uint(ids.w)); return; } - //skinning for >4 weights + // skinning for >4 weights vec3 normSum = weights.x * mulBoneNormal(n, uint(ids.x)); normSum += weights.y * mulBoneNormal(n, uint(ids.y)) ; normSum += weights.z * mulBoneNormal(n, uint(ids.z)); From 8e3e04bc14dff47980480c00ff10fdc4111d63ef Mon Sep 17 00:00:00 2001 From: brunojezek Date: Wed, 3 May 2023 19:42:14 +0200 Subject: [PATCH 05/24] Fix setting of bone indices and weights for skinning move skinning parameters checks from setting methods to build method simplify bone indices and weights definition api --- filament/include/filament/RenderableManager.h | 28 +-- filament/src/components/RenderableManager.cpp | 185 ++++++------------ samples/skinningtest.cpp | 7 +- 3 files changed, 63 insertions(+), 157 deletions(-) diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index 8066f33347a..4863de03318 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -357,33 +357,17 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * defined in the VertexBuffer. Both ways of indices and weights definition must not be combined in one primitive. * Number of pairs is not limited to 4 bones per vertex. * All bone weights of one vertex should sum to one. Otherwise they will be normalized. - * Data must be rectangular and number of pairs must be same for all vertices of this primitive. + * Data must be rectangular and number of bone pairs must be same for all vertices of this primitive. * The data is arranged sequentially, all bone pairs for the first vertex, then for the second vertex, and so on. * * @param primitiveIndex zero-based index of the primitive, must be less than the primitive count passed to Builder constructor * @param indicesAndWeights pairs of bone index and bone weight for all vertices sequentially, * @param count number of all pairs, must be a multiple of vertexCount of the primitive + * @param bonesPerVertex number of bone pairs, same for all vertices of the primitive * * @return Builder reference for chaining calls. */ - Builder& boneIndicesAndWeights(size_t primitiveIndex,math::float2 const* indicesAndWeights, size_t count); - - /** - * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the - * second value is the bone weight. The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS - * defined in the VertexBuffer. Both ways of indices and weights definition must not be combined in one primitive. - * Number of pairs is not limited to 4 bones per vertex. - * All bone weights of one vertex should sum to one. Otherwise they will be normalized. - * Data must be rectangular and number of pairs must be same for all vertices and all primitives of renderable. - * The data is arranged sequentially, all bone pairs for the first vertex of the first primitive, then for the second vertex of - * the first primitive, ..., all bone pairs for the first vertex of the second primitive, ..., and so on. - * - * @param indicesAndWeightsArray pairs of bone index and bone weight for all vertices and primitives sequentially - * @param count number of all pairs, must be a multiple of vertexCount by primitiveCount - * - * @return Builder reference for chaining calls. - */ - Builder& boneIndicesAndWeights(math::float2 const* indicesAndWeightsArray, size_t count); + Builder& boneIndicesAndWeights(size_t primitiveIndex,math::float2 const* indicesAndWeights, size_t count, size_t bonesPerVertex) noexcept; /** * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the @@ -401,7 +385,7 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { */ Builder& boneIndicesAndWeights(size_t primitiveIndex, utils::FixedCapacityVector< - utils::FixedCapacityVector> const &indicesAndWeightsVector); + utils::FixedCapacityVector> const &indicesAndWeightsVector) noexcept; /** * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the * second value is the bone weight. The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS @@ -569,10 +553,6 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { size_t offset = 0; size_t count = 0; } morphing; - struct { - bool bonePairsSet = false; - utils::FixedCapacityVector> bonePairs; //bone indices and weights for each entry(primitive) - } skinning; }; void processBoneIndicesAndWights(Engine& engine, utils::Entity entity); }; diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 055c7f5824c..014d3db133c 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -37,7 +37,7 @@ #include #include #include - +#include using namespace filament::math; using namespace utils; @@ -71,9 +71,12 @@ struct RenderableManager::BuilderDetails { float2* mBoneIndicesAndWeight = nullptr; size_t mBoneIndicesAndWeightsCount = 0; + std::map>> mBonePairs; //bone indices and weights defined for primitive index + explicit BuilderDetails(size_t count) : mEntries(count), mCulling(true), mCastShadows(false), mReceiveShadows(true), - mScreenSpaceContactShadows(false), mSkinningBufferMode(false), mFogEnabled(true) { + mScreenSpaceContactShadows(false), mSkinningBufferMode(false), mBonePairs(), mFogEnabled(true) { } // this is only needed for the explicit instantiation below BuilderDetails() = default; @@ -208,87 +211,24 @@ RenderableManager::Builder& RenderableManager::Builder::enableSkinningBuffers(bo } RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(size_t primitiveIndex, - math::float2 const* indicesAndWeights, size_t count) { - std::vector& entries = mImpl->mEntries; - - ASSERT_PRECONDITION(primitiveIndex < entries.size() && primitiveIndex >= 0, - "[primitive @ %u] index is out of size (%u)", primitiveIndex, entries.size()); - auto vertexCount = entries[primitiveIndex].vertices->getVertexCount(); - ASSERT_PRECONDITION(vertexCount > 0, - "[primitive @ %u] no defined vertices (%u)", primitiveIndex, vertexCount); - auto pairsPerVertexCount = count / vertexCount; - ASSERT_PRECONDITION(pairsPerVertexCount > 0 && count % vertexCount == 0, - "[primitive @ %u] bone indices and weights pairs count (%u) must be a multiple of vertex count (%u)", - primitiveIndex, count, vertexCount); - + math::float2 const* indicesAndWeights, size_t count, size_t bonesPerVertex) noexcept{ + auto vertexCount = count / bonesPerVertex; utils::FixedCapacityVector> bonePairs(vertexCount); for( size_t iVertex = 0; iVertex < vertexCount; iVertex++){ - utils::FixedCapacityVector vertexData(pairsPerVertexCount); - std::memcpy(&vertexData[0], &indicesAndWeights[iVertex * pairsPerVertexCount], - pairsPerVertexCount * sizeof(float2)); + utils::FixedCapacityVector vertexData(bonesPerVertex); + std::memcpy(&vertexData[0], &indicesAndWeights[iVertex * bonesPerVertex], + bonesPerVertex * sizeof(float2)); bonePairs[iVertex] = vertexData; } return boneIndicesAndWeights(primitiveIndex, bonePairs); } -RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights( - math::float2 const* indicesAndWeightsArray, size_t count){ - std::vector& entries = mImpl->mEntries; - size_t primitiveCount = entries.size(); - size_t allVerticesCount = 0; - // number off all vertices of all primitives calculation - for (size_t iEntry = 0; iEntry < primitiveCount; iEntry++){ - allVerticesCount += entries[iEntry].vertices->getVertexCount(); - } - size_t pairsPerAllVerticesCount = count / allVerticesCount; - ASSERT_PRECONDITION(pairsPerAllVerticesCount > 0 && count % allVerticesCount == 0, - "bone indices and weights pairs count (%u) must be a multiple of vertex counts of all primitives (%u)", - count, allVerticesCount); - size_t pairSkipped = 0; - for (size_t iEntry = 0; iEntry < primitiveCount; iEntry++){ - size_t pairsPerPrimitiveCount = pairsPerAllVerticesCount * entries[iEntry].vertices->getVertexCount(); - boneIndicesAndWeights(iEntry, - indicesAndWeightsArray + pairSkipped, - pairsPerPrimitiveCount); - pairSkipped += pairsPerAllVerticesCount; - } - return *this; -} - RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(size_t primitiveIndex, - const utils::FixedCapacityVector< utils::FixedCapacityVector> &indicesAndWeightsVector) { - auto count = indicesAndWeightsVector.size(); - if (!count) { - // skip if no skinning data - // mImpl->mEntries[primitiveIndex].skinning.bonePairsSet = true; - return *this; - } - std::vector& entries = mImpl->mEntries; - ASSERT_PRECONDITION(primitiveIndex < entries.size() && primitiveIndex >= 0, - "[primitive @ %u] index is out of size (%u)", primitiveIndex, entries.size()); - auto vertexCount = entries[primitiveIndex].vertices->getVertexCount(); - ASSERT_PRECONDITION(vertexCount > 0, - "[primitive @ %u] no defined vertices (%u)", primitiveIndex, vertexCount); - auto pairsPerVertexCount = count / vertexCount; - ASSERT_PRECONDITION(pairsPerVertexCount > 0 && count % vertexCount == 0, - "[primitive @ %u] bone indices and weights pairs count (%u) must be a multiple of vertex count (%u)", - primitiveIndex, count, vertexCount); - auto& skinning = entries[primitiveIndex].skinning; - ASSERT_PRECONDITION(skinning.bonePairs.empty(), - "[primitive @ %u] bone indices and weights data already exists", primitiveIndex); - skinning.bonePairs = indicesAndWeightsVector; // copy - skinning.bonePairsSet = true; - + const utils::FixedCapacityVector< + utils::FixedCapacityVector> &indicesAndWeightsVector) noexcept{ + mImpl->mBonePairs[primitiveIndex] = indicesAndWeightsVector; return *this; } - -RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights( - const utils::FixedCapacityVector>> &indicesAndWeightsVectors) noexcept{ - for (size_t iEntry = 0, c = min((uint)mImpl->mEntries.size(), indicesAndWeightsVectors.size()); iEntry < c; iEntry++) - boneIndicesAndWeights(iEntry, indicesAndWeightsVectors[iEntry]); - return *this; -} - RenderableManager::Builder& RenderableManager::Builder::fog(bool enabled) noexcept { mImpl->mFogEnabled = enabled; return *this; @@ -329,60 +269,64 @@ RenderableManager::Builder& RenderableManager::Builder::globalBlendOrderEnabled( UTILS_NOINLINE void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Entity entity){ - size_t maxPairsCount = 0; - size_t maxPairsCountPerPrimitive = 0; - - for (size_t iEntry = 0, c = mImpl->mEntries.size(); iEntry < c; iEntry++) { - auto& entry = mImpl->mEntries[iEntry]; - if (entry.skinning.bonePairs.size()) { - auto const& declaredAttributes = downcast(entry.vertices)->getDeclaredAttributes(); - ASSERT_PRECONDITION(!declaredAttributes[VertexAttribute::BONE_INDICES], - "[entity=%u, primitive @ %u] vertex attribute for skinning BONE_INDICES are already defined", - entity.getId(), iEntry); - ASSERT_PRECONDITION(!declaredAttributes[VertexAttribute::BONE_WEIGHTS], - "[entity=%u, primitive @ %u] vertex attribute BONE_WEIGHTS for skinning are already defined", - entity.getId(), iEntry); - for (size_t iVertex = 0, vertexCount = entry.skinning.bonePairs.size(); iVertex < vertexCount; iVertex++){ - auto pairCountPerVertex = entry.skinning.bonePairs[iVertex].size(); - maxPairsCount += pairCountPerVertex; - maxPairsCountPerPrimitive = max(pairCountPerVertex, (uint)maxPairsCountPerPrimitive); - } + size_t maxPairsCount = 0; //size of texture, number of bone pairs + size_t maxPairsCountPerVertex = 0; //maximum of number of bone per vertex + + for(auto iBonePair = mImpl->mBonePairs.begin(); iBonePair != mImpl->mBonePairs.end(); ++iBonePair){ + auto primitiveIndex = iBonePair->first; + auto entries = mImpl->mEntries; + ASSERT_PRECONDITION(primitiveIndex < (int) entries.size() && primitiveIndex >= 0, + "[primitive @ %u] primitiveindex is out of size (%u)", primitiveIndex, entries.size()); + auto entry = mImpl->mEntries[primitiveIndex]; + auto bonePairsForPrimitive = iBonePair->second; + auto vertexCount = entry.vertices->getVertexCount(); + ASSERT_PRECONDITION(bonePairsForPrimitive.size() == vertexCount, + "[primitive @ %u] bone indices and weights pairs count (%u) must be equal to vertex count (%u)", + primitiveIndex, bonePairsForPrimitive.size(), vertexCount); + auto const& declaredAttributes = downcast(entry.vertices)->getDeclaredAttributes(); + ASSERT_PRECONDITION(!declaredAttributes[VertexAttribute::BONE_INDICES], + "[entity=%u, primitive @ %u] vertex attribute BONE_INDICES for skinning are already defined", + entity.getId(), primitiveIndex); + ASSERT_PRECONDITION(!declaredAttributes[VertexAttribute::BONE_WEIGHTS], + "[entity=%u, primitive @ %u] vertex attribute BONE_WEIGHTS for skinning are already defined", + entity.getId(), primitiveIndex); + for (size_t iVertex = 0; iVertex < vertexCount; iVertex++){ + auto bonesPerVertex = bonePairsForPrimitive[iVertex].size(); + maxPairsCount += bonesPerVertex; + maxPairsCountPerVertex = max(bonesPerVertex, (uint) maxPairsCountPerVertex); } } + size_t pairsCount = 0; // counting of number of pairs stored in texture float2* tempPairs; // temporary indices and weights for one vertex if (maxPairsCount) { // at least one primitive has bone indices and weights mImpl->mBoneIndicesAndWeight = (float2*) malloc( maxPairsCount * 2 * 4); // final texture data, indices and weights - tempPairs = (float2*) malloc(maxPairsCountPerPrimitive * 2 + tempPairs = (float2*) malloc(maxPairsCountPerVertex * 2 * 4); // temporary indices and weights for one vertex - } - for (size_t iEntry = 0, entriesCount = mImpl->mEntries.size(); iEntry < entriesCount; iEntry++) { - auto& entry = mImpl->mEntries[iEntry]; - // bone data are defined boneIndicesAndWeights() - if (entry.skinning.bonePairsSet) { - if (entry.skinning.bonePairs.size()){ - size_t vertexCount = entry.vertices->getVertexCount(); + for(auto iBonePair = mImpl->mBonePairs.begin(); iBonePair != mImpl->mBonePairs.end(); ++iBonePair){ + auto primitiveIndex = iBonePair->first; + auto bonePairsForPrimitive = iBonePair->second; + if (bonePairsForPrimitive.size()){ + size_t vertexCount = mImpl->mEntries[primitiveIndex].vertices->getVertexCount(); auto skinJoints = (ushort*) malloc(vertexCount * 4 * 2); auto skinWeights = (float*) malloc(vertexCount * 4 * 4); for(size_t iVertex = 0; iVertex < vertexCount; iVertex++) { - size_t pairsPerVertexCount = entry.skinning.bonePairs[iVertex].size(); - // if (!pairsPerVertexCount) continue; size_t tempPairCount = 0; float boneWeightsSum = 0; - for (size_t k = 0; k < pairsPerVertexCount; k++){ - auto boneWeight = entry.skinning.bonePairs[iVertex][k][1]; - auto boneIndex= entry.skinning.bonePairs[iVertex][k][0]; + for (size_t k = 0; k < bonePairsForPrimitive[iVertex].size(); k++){ + auto boneWeight = bonePairsForPrimitive[iVertex][k][1]; + auto boneIndex= bonePairsForPrimitive[iVertex][k][0]; ASSERT_PRECONDITION(boneWeight >= 0, "[entity=%u, primitive @ %u] bone weight (%f) of vertex=%u is negative ", - entity.getId(), iEntry, boneWeight, iVertex); + entity.getId(), primitiveIndex, boneWeight, iVertex); if (boneWeight){ ASSERT_PRECONDITION(boneIndex >= 0, "[entity=%u, primitive @ %u] bone index (%i) of vertex=%u is negative ", - entity.getId(), iEntry, (int) boneIndex, iVertex); + entity.getId(), primitiveIndex, (int) boneIndex, iVertex); ASSERT_PRECONDITION(boneIndex < mImpl->mSkinningBoneCount, "[entity=%u, primitive @ %u] bone index (%i) of vertex=%u is bigger then bone count (%u) ", - entity.getId(), iEntry, (int) boneIndex, iVertex, mImpl->mSkinningBoneCount); + entity.getId(), primitiveIndex, (int) boneIndex, iVertex, mImpl->mSkinningBoneCount); boneWeightsSum += boneWeight; tempPairs[tempPairCount][0] = boneIndex; tempPairs[tempPairCount][1] = boneWeight; @@ -392,9 +336,9 @@ void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Ent ASSERT_PRECONDITION(boneWeightsSum > 0, "[entity=%u, primitive @ %u] sum of bone weights of vertex=%u is %f, it should be positive.", - entity.getId(), iEntry, iVertex, boneWeightsSum); + entity.getId(), primitiveIndex, iVertex, boneWeightsSum); if (abs(boneWeightsSum - 1.f) > std::numeric_limits::epsilon()) - utils::slog.w << "Warning of skinning: [entity=%" << entity.getId() <<", primitive @ %" << iEntry + utils::slog.w << "Warning of skinning: [entity=%" << entity.getId() <<", primitive @ %" << primitiveIndex << "] sum of bone weights of vertex=" << iVertex << " is " << boneWeightsSum << ", it should be one. Weights will be normalized." << utils::io::endl; @@ -420,35 +364,20 @@ void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Ent } } } // for all vertices per primitive - - downcast(mImpl->mEntries[iEntry].vertices) + downcast(mImpl->mEntries[primitiveIndex].vertices) ->updateBoneIndicesAndWeights(downcast(engine), skinJoints, skinWeights); - } - } - }// for all primitives + }// for all primitives + } mImpl->mBoneIndicesAndWeightsCount = pairsCount; - } + RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& engine, Entity entity) { bool isEmpty = true; ASSERT_PRECONDITION(mImpl->mSkinningBoneCount <= CONFIG_MAX_BONE_COUNT, "bone count > %u", CONFIG_MAX_BONE_COUNT); - ASSERT_PRECONDITION( - mImpl->mInstanceCount <= engine.getMaxAutomaticInstances() || !mImpl->mInstanceBuffer, - "instance count is %zu, but instance count is limited to " - "Engine::getMaxAutomaticInstances() (%zu) instances when supplying transforms via an " - "InstanceBuffer.", - mImpl->mInstanceCount, engine.getMaxAutomaticInstances()); - if (mImpl->mInstanceBuffer) { - size_t bufferInstanceCount = mImpl->mInstanceBuffer->mInstanceCount; - ASSERT_PRECONDITION(mImpl->mInstanceCount <= bufferInstanceCount, - "instance count (%zu) must be less than or equal to the InstanceBuffer's instance " - "count (%zu).", - mImpl->mInstanceCount, bufferInstanceCount); - } if (UTILS_LIKELY(mImpl->mSkinningBoneCount) || UTILS_LIKELY(mImpl->mSkinningBufferMode)) { processBoneIndicesAndWights(engine, entity); diff --git a/samples/skinningtest.cpp b/samples/skinningtest.cpp index 3c2681dd397..0c0c2b74a01 100644 --- a/samples/skinningtest.cpp +++ b/samples/skinningtest.cpp @@ -105,7 +105,7 @@ mat4f transforms[] = {math::mat4f(1), mat4f::translation(float3(1, -1, 0))}; utils::FixedCapacityVector> boneDataPerPrimitive(3), boneDataPerPrimitive2(6); -utils::FixedCapacityVector>> boneDataPerRenderable(3); +utils::FixedCapacityVector>> boneDataPerRenderable(2); int main(int argc, char** argv) { Config config; @@ -127,8 +127,6 @@ int main(int argc, char** argv) { boneDataPerVertex2[idx] = float2(idx, weight); } - utils::FixedCapacityVector emptyBoneDataPerVertex(0); - utils::FixedCapacityVector> emptyBoneDataPerPrimitive(0); auto idx = 0; boneDataPerPrimitive[idx++] = boneDataPerVertex; boneDataPerPrimitive[idx++] = boneDataPerVertex; @@ -145,7 +143,6 @@ int main(int argc, char** argv) { idx = 0; boneDataPerRenderable[idx++] = boneDataPerPrimitive; boneDataPerRenderable[idx++] = boneDataPerPrimitive; - boneDataPerRenderable[idx++] = emptyBoneDataPerPrimitive; App app; auto setup = [&app](Engine* engine, View* view, Scene* scene) { @@ -320,7 +317,7 @@ int main(int argc, char** argv) { .skinning(app.sb, 9, 0) .boneIndicesAndWeights(0, boneDataPerPrimitive) - .boneIndicesAndWeights(1, boneDataArray, 24) + .boneIndicesAndWeights(1, boneDataArray, 24, 8) .morphing(3) .morphing(0,2,app.mt) .build(*engine, app.renderable1); From c5263f138aaa03ffdf7cd13dd448ae72ae3465c2 Mon Sep 17 00:00:00 2001 From: brunojezek Date: Thu, 4 May 2023 15:55:42 +0200 Subject: [PATCH 06/24] Simplify API and fix memory operations map changed to unordered_map std::memcpy changed to std::copy_n used std::move --- filament/include/filament/RenderableManager.h | 55 ++++++++----------- filament/src/components/RenderableManager.cpp | 21 ++++--- samples/skinningtest.cpp | 30 +--------- 3 files changed, 36 insertions(+), 70 deletions(-) diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index 4863de03318..fadf2be11d6 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -352,16 +352,21 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { Builder& skinning(size_t boneCount) noexcept; //!< \overload /** - * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the - * second value is the bone weight. The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS - * defined in the VertexBuffer. Both ways of indices and weights definition must not be combined in one primitive. + * Define bone indices and weights for vertex skinning. The first pair value defines index + * of the bone and the second value is the bone weight. The pairs substitute \c BONE_INDICES + * and the \c BONE_WEIGHTS defined in the VertexBuffer. Both ways of indices and weights + * definition must not be combined in one primitive. * Number of pairs is not limited to 4 bones per vertex. * All bone weights of one vertex should sum to one. Otherwise they will be normalized. - * Data must be rectangular and number of bone pairs must be same for all vertices of this primitive. - * The data is arranged sequentially, all bone pairs for the first vertex, then for the second vertex, and so on. - * - * @param primitiveIndex zero-based index of the primitive, must be less than the primitive count passed to Builder constructor - * @param indicesAndWeights pairs of bone index and bone weight for all vertices sequentially, + * Data must be rectangular and number of bone pairs must be same for all vertices of this + * primitive. + * The data is arranged sequentially, all bone pairs for the first vertex, then for the + * second vertex, and so on. + * + * @param primitiveIndex zero-based index of the primitive, must be less than the primitive + * count passed to Builder constructor + * @param indicesAndWeights pairs of bone index and bone weight for all vertices + * sequentially * @param count number of all pairs, must be a multiple of vertexCount of the primitive * @param bonesPerVertex number of bone pairs, same for all vertices of the primitive * @@ -370,40 +375,26 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { Builder& boneIndicesAndWeights(size_t primitiveIndex,math::float2 const* indicesAndWeights, size_t count, size_t bonesPerVertex) noexcept; /** - * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the - * second value is the bone weight. The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS - * defined in the VertexBuffer. Both ways of indices and weights definition must not be combined in one primitive. + * Define bone indices and weights for vertex skinning. The first pair value defines index + * of the bone and the second value is the bone weight. The pairs substitute \c BONE_INDICES + * and the \c BONE_WEIGHTS defined in the VertexBuffer. Both ways of indices and weights + * definition must not be combined in one primitive. * Number of pairs is not limited to 4 bones per vertex. * All bone weights of one vertex should sum to one. Otherwise they will be normalized. - * Data doesn't have to be rectangular and number of pairs per vertices of primitive can be variable. + * Data doesn't have to be rectangular and number of pairs per vertices of primitive can be + * variable. * The vector of the vertices contains the vectors of the pairs * - * @param primitiveIndex zero-based index of the primitive, must be less than the primitive count passed to Builder constructor - * @param indicesAndWeightsVectors pairs of bone index and bone weight for all vertices of the primitive sequentially + * @param primitiveIndex zero-based index of the primitive, must be less than the primitive + * count passed to Builder constructor + * @param indicesAndWeightsVectors pairs of bone index and bone weight for all vertices of + * the primitive sequentially * * @return Builder reference for chaining calls. */ Builder& boneIndicesAndWeights(size_t primitiveIndex, utils::FixedCapacityVector< utils::FixedCapacityVector> const &indicesAndWeightsVector) noexcept; - /** - * Define bone indices and weights for vertex skinning. The first pair value defines index of the bone and the - * second value is the bone weight. The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS - * defined in the VertexBuffer. Both ways of indices and weights definition must not be combined in one primitive. - * Number of pairs is not limited to 4 bones per vertex. - * All bone weights of one vertex should sum to one. Otherwise they will be normalized. - * Data doesn't have to be rectangular and number of pairs per vertices and primitives can be variable. - * The vector of the primitives contains the vectors of the vertices with the vectors of the pairs - * - * @param indicesAndWeightsVectors pairs of bone index and bone weight for all vertices and primitives sequentially - * - * @return Builder reference for chaining calls. - */ - Builder& boneIndicesAndWeights( - utils::FixedCapacityVector< - utils::FixedCapacityVector< - utils::FixedCapacityVector>> const &indicesAndWeightsVectors) noexcept; - /** * Controls if the renderable has vertex morphing targets, zero by default. This is * required to enable GPU morphing. diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 014d3db133c..e6ea5dc883c 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -37,7 +37,7 @@ #include #include #include -#include +#include using namespace filament::math; using namespace utils; @@ -71,7 +71,7 @@ struct RenderableManager::BuilderDetails { float2* mBoneIndicesAndWeight = nullptr; size_t mBoneIndicesAndWeightsCount = 0; - std::map>> mBonePairs; //bone indices and weights defined for primitive index explicit BuilderDetails(size_t count) @@ -212,13 +212,13 @@ RenderableManager::Builder& RenderableManager::Builder::enableSkinningBuffers(bo RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(size_t primitiveIndex, math::float2 const* indicesAndWeights, size_t count, size_t bonesPerVertex) noexcept{ - auto vertexCount = count / bonesPerVertex; + size_t vertexCount = count / bonesPerVertex; utils::FixedCapacityVector> bonePairs(vertexCount); - for( size_t iVertex = 0; iVertex < vertexCount; iVertex++){ + for( size_t iVertex = 0; iVertex < vertexCount; iVertex++) { utils::FixedCapacityVector vertexData(bonesPerVertex); - std::memcpy(&vertexData[0], &indicesAndWeights[iVertex * bonesPerVertex], - bonesPerVertex * sizeof(float2)); - bonePairs[iVertex] = vertexData; + std::copy_n(indicesAndWeights + iVertex * bonesPerVertex, + bonesPerVertex, vertexData.data()); + bonePairs[iVertex] = std::move(vertexData); } return boneIndicesAndWeights(primitiveIndex, bonePairs); } @@ -226,9 +226,10 @@ RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(si RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(size_t primitiveIndex, const utils::FixedCapacityVector< utils::FixedCapacityVector> &indicesAndWeightsVector) noexcept{ - mImpl->mBonePairs[primitiveIndex] = indicesAndWeightsVector; + mImpl->mBonePairs[primitiveIndex] = std::move(indicesAndWeightsVector); return *this; } + RenderableManager::Builder& RenderableManager::Builder::fog(bool enabled) noexcept { mImpl->mFogEnabled = enabled; return *this; @@ -275,7 +276,7 @@ void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Ent for(auto iBonePair = mImpl->mBonePairs.begin(); iBonePair != mImpl->mBonePairs.end(); ++iBonePair){ auto primitiveIndex = iBonePair->first; auto entries = mImpl->mEntries; - ASSERT_PRECONDITION(primitiveIndex < (int) entries.size() && primitiveIndex >= 0, + ASSERT_PRECONDITION(primitiveIndex < entries.size() && primitiveIndex >= 0, "[primitive @ %u] primitiveindex is out of size (%u)", primitiveIndex, entries.size()); auto entry = mImpl->mEntries[primitiveIndex]; auto bonePairsForPrimitive = iBonePair->second; @@ -372,7 +373,6 @@ void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Ent mImpl->mBoneIndicesAndWeightsCount = pairsCount; } - RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& engine, Entity entity) { bool isEmpty = true; @@ -383,7 +383,6 @@ RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& eng processBoneIndicesAndWights(engine, entity); } - for (size_t i = 0, c = mImpl->mEntries.size(); i < c; i++) { auto& entry = mImpl->mEntries[i]; diff --git a/samples/skinningtest.cpp b/samples/skinningtest.cpp index 0c0c2b74a01..0f6052fcebb 100644 --- a/samples/skinningtest.cpp +++ b/samples/skinningtest.cpp @@ -48,7 +48,7 @@ struct App { Camera* cam; Entity camera; Skybox* skybox; - Entity renderable1, renderable2, renderable3; + Entity renderable1, renderable2; SkinningBuffer *sb, *sb2; MorphTargetBuffer *mt; BufferObject *boTriangle, *boVertices, *boJoints, *boWeights; @@ -323,31 +323,9 @@ int main(int argc, char** argv) { .build(*engine, app.renderable1); // renderable 2: -// primitive 0 = skinning and morphing triangle, bone data defined as vector for all primitives of renderable, -// primitive 1 = skinning triangle, bone data defined as vector for all primitives of renderable, - app.renderable2 = EntityManager::get().create(); - RenderableManager::Builder(2) - .boundingBox({{-1, -1, -1}, {1, 1, 1}}) - .material(0, app.mat->getDefaultInstance()) - .material(1, app.mat->getDefaultInstance()) - .geometry(0,RenderableManager::PrimitiveType::TRIANGLES, - app.vb1,app.ib,0,3) - .geometry(1,RenderableManager::PrimitiveType::TRIANGLES, - app.vb6,app.ib,0,3) - .culling(false) - .receiveShadows(false) - .castShadows(false) - .enableSkinningBuffers(true) - .skinning(app.sb2, 9, 0) - .boneIndicesAndWeights(boneDataPerRenderable) - .morphing(3) - .morphing(0,0,app.mt) - .build(*engine, app.renderable2); - -// renderable 3: // primitive 0 = skinning of two triangles, bone data defined as vector with various number of bones per vertex, // primitive 1 = skinning triangle, bone data defined as vector with various number of bones per vertex, - app.renderable3 = EntityManager::get().create(); + app.renderable2 = EntityManager::get().create(); RenderableManager::Builder(2) .boundingBox({{-1, -1, -1}, {1, 1, 1}}) .material(0, app.mat->getDefaultInstance()) @@ -364,11 +342,10 @@ int main(int argc, char** argv) { .boneIndicesAndWeights( 1, boneDataPerPrimitive) .boneIndicesAndWeights( 0, boneDataPerPrimitive2) - .build(*engine, app.renderable3); + .build(*engine, app.renderable2); scene->addEntity(app.renderable1); scene->addEntity(app.renderable2); - scene->addEntity(app.renderable3); app.camera = utils::EntityManager::get().create(); app.cam = engine->createCamera(app.camera); view->setCamera(app.cam); @@ -378,7 +355,6 @@ int main(int argc, char** argv) { engine->destroy(app.skybox); engine->destroy(app.renderable1); engine->destroy(app.renderable2); - engine->destroy(app.renderable3); engine->destroy(app.mat); engine->destroy(app.vb0); engine->destroy(app.vb1); From 1d171eacccae22f288fb0171c1aafe988ca99540 Mon Sep 17 00:00:00 2001 From: brunojezek Date: Tue, 9 May 2023 23:59:11 +0200 Subject: [PATCH 07/24] Fix formatting and small changes according reviews Add spaces and brackets, fix indentation, clarify comments Replace #pragma nounroll by UTILS_NOUNROLL in vertex shader: Fix mulBoneNormal method calling Replace -uint(weights.w + 1.) by uint(-weights.w - 1.) Rename skinNormalTangent method --- filament/include/filament/RenderableManager.h | 25 ++++++------ filament/src/RenderPass.cpp | 5 ++- filament/src/details/SkinningBuffer.cpp | 2 - filament/src/details/SkinningBuffer.h | 2 +- filament/src/details/VertexBuffer.cpp | 17 ++++---- libs/filamat/src/shaders/SibGenerator.cpp | 2 +- samples/hellomorphing.cpp | 6 +-- samples/helloskinning.cpp | 4 +- samples/helloskinningbuffer.cpp | 8 ++-- samples/helloskinningbuffer_morebones.cpp | 11 +++--- samples/skinningtest.cpp | 10 ++--- samples/suzanneskinning.cpp | 12 +++--- shaders/src/getters.vs | 39 ++++++++++--------- shaders/src/main.vs | 2 +- 14 files changed, 74 insertions(+), 71 deletions(-) diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index fadf2be11d6..25dd9fce6f6 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -352,11 +352,11 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { Builder& skinning(size_t boneCount) noexcept; //!< \overload /** - * Define bone indices and weights for vertex skinning. The first pair value defines index - * of the bone and the second value is the bone weight. The pairs substitute \c BONE_INDICES - * and the \c BONE_WEIGHTS defined in the VertexBuffer. Both ways of indices and weights - * definition must not be combined in one primitive. - * Number of pairs is not limited to 4 bones per vertex. + * Define bone indices and weights "pairs" for vertex skinning as a float2. + * The unsigned int(pair.x) defines index of the bone and pair.y is the bone weight. + * The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS defined in the VertexBuffer. + * Both ways of indices and weights definition must not be combined in one primitive. + * Number of pairs per vertex bonesPerVertex is not limited to 4 bones. * All bone weights of one vertex should sum to one. Otherwise they will be normalized. * Data must be rectangular and number of bone pairs must be same for all vertices of this * primitive. @@ -372,13 +372,14 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * * @return Builder reference for chaining calls. */ - Builder& boneIndicesAndWeights(size_t primitiveIndex,math::float2 const* indicesAndWeights, size_t count, size_t bonesPerVertex) noexcept; + Builder& boneIndicesAndWeights(size_t primitiveIndex, + math::float2 const* indicesAndWeights, size_t count, size_t bonesPerVertex) noexcept; /** - * Define bone indices and weights for vertex skinning. The first pair value defines index - * of the bone and the second value is the bone weight. The pairs substitute \c BONE_INDICES - * and the \c BONE_WEIGHTS defined in the VertexBuffer. Both ways of indices and weights - * definition must not be combined in one primitive. + * Define bone indices and weights "pairs" for vertex skinning as a float2. + * The unsigned int(pair.x) defines index of the bone and pair.y is the bone weight. + * The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS defined in the VertexBuffer. + * Both ways of indices and weights definition must not be combined in one primitive. * Number of pairs is not limited to 4 bones per vertex. * All bone weights of one vertex should sum to one. Otherwise they will be normalized. * Data doesn't have to be rectangular and number of pairs per vertices of primitive can be @@ -393,8 +394,8 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * @return Builder reference for chaining calls. */ Builder& boneIndicesAndWeights(size_t primitiveIndex, - utils::FixedCapacityVector< - utils::FixedCapacityVector> const &indicesAndWeightsVector) noexcept; + utils::FixedCapacityVector< + utils::FixedCapacityVector> const &indicesAndWeightsVector) noexcept; /** * Controls if the renderable has vertex morphing targets, zero by default. This is * required to enable GPU morphing. diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp index c7d5492c911..a9fa1dc4cac 100644 --- a/filament/src/RenderPass.cpp +++ b/filament/src/RenderPass.cpp @@ -879,9 +879,10 @@ void RenderPass::Executor::execute(backend::DriverApi& driver, driver.bindSamplers(+SamplerBindingPoints::PER_RENDERABLE_MORPHING, info.morphTargetBuffer); - if (UTILS_UNLIKELY(info.skinningTexture)) + if (UTILS_UNLIKELY(info.skinningTexture)) { driver.bindSamplers(+SamplerBindingPoints::PER_RENDERABLE_SKINNING, - info.skinningTexture); + info.skinningTexture); + } } if (UTILS_UNLIKELY(info.morphWeightBuffer)) { diff --git a/filament/src/details/SkinningBuffer.cpp b/filament/src/details/SkinningBuffer.cpp index e03585870bc..4145d70de33 100644 --- a/filament/src/details/SkinningBuffer.cpp +++ b/filament/src/details/SkinningBuffer.cpp @@ -227,8 +227,6 @@ FSkinningBuffer::HandleIndicesAndWeights FSkinningBuffer::createIndicesAndWeight FEngine::DriverApi& driver = engine.getDriverApi(); auto size = getSkinningBufferSize(count); // create a texture for skinning pairs data (bone index and weight) - size = getSkinningBufferSize(count); - textureHandle = driver.createTexture(SamplerType::SAMPLER_2D, 1, TextureFormat::RG32F, 1, getSkinningBufferWidth(size), getSkinningBufferHeight(size), 1, diff --git a/filament/src/details/SkinningBuffer.h b/filament/src/details/SkinningBuffer.h index bfc1884fe70..49e067b6789 100644 --- a/filament/src/details/SkinningBuffer.h +++ b/filament/src/details/SkinningBuffer.h @@ -23,7 +23,7 @@ #include "private/filament/EngineEnums.h" #include "private/filament/UibStructs.h" -#include "backend/DriverApiForward.h" +#include #include diff --git a/filament/src/details/VertexBuffer.cpp b/filament/src/details/VertexBuffer.cpp index e8744cc7d74..db51ac63fdb 100644 --- a/filament/src/details/VertexBuffer.cpp +++ b/filament/src/details/VertexBuffer.cpp @@ -240,7 +240,7 @@ void FVertexBuffer::setBufferObjectAt(FEngine& engine, uint8_t bufferIndex, // store handle to recreate VertexBuffer in the case extra bone indices and weights definition // used only in buffer object mode mBufferObjects[bufferIndex] = hwBufferObject; - } else { + } else { ASSERT_PRECONDITION(bufferIndex < mBufferCount, "bufferIndex must be < bufferCount"); } } @@ -281,7 +281,7 @@ void FVertexBuffer::updateBoneIndicesAndWeights(FEngine& engine, auto const& attributes = mAttributes; uint8_t attributeCount = (uint8_t) mDeclaredAttributes.count(); - #pragma nounroll + UTILS_NOUNROLL for (size_t i = 0, n = attributeArray.size(); i < n; ++i) { if (declaredAttributes[i]) { const uint32_t offset = attributes[i].offset; @@ -302,20 +302,23 @@ void FVertexBuffer::updateBoneIndicesAndWeights(FEngine& engine, FEngine::DriverApi& driver = engine.getDriverApi(); //destroy old bone buffer objects if any if (!mBufferObjectsEnabled) { - if (slotIndicesOld != Attribute::BUFFER_UNUSED) + if (slotIndicesOld != Attribute::BUFFER_UNUSED) { driver.destroyBufferObject(mBufferObjects[slotIndicesOld]); - if (slotIndicesOld != Attribute::BUFFER_UNUSED) + } + if (slotIndicesOld != Attribute::BUFFER_UNUSED) { driver.destroyBufferObject(mBufferObjects[slotWeightsOld]); + } } //destroy old and create new vertex buffer auto oldHandle = mHandle; mHandle = driver.createVertexBuffer(mBufferCount + 2, attributeCount, mVertexCount, attributeArray); driver.destroyVertexBuffer(oldHandle); - #pragma nounroll + UTILS_NOUNROLL for (size_t i = 0; i < mBufferCount; ++i) - if (bufferSizes[i] > 0) + if (bufferSizes[i] > 0) { driver.setVertexBufferObject(mHandle, i, mBufferObjects[i]); + } // add new bone buffer objects mBufferCount++; auto boneJointsHandle = driver.createBufferObject(bufferSizes[mBufferCount - 1], @@ -334,7 +337,7 @@ void FVertexBuffer::updateBoneIndicesAndWeights(FEngine& engine, if (!mBufferObjectsEnabled) { mBufferObjects[mBufferCount - 2] = boneJointsHandle; mBufferObjects[mBufferCount - 1] = boneWeightsHandle; - }else{ + } else { //for correct destroy bone buffer object mBoneBufferObjectsUsed = true; mBoneJointsHandle = boneJointsHandle; diff --git a/libs/filamat/src/shaders/SibGenerator.cpp b/libs/filamat/src/shaders/SibGenerator.cpp index c6b774f16f8..b03a6f3035e 100644 --- a/libs/filamat/src/shaders/SibGenerator.cpp +++ b/libs/filamat/src/shaders/SibGenerator.cpp @@ -115,7 +115,7 @@ SamplerInterfaceBlock const& SibGenerator::getPerRenderPrimitiveBonesSib(Variant static SamplerInterfaceBlock sib = SamplerInterfaceBlock::Builder() .name("BonesBuffer") .stageFlags(backend::ShaderStageFlags::VERTEX) - .add({ { "indicesAndWeights", Type::SAMPLER_2D, Format::FLOAT, Precision::HIGH }}) + .add({{"indicesAndWeights", Type::SAMPLER_2D, Format::FLOAT, Precision::HIGH }}) .build(); return sib; diff --git a/samples/hellomorphing.cpp b/samples/hellomorphing.cpp index 1eee2e63269..b5886d3b7b9 100644 --- a/samples/hellomorphing.cpp +++ b/samples/hellomorphing.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -116,12 +116,12 @@ int main(int argc, char** argv) { app.mt1 = MorphTargetBuffer::Builder() .vertexCount(9) .count(3) - .build( *engine); + .build(*engine); app.mt2 = MorphTargetBuffer::Builder() .vertexCount(9) .count(3) - .build( *engine); + .build(*engine); app.mt1->setPositionsAt(*engine,0, targets_pos1, 3, 0); app.mt1->setPositionsAt(*engine,1, targets_pos1+3, 3, 0); diff --git a/samples/helloskinning.cpp b/samples/helloskinning.cpp index 71a152c7b10..f803eafec2d 100644 --- a/samples/helloskinning.cpp +++ b/samples/helloskinning.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -165,7 +165,7 @@ int main(int argc, char** argv) { mat4f trans[] = {filament::math::mat4f::translation(filament::math::float3{tr, 0, 0}), filament::math::mat4f::translation(filament::math::float3{-1, tr, 0}), filament::math::mat4f(1.f)}; - rm.setBones(rm.getInstance(app.renderable), trans,3, 0); + rm.setBones(rm.getInstance(app.renderable), trans, 3, 0); }); diff --git a/samples/helloskinningbuffer.cpp b/samples/helloskinningbuffer.cpp index bec7daf8618..a2b1326f9b6 100644 --- a/samples/helloskinningbuffer.cpp +++ b/samples/helloskinningbuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -85,8 +85,6 @@ mat4f transforms[] = {math::mat4f(1.f), mat4f::translation(float3(0, -1, 0)), mat4f::translation(float3(1, -1, 0))}; - - int main(int argc, char** argv) { Config config; config.title = "skinning buffer common for two renderables"; @@ -193,7 +191,7 @@ int main(int argc, char** argv) { app.cam->setProjection(Camera::Projection::ORTHO, -aspect * ZOOM, aspect * ZOOM, -ZOOM, ZOOM, 0, 1); - auto& tcm = engine->getTransformManager(); + auto& tcm = engine->getTransformManager(); // Transformation of both renderables tcm.setTransform(tcm.getInstance(app.renderable1), @@ -211,7 +209,7 @@ int main(int argc, char** argv) { mat4f translate[] = {mat4f::translation(float3(s, c, 0))}; mat4f trans1of8[9] = {}; - for(uint i = 0; i<9; i++){ + for (uint i = 0; i < 9; i++) { trans1of8[i] = filament::math::mat4f(1); } s *= 5; diff --git a/samples/helloskinningbuffer_morebones.cpp b/samples/helloskinningbuffer_morebones.cpp index fa00c82dcfa..3869cbb381c 100644 --- a/samples/helloskinningbuffer_morebones.cpp +++ b/samples/helloskinningbuffer_morebones.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,8 +84,9 @@ int main(int argc, char** argv) { size_t boneCount = 9; utils::FixedCapacityVector boneDataPerVertex(9); float weight = 1.f / boneCount; - for (size_t idx = 0; idx < boneCount; idx++) - boneDataPerVertex[idx] = float2(idx, weight); + for (size_t idx = 0; idx < boneCount; idx++) { + boneDataPerVertex[idx] = float2(idx, weight); + } auto idx = 0; boneDataPerPrimitive[idx++] = boneDataPerVertex; boneDataPerPrimitive[idx++] = boneDataPerVertex; @@ -197,7 +198,7 @@ int main(int argc, char** argv) { app.cam->setProjection(Camera::Projection::ORTHO, -aspect * ZOOM, aspect * ZOOM, -ZOOM, ZOOM, 0, 1); - auto& tcm = engine->getTransformManager(); + auto& tcm = engine->getTransformManager(); // Transformation of both renderables tcm.setTransform(tcm.getInstance(app.renderable1), @@ -215,7 +216,7 @@ int main(int argc, char** argv) { mat4f translate[] = {mat4f::translation(float3(s, c, 0))}; mat4f trans[9] = {}; - for(uint i = 0; i < 9; i++){ + for (uint i = 0; i < 9; i++) { trans[i] = filament::math::mat4f(1); } s *= 5; diff --git a/samples/skinningtest.cpp b/samples/skinningtest.cpp index 0f6052fcebb..189945eef4e 100644 --- a/samples/skinningtest.cpp +++ b/samples/skinningtest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -114,7 +114,7 @@ int main(int argc, char** argv) { size_t boneCount = 8; utils::FixedCapacityVector boneDataPerVertex(boneCount); float weight = 1.f / boneCount; - for (uint idx = 0; idx < boneCount; idx++){ + for (uint idx = 0; idx < boneCount; idx++) { boneDataArray[idx] = float2(idx, weight); boneDataArray[idx + boneCount] = float2(idx, weight); boneDataArray[idx + 2*boneCount] = float2(idx, weight); @@ -123,7 +123,7 @@ int main(int argc, char** argv) { utils::FixedCapacityVector boneDataPerVertex2(3); boneCount = 3; weight = 1.f / boneCount; - for (uint idx = 0; idx < boneCount; idx++){ + for (uint idx = 0; idx < boneCount; idx++) { boneDataPerVertex2[idx] = float2(idx, weight); } @@ -389,11 +389,11 @@ int main(int argc, char** argv) { uint offset = ((uint)now) % 9; float s = sin(t * f::PI * 2.f) * 10; mat4f trans[9] = {}; - for(uint i = 0; i < 9; i++){ + for (uint i = 0; i < 9; i++) { trans[i] = filament::math::mat4f(1); } mat4f trans2[9] = {}; - for(uint i = 0; i < 9; i++){ + for (uint i = 0; i < 9; i++) { trans2[i] = filament::math::mat4f(1); } mat4f transA[] = { diff --git a/samples/suzanneskinning.cpp b/samples/suzanneskinning.cpp index 1d835c9fd63..9ee35738b05 100644 --- a/samples/suzanneskinning.cpp +++ b/samples/suzanneskinning.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -152,10 +152,11 @@ int main(int argc, char** argv) { int boneCount = 9; utils::FixedCapacityVector boneDataPerVertex(boneCount); // index and weight for one vertex - for (size_t idx = 0; idx < boneCount; idx++) - boneDataPerVertex[idx] = float2(idx, 1.f / boneCount); - for (size_t idx = 0; idx < boneDataPerPrimitive.size(); idx++){ - boneDataPerPrimitive[idx] = boneDataPerVertex; + for (size_t idx = 0; idx < boneCount; idx++) { + boneDataPerVertex[idx] = float2(idx, 1.f / boneCount); + } + for (size_t idx = 0; idx < boneDataPerPrimitive.size(); idx++) { + boneDataPerPrimitive[idx] = boneDataPerVertex; } Config config; @@ -276,7 +277,6 @@ FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { mat4f::translation(float3(s1, 0, 0)), mat4f::translation(float3(0, s2, 0)), mat4f::translation(float3(0, 0, s3)), -// mat4f::translation(float3(0, 0, 20))*mat4f::rotation(t * f::PI * 2.f, float3(1, 0, 0))*mat4f::translation(float3(0, 0, -20)) }; app.sb->setBones(*engine,trans,9,0); diff --git a/shaders/src/getters.vs b/shaders/src/getters.vs index ee1e33d3dc9..b77dc053849 100644 --- a/shaders/src/getters.vs +++ b/shaders/src/getters.vs @@ -65,7 +65,7 @@ vec3 mulBoneVertex(vec3 v, uint i) { void skinPosition(inout vec3 p, const uvec4 ids, const vec4 weights) { // standard skinning for 4 weights, some of them could be zero - if (weights.w >= 0.0){ + if (weights.w >= 0.0) { p = weights.x * mulBoneVertex(p, uint(ids.x)) + weights.y * mulBoneVertex(p, uint(ids.y)) + weights.z * mulBoneVertex(p, uint(ids.z)) @@ -75,7 +75,8 @@ void skinPosition(inout vec3 p, const uvec4 ids, const vec4 weights) { // skinning for >4 weights vec3 posSum = weights.x * mulBoneVertex(p, uint(ids.x)); posSum += weights.y * mulBoneVertex(p, uint(ids.y)); - posSum += weights.z * mulBoneVertex(p, uint(ids.z));uint pairIndex = -uint(weights.w + 1.); + posSum += weights.z * mulBoneVertex(p, uint(ids.z)); + uint pairIndex = uint(-weights.w - 1.); uint pairStop = pairIndex + uint(ids.w - 3u); for (uint i = pairIndex; i < pairStop; i = i + 1u) { ivec2 texcoord = ivec2(i % MAX_SKINNING_BUFFER_WIDTH, i / MAX_SKINNING_BUFFER_WIDTH); @@ -87,18 +88,18 @@ void skinPosition(inout vec3 p, const uvec4 ids, const vec4 weights) { void skinNormal(inout vec3 n, const uvec4 ids, const vec4 weights) { // standard skinning for 4 weights, some of them could be zero - if (weights.w >= 0.0){ - n = weights.x * mulBoneVertex(n, uint(ids.x)) - + weights.y * mulBoneVertex(n, uint(ids.y)) - + weights.z * mulBoneVertex(n, uint(ids.z)) - + weights.w * mulBoneVertex(n, uint(ids.w)); + if (weights.w >= 0.0) { + n = weights.x * mulBoneNormal(n, uint(ids.x)) + + weights.y * mulBoneNormal(n, uint(ids.y)) + + weights.z * mulBoneNormal(n, uint(ids.z)) + + weights.w * mulBoneNormal(n, uint(ids.w)); return; } // skinning for >4 weights vec3 normSum = weights.x * mulBoneNormal(n, uint(ids.x)); normSum += weights.y * mulBoneNormal(n, uint(ids.y)); normSum += weights.z * mulBoneNormal(n, uint(ids.z)); - uint pairIndex = -uint(weights.w + 1.); + uint pairIndex = uint(-weights.w - 1.); uint pairStop = pairIndex + uint(ids.w - 3u); for (uint i = pairIndex; i < pairStop; i = i + 1u) { ivec2 texcoord = ivec2(i % MAX_SKINNING_BUFFER_WIDTH, i / MAX_SKINNING_BUFFER_WIDTH); @@ -109,17 +110,17 @@ void skinNormal(inout vec3 n, const uvec4 ids, const vec4 weights) { n = normSum; } -void skinTwoVectors(inout vec3 n, inout vec3 t, const uvec4 ids, const vec4 weights) { +void skinNormalTangent(inout vec3 n, inout vec3 t, const uvec4 ids, const vec4 weights) { // standard skinning for 4 weights, some of them could be zero - if (weights.w >= 0.0){ - n = weights.x * mulBoneVertex(n, uint(ids.x)) - + weights.y * mulBoneVertex(n, uint(ids.y)) - + weights.z * mulBoneVertex(n, uint(ids.z)) - + weights.w * mulBoneVertex(n, uint(ids.w)); - t = weights.x * mulBoneVertex(t, uint(ids.x)) - + weights.y * mulBoneVertex(t, uint(ids.y)) - + weights.z * mulBoneVertex(t, uint(ids.z)) - + weights.w * mulBoneVertex(t, uint(ids.w)); + if (weights.w >= 0.0) { + n = weights.x * mulBoneNormal(n, uint(ids.x)) + + weights.y * mulBoneNormal(n, uint(ids.y)) + + weights.z * mulBoneNormal(n, uint(ids.z)) + + weights.w * mulBoneNormal(n, uint(ids.w)); + t = weights.x * mulBoneNormal(t, uint(ids.x)) + + weights.y * mulBoneNormal(t, uint(ids.y)) + + weights.z * mulBoneNormal(t, uint(ids.z)) + + weights.w * mulBoneNormal(t, uint(ids.w)); return; } // skinning for >4 weights @@ -129,7 +130,7 @@ void skinTwoVectors(inout vec3 n, inout vec3 t, const uvec4 ids, const vec4 weig vec3 tangSum = weights.x * mulBoneNormal(t, uint(ids.x)); tangSum += weights.y * mulBoneNormal(t, uint(ids.y)); tangSum += weights.z * mulBoneNormal(t, uint(ids.z)); - uint pairIndex = -uint(weights.w + 1.); + uint pairIndex = uint(-weights.w - 1.); uint pairStop = pairIndex + uint(ids.w - 3u); for (uint i = pairIndex; i < pairStop; i = i + 1u) { ivec2 texcoord = ivec2(i % MAX_SKINNING_BUFFER_WIDTH, i / MAX_SKINNING_BUFFER_WIDTH); diff --git a/shaders/src/main.vs b/shaders/src/main.vs index 37bbc123a9b..a416bccc37b 100644 --- a/shaders/src/main.vs +++ b/shaders/src/main.vs @@ -81,7 +81,7 @@ void main() { } if ((object_uniforms.flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) { - skinTwoVectors(material.worldNormal, vertex_worldTangent.xyz, mesh_bone_indices, mesh_bone_weights); + skinNormalTangent(material.worldNormal, vertex_worldTangent.xyz, mesh_bone_indices, mesh_bone_weights); } #endif From f5900e2b6e8d734ff4f70d3b4f6cd325d22cdad9 Mon Sep 17 00:00:00 2001 From: brunojezek Date: Thu, 11 May 2023 15:23:50 +0200 Subject: [PATCH 08/24] Clean the code --- filament/include/filament/RenderableManager.h | 1 - filament/src/components/RenderableManager.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index 25dd9fce6f6..bebcce0f6cd 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -31,7 +31,6 @@ #include #include -#include namespace utils { class Entity; diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index e6ea5dc883c..24afa3c0aca 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -379,7 +379,7 @@ RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& eng ASSERT_PRECONDITION(mImpl->mSkinningBoneCount <= CONFIG_MAX_BONE_COUNT, "bone count > %u", CONFIG_MAX_BONE_COUNT); - if (UTILS_LIKELY(mImpl->mSkinningBoneCount) || UTILS_LIKELY(mImpl->mSkinningBufferMode)) { + if (UTILS_LIKELY(mImpl->mSkinningBoneCount || mImpl->mSkinningBufferMode)) { processBoneIndicesAndWights(engine, entity); } From a7f248245d67aa7f77d54472c9fe0c2b64d49e3d Mon Sep 17 00:00:00 2001 From: brunojezek Date: Fri, 12 May 2023 15:52:59 +0200 Subject: [PATCH 09/24] Fix memory operations Use std::unique_ptr for skinJoints, skinWeights, and tempPairs variables to free memory Move processBoneIndicesAndWights to RenderableManager::BuilderDetails --- filament/include/filament/RenderableManager.h | 1 - filament/src/components/RenderableManager.cpp | 96 +++++++++++-------- filament/src/details/VertexBuffer.cpp | 12 ++- filament/src/details/VertexBuffer.h | 3 +- 4 files changed, 66 insertions(+), 46 deletions(-) diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index bebcce0f6cd..6a79d1dfcaa 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -545,7 +545,6 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { size_t count = 0; } morphing; }; - void processBoneIndicesAndWights(Engine& engine, utils::Entity entity); }; /** diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 24afa3c0aca..3feba38a85a 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -80,6 +80,9 @@ struct RenderableManager::BuilderDetails { } // this is only needed for the explicit instantiation below BuilderDetails() = default; + + void processBoneIndicesAndWights(Engine& engine, utils::Entity entity); + }; using BuilderType = RenderableManager; @@ -211,21 +214,21 @@ RenderableManager::Builder& RenderableManager::Builder::enableSkinningBuffers(bo } RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(size_t primitiveIndex, - math::float2 const* indicesAndWeights, size_t count, size_t bonesPerVertex) noexcept{ + math::float2 const* indicesAndWeights, size_t count, size_t bonesPerVertex) noexcept { size_t vertexCount = count / bonesPerVertex; utils::FixedCapacityVector> bonePairs(vertexCount); - for( size_t iVertex = 0; iVertex < vertexCount; iVertex++) { + for ( size_t iVertex = 0; iVertex < vertexCount; iVertex++) { utils::FixedCapacityVector vertexData(bonesPerVertex); std::copy_n(indicesAndWeights + iVertex * bonesPerVertex, bonesPerVertex, vertexData.data()); bonePairs[iVertex] = std::move(vertexData); } - return boneIndicesAndWeights(primitiveIndex, bonePairs); + return boneIndicesAndWeights(primitiveIndex, bonePairs); } RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(size_t primitiveIndex, - const utils::FixedCapacityVector< - utils::FixedCapacityVector> &indicesAndWeightsVector) noexcept{ + utils::FixedCapacityVector< + utils::FixedCapacityVector> const &indicesAndWeightsVector) noexcept { mImpl->mBonePairs[primitiveIndex] = std::move(indicesAndWeightsVector); return *this; } @@ -269,16 +272,16 @@ RenderableManager::Builder& RenderableManager::Builder::globalBlendOrderEnabled( } UTILS_NOINLINE -void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Entity entity){ +void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engine, Entity entity) { size_t maxPairsCount = 0; //size of texture, number of bone pairs size_t maxPairsCountPerVertex = 0; //maximum of number of bone per vertex - for(auto iBonePair = mImpl->mBonePairs.begin(); iBonePair != mImpl->mBonePairs.end(); ++iBonePair){ + for (auto iBonePair = mBonePairs.begin(); iBonePair != mBonePairs.end(); ++iBonePair){ auto primitiveIndex = iBonePair->first; - auto entries = mImpl->mEntries; + auto entries = mEntries; ASSERT_PRECONDITION(primitiveIndex < entries.size() && primitiveIndex >= 0, "[primitive @ %u] primitiveindex is out of size (%u)", primitiveIndex, entries.size()); - auto entry = mImpl->mEntries[primitiveIndex]; + auto entry = mEntries[primitiveIndex]; auto bonePairsForPrimitive = iBonePair->second; auto vertexCount = entry.vertices->getVertexCount(); ASSERT_PRECONDITION(bonePairsForPrimitive.size() == vertexCount, @@ -291,7 +294,7 @@ void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Ent ASSERT_PRECONDITION(!declaredAttributes[VertexAttribute::BONE_WEIGHTS], "[entity=%u, primitive @ %u] vertex attribute BONE_WEIGHTS for skinning are already defined", entity.getId(), primitiveIndex); - for (size_t iVertex = 0; iVertex < vertexCount; iVertex++){ + for (size_t iVertex = 0; iVertex < vertexCount; iVertex++) { auto bonesPerVertex = bonePairsForPrimitive[iVertex].size(); maxPairsCount += bonesPerVertex; maxPairsCountPerVertex = max(bonesPerVertex, (uint) maxPairsCountPerVertex); @@ -299,35 +302,36 @@ void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Ent } size_t pairsCount = 0; // counting of number of pairs stored in texture - float2* tempPairs; // temporary indices and weights for one vertex if (maxPairsCount) { // at least one primitive has bone indices and weights - mImpl->mBoneIndicesAndWeight = (float2*) malloc( - maxPairsCount * 2 * 4); // final texture data, indices and weights - tempPairs = (float2*) malloc(maxPairsCountPerVertex * 2 - * 4); // temporary indices and weights for one vertex - for(auto iBonePair = mImpl->mBonePairs.begin(); iBonePair != mImpl->mBonePairs.end(); ++iBonePair){ + mBoneIndicesAndWeight = (float2*) calloc(maxPairsCount, + sizeof(float2)); // final texture data, indices and weights + std::unique_ptr tempPairs( + new float2[maxPairsCountPerVertex]); // temporary indices and weights for one vertex + for (auto iBonePair = mBonePairs.begin(); iBonePair != mBonePairs.end(); ++iBonePair) { auto primitiveIndex = iBonePair->first; auto bonePairsForPrimitive = iBonePair->second; - if (bonePairsForPrimitive.size()){ - size_t vertexCount = mImpl->mEntries[primitiveIndex].vertices->getVertexCount(); - auto skinJoints = (ushort*) malloc(vertexCount * 4 * 2); - auto skinWeights = (float*) malloc(vertexCount * 4 * 4); - for(size_t iVertex = 0; iVertex < vertexCount; iVertex++) { + if (bonePairsForPrimitive.size()) { + size_t vertexCount = mEntries[primitiveIndex].vertices->getVertexCount(); + std::unique_ptr skinJoints( + new ushort[4 * vertexCount]()); // temporary indices for one vertex + std::unique_ptr skinWeights( + new float[4 * vertexCount]()); // temporary weights for one vertex + for (size_t iVertex = 0; iVertex < vertexCount; iVertex++) { size_t tempPairCount = 0; float boneWeightsSum = 0; - for (size_t k = 0; k < bonePairsForPrimitive[iVertex].size(); k++){ + for (size_t k = 0; k < bonePairsForPrimitive[iVertex].size(); k++) { auto boneWeight = bonePairsForPrimitive[iVertex][k][1]; auto boneIndex= bonePairsForPrimitive[iVertex][k][0]; ASSERT_PRECONDITION(boneWeight >= 0, "[entity=%u, primitive @ %u] bone weight (%f) of vertex=%u is negative ", entity.getId(), primitiveIndex, boneWeight, iVertex); - if (boneWeight){ + if (boneWeight) { ASSERT_PRECONDITION(boneIndex >= 0, "[entity=%u, primitive @ %u] bone index (%i) of vertex=%u is negative ", entity.getId(), primitiveIndex, (int) boneIndex, iVertex); - ASSERT_PRECONDITION(boneIndex < mImpl->mSkinningBoneCount, + ASSERT_PRECONDITION(boneIndex < mSkinningBoneCount, "[entity=%u, primitive @ %u] bone index (%i) of vertex=%u is bigger then bone count (%u) ", - entity.getId(), primitiveIndex, (int) boneIndex, iVertex, mImpl->mSkinningBoneCount); + entity.getId(), primitiveIndex, (int) boneIndex, iVertex, mSkinningBoneCount); boneWeightsSum += boneWeight; tempPairs[tempPairCount][0] = boneIndex; tempPairs[tempPairCount][1] = boneWeight; @@ -338,11 +342,12 @@ void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Ent ASSERT_PRECONDITION(boneWeightsSum > 0, "[entity=%u, primitive @ %u] sum of bone weights of vertex=%u is %f, it should be positive.", entity.getId(), primitiveIndex, iVertex, boneWeightsSum); - if (abs(boneWeightsSum - 1.f) > std::numeric_limits::epsilon()) - utils::slog.w << "Warning of skinning: [entity=%" << entity.getId() <<", primitive @ %" << primitiveIndex - << "] sum of bone weights of vertex=" << iVertex << " is " << boneWeightsSum - << ", it should be one. Weights will be normalized." << utils::io::endl; - + if (abs(boneWeightsSum - 1.f) > std::numeric_limits::epsilon()) { + utils::slog.w << "Warning of skinning: [entity=%" << entity.getId() + << ", primitive @ %" << primitiveIndex + << "] sum of bone weights of vertex=" << iVertex << " is " << boneWeightsSum + << ", it should be one. Weights will be normalized." << utils::io::endl; + } // prepare data for vertex attributes auto offset = iVertex * 4; // set attributes, indices and weights, for <= 4 pairs @@ -350,27 +355,23 @@ void RenderableManager::Builder::processBoneIndicesAndWights(Engine& engine, Ent skinJoints[j + offset] = tempPairs[j][0]; skinWeights[j + offset] = tempPairs[j][1] / boneWeightsSum; } - // reset rest weights - for (size_t j = tempPairCount; j < 4; j++) - skinWeights[j + offset] = 0; // prepare data for texture - if (tempPairCount > 4) - { // set attributes, indices and weights, for > 4 pairs + if (tempPairCount > 4) { // set attributes, indices and weights, for > 4 pairs skinWeights[3 + offset] = -(float) (pairsCount + 1); // negative offset to texture 0..-1, 1..-2 skinJoints[3 + offset] = (ushort) tempPairCount; // number pairs per vertex in texture for (size_t j = 3; j < tempPairCount; j++) { - mImpl->mBoneIndicesAndWeight[pairsCount][0] = tempPairs[j][0]; - mImpl->mBoneIndicesAndWeight[pairsCount][1] = tempPairs[j][1] / boneWeightsSum; + mBoneIndicesAndWeight[pairsCount][0] = tempPairs[j][0]; + mBoneIndicesAndWeight[pairsCount][1] = tempPairs[j][1] / boneWeightsSum; pairsCount++; } } } // for all vertices per primitive - downcast(mImpl->mEntries[primitiveIndex].vertices) - ->updateBoneIndicesAndWeights(downcast(engine), skinJoints, skinWeights); + downcast(mEntries[primitiveIndex].vertices) + ->updateBoneIndicesAndWeights(downcast(engine), std::move(skinJoints), std::move(skinWeights)); } }// for all primitives } - mImpl->mBoneIndicesAndWeightsCount = pairsCount; + mBoneIndicesAndWeightsCount = pairsCount; } RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& engine, Entity entity) { @@ -378,9 +379,22 @@ RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& eng ASSERT_PRECONDITION(mImpl->mSkinningBoneCount <= CONFIG_MAX_BONE_COUNT, "bone count > %u", CONFIG_MAX_BONE_COUNT); + ASSERT_PRECONDITION(mImpl->mInstanceCount <= CONFIG_MAX_INSTANCES || !mImpl->mInstanceBuffer, + "instance count is %zu, but instance count is limited to CONFIG_MAX_INSTANCES (%zu) " + "instances when supplying transforms via an InstanceBuffer.", + mImpl->mInstanceCount, + CONFIG_MAX_INSTANCES); + if (mImpl->mInstanceBuffer) { + size_t bufferInstanceCount = mImpl->mInstanceBuffer->mInstanceCount; + ASSERT_PRECONDITION(mImpl->mInstanceCount <= bufferInstanceCount, + "instance count (%zu) must be less than or equal to the InstanceBuffer's instance " + "count " + "(%zu).", + mImpl->mInstanceCount, bufferInstanceCount); + } if (UTILS_LIKELY(mImpl->mSkinningBoneCount || mImpl->mSkinningBufferMode)) { - processBoneIndicesAndWights(engine, entity); + mImpl->processBoneIndicesAndWights(engine, entity); } for (size_t i = 0, c = mImpl->mEntries.size(); i < c; i++) { diff --git a/filament/src/details/VertexBuffer.cpp b/filament/src/details/VertexBuffer.cpp index db51ac63fdb..9703a539b24 100644 --- a/filament/src/details/VertexBuffer.cpp +++ b/filament/src/details/VertexBuffer.cpp @@ -244,8 +244,10 @@ void FVertexBuffer::setBufferObjectAt(FEngine& engine, uint8_t bufferIndex, ASSERT_PRECONDITION(bufferIndex < mBufferCount, "bufferIndex must be < bufferCount"); } } + void FVertexBuffer::updateBoneIndicesAndWeights(FEngine& engine, - ushort* skinJoints, float* skinWeights) { + std::unique_ptr skinJoints, + std::unique_ptr skinWeights) { AttributeArray attributeArray; static_assert(attributeArray.size() == MAX_VERTEX_ATTRIBUTE_COUNT, @@ -324,15 +326,19 @@ void FVertexBuffer::updateBoneIndicesAndWeights(FEngine& engine, auto boneJointsHandle = driver.createBufferObject(bufferSizes[mBufferCount - 1], backend::BufferObjectBinding::VERTEX, backend::BufferUsage::STATIC); driver.setVertexBufferObject(mHandle, mBufferCount - 1, boneJointsHandle); + auto jointsData = skinJoints.release(); auto bdJoints = BufferDescriptor( - skinJoints, bufferSizes[mBufferCount - 1], nullptr); + jointsData, bufferSizes[mBufferCount - 1], + [](void *buffer, size_t size, void *user) { delete static_cast(buffer); }); driver.updateBufferObject(boneJointsHandle,std::move(bdJoints), 0); mBufferCount++; auto boneWeightsHandle = driver.createBufferObject(bufferSizes[mBufferCount - 1], backend::BufferObjectBinding::VERTEX, backend::BufferUsage::STATIC); driver.setVertexBufferObject(mHandle, mBufferCount - 1, boneWeightsHandle); + auto weightsData = skinWeights.release(); auto bdWeights = BufferDescriptor( - skinWeights, bufferSizes[mBufferCount - 1], nullptr); + weightsData, bufferSizes[mBufferCount - 1], + [](void *buffer, size_t size, void *user) { delete static_cast(buffer); }); driver.updateBufferObject(boneWeightsHandle,std::move(bdWeights), 0); if (!mBufferObjectsEnabled) { mBufferObjects[mBufferCount - 2] = boneJointsHandle; diff --git a/filament/src/details/VertexBuffer.h b/filament/src/details/VertexBuffer.h index 040d411e0cd..c713b9b52f9 100644 --- a/filament/src/details/VertexBuffer.h +++ b/filament/src/details/VertexBuffer.h @@ -61,7 +61,8 @@ class FVertexBuffer : public VertexBuffer { void setBufferObjectAt(FEngine& engine, uint8_t bufferIndex, FBufferObject const * bufferObject); - void updateBoneIndicesAndWeights(FEngine& engine, ushort* skinJoints, float* skinWeights); + void updateBoneIndicesAndWeights(FEngine& engine, std::unique_ptr skinJoints, + std::unique_ptr skinWeights); private: friend class VertexBuffer; From c95ef89b7e2defd8d103e260ffd610a29f616ad2 Mon Sep 17 00:00:00 2001 From: brunojezek Date: Thu, 25 May 2023 10:10:46 +0200 Subject: [PATCH 10/24] Update advanced skinning API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add VertexBuffer::Builder:advancedSkinning Update samples for this api Sample “suzanneskinning” does not work !! --- filament/include/filament/RenderableManager.h | 6 + filament/include/filament/VertexBuffer.h | 11 + filament/src/RenderPass.h | 4 +- filament/src/components/RenderableManager.cpp | 21 +- filament/src/details/VertexBuffer.cpp | 159 ++---- filament/src/details/VertexBuffer.h | 4 +- samples/helloskinning.cpp | 2 +- samples/helloskinningbuffer_morebones.cpp | 2 + samples/skinningtest.cpp | 513 +++++++++++------- samples/suzanneskinning.cpp | 2 +- 10 files changed, 417 insertions(+), 307 deletions(-) diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index 6a79d1dfcaa..2c5dd60304e 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -356,6 +356,7 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS defined in the VertexBuffer. * Both ways of indices and weights definition must not be combined in one primitive. * Number of pairs per vertex bonesPerVertex is not limited to 4 bones. + * Vertex buffer used for \c primitiveIndex must be set for advance skinning. * All bone weights of one vertex should sum to one. Otherwise they will be normalized. * Data must be rectangular and number of bone pairs must be same for all vertices of this * primitive. @@ -370,6 +371,8 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * @param bonesPerVertex number of bone pairs, same for all vertices of the primitive * * @return Builder reference for chaining calls. + * + * @see VertexBuffer:Builder:advancedSkinning */ Builder& boneIndicesAndWeights(size_t primitiveIndex, math::float2 const* indicesAndWeights, size_t count, size_t bonesPerVertex) noexcept; @@ -380,6 +383,7 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS defined in the VertexBuffer. * Both ways of indices and weights definition must not be combined in one primitive. * Number of pairs is not limited to 4 bones per vertex. + * Vertex buffer used for \c primitiveIndex must be set for advance skinning. * All bone weights of one vertex should sum to one. Otherwise they will be normalized. * Data doesn't have to be rectangular and number of pairs per vertices of primitive can be * variable. @@ -391,6 +395,8 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * the primitive sequentially * * @return Builder reference for chaining calls. + * + * @see VertexBuffer:Builder:advancedSkinning */ Builder& boneIndicesAndWeights(size_t primitiveIndex, utils::FixedCapacityVector< diff --git a/filament/include/filament/VertexBuffer.h b/filament/include/filament/VertexBuffer.h index 9557a541bc0..9c76e075da7 100644 --- a/filament/include/filament/VertexBuffer.h +++ b/filament/include/filament/VertexBuffer.h @@ -142,6 +142,17 @@ class UTILS_PUBLIC VertexBuffer : public FilamentAPI { */ Builder& normalized(VertexAttribute attribute, bool normalize = true) noexcept; + /** + * Sets advanced skinning mode. Bone data, indices and weights will be + * set in RenderableManager:Builder:boneIndicesAndWeights methods. + * Works with or without buffer objects. + * + * @return A reference to this Builder for chaining calls. + * + * @see RenderableManager:Builder:boneIndicesAndWeights + */ + Builder& advancedSkinning() noexcept; + /** * Creates the VertexBuffer object and returns a pointer to it. * diff --git a/filament/src/RenderPass.h b/filament/src/RenderPass.h index 6e1254b4e77..abcba7288c2 100644 --- a/filament/src/RenderPass.h +++ b/filament/src/RenderPass.h @@ -224,7 +224,7 @@ class RenderPass { return boolish ? value : uint64_t(0); } - struct PrimitiveInfo { // 56 bytes + struct PrimitiveInfo { // 48 bytes union { FMaterialInstance const* mi; uint64_t padding = {}; // ensures mi is 8 bytes on all archs @@ -240,7 +240,7 @@ class RenderPass { uint32_t skinningOffset = 0; // 4 bytes uint16_t instanceCount; // 2 bytes [MSb: user] Variant materialVariant; // 1 byte - uint8_t reserved[0] = {}; // 1 byte + uint8_t reserved[0] = {}; // 4 bytes static const uint16_t USER_INSTANCE_MASK = 0x8000u; static const uint16_t INSTANCE_COUNT_MASK = 0x7fffu; diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 3feba38a85a..f9d1e75d4f7 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -68,7 +68,7 @@ struct RenderableManager::BuilderDetails { FSkinningBuffer* mSkinningBuffer = nullptr; FInstanceBuffer* mInstanceBuffer = nullptr; uint32_t mSkinningBufferOffset = 0; - float2* mBoneIndicesAndWeight = nullptr; + float2* mBoneIndicesAndWeights = nullptr; size_t mBoneIndicesAndWeightsCount = 0; std::unordered_map> const &indicesAndWeightsVector) noexcept { - mImpl->mBonePairs[primitiveIndex] = std::move(indicesAndWeightsVector); + //mImpl->mBonePairs[primitiveIndex] = std::move(indicesAndWeightsVector); + mImpl->mBonePairs[primitiveIndex] = indicesAndWeightsVector; return *this; } @@ -288,11 +289,8 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi "[primitive @ %u] bone indices and weights pairs count (%u) must be equal to vertex count (%u)", primitiveIndex, bonePairsForPrimitive.size(), vertexCount); auto const& declaredAttributes = downcast(entry.vertices)->getDeclaredAttributes(); - ASSERT_PRECONDITION(!declaredAttributes[VertexAttribute::BONE_INDICES], - "[entity=%u, primitive @ %u] vertex attribute BONE_INDICES for skinning are already defined", - entity.getId(), primitiveIndex); - ASSERT_PRECONDITION(!declaredAttributes[VertexAttribute::BONE_WEIGHTS], - "[entity=%u, primitive @ %u] vertex attribute BONE_WEIGHTS for skinning are already defined", + ASSERT_PRECONDITION(declaredAttributes[VertexAttribute::BONE_INDICES] || declaredAttributes[VertexAttribute::BONE_WEIGHTS], + "[entity=%u, primitive @ %u] for advanced skinning set VertexBuffer::Builder::advancedSkinning()", entity.getId(), primitiveIndex); for (size_t iVertex = 0; iVertex < vertexCount; iVertex++) { auto bonesPerVertex = bonePairsForPrimitive[iVertex].size(); @@ -303,7 +301,7 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi size_t pairsCount = 0; // counting of number of pairs stored in texture if (maxPairsCount) { // at least one primitive has bone indices and weights - mBoneIndicesAndWeight = (float2*) calloc(maxPairsCount, + mBoneIndicesAndWeights = (float2*) calloc(maxPairsCount, sizeof(float2)); // final texture data, indices and weights std::unique_ptr tempPairs( new float2[maxPairsCountPerVertex]); // temporary indices and weights for one vertex @@ -360,8 +358,8 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi skinWeights[3 + offset] = -(float) (pairsCount + 1); // negative offset to texture 0..-1, 1..-2 skinJoints[3 + offset] = (ushort) tempPairCount; // number pairs per vertex in texture for (size_t j = 3; j < tempPairCount; j++) { - mBoneIndicesAndWeight[pairsCount][0] = tempPairs[j][0]; - mBoneIndicesAndWeight[pairsCount][1] = tempPairs[j][1] / boneWeightsSum; + mBoneIndicesAndWeights[pairsCount][0] = tempPairs[j][0]; + mBoneIndicesAndWeights[pairsCount][1] = tempPairs[j][1] / boneWeightsSum; pairsCount++; } } @@ -605,7 +603,8 @@ void FRenderableManager::create( downcast(builder->mSkinningBuffer)-> setIndicesAndWeightsData(downcast(engine), handle.texture, - builder->mBoneIndicesAndWeight, builder->mBoneIndicesAndWeightsCount); + builder->mBoneIndicesAndWeights, builder->mBoneIndicesAndWeightsCount); + delete[] builder->mBoneIndicesAndWeights; } // Create and initialize all needed MorphTargets. diff --git a/filament/src/details/VertexBuffer.cpp b/filament/src/details/VertexBuffer.cpp index 9703a539b24..89a142cdf57 100644 --- a/filament/src/details/VertexBuffer.cpp +++ b/filament/src/details/VertexBuffer.cpp @@ -36,6 +36,7 @@ struct VertexBuffer::BuilderDetails { uint32_t mVertexCount = 0; uint8_t mBufferCount = 0; bool mBufferObjectsEnabled = false; + bool mAdvancedSkinningEnabled = false; // TODO: use bits to save memory }; using BuilderType = VertexBuffer; @@ -112,6 +113,11 @@ VertexBuffer::Builder& VertexBuffer::Builder::normalized(VertexAttribute attribu return *this; } +VertexBuffer::Builder& VertexBuffer::Builder::advancedSkinning() noexcept { + mImpl->mAdvancedSkinningEnabled = true; + return *this; +} + VertexBuffer* VertexBuffer::Builder::build(Engine& engine) { ASSERT_PRECONDITION(mImpl->mVertexCount > 0, "vertexCount cannot be 0"); ASSERT_PRECONDITION(mImpl->mBufferCount > 0, "bufferCount cannot be 0"); @@ -139,7 +145,8 @@ VertexBuffer* VertexBuffer::Builder::build(Engine& engine) { FVertexBuffer::FVertexBuffer(FEngine& engine, const VertexBuffer::Builder& builder) : mVertexCount(builder->mVertexCount), mBufferCount(builder->mBufferCount), - mBufferObjectsEnabled(builder->mBufferObjectsEnabled) { + mBufferObjectsEnabled(builder->mBufferObjectsEnabled), + mAdvancedSkinningEnabled(builder->mAdvancedSkinningEnabled){ std::copy(std::begin(builder->mAttributes), std::end(builder->mAttributes), mAttributes.begin()); mDeclaredAttributes = builder->mDeclaredAttributes; @@ -153,6 +160,30 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const VertexBuffer::Builder& build static_assert(sizeof(Attribute) == sizeof(AttributeData), "Attribute and Builder::Attribute must match"); + if (mAdvancedSkinningEnabled) { + ASSERT_PRECONDITION(!mDeclaredAttributes[VertexAttribute::BONE_INDICES], + "Vertex buffer attribute BONE_INDICES is already defined"); + ASSERT_PRECONDITION(!mDeclaredAttributes[VertexAttribute::BONE_WEIGHTS], + "Vertex buffer attribute BONE_WEIGHTS is already defined"); + // ASSERT_PRECONDITION(mBufferObjectsEnabled, "Please use enableBufferObjects()"); + ASSERT_PRECONDITION(mBufferCount < (MAX_VERTEX_BUFFER_COUNT - 2), + "Vertex buffer uses to many buffers (%u)", mBufferCount); + mDeclaredAttributes.set(VertexAttribute::BONE_INDICES); + mAttributes[VertexAttribute::BONE_INDICES].offset = 0; + mAttributes[VertexAttribute::BONE_INDICES].stride = 8; + mAttributes[VertexAttribute::BONE_INDICES].buffer = mBufferCount; + mAttributes[VertexAttribute::BONE_INDICES].type = VertexBuffer::AttributeType::USHORT4; + mAttributes[VertexAttribute::BONE_INDICES].flags = Attribute::FLAG_INTEGER_TARGET; + mBufferCount++; + mDeclaredAttributes.set(VertexAttribute::BONE_WEIGHTS); + mAttributes[VertexAttribute::BONE_WEIGHTS].offset = 0; + mAttributes[VertexAttribute::BONE_WEIGHTS].stride = 16; + mAttributes[VertexAttribute::BONE_WEIGHTS].buffer = mBufferCount; + mAttributes[VertexAttribute::BONE_WEIGHTS].type = VertexBuffer::AttributeType::FLOAT4; + mAttributes[VertexAttribute::BONE_WEIGHTS].flags = 0; + mBufferCount++; + } + size_t bufferSizes[MAX_VERTEX_BUFFER_COUNT] = {}; auto const& declaredAttributes = mDeclaredAttributes; @@ -196,7 +227,18 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const VertexBuffer::Builder& build mBufferObjects[i] = bo; } } + } else { + // add buffer objects for indices and weights + if (mAdvancedSkinningEnabled) { + for (size_t i = mBufferCount - 2; i < mBufferCount; ++i) { + BufferObjectHandle const bo = driver.createBufferObject(bufferSizes[i], + backend::BufferObjectBinding::VERTEX, backend::BufferUsage::STATIC); + driver.setVertexBufferObject(mHandle, i, bo); + mBufferObjects[i] = bo; + } + } } + } void FVertexBuffer::terminate(FEngine& engine) { @@ -206,11 +248,7 @@ void FVertexBuffer::terminate(FEngine& engine) { driver.destroyBufferObject(bo); } } - if (mBoneBufferObjectsUsed){ - driver.destroyBufferObject(mBoneJointsHandle); - driver.destroyBufferObject(mBoneWeightsHandle); - } - driver.destroyVertexBuffer(mHandle); + driver.destroyVertexBuffer(mHandle); } size_t FVertexBuffer::getVertexCount() const noexcept { @@ -248,106 +286,21 @@ void FVertexBuffer::setBufferObjectAt(FEngine& engine, uint8_t bufferIndex, void FVertexBuffer::updateBoneIndicesAndWeights(FEngine& engine, std::unique_ptr skinJoints, std::unique_ptr skinWeights) { - AttributeArray attributeArray; - - static_assert(attributeArray.size() == MAX_VERTEX_ATTRIBUTE_COUNT, - "Attribute and Builder::Attribute arrays must match"); - - static_assert(sizeof(Attribute) == sizeof(AttributeData), - "Attribute and Builder::Attribute must match"); - - ASSERT_PRECONDITION(!mDeclaredAttributes[VertexAttribute::BONE_INDICES], - "Vertex buffer attribute BONE_INDICES is already defined"); - ASSERT_PRECONDITION(!mDeclaredAttributes[VertexAttribute::BONE_WEIGHTS], - "Vertex buffer attribute BONE_WEIGHTS is already defined"); - ASSERT_PRECONDITION(mBufferCount < (MAX_VERTEX_BUFFER_COUNT - 2), - "Vertex buffer uses to many buffers (%u)", mBufferCount); - - size_t bufferSizes[MAX_VERTEX_BUFFER_COUNT] = {}; - auto slotIndicesOld = mAttributes[VertexAttribute::BONE_INDICES].buffer; - mDeclaredAttributes.set(VertexAttribute::BONE_INDICES); - mAttributes[VertexAttribute::BONE_INDICES].offset = 0; - mAttributes[VertexAttribute::BONE_INDICES].stride = 8; - mAttributes[VertexAttribute::BONE_INDICES].buffer = mBufferCount; - mAttributes[VertexAttribute::BONE_INDICES].type = VertexBuffer::AttributeType::USHORT4; - mAttributes[VertexAttribute::BONE_INDICES].flags = Attribute::FLAG_INTEGER_TARGET; - auto slotWeightsOld = mAttributes[VertexAttribute::BONE_INDICES].buffer; - mDeclaredAttributes.set(VertexAttribute::BONE_WEIGHTS); - mAttributes[VertexAttribute::BONE_WEIGHTS].offset = 0; - mAttributes[VertexAttribute::BONE_WEIGHTS].stride = 16; - mAttributes[VertexAttribute::BONE_WEIGHTS].buffer = mBufferCount + 1; - mAttributes[VertexAttribute::BONE_WEIGHTS].type = VertexBuffer::AttributeType::FLOAT4; - mAttributes[VertexAttribute::BONE_WEIGHTS].flags = 0; - - auto const& declaredAttributes = mDeclaredAttributes; - auto const& attributes = mAttributes; - - uint8_t attributeCount = (uint8_t) mDeclaredAttributes.count(); - UTILS_NOUNROLL - for (size_t i = 0, n = attributeArray.size(); i < n; ++i) { - if (declaredAttributes[i]) { - const uint32_t offset = attributes[i].offset; - const uint8_t stride = attributes[i].stride; - const uint8_t slot = attributes[i].buffer; - - attributeArray[i].offset = offset; - attributeArray[i].stride = stride; - attributeArray[i].buffer = slot; - attributeArray[i].type = attributes[i].type; - attributeArray[i].flags = attributes[i].flags; - - const size_t end = offset + mVertexCount * stride; - bufferSizes[slot] = math::max(bufferSizes[slot], end); - } - } - - FEngine::DriverApi& driver = engine.getDriverApi(); - //destroy old bone buffer objects if any - if (!mBufferObjectsEnabled) { - if (slotIndicesOld != Attribute::BUFFER_UNUSED) { - driver.destroyBufferObject(mBufferObjects[slotIndicesOld]); - } - if (slotIndicesOld != Attribute::BUFFER_UNUSED) { - driver.destroyBufferObject(mBufferObjects[slotWeightsOld]); - } - } - - //destroy old and create new vertex buffer - auto oldHandle = mHandle; - mHandle = driver.createVertexBuffer(mBufferCount + 2, attributeCount, mVertexCount, attributeArray); - driver.destroyVertexBuffer(oldHandle); - UTILS_NOUNROLL - for (size_t i = 0; i < mBufferCount; ++i) - if (bufferSizes[i] > 0) { - driver.setVertexBufferObject(mHandle, i, mBufferObjects[i]); - } - // add new bone buffer objects - mBufferCount++; - auto boneJointsHandle = driver.createBufferObject(bufferSizes[mBufferCount - 1], - backend::BufferObjectBinding::VERTEX, backend::BufferUsage::STATIC); - driver.setVertexBufferObject(mHandle, mBufferCount - 1, boneJointsHandle); auto jointsData = skinJoints.release(); auto bdJoints = BufferDescriptor( - jointsData, bufferSizes[mBufferCount - 1], - [](void *buffer, size_t size, void *user) { delete static_cast(buffer); }); - driver.updateBufferObject(boneJointsHandle,std::move(bdJoints), 0); - mBufferCount++; - auto boneWeightsHandle = driver.createBufferObject(bufferSizes[mBufferCount - 1], - backend::BufferObjectBinding::VERTEX, backend::BufferUsage::STATIC); - driver.setVertexBufferObject(mHandle, mBufferCount - 1, boneWeightsHandle); + jointsData, mVertexCount * 8, + [](void *buffer, size_t size, void *user) { + delete static_cast(buffer); }); + engine.getDriverApi().updateBufferObject(mBufferObjects[mBufferCount - 2], + std::move(bdJoints), 0); + auto weightsData = skinWeights.release(); auto bdWeights = BufferDescriptor( - weightsData, bufferSizes[mBufferCount - 1], - [](void *buffer, size_t size, void *user) { delete static_cast(buffer); }); - driver.updateBufferObject(boneWeightsHandle,std::move(bdWeights), 0); - if (!mBufferObjectsEnabled) { - mBufferObjects[mBufferCount - 2] = boneJointsHandle; - mBufferObjects[mBufferCount - 1] = boneWeightsHandle; - } else { - //for correct destroy bone buffer object - mBoneBufferObjectsUsed = true; - mBoneJointsHandle = boneJointsHandle; - mBoneWeightsHandle = boneWeightsHandle; - } + weightsData, mVertexCount * 16, + [](void *buffer, size_t size, void *user) { + delete static_cast(buffer); }); + engine.getDriverApi().updateBufferObject(mBufferObjects[mBufferCount - 1], + std::move(bdWeights), 0); + } } // namespace filament diff --git a/filament/src/details/VertexBuffer.h b/filament/src/details/VertexBuffer.h index c713b9b52f9..dab4bb34dee 100644 --- a/filament/src/details/VertexBuffer.h +++ b/filament/src/details/VertexBuffer.h @@ -78,9 +78,7 @@ class FVertexBuffer : public VertexBuffer { uint32_t mVertexCount = 0; uint8_t mBufferCount = 0; bool mBufferObjectsEnabled = false; - bool mBoneBufferObjectsUsed = false; // mBoJointsHandle and mBoWeightsHandle are used, only in buffer object mode - BufferObjectHandle mBoneJointsHandle; // handle for extra bone indices BufferObject - BufferObjectHandle mBoneWeightsHandle; // handle for extra bone weights BufferObject + bool mAdvancedSkinningEnabled = false; }; FILAMENT_DOWNCAST(VertexBuffer) diff --git a/samples/helloskinning.cpp b/samples/helloskinning.cpp index f803eafec2d..d15f78ba1ff 100644 --- a/samples/helloskinning.cpp +++ b/samples/helloskinning.cpp @@ -108,7 +108,7 @@ int main(int argc, char** argv) { app.vb2->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES_WITHBONES + 3, 108, nullptr)); app.ib = IndexBuffer::Builder() - .indexCount(6) + .indexCount(4) .bufferType(IndexBuffer::IndexType::USHORT) .build(*engine); app.ib->setBuffer(*engine, diff --git a/samples/helloskinningbuffer_morebones.cpp b/samples/helloskinningbuffer_morebones.cpp index 3869cbb381c..31ee785cccd 100644 --- a/samples/helloskinningbuffer_morebones.cpp +++ b/samples/helloskinningbuffer_morebones.cpp @@ -105,6 +105,7 @@ int main(int argc, char** argv) { .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) + .advancedSkinning() .build(*engine); app.vb1->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr)); @@ -114,6 +115,7 @@ int main(int argc, char** argv) { .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) + .advancedSkinning() .build(*engine); app.vb2->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr)); diff --git a/samples/skinningtest.cpp b/samples/skinningtest.cpp index 189945eef4e..9f70dd64f47 100644 --- a/samples/skinningtest.cpp +++ b/samples/skinningtest.cpp @@ -42,16 +42,18 @@ using utils::EntityManager; using namespace filament::math; struct App { - VertexBuffer *vb0, *vb1, *vb2, *vb3, *vb4, *vb5, *vb6; - IndexBuffer* ib, *ib2; + VertexBuffer* vbs[10]; + size_t vbCount = 0; + IndexBuffer *ib, *ib2; Material* mat; Camera* cam; Entity camera; Skybox* skybox; - Entity renderable1, renderable2; + Entity renderables[4]; SkinningBuffer *sb, *sb2; MorphTargetBuffer *mt; - BufferObject *boTriangle, *boVertices, *boJoints, *boWeights; + BufferObject* bos[10]; + size_t boCount = 0; }; struct Vertex { @@ -59,40 +61,57 @@ struct Vertex { uint32_t color; }; -static const Vertex TRIANGLE_VERTICES[6] = { - {{1, 0}, 0xffff0000u}, - {{cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ff00u}, - {{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu}, - {{0, 1}, 0xffffff00u}, - {{-cos(M_PI * 2 / 3), -sin(M_PI * 2 / 3)}, 0xff00ffffu}, - {{-cos(M_PI * 4 / 3), -sin(M_PI * 4 / 3)}, 0xffff00ffu}, +static const Vertex TRIANGLE_VERTICES_1[6] = { + {{ 1, 0}, 0xff00ff00u}, + {{ cos(M_PI * 1 / 3), sin(M_PI * 1 / 3)}, 0xff330088u}, + {{ cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff880033u}, + {{-1, 0}, 0xff00ff00u}, + {{ cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff330088u}, + {{ cos(M_PI * 5 / 3), sin(M_PI * 5 / 3)}, 0xff880033u}, }; +static const Vertex TRIANGLE_VERTICES_2[6] = { + {{ 1, 0}, 0xff0000ffu}, + {{ cos(M_PI * 1 / 3), sin(M_PI * 1 / 3)}, 0xfff055ffu}, + {{ cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff880088u}, + {{-1, 0}, 0xff0000ffu}, + {{ cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xfff055ffu}, + {{ cos(M_PI * 5 / 3), sin(M_PI * 5 / 3)}, 0xff880088u}, +}; + +static const Vertex TRIANGLE_VERTICES_3[6] = { + {{ 1, 0}, 0xfff00f88u}, + {{ cos(M_PI * 1 / 3), sin(M_PI * 1 / 3)}, 0xff00ffaau}, + {{ cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ffffu}, + {{-1, 0}, 0xfff00f88u}, + {{ cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff00ffaau}, + {{ cos(M_PI * 5 / 3), sin(M_PI * 5 / 3)}, 0xff00ffffu}, +}; + + static const float3 targets_pos[9] = { - {-2, 0, 0},{0, 2, 0},{1, 0, 0}, - {1, 1, 0},{-1, 0, 0},{-1, 0, 0}, - {0, 0, 0},{0, 0, 0},{0, 0, 0} + { -2, 0, 0},{ 0, 2, 0},{ 1, 0, 0}, + { 1, 1, 0},{ -1, 0, 0},{ -1, 0, 0}, + { 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0} }; static const short4 targets_tan[9] = { - {0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}, - {0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}, - {0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0} -}; + { 0, 0, 0, 0},{ 0, 0, 0, 0},{ 0, 0, 0, 0}, + { 0, 0, 0, 0},{ 0, 0, 0, 0},{ 0, 0, 0, 0}, + { 0, 0, 0, 0},{ 0, 0, 0, 0},{ 0, 0, 0, 0}}; -static const ushort skinJoints[] = {0,1,2,5, +static const ushort skinJoints[] = { 0,1,2,5, 0,2,3,5, - 0,3,1,5 -}; + 0,3,1,5}; -static const float skinWeights[] = {0.5f,0.0f,0.0f,0.5f, - 0.5f,0.0f,0.f,0.5f, +static const float skinWeights[] = { 0.5f,0.0f,0.0f,0.5f, 0.5f,0.0f,0.f,0.5f, -}; + 0.5f,0.0f,0.f,0.5f,}; static float2 boneDataArray[48] = {}; //index and weight for 3 vertices X 8 bones -static constexpr uint16_t TRIANGLE_INDICES[6] = { 0, 1, 2, 3, 4, 5 }; +static constexpr uint16_t TRIANGLE_INDICES[3] = { 0, 1, 2 }, +TRIANGLE_INDICES_2[6] = { 0, 2, 4, 1, 3, 5 }; mat4f transforms[] = {math::mat4f(1), mat4f::translation(float3(1, 0, 0)), @@ -104,8 +123,8 @@ mat4f transforms[] = {math::mat4f(1), mat4f::translation(float3(0, -1, 0)), mat4f::translation(float3(1, -1, 0))}; -utils::FixedCapacityVector> boneDataPerPrimitive(3), boneDataPerPrimitive2(6); -utils::FixedCapacityVector>> boneDataPerRenderable(2); +utils::FixedCapacityVector> boneDataPerPrimitive(3), + boneDataPerPrimitive2(6); int main(int argc, char** argv) { Config config; @@ -117,7 +136,7 @@ int main(int argc, char** argv) { for (uint idx = 0; idx < boneCount; idx++) { boneDataArray[idx] = float2(idx, weight); boneDataArray[idx + boneCount] = float2(idx, weight); - boneDataArray[idx + 2*boneCount] = float2(idx, weight); + boneDataArray[idx + 2 * boneCount] = float2(idx, weight); boneDataPerVertex[idx] = float2(idx, weight); } utils::FixedCapacityVector boneDataPerVertex2(3); @@ -140,140 +159,203 @@ int main(int argc, char** argv) { boneDataPerPrimitive2[idx++] = boneDataPerVertex2; boneDataPerPrimitive2[idx++] = boneDataPerVertex; - idx = 0; - boneDataPerRenderable[idx++] = boneDataPerPrimitive; - boneDataPerRenderable[idx++] = boneDataPerPrimitive; - App app; auto setup = [&app](Engine* engine, View* view, Scene* scene) { - app.skybox = Skybox::Builder().color({0.1, 0.125, 0.25, 1.0}).build(*engine); + app.skybox = Skybox::Builder().color({ 0.1, 0.125, 0.25, 1.0}).build(*engine); scene->setSkybox(app.skybox); view->setPostProcessingEnabled(false); static_assert(sizeof(Vertex) == 12, "Strange vertex size."); - // primitive 0, triangle without skinning vertex attributes - app.vb0 = VertexBuffer::Builder() - .vertexCount(3) - .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) - .normalized(VertexAttribute::COLOR) - .build(*engine); - - // primitive 1, triangle without skinning vertex attributes - app.vb1 = VertexBuffer::Builder() - .vertexCount(3) - .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) - .normalized(VertexAttribute::COLOR) - .build(*engine); - - // primitive 2, triangle with skinning vertex attributes, buffer object disabled - app.vb2 = VertexBuffer::Builder() - .vertexCount(3) - .bufferCount(3) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) - .normalized(VertexAttribute::COLOR) - .attribute(VertexAttribute::BONE_INDICES, 1, VertexBuffer::AttributeType::USHORT4, 0, 8) - .attribute(VertexAttribute::BONE_WEIGHTS, 2, VertexBuffer::AttributeType::FLOAT4, 0, 16) - .build(*engine); - - // primitive 3, triangle without skinning vertex attributes, buffer object enabled - app.vb3 = VertexBuffer::Builder() - .vertexCount(3) - .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) - .normalized(VertexAttribute::COLOR) - .enableBufferObjects() - .build(*engine); - - // primitive 4, triangle without skinning vertex attributes - app.vb4 = VertexBuffer::Builder() - .vertexCount(3) - .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) - .normalized(VertexAttribute::COLOR) - .build(*engine); - - // primitive 5, two triangles without skinning vertex attributes - app.vb5 = VertexBuffer::Builder() - .vertexCount(6) - .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) - .normalized(VertexAttribute::COLOR) - .build(*engine); - - // primitive 6, triangle without skinning vertex attributes - app.vb6 = VertexBuffer::Builder() - .vertexCount(3) - .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) - .normalized(VertexAttribute::COLOR) - .build(*engine); -// --------data for primitive 0 - app.vb0->setBufferAt(*engine, 0, - VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr)); -// --------data for primitive 1 - app.vb1->setBufferAt(*engine, 0, - VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 3, 36, nullptr)); - app.vb2->setBufferAt(*engine, 0, - VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 3, 36, nullptr)); - -// --------data for primitive 2 - app.vb2->setBufferAt(*engine, 1, - VertexBuffer::BufferDescriptor(skinJoints, 24, nullptr)); - app.vb2->setBufferAt(*engine, 2, - VertexBuffer::BufferDescriptor(skinWeights, 48, nullptr)); - -// --------data for primitive 3 - app.boTriangle = BufferObject::Builder() - .size(3 * 4 * sizeof(Vertex)) + + // primitives for renderable 0 ------------------------- + // primitive 0/1, triangle without skinning + app.vbs[app.vbCount] = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .build(*engine); + app.vbs[app.vbCount]->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES_1, 36, nullptr)); + app.vbCount++; + + // primitive 0/2, triangle without skinning, buffer objects enabled + app.vbs[app.vbCount] = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .enableBufferObjects() + .build(*engine); + app.bos[app.boCount] = BufferObject::Builder() + .size(3 * sizeof(Vertex)) + .build(*engine); + app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( + TRIANGLE_VERTICES_1 + 3, app.bos[app.boCount]->getByteCount(), nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, app.bos[app.boCount]); + app.vbCount++; + app.boCount++; + + // primitives for renderable 1 ------------------------- + // primitive 1/1, triangle with skinning vertex attributes (only 4 bones), buffer object disabled + app.vbs[app.vbCount] = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(3) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .attribute(VertexAttribute::BONE_INDICES, 1, VertexBuffer::AttributeType::USHORT4, 0, 8) + .attribute(VertexAttribute::BONE_WEIGHTS, 2, VertexBuffer::AttributeType::FLOAT4, 0, 16) + .build(*engine); + app.vbs[app.vbCount]->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES_2, 36, nullptr)); + app.vbs[app.vbCount]->setBufferAt(*engine, 1, + VertexBuffer::BufferDescriptor(skinJoints, 24, nullptr)); + app.vbs[app.vbCount]->setBufferAt(*engine, 2, + VertexBuffer::BufferDescriptor(skinWeights, 48, nullptr)); + app.vbCount++; + + // primitive 1/2, triangle with skinning vertex attributes (only 4 bones), buffer objects enabled + app.vbs[app.vbCount] = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(3) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .attribute(VertexAttribute::BONE_INDICES, 1, VertexBuffer::AttributeType::USHORT4, 0, 8) + .attribute(VertexAttribute::BONE_WEIGHTS, 2, VertexBuffer::AttributeType::FLOAT4, 0, 16) + .enableBufferObjects() .build(*engine); - app.boTriangle->setBuffer(*engine, BufferObject::BufferDescriptor( - TRIANGLE_VERTICES + 2, app.boTriangle->getByteCount(), nullptr)); - app.vb3->setBufferObjectAt(*engine, 0,app.boTriangle); - -// --------data for primitive 4 - app.vb4->setBufferAt(*engine, 0, - VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 1, 36, nullptr),0); -// --------data for primitive 5 - app.vb5->setBufferAt(*engine, 0, - VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 0, 72, nullptr),0); -// --------data for primitive 6 - app.vb6->setBufferAt(*engine, 0, - VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES + 0, 36, nullptr),0); -// index buffer data + app.bos[app.boCount] = BufferObject::Builder() + .size(3 * sizeof(Vertex)) + .build(*engine); + app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( + TRIANGLE_VERTICES_2 + 2, app.bos[app.boCount]->getByteCount(), nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, app.bos[app.boCount]); + app.boCount++; + app.bos[app.boCount] = BufferObject::Builder() + .size(24) + .build(*engine); + app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( + skinJoints, app.bos[app.boCount]->getByteCount(), nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 1, app.bos[app.boCount]); + app.boCount++; + app.bos[app.boCount] = BufferObject::Builder() + .size(48) + .build(*engine); + app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( + skinWeights, app.bos[app.boCount]->getByteCount(), nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 2, app.bos[app.boCount]); + app.boCount++; + app.vbCount++; + + // primitives for renderable 2 ------------------------- + // primitive 2/1, triangle with advanced skinning, buffer objects enabled + app.vbs[app.vbCount] = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .enableBufferObjects() + .advancedSkinning() + .build(*engine); + app.bos[app.boCount] = BufferObject::Builder() + .size(3 * sizeof(Vertex)) + .build(*engine); + app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( + TRIANGLE_VERTICES_3, app.bos[app.boCount]->getByteCount(), nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, app.bos[app.boCount]); + app.boCount++; + app.vbCount++; + + // primitive 2/2, triangle with advanced skinning, buffer objects enabled, for morph + app.vbs[app.vbCount] = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .enableBufferObjects() + .advancedSkinning() + .build(*engine); + app.bos[app.boCount] = BufferObject::Builder() + .size(3 * sizeof(Vertex)) + .build(*engine); + app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( + TRIANGLE_VERTICES_3 + 1, app.bos[app.boCount]->getByteCount(), nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, app.bos[app.boCount]); + app.boCount++; + app.vbCount++; + + // primitive 2/3, triangle with advanced skinning, buffer objects enabled, + app.vbs[app.vbCount] = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .enableBufferObjects() + .advancedSkinning() + .build(*engine); + app.bos[app.boCount] = BufferObject::Builder() + .size(3 * sizeof(Vertex)) + .build(*engine); + app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( + TRIANGLE_VERTICES_3 + 2, app.bos[app.boCount]->getByteCount(), nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, app.bos[app.boCount]); + app.boCount++; + app.vbCount++; + + // primitives for renderable 3 ------------------------- + // primitive 3/1, two triangles with advanced skinning, buffer objects enabled, + app.vbs[app.vbCount] = VertexBuffer::Builder() + .vertexCount(6) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .enableBufferObjects() + .advancedSkinning() + .build(*engine); + app.bos[app.boCount] = BufferObject::Builder() + .size(6 * sizeof(Vertex)) + .build(*engine); + app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( + TRIANGLE_VERTICES_1, app.bos[app.boCount]->getByteCount(), nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, app.bos[app.boCount]); + app.boCount++; + app.vbCount++; + + + // index buffer data app.ib = IndexBuffer::Builder() - .indexCount(3) - .bufferType(IndexBuffer::IndexType::USHORT) - .build(*engine); + .indexCount(3) + .bufferType(IndexBuffer::IndexType::USHORT) + .build(*engine); app.ib->setBuffer(*engine, - IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 6, nullptr)); + IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 3 * sizeof(ushort), nullptr)); app.ib2 = IndexBuffer::Builder() - .indexCount(6) - .bufferType(IndexBuffer::IndexType::USHORT) - .build(*engine); + .indexCount(6) + .bufferType(IndexBuffer::IndexType::USHORT) + .build(*engine); app.ib2->setBuffer(*engine, - IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 12, nullptr)); + IndexBuffer::BufferDescriptor(TRIANGLE_INDICES_2, 6 * sizeof(ushort), nullptr)); app.mat = Material::Builder() - .package(RESOURCES_BAKEDCOLOR_DATA, RESOURCES_BAKEDCOLOR_SIZE) - .build(*engine); + .package(RESOURCES_BAKEDCOLOR_DATA, RESOURCES_BAKEDCOLOR_SIZE) + .build(*engine); -// Skinning buffer for renderable 1 +// Skinning buffer for renderable 2 app.sb = SkinningBuffer::Builder() .boneCount(9) .initialize(true) .build(*engine); -// Skinning buffer common for renderable 2 and 3 +// Skinning buffer common for renderable 3 app.sb2 = SkinningBuffer::Builder() .boneCount(9) .initialize(true) @@ -294,58 +376,119 @@ int main(int argc, char** argv) { app.mt->setTangentsAt(*engine,1, targets_tan, 9, 0); app.mt->setTangentsAt(*engine,2, targets_tan, 9, 0); -// renderable 1: -// primitive 0 = skinned triangle, bone data defined as vector per primitive, -// primitive 1 = skinned triangle, bone data defined as array per primitive, -// primitive 2 = triangle without skinning and with morphing, bone data defined as vertex attributes - app.renderable1 = EntityManager::get().create(); +// renderable 0: no skinning +// primitive 0 = triangle, no skinning, no morph target +// primitive 1 = triangle, no skinning, morph target +// primitive 2 = triangle, no skinning, no morph target, buffer objects enabled +// primitive 3 = triangle, no skinning, morph target, buffer objects enabled + app.renderables[0] = EntityManager::get().create(); + RenderableManager::Builder(4) + .boundingBox({{ -1, -1, -1}, { 1, 1, 1}}) + .material(0, app.mat->getDefaultInstance()) + .material(1, app.mat->getDefaultInstance()) + .material(2, app.mat->getDefaultInstance()) + .material(3, app.mat->getDefaultInstance()) + .geometry(0,RenderableManager::PrimitiveType::TRIANGLES, + app.vbs[0],app.ib,0,3) + .geometry(1,RenderableManager::PrimitiveType::TRIANGLES, + app.vbs[0],app.ib,0,3) + .geometry(2,RenderableManager::PrimitiveType::TRIANGLES, + app.vbs[1],app.ib,0,3) + .geometry(3,RenderableManager::PrimitiveType::TRIANGLES, + app.vbs[1],app.ib,0,3) + .culling(false) + .receiveShadows(false) + .castShadows(false) + .morphing(3) + .morphing(0,1,app.mt) + .morphing(0,3,app.mt) + .build(*engine, app.renderables[0]); + +// renderable 1: attribute bone data definitions +// primitive 1 = trinagle with skinning, bone data defined as vertex attributes +// primitive 3 = triangle with skinning, bone data defined as vertex attributes (buffer object) +// primitive 2 = triangle with skinning and with morphing, bone data defined as vertex attributes +// primitive 0 = triangle with skinning and with morphing, bone data defined as vertex attributes (buffer object) + app.renderables[1] = EntityManager::get().create(); + RenderableManager::Builder(4) + .boundingBox({{ -1, -1, -1}, { 1, 1, 1}}) + .material(0, app.mat->getDefaultInstance()) + .material(1, app.mat->getDefaultInstance()) + .material(2, app.mat->getDefaultInstance()) + .material(3, app.mat->getDefaultInstance()) + .geometry(1,RenderableManager::PrimitiveType::TRIANGLES, + app.vbs[2],app.ib,0,3) + .geometry(2,RenderableManager::PrimitiveType::TRIANGLES, + app.vbs[2],app.ib,0,3) + .geometry(0,RenderableManager::PrimitiveType::TRIANGLES, + app.vbs[3],app.ib,0,3) + .geometry(3,RenderableManager::PrimitiveType::TRIANGLES, + app.vbs[3],app.ib,0,3) + .culling(false) + .receiveShadows(false) + .castShadows(false) + .enableSkinningBuffers(true) + .skinning(app.sb, 9, 0) + .morphing(3) + .morphing(0,2,app.mt) + .morphing(0,0,app.mt) + .build(*engine, app.renderables[1]); + +// renderable 2: various vays of definitions +// primitive 0 = skinned triangle, advanced bone data defined as array per primitive, +// primitive 1 = skinned triangle, advanced bone data defined as vector per primitive, +// primitive 2 = triangle with skinning and with morphing, advanced bone data defined as vector per primitive + app.renderables[2] = EntityManager::get().create(); RenderableManager::Builder(3) - .boundingBox({{-1, -1, -1}, {1, 1, 1}}) + .boundingBox({{ -1, -1, -1}, { 1, 1, 1}}) .material(0, app.mat->getDefaultInstance()) .material(1, app.mat->getDefaultInstance()) .material(2, app.mat->getDefaultInstance()) .geometry(0,RenderableManager::PrimitiveType::TRIANGLES, - app.vb0,app.ib,0,3) + app.vbs[4], app.ib, 0, 3) .geometry(1,RenderableManager::PrimitiveType::TRIANGLES, - app.vb3,app.ib,0,3) + app.vbs[5], app.ib, 0, 3) .geometry(2,RenderableManager::PrimitiveType::TRIANGLES, - app.vb2,app.ib,0,3) + app.vbs[6], app.ib, 0, 3) .culling(false) .receiveShadows(false) .castShadows(false) .enableSkinningBuffers(true) .skinning(app.sb, 9, 0) - .boneIndicesAndWeights(0, boneDataPerPrimitive) - .boneIndicesAndWeights(1, boneDataArray, 24, 8) + .boneIndicesAndWeights(0, boneDataArray, 24, 8) + .boneIndicesAndWeights(1, boneDataPerPrimitive) + .boneIndicesAndWeights(2, boneDataArray, 24, 8) .morphing(3) - .morphing(0,2,app.mt) - .build(*engine, app.renderable1); + .morphing(0, 2, app.mt) + .build(*engine, app.renderables[2]); -// renderable 2: -// primitive 0 = skinning of two triangles, bone data defined as vector with various number of bones per vertex, -// primitive 1 = skinning triangle, bone data defined as vector with various number of bones per vertex, - app.renderable2 = EntityManager::get().create(); +// renderable 3: combination attribute and advance bone data +// primitive 0 = skinning of two triangles, advanced bone data defined as vector per primitive +// primitive 1 = skinning triangle, bone data defined as vertex attributes + app.renderables[3] = EntityManager::get().create(); RenderableManager::Builder(2) - .boundingBox({{-1, -1, -1}, {1, 1, 1}}) + .boundingBox({{ -1, -1, -1}, { 1, 1, 1}}) .material(0, app.mat->getDefaultInstance()) .material(1, app.mat->getDefaultInstance()) .geometry(0,RenderableManager::PrimitiveType::TRIANGLES, - app.vb5,app.ib2,0,6) + app.vbs[2], app.ib, 0, 3) .geometry(1,RenderableManager::PrimitiveType::TRIANGLES, - app.vb4,app.ib,0,3) + app.vbs[7], app.ib2, 0, 6) .culling(false) .receiveShadows(false) .castShadows(false) .enableSkinningBuffers(true) .skinning(app.sb2, 9, 0) - .boneIndicesAndWeights( 1, boneDataPerPrimitive) - .boneIndicesAndWeights( 0, boneDataPerPrimitive2) - .build(*engine, app.renderable2); + .boneIndicesAndWeights(1, boneDataPerPrimitive2) + .boneIndicesAndWeights(0, boneDataPerPrimitive) + .build(*engine, app.renderables[3]); - scene->addEntity(app.renderable1); - scene->addEntity(app.renderable2); + scene->addEntity(app.renderables[0]); + scene->addEntity(app.renderables[1]); + scene->addEntity(app.renderables[2]); + scene->addEntity(app.renderables[3]); app.camera = utils::EntityManager::get().create(); app.cam = engine->createCamera(app.camera); view->setCamera(app.cam); @@ -353,24 +496,23 @@ int main(int argc, char** argv) { auto cleanup = [&app](Engine* engine, View*, Scene*) { engine->destroy(app.skybox); - engine->destroy(app.renderable1); - engine->destroy(app.renderable2); engine->destroy(app.mat); - engine->destroy(app.vb0); - engine->destroy(app.vb1); - engine->destroy(app.vb2); - engine->destroy(app.vb3); - engine->destroy(app.vb4); - engine->destroy(app.vb5); - engine->destroy(app.vb6); engine->destroy(app.ib); engine->destroy(app.ib2); engine->destroy(app.sb); engine->destroy(app.sb2); engine->destroy(app.mt); - engine->destroy(app.boTriangle); engine->destroyCameraComponent(app.camera); utils::EntityManager::get().destroy(app.camera); + for (auto i = 0; i < app.vbCount; i++) { + engine->destroy(app.vbs[i]); + } + for ( auto i = 0; i < app.boCount; i++) { + engine->destroy(app.bos[i]); + } + for ( auto i = 0; i < 4; i++) { + engine->destroy(app.renderables[i]); + } }; FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { @@ -397,8 +539,7 @@ int main(int argc, char** argv) { trans2[i] = filament::math::mat4f(1); } mat4f transA[] = { - mat4f::scaling(float3(s / 10.f,s / 10.f, 1)), - //filament::math::mat4f(1), + mat4f::scaling(float3(s / 10.f,s / 10.f, 1.f)), mat4f::translation(float3(s, 0, 0)), mat4f::translation(float3(s, s, 0)), mat4f::translation(float3(0, s, 0)), @@ -409,17 +550,17 @@ int main(int argc, char** argv) { mat4f::translation(float3(s, -s, 0)), filament::math::mat4f(1)}; trans[offset] = transA[offset]; - trans2[offset] = transA[(offset + 0) % 9]; + trans2[offset] = transA[(offset + 3) % 9]; - app.sb->setBones(*engine,trans,9,0); - app.sb2->setBones(*engine,trans2,9,0); + app.sb->setBones(*engine,trans, 9, 0); + app.sb2->setBones(*engine,trans2, 9, 0); // Morph targets (blendshapes) animation float z = (float)(sin(now)/2.f + 0.5f); - float weights[] = {1 - z, 0, z}; - rm.setMorphWeights(rm.getInstance(app.renderable1), weights, 3, 0); - rm.setMorphWeights(rm.getInstance(app.renderable2), weights, 3, 0); - + float weights[] = { 1 - z, 0, z}; + rm.setMorphWeights(rm.getInstance(app.renderables[0]), weights, 3, 0); + rm.setMorphWeights(rm.getInstance(app.renderables[1]), weights, 3, 0); + rm.setMorphWeights(rm.getInstance(app.renderables[2]), weights, 3, 0); }); FilamentApp::get().run(config, setup, cleanup); diff --git a/samples/suzanneskinning.cpp b/samples/suzanneskinning.cpp index 9ee35738b05..a1b2ef95cdb 100644 --- a/samples/suzanneskinning.cpp +++ b/samples/suzanneskinning.cpp @@ -229,7 +229,7 @@ int main(int argc, char** argv) { app.renderable = EntityManager::get().create(); RenderableManager::Builder(1) .boundingBox({{ -2, -2, -2 }, { 2, 2, 2 }}) - .material(0, app.materialInstance) + .material(0, app.materialInstance) .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.mesh.vertexBuffer, app.mesh.indexBuffer) .receiveShadows(true) .castShadows(false) From ae9c9511e44107c8ef054dac68c99fea889dc9cd Mon Sep 17 00:00:00 2001 From: brunojezek Date: Tue, 30 May 2023 12:01:53 +0200 Subject: [PATCH 11/24] Change ushort to uint16_t clean code change delete to free --- filament/src/components/RenderableManager.cpp | 8 ++++---- filament/src/details/VertexBuffer.cpp | 4 ++-- filament/src/details/VertexBuffer.h | 2 +- samples/helloskinningbuffer.cpp | 12 ++++++------ samples/skinningtest.cpp | 16 ++++++++-------- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index f9d1e75d4f7..69cca8b4034 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -310,8 +310,8 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi auto bonePairsForPrimitive = iBonePair->second; if (bonePairsForPrimitive.size()) { size_t vertexCount = mEntries[primitiveIndex].vertices->getVertexCount(); - std::unique_ptr skinJoints( - new ushort[4 * vertexCount]()); // temporary indices for one vertex + std::unique_ptr skinJoints( + new uint16_t[4 * vertexCount]()); // temporary indices for one vertex std::unique_ptr skinWeights( new float[4 * vertexCount]()); // temporary weights for one vertex for (size_t iVertex = 0; iVertex < vertexCount; iVertex++) { @@ -356,7 +356,7 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi // prepare data for texture if (tempPairCount > 4) { // set attributes, indices and weights, for > 4 pairs skinWeights[3 + offset] = -(float) (pairsCount + 1); // negative offset to texture 0..-1, 1..-2 - skinJoints[3 + offset] = (ushort) tempPairCount; // number pairs per vertex in texture + skinJoints[3 + offset] = (uint16_t) tempPairCount; // number pairs per vertex in texture for (size_t j = 3; j < tempPairCount; j++) { mBoneIndicesAndWeights[pairsCount][0] = tempPairs[j][0]; mBoneIndicesAndWeights[pairsCount][1] = tempPairs[j][1] / boneWeightsSum; @@ -604,7 +604,7 @@ void FRenderableManager::create( downcast(builder->mSkinningBuffer)-> setIndicesAndWeightsData(downcast(engine), handle.texture, builder->mBoneIndicesAndWeights, builder->mBoneIndicesAndWeightsCount); - delete[] builder->mBoneIndicesAndWeights; + free(builder->mBoneIndicesAndWeights); } // Create and initialize all needed MorphTargets. diff --git a/filament/src/details/VertexBuffer.cpp b/filament/src/details/VertexBuffer.cpp index 89a142cdf57..d58618da8f3 100644 --- a/filament/src/details/VertexBuffer.cpp +++ b/filament/src/details/VertexBuffer.cpp @@ -284,13 +284,13 @@ void FVertexBuffer::setBufferObjectAt(FEngine& engine, uint8_t bufferIndex, } void FVertexBuffer::updateBoneIndicesAndWeights(FEngine& engine, - std::unique_ptr skinJoints, + std::unique_ptr skinJoints, std::unique_ptr skinWeights) { auto jointsData = skinJoints.release(); auto bdJoints = BufferDescriptor( jointsData, mVertexCount * 8, [](void *buffer, size_t size, void *user) { - delete static_cast(buffer); }); + delete static_cast(buffer); }); engine.getDriverApi().updateBufferObject(mBufferObjects[mBufferCount - 2], std::move(bdJoints), 0); diff --git a/filament/src/details/VertexBuffer.h b/filament/src/details/VertexBuffer.h index dab4bb34dee..24ebaa91554 100644 --- a/filament/src/details/VertexBuffer.h +++ b/filament/src/details/VertexBuffer.h @@ -61,7 +61,7 @@ class FVertexBuffer : public VertexBuffer { void setBufferObjectAt(FEngine& engine, uint8_t bufferIndex, FBufferObject const * bufferObject); - void updateBoneIndicesAndWeights(FEngine& engine, std::unique_ptr skinJoints, + void updateBoneIndicesAndWeights(FEngine& engine, std::unique_ptr skinJoints, std::unique_ptr skinWeights); private: diff --git a/samples/helloskinningbuffer.cpp b/samples/helloskinningbuffer.cpp index a2b1326f9b6..c31bf12f0ae 100644 --- a/samples/helloskinningbuffer.cpp +++ b/samples/helloskinningbuffer.cpp @@ -63,14 +63,14 @@ static const Vertex TRIANGLE_VERTICES[3] = { {{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu}, }; -static const ushort skinJoints[] = {0,1,2,3, - 0,1,2,3, - 0,1,2,3 +static const uint16_t skinJoints[] = { 0, 1, 2, 3, + 0, 1, 2, 3, + 0, 1, 2, 3 }; -static const float skinWeights[] = {0.25f,0.25f,0.25f,0.25f, - 0.25f,0.25f,0.25f,0.25f, - 0.25f,0.25f,0.25f,0.25f +static const float skinWeights[] = { 0.25f, 0.25f, 0.25f, 0.25f, + 0.25f, 0.25f, 0.25f, 0.25f, + 0.25f, 0.25f, 0.25f, 0.25f }; static constexpr uint16_t TRIANGLE_INDICES[] = { 0, 1, 2, 3 }; diff --git a/samples/skinningtest.cpp b/samples/skinningtest.cpp index 9f70dd64f47..c886d457fb7 100644 --- a/samples/skinningtest.cpp +++ b/samples/skinningtest.cpp @@ -100,13 +100,13 @@ static const short4 targets_tan[9] = { { 0, 0, 0, 0},{ 0, 0, 0, 0},{ 0, 0, 0, 0}, { 0, 0, 0, 0},{ 0, 0, 0, 0},{ 0, 0, 0, 0}}; -static const ushort skinJoints[] = { 0,1,2,5, - 0,2,3,5, - 0,3,1,5}; +static const uint16_t skinJoints[] = { 0, 1, 2, 5, + 0, 2, 3, 5, + 0, 3, 1, 5}; -static const float skinWeights[] = { 0.5f,0.0f,0.0f,0.5f, - 0.5f,0.0f,0.f,0.5f, - 0.5f,0.0f,0.f,0.5f,}; +static const float skinWeights[] = { 0.5f, 0.0f, 0.0f, 0.5f, + 0.5f, 0.0f, 0.f, 0.5f, + 0.5f, 0.0f, 0.f, 0.5f,}; static float2 boneDataArray[48] = {}; //index and weight for 3 vertices X 8 bones @@ -336,14 +336,14 @@ int main(int argc, char** argv) { .bufferType(IndexBuffer::IndexType::USHORT) .build(*engine); app.ib->setBuffer(*engine, - IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 3 * sizeof(ushort), nullptr)); + IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 3 * sizeof(uint16_t), nullptr)); app.ib2 = IndexBuffer::Builder() .indexCount(6) .bufferType(IndexBuffer::IndexType::USHORT) .build(*engine); app.ib2->setBuffer(*engine, - IndexBuffer::BufferDescriptor(TRIANGLE_INDICES_2, 6 * sizeof(ushort), nullptr)); + IndexBuffer::BufferDescriptor(TRIANGLE_INDICES_2, 6 * sizeof(uint16_t), nullptr)); app.mat = Material::Builder() .package(RESOURCES_BAKEDCOLOR_DATA, RESOURCES_BAKEDCOLOR_SIZE) From 9185de503526f0c823b4837202c01673a289d826 Mon Sep 17 00:00:00 2001 From: brunojezek Date: Tue, 6 Jun 2023 17:09:42 +0200 Subject: [PATCH 12/24] Fix memory allocation Change RenderableManager::BuilderDetails::mBoneIndicesAndWeights to FixedCapacityVector --- filament/src/components/RenderableManager.cpp | 20 ++++++++----------- filament/src/details/SkinningBuffer.cpp | 5 +++-- filament/src/details/SkinningBuffer.h | 5 ++++- filament/src/details/VertexBuffer.cpp | 1 + filament/src/details/VertexBuffer.h | 1 + 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 69cca8b4034..19002c24e35 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -24,11 +24,8 @@ #include "details/VertexBuffer.h" #include "details/IndexBuffer.h" #include "details/InstanceBuffer.h" -#include "details/Texture.h" #include "details/Material.h" -#include - #include "filament/RenderableManager.h" @@ -68,11 +65,12 @@ struct RenderableManager::BuilderDetails { FSkinningBuffer* mSkinningBuffer = nullptr; FInstanceBuffer* mInstanceBuffer = nullptr; uint32_t mSkinningBufferOffset = 0; - float2* mBoneIndicesAndWeights = nullptr; - size_t mBoneIndicesAndWeightsCount = 0; + utils::FixedCapacityVector mBoneIndicesAndWeights; + size_t mBoneIndicesAndWeightsCount = 0; + // bone indices and weights defined for primitive index std::unordered_map>> mBonePairs; //bone indices and weights defined for primitive index + utils::FixedCapacityVector>> mBonePairs; explicit BuilderDetails(size_t count) : mEntries(count), mCulling(true), mCastShadows(false), mReceiveShadows(true), @@ -301,10 +299,10 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi size_t pairsCount = 0; // counting of number of pairs stored in texture if (maxPairsCount) { // at least one primitive has bone indices and weights - mBoneIndicesAndWeights = (float2*) calloc(maxPairsCount, - sizeof(float2)); // final texture data, indices and weights - std::unique_ptr tempPairs( - new float2[maxPairsCountPerVertex]); // temporary indices and weights for one vertex + // final texture data, indices and weights + mBoneIndicesAndWeights = utils::FixedCapacityVector(maxPairsCount); + // temporary indices and weights for one vertex + std::unique_ptr tempPairs(new float2[maxPairsCountPerVertex]()); for (auto iBonePair = mBonePairs.begin(); iBonePair != mBonePairs.end(); ++iBonePair) { auto primitiveIndex = iBonePair->first; auto bonePairsForPrimitive = iBonePair->second; @@ -600,11 +598,9 @@ void FRenderableManager::create( createIndicesAndWeightsHandle(downcast(engine), builder->mBoneIndicesAndWeightsCount); bones.handleSamplerGroup = handle.sampler; bones.handleTexture = handle.texture; - downcast(builder->mSkinningBuffer)-> setIndicesAndWeightsData(downcast(engine), handle.texture, builder->mBoneIndicesAndWeights, builder->mBoneIndicesAndWeightsCount); - free(builder->mBoneIndicesAndWeights); } // Create and initialize all needed MorphTargets. diff --git a/filament/src/details/SkinningBuffer.cpp b/filament/src/details/SkinningBuffer.cpp index 4145d70de33..43966d729bd 100644 --- a/filament/src/details/SkinningBuffer.cpp +++ b/filament/src/details/SkinningBuffer.cpp @@ -244,12 +244,13 @@ FSkinningBuffer::HandleIndicesAndWeights FSkinningBuffer::createIndicesAndWeight } void FSkinningBuffer::setIndicesAndWeightsData(FEngine& engine, - backend::Handle textureHandle, math::float2 const* pairs, size_t count) { + backend::Handle textureHandle, + const utils::FixedCapacityVector& pairs, size_t count) { FEngine::DriverApi& driver = engine.getDriverApi(); auto size = getSkinningBufferSize(count); auto* out = (float2*) malloc(size); - std::transform(pairs, pairs + count, out, + std::transform(pairs.begin(), pairs.end(), out, [](const float2& p) { return float2(p); }); updateDataAt(driver, textureHandle, diff --git a/filament/src/details/SkinningBuffer.h b/filament/src/details/SkinningBuffer.h index 49e067b6789..23e6a48ce84 100644 --- a/filament/src/details/SkinningBuffer.h +++ b/filament/src/details/SkinningBuffer.h @@ -28,6 +28,7 @@ #include #include +#include // for gtest class FilamentTest_Bones_Test; @@ -81,7 +82,9 @@ class FSkinningBuffer : public SkinningBuffer { HandleIndicesAndWeights createIndicesAndWeightsHandle(FEngine& engine, size_t count); void setIndicesAndWeightsData(FEngine& engine, - backend::Handle textureHandle, math::float2 const* pairs, size_t count); + backend::Handle textureHandle, + const utils::FixedCapacityVector& pairs, + size_t count); backend::Handle mHandle; uint32_t mBoneCount; diff --git a/filament/src/details/VertexBuffer.cpp b/filament/src/details/VertexBuffer.cpp index d58618da8f3..d133e609d67 100644 --- a/filament/src/details/VertexBuffer.cpp +++ b/filament/src/details/VertexBuffer.cpp @@ -22,6 +22,7 @@ #include "FilamentAPI-impl.h" #include +#include #include diff --git a/filament/src/details/VertexBuffer.h b/filament/src/details/VertexBuffer.h index 24ebaa91554..29bae33a608 100644 --- a/filament/src/details/VertexBuffer.h +++ b/filament/src/details/VertexBuffer.h @@ -26,6 +26,7 @@ #include #include +#include #include #include From 7faf01682540a078950126da2474f2979b23f31b Mon Sep 17 00:00:00 2001 From: brunojezek Date: Wed, 9 Aug 2023 14:44:17 +0200 Subject: [PATCH 13/24] Fix memory management Fix copy of bone data to texture Clean the code --- NEW_RELEASE_NOTES.md | 2 + filament/include/filament/RenderableManager.h | 2 +- filament/src/components/RenderableManager.cpp | 14 +- filament/src/details/SkinningBuffer.cpp | 6 +- filament/src/details/VertexBuffer.cpp | 11 +- samples/helloskinningbuffer_morebones.cpp | 3 +- samples/skinningtest.cpp | 248 ++++++++++++------ 7 files changed, 185 insertions(+), 101 deletions(-) diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 1cf1cf6fd3f..2fdafa30036 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -8,6 +8,8 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut +- matc: fix VSM high precision option on mobile [⚠️ **Recompile materials**] +- engine: add support for skinning with more than four bones per vertex. - Fix possible NPE when updating fog options from Java/Kotlin - The `emissive` property was not applied properly to `MASKED` materials, and could cause dark fringes to appear (recompile materials) diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index 2c5dd60304e..06214ffc2df 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -400,7 +400,7 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { */ Builder& boneIndicesAndWeights(size_t primitiveIndex, utils::FixedCapacityVector< - utils::FixedCapacityVector> const &indicesAndWeightsVector) noexcept; + utils::FixedCapacityVector> indicesAndWeightsVector) noexcept; /** * Controls if the renderable has vertex morphing targets, zero by default. This is * required to enable GPU morphing. diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 19002c24e35..a3f32ad6aaa 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -226,8 +226,7 @@ RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(si RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(size_t primitiveIndex, utils::FixedCapacityVector< - utils::FixedCapacityVector> const &indicesAndWeightsVector) noexcept { - //mImpl->mBonePairs[primitiveIndex] = std::move(indicesAndWeightsVector); + utils::FixedCapacityVector> indicesAndWeightsVector) noexcept { mImpl->mBonePairs[primitiveIndex] = indicesAndWeightsVector; return *this; } @@ -287,7 +286,8 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi "[primitive @ %u] bone indices and weights pairs count (%u) must be equal to vertex count (%u)", primitiveIndex, bonePairsForPrimitive.size(), vertexCount); auto const& declaredAttributes = downcast(entry.vertices)->getDeclaredAttributes(); - ASSERT_PRECONDITION(declaredAttributes[VertexAttribute::BONE_INDICES] || declaredAttributes[VertexAttribute::BONE_WEIGHTS], + ASSERT_PRECONDITION(declaredAttributes[VertexAttribute::BONE_INDICES] + || declaredAttributes[VertexAttribute::BONE_WEIGHTS], "[entity=%u, primitive @ %u] for advanced skinning set VertexBuffer::Builder::advancedSkinning()", entity.getId(), primitiveIndex); for (size_t iVertex = 0; iVertex < vertexCount; iVertex++) { @@ -363,11 +363,13 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi } } // for all vertices per primitive downcast(mEntries[primitiveIndex].vertices) - ->updateBoneIndicesAndWeights(downcast(engine), std::move(skinJoints), std::move(skinWeights)); + ->updateBoneIndicesAndWeights(downcast(engine), + std::move(skinJoints), + std::move(skinWeights)); } - }// for all primitives + } // for all primitives } - mBoneIndicesAndWeightsCount = pairsCount; + mBoneIndicesAndWeightsCount = pairsCount; // only part of mBoneIndicesAndWeights is used for real data } RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& engine, Entity entity) { diff --git a/filament/src/details/SkinningBuffer.cpp b/filament/src/details/SkinningBuffer.cpp index 43966d729bd..d0923571e73 100644 --- a/filament/src/details/SkinningBuffer.cpp +++ b/filament/src/details/SkinningBuffer.cpp @@ -173,7 +173,7 @@ static inline size_t getSkinningBufferWidth(size_t pairCount) noexcept { } static inline size_t getSkinningBufferHeight(size_t pairCount) noexcept { - return (pairCount + MAX_SKINNING_BUFFER_WIDTH) / MAX_SKINNING_BUFFER_WIDTH; + return pairCount / MAX_SKINNING_BUFFER_WIDTH + 1; } inline size_t getSkinningBufferSize(size_t pairCount) noexcept { @@ -250,13 +250,13 @@ void FSkinningBuffer::setIndicesAndWeightsData(FEngine& engine, FEngine::DriverApi& driver = engine.getDriverApi(); auto size = getSkinningBufferSize(count); auto* out = (float2*) malloc(size); - std::transform(pairs.begin(), pairs.end(), out, + std::transform(pairs.begin(), pairs.begin() + count, out, [](const float2& p) { return float2(p); }); updateDataAt(driver, textureHandle, Texture::Format::RG, Texture::Type::FLOAT, (char const*)out, sizeof(float2), - count, size); + count, size); } } // namespace filament diff --git a/filament/src/details/VertexBuffer.cpp b/filament/src/details/VertexBuffer.cpp index d133e609d67..bd4ff95a0ad 100644 --- a/filament/src/details/VertexBuffer.cpp +++ b/filament/src/details/VertexBuffer.cpp @@ -163,10 +163,9 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const VertexBuffer::Builder& build if (mAdvancedSkinningEnabled) { ASSERT_PRECONDITION(!mDeclaredAttributes[VertexAttribute::BONE_INDICES], - "Vertex buffer attribute BONE_INDICES is already defined"); + "Vertex buffer attribute BONE_INDICES is already defined, no advanced skinning is allowed"); ASSERT_PRECONDITION(!mDeclaredAttributes[VertexAttribute::BONE_WEIGHTS], - "Vertex buffer attribute BONE_WEIGHTS is already defined"); - // ASSERT_PRECONDITION(mBufferObjectsEnabled, "Please use enableBufferObjects()"); + "Vertex buffer attribute BONE_WEIGHTS is already defined, no advanced skinning is allowed"); ASSERT_PRECONDITION(mBufferCount < (MAX_VERTEX_BUFFER_COUNT - 2), "Vertex buffer uses to many buffers (%u)", mBufferCount); mDeclaredAttributes.set(VertexAttribute::BONE_INDICES); @@ -287,11 +286,13 @@ void FVertexBuffer::setBufferObjectAt(FEngine& engine, uint8_t bufferIndex, void FVertexBuffer::updateBoneIndicesAndWeights(FEngine& engine, std::unique_ptr skinJoints, std::unique_ptr skinWeights) { + + ASSERT_PRECONDITION(mAdvancedSkinningEnabled, "No advanced skinning enabled"); auto jointsData = skinJoints.release(); auto bdJoints = BufferDescriptor( jointsData, mVertexCount * 8, [](void *buffer, size_t size, void *user) { - delete static_cast(buffer); }); + delete[] static_cast(buffer); }); engine.getDriverApi().updateBufferObject(mBufferObjects[mBufferCount - 2], std::move(bdJoints), 0); @@ -299,7 +300,7 @@ void FVertexBuffer::updateBoneIndicesAndWeights(FEngine& engine, auto bdWeights = BufferDescriptor( weightsData, mVertexCount * 16, [](void *buffer, size_t size, void *user) { - delete static_cast(buffer); }); + delete[] static_cast(buffer); }); engine.getDriverApi().updateBufferObject(mBufferObjects[mBufferCount - 1], std::move(bdWeights), 0); diff --git a/samples/helloskinningbuffer_morebones.cpp b/samples/helloskinningbuffer_morebones.cpp index 31ee785cccd..a8e30fae37d 100644 --- a/samples/helloskinningbuffer_morebones.cpp +++ b/samples/helloskinningbuffer_morebones.cpp @@ -80,7 +80,6 @@ utils::FixedCapacityVector> boneDataPerPrimit int main(int argc, char** argv) { Config config; config.title = "skinning buffer common for two renderables"; - auto offset = 0; size_t boneCount = 9; utils::FixedCapacityVector boneDataPerVertex(9); float weight = 1.f / boneCount; @@ -221,7 +220,7 @@ int main(int argc, char** argv) { for (uint i = 0; i < 9; i++) { trans[i] = filament::math::mat4f(1); } - s *= 5; + s *= 8; mat4f transA[] = { mat4f::translation(float3(s, 0, 0)), mat4f::translation(float3(s, s, 0)), diff --git a/samples/skinningtest.cpp b/samples/skinningtest.cpp index c886d457fb7..f0fbd0c6fe3 100644 --- a/samples/skinningtest.cpp +++ b/samples/skinningtest.cpp @@ -39,6 +39,7 @@ using namespace filament; using utils::Entity; using utils::EntityManager; +using utils::FixedCapacityVector; using namespace filament::math; struct App { @@ -54,6 +55,10 @@ struct App { MorphTargetBuffer *mt; BufferObject* bos[10]; size_t boCount = 0; + size_t bonesPerVertex; + FixedCapacityVector> + boneDataPerPrimitive, + boneDataPerPrimitiveMulti; }; struct Vertex { @@ -108,7 +113,7 @@ static const float skinWeights[] = { 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.f, 0.5f, 0.5f, 0.0f, 0.f, 0.5f,}; -static float2 boneDataArray[48] = {}; //index and weight for 3 vertices X 8 bones +static float2 boneDataArray[48] = {}; //indices and weights for up to 3 vertices with 8 bones static constexpr uint16_t TRIANGLE_INDICES[3] = { 0, 1, 2 }, TRIANGLE_INDICES_2[6] = { 0, 2, 4, 1, 3, 5 }; @@ -123,45 +128,48 @@ mat4f transforms[] = {math::mat4f(1), mat4f::translation(float3(0, -1, 0)), mat4f::translation(float3(1, -1, 0))}; -utils::FixedCapacityVector> boneDataPerPrimitive(3), - boneDataPerPrimitive2(6); - int main(int argc, char** argv) { + App app; + + app.boneDataPerPrimitive = FixedCapacityVector>(3); + app.boneDataPerPrimitiveMulti = FixedCapacityVector>(6); + app.bonesPerVertex = 8; + Config config; config.title = "skinning test with more than 4 bones per vertex"; - size_t boneCount = 8; - utils::FixedCapacityVector boneDataPerVertex(boneCount); + size_t boneCount = app.bonesPerVertex; float weight = 1.f / boneCount; + FixedCapacityVector boneDataPerVertex(boneCount); for (uint idx = 0; idx < boneCount; idx++) { + boneDataPerVertex[idx] = float2(idx, weight); boneDataArray[idx] = float2(idx, weight); boneDataArray[idx + boneCount] = float2(idx, weight); boneDataArray[idx + 2 * boneCount] = float2(idx, weight); - boneDataPerVertex[idx] = float2(idx, weight); - } - utils::FixedCapacityVector boneDataPerVertex2(3); - boneCount = 3; - weight = 1.f / boneCount; - for (uint idx = 0; idx < boneCount; idx++) { - boneDataPerVertex2[idx] = float2(idx, weight); + boneDataArray[idx + 3 * boneCount] = float2(idx, weight); + boneDataArray[idx + 4 * boneCount] = float2(idx, weight); + boneDataArray[idx + 5 * boneCount] = float2(idx, weight); } auto idx = 0; - boneDataPerPrimitive[idx++] = boneDataPerVertex; - boneDataPerPrimitive[idx++] = boneDataPerVertex; - boneDataPerPrimitive[idx++] = boneDataPerVertex; - - idx = 0; - boneDataPerPrimitive2[idx++] = boneDataPerVertex; - boneDataPerPrimitive2[idx++] = boneDataPerVertex2; - boneDataPerPrimitive2[idx++] = boneDataPerVertex; - boneDataPerPrimitive2[idx++] = boneDataPerVertex; - boneDataPerPrimitive2[idx++] = boneDataPerVertex2; - boneDataPerPrimitive2[idx++] = boneDataPerVertex; + app.boneDataPerPrimitive[idx++] = boneDataPerVertex; + app.boneDataPerPrimitive[idx++] = boneDataPerVertex; + app.boneDataPerPrimitive[idx++] = boneDataPerVertex; + + for (uint vertex_idx = 0; vertex_idx < 6; vertex_idx++) { + boneCount = vertex_idx % app.bonesPerVertex + 1; + weight = 1.f / boneCount; + FixedCapacityVector boneDataPerVertex1(boneCount); + for (uint idx = 0; idx < boneCount; idx++) { + boneDataPerVertex1[idx] = float2(idx, weight); + } + app.boneDataPerPrimitiveMulti[vertex_idx] = boneDataPerVertex1; + } - App app; - auto setup = [&app](Engine* engine, View* view, Scene* scene) { - app.skybox = Skybox::Builder().color({ 0.1, 0.125, 0.25, 1.0}).build(*engine); + auto setup = + [&app](Engine* engine, View* view, Scene* scene) { + app.skybox = Skybox::Builder().color({ 0.1, 0.125, 0.25, 1.0}) + .build(*engine); scene->setSkybox(app.skybox); view->setPostProcessingEnabled(false); @@ -172,20 +180,25 @@ int main(int argc, char** argv) { app.vbs[app.vbCount] = VertexBuffer::Builder() .vertexCount(3) .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .attribute(VertexAttribute::POSITION, 0, + VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, + VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) .build(*engine); app.vbs[app.vbCount]->setBufferAt(*engine, 0, - VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES_1, 36, nullptr)); + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES_1, 36, + nullptr)); app.vbCount++; // primitive 0/2, triangle without skinning, buffer objects enabled app.vbs[app.vbCount] = VertexBuffer::Builder() .vertexCount(3) .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .attribute(VertexAttribute::POSITION, 0, + VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, + VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) .enableBufferObjects() .build(*engine); @@ -193,61 +206,78 @@ int main(int argc, char** argv) { .size(3 * sizeof(Vertex)) .build(*engine); app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( - TRIANGLE_VERTICES_1 + 3, app.bos[app.boCount]->getByteCount(), nullptr)); - app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, app.bos[app.boCount]); + TRIANGLE_VERTICES_1 + 3, app.bos[app.boCount]->getByteCount(), + nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, + app.bos[app.boCount]); app.vbCount++; app.boCount++; // primitives for renderable 1 ------------------------- - // primitive 1/1, triangle with skinning vertex attributes (only 4 bones), buffer object disabled + // primitive 1/1, triangle with skinning vertex attributes (only 4 bones), + // buffer object disabled app.vbs[app.vbCount] = VertexBuffer::Builder() .vertexCount(3) .bufferCount(3) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .attribute(VertexAttribute::POSITION, 0, + VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, + VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) - .attribute(VertexAttribute::BONE_INDICES, 1, VertexBuffer::AttributeType::USHORT4, 0, 8) - .attribute(VertexAttribute::BONE_WEIGHTS, 2, VertexBuffer::AttributeType::FLOAT4, 0, 16) + .attribute(VertexAttribute::BONE_INDICES, 1, + VertexBuffer::AttributeType::USHORT4, 0, 8) + .attribute(VertexAttribute::BONE_WEIGHTS, 2, + VertexBuffer::AttributeType::FLOAT4, 0, 16) .build(*engine); app.vbs[app.vbCount]->setBufferAt(*engine, 0, - VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES_2, 36, nullptr)); + VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES_2, 36, + nullptr)); app.vbs[app.vbCount]->setBufferAt(*engine, 1, VertexBuffer::BufferDescriptor(skinJoints, 24, nullptr)); app.vbs[app.vbCount]->setBufferAt(*engine, 2, VertexBuffer::BufferDescriptor(skinWeights, 48, nullptr)); app.vbCount++; - // primitive 1/2, triangle with skinning vertex attributes (only 4 bones), buffer objects enabled + // primitive 1/2, triangle with skinning vertex attributes (only 4 bones), + // buffer objects enabled app.vbs[app.vbCount] = VertexBuffer::Builder() .vertexCount(3) .bufferCount(3) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .attribute(VertexAttribute::POSITION, 0, + VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, + VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) - .attribute(VertexAttribute::BONE_INDICES, 1, VertexBuffer::AttributeType::USHORT4, 0, 8) - .attribute(VertexAttribute::BONE_WEIGHTS, 2, VertexBuffer::AttributeType::FLOAT4, 0, 16) + .attribute(VertexAttribute::BONE_INDICES, 1, + VertexBuffer::AttributeType::USHORT4, 0, 8) + .attribute(VertexAttribute::BONE_WEIGHTS, 2, + VertexBuffer::AttributeType::FLOAT4, 0, 16) .enableBufferObjects() .build(*engine); app.bos[app.boCount] = BufferObject::Builder() .size(3 * sizeof(Vertex)) .build(*engine); app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( - TRIANGLE_VERTICES_2 + 2, app.bos[app.boCount]->getByteCount(), nullptr)); - app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, app.bos[app.boCount]); + TRIANGLE_VERTICES_2 + 2, app.bos[app.boCount]->getByteCount(), + nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, + app.bos[app.boCount]); app.boCount++; app.bos[app.boCount] = BufferObject::Builder() .size(24) .build(*engine); app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( skinJoints, app.bos[app.boCount]->getByteCount(), nullptr)); - app.vbs[app.vbCount]->setBufferObjectAt(*engine, 1, app.bos[app.boCount]); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 1, + app.bos[app.boCount]); app.boCount++; app.bos[app.boCount] = BufferObject::Builder() .size(48) .build(*engine); app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( skinWeights, app.bos[app.boCount]->getByteCount(), nullptr)); - app.vbs[app.vbCount]->setBufferObjectAt(*engine, 2, app.bos[app.boCount]); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 2, + app.bos[app.boCount]); app.boCount++; app.vbCount++; @@ -256,8 +286,10 @@ int main(int argc, char** argv) { app.vbs[app.vbCount] = VertexBuffer::Builder() .vertexCount(3) .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .attribute(VertexAttribute::POSITION, 0, + VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, + VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) .enableBufferObjects() .advancedSkinning() @@ -267,7 +299,8 @@ int main(int argc, char** argv) { .build(*engine); app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( TRIANGLE_VERTICES_3, app.bos[app.boCount]->getByteCount(), nullptr)); - app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, app.bos[app.boCount]); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, + app.bos[app.boCount]); app.boCount++; app.vbCount++; @@ -275,8 +308,10 @@ int main(int argc, char** argv) { app.vbs[app.vbCount] = VertexBuffer::Builder() .vertexCount(3) .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .attribute(VertexAttribute::POSITION, 0, + VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, + VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) .enableBufferObjects() .advancedSkinning() @@ -285,8 +320,10 @@ int main(int argc, char** argv) { .size(3 * sizeof(Vertex)) .build(*engine); app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( - TRIANGLE_VERTICES_3 + 1, app.bos[app.boCount]->getByteCount(), nullptr)); - app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, app.bos[app.boCount]); + TRIANGLE_VERTICES_3 + 1, app.bos[app.boCount]->getByteCount(), + nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, + app.bos[app.boCount]); app.boCount++; app.vbCount++; @@ -294,8 +331,10 @@ int main(int argc, char** argv) { app.vbs[app.vbCount] = VertexBuffer::Builder() .vertexCount(3) .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .attribute(VertexAttribute::POSITION, 0, + VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, + VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) .enableBufferObjects() .advancedSkinning() @@ -304,8 +343,10 @@ int main(int argc, char** argv) { .size(3 * sizeof(Vertex)) .build(*engine); app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( - TRIANGLE_VERTICES_3 + 2, app.bos[app.boCount]->getByteCount(), nullptr)); - app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, app.bos[app.boCount]); + TRIANGLE_VERTICES_3 + 2, app.bos[app.boCount]->getByteCount(), + nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, + app.bos[app.boCount]); app.boCount++; app.vbCount++; @@ -314,8 +355,10 @@ int main(int argc, char** argv) { app.vbs[app.vbCount] = VertexBuffer::Builder() .vertexCount(6) .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) + .attribute(VertexAttribute::POSITION, 0, + VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, + VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) .enableBufferObjects() .advancedSkinning() @@ -324,26 +367,51 @@ int main(int argc, char** argv) { .size(6 * sizeof(Vertex)) .build(*engine); app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( - TRIANGLE_VERTICES_1, app.bos[app.boCount]->getByteCount(), nullptr)); - app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, app.bos[app.boCount]); + TRIANGLE_VERTICES_1, app.bos[app.boCount]->getByteCount(), + nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, + app.bos[app.boCount]); + app.boCount++; + app.vbCount++; + // primitive 3/2, triangle with advanced skinning and morph, buffer objects enabled, + app.vbs[app.vbCount] = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, + VertexBuffer::AttributeType::FLOAT2, 0, 12) + .attribute(VertexAttribute::COLOR, 0, + VertexBuffer::AttributeType::UBYTE4, 8, 12) + .normalized(VertexAttribute::COLOR) + .enableBufferObjects() + .advancedSkinning() + .build(*engine); + app.bos[app.boCount] = BufferObject::Builder() + .size(3 * sizeof(Vertex)) + .build(*engine); + app.bos[app.boCount]->setBuffer(*engine, BufferObject::BufferDescriptor( + TRIANGLE_VERTICES_3 + 2, app.bos[app.boCount]->getByteCount(), + nullptr)); + app.vbs[app.vbCount]->setBufferObjectAt(*engine, 0, + app.bos[app.boCount]); app.boCount++; app.vbCount++; - - // index buffer data + // Index buffer data app.ib = IndexBuffer::Builder() .indexCount(3) .bufferType(IndexBuffer::IndexType::USHORT) .build(*engine); app.ib->setBuffer(*engine, - IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 3 * sizeof(uint16_t), nullptr)); + IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, + 3 * sizeof(uint16_t),nullptr)); app.ib2 = IndexBuffer::Builder() .indexCount(6) .bufferType(IndexBuffer::IndexType::USHORT) .build(*engine); app.ib2->setBuffer(*engine, - IndexBuffer::BufferDescriptor(TRIANGLE_INDICES_2, 6 * sizeof(uint16_t), nullptr)); + IndexBuffer::BufferDescriptor(TRIANGLE_INDICES_2, + 6 * sizeof(uint16_t),nullptr)); app.mat = Material::Builder() .package(RESOURCES_BAKEDCOLOR_DATA, RESOURCES_BAKEDCOLOR_SIZE) @@ -404,11 +472,11 @@ int main(int argc, char** argv) { .morphing(0,3,app.mt) .build(*engine, app.renderables[0]); -// renderable 1: attribute bone data definitions +// renderable 1: attribute bone data definitions skinning +// primitive 0 = triangle with skinning and with morphing, bone data defined as vertex attributes (buffer object) // primitive 1 = trinagle with skinning, bone data defined as vertex attributes // primitive 3 = triangle with skinning, bone data defined as vertex attributes (buffer object) // primitive 2 = triangle with skinning and with morphing, bone data defined as vertex attributes -// primitive 0 = triangle with skinning and with morphing, bone data defined as vertex attributes (buffer object) app.renderables[1] = EntityManager::get().create(); RenderableManager::Builder(4) .boundingBox({{ -1, -1, -1}, { 1, 1, 1}}) @@ -434,10 +502,11 @@ int main(int argc, char** argv) { .morphing(0,0,app.mt) .build(*engine, app.renderables[1]); -// renderable 2: various vays of definitions +// renderable 2: various ways of skinning definitions // primitive 0 = skinned triangle, advanced bone data defined as array per primitive, // primitive 1 = skinned triangle, advanced bone data defined as vector per primitive, -// primitive 2 = triangle with skinning and with morphing, advanced bone data defined as vector per primitive +// primitive 2 = triangle with skinning and with morphing, advanced bone data +// defined as vector per primitive app.renderables[2] = EntityManager::get().create(); RenderableManager::Builder(3) .boundingBox({{ -1, -1, -1}, { 1, 1, 1}}) @@ -456,40 +525,50 @@ int main(int argc, char** argv) { .enableSkinningBuffers(true) .skinning(app.sb, 9, 0) - .boneIndicesAndWeights(0, boneDataArray, 24, 8) - .boneIndicesAndWeights(1, boneDataPerPrimitive) - .boneIndicesAndWeights(2, boneDataArray, 24, 8) + .boneIndicesAndWeights(0, boneDataArray, + 3 * app.bonesPerVertex, app.bonesPerVertex) + .boneIndicesAndWeights(1, app.boneDataPerPrimitive) + .boneIndicesAndWeights(2, app.boneDataPerPrimitive) + .morphing(3) .morphing(0, 2, app.mt) .build(*engine, app.renderables[2]); // renderable 3: combination attribute and advance bone data -// primitive 0 = skinning of two triangles, advanced bone data defined as vector per primitive -// primitive 1 = skinning triangle, bone data defined as vertex attributes +// primitive 0 = triangle with skinning and morphing, bone data defined as vertex attributes +// primitive 1 = skinning of two triangles, advanced bone data defined as vector per primitive, +// various number of bones per vertex 1, 2, ... 6 +// primitive 2 = triangle with skinning and morphing, advanced bone data defined +// as vector per primitive app.renderables[3] = EntityManager::get().create(); - RenderableManager::Builder(2) + RenderableManager::Builder(3) .boundingBox({{ -1, -1, -1}, { 1, 1, 1}}) .material(0, app.mat->getDefaultInstance()) .material(1, app.mat->getDefaultInstance()) + .material(2, app.mat->getDefaultInstance()) .geometry(0,RenderableManager::PrimitiveType::TRIANGLES, app.vbs[2], app.ib, 0, 3) .geometry(1,RenderableManager::PrimitiveType::TRIANGLES, app.vbs[7], app.ib2, 0, 6) + .geometry(2,RenderableManager::PrimitiveType::TRIANGLES, + app.vbs[8], app.ib, 0, 3) .culling(false) .receiveShadows(false) .castShadows(false) .enableSkinningBuffers(true) - .skinning(app.sb2, 9, 0) - - .boneIndicesAndWeights(1, boneDataPerPrimitive2) - .boneIndicesAndWeights(0, boneDataPerPrimitive) + .skinning(app.sb, 9, 0) + .boneIndicesAndWeights(1, app.boneDataPerPrimitiveMulti) + .boneIndicesAndWeights(2, app.boneDataPerPrimitive) + .morphing(3) + .morphing(0,0,app.mt) + .morphing(0,2,app.mt) .build(*engine, app.renderables[3]); scene->addEntity(app.renderables[0]); scene->addEntity(app.renderables[1]); scene->addEntity(app.renderables[2]); scene->addEntity(app.renderables[3]); - app.camera = utils::EntityManager::get().create(); + app.camera = EntityManager::get().create(); app.cam = engine->createCamera(app.camera); view->setCamera(app.cam); }; @@ -503,7 +582,7 @@ int main(int argc, char** argv) { engine->destroy(app.sb2); engine->destroy(app.mt); engine->destroyCameraComponent(app.camera); - utils::EntityManager::get().destroy(app.camera); + EntityManager::get().destroy(app.camera); for (auto i = 0; i < app.vbCount; i++) { engine->destroy(app.vbs[i]); } @@ -561,6 +640,7 @@ int main(int argc, char** argv) { rm.setMorphWeights(rm.getInstance(app.renderables[0]), weights, 3, 0); rm.setMorphWeights(rm.getInstance(app.renderables[1]), weights, 3, 0); rm.setMorphWeights(rm.getInstance(app.renderables[2]), weights, 3, 0); + rm.setMorphWeights(rm.getInstance(app.renderables[3]), weights, 3, 0); }); FilamentApp::get().run(config, setup, cleanup); From 9f1c40cd357476cfd2746b4a655569b9dab97973 Mon Sep 17 00:00:00 2001 From: brunojezek Date: Mon, 28 Aug 2023 23:06:49 +0200 Subject: [PATCH 14/24] Fix memory allocation for skinning data Texture size calculation fixed Memory allocation for texture data fixed --- filament/include/filament/RenderableManager.h | 1 + filament/src/components/RenderableManager.cpp | 2 +- filament/src/details/SkinningBuffer.cpp | 38 ++++++++++--------- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index 06214ffc2df..30705b8d62f 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -368,6 +368,7 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI { * @param indicesAndWeights pairs of bone index and bone weight for all vertices * sequentially * @param count number of all pairs, must be a multiple of vertexCount of the primitive + * count = vertexCount * bonesPerVertex * @param bonesPerVertex number of bone pairs, same for all vertices of the primitive * * @return Builder reference for chaining calls. diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index a3f32ad6aaa..b3e068c8f5c 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -227,7 +227,7 @@ RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(si RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(size_t primitiveIndex, utils::FixedCapacityVector< utils::FixedCapacityVector> indicesAndWeightsVector) noexcept { - mImpl->mBonePairs[primitiveIndex] = indicesAndWeightsVector; + mImpl->mBonePairs[primitiveIndex] = std::move(indicesAndWeightsVector); return *this; } diff --git a/filament/src/details/SkinningBuffer.cpp b/filament/src/details/SkinningBuffer.cpp index d0923571e73..5769c756cfa 100644 --- a/filament/src/details/SkinningBuffer.cpp +++ b/filament/src/details/SkinningBuffer.cpp @@ -173,7 +173,7 @@ static inline size_t getSkinningBufferWidth(size_t pairCount) noexcept { } static inline size_t getSkinningBufferHeight(size_t pairCount) noexcept { - return pairCount / MAX_SKINNING_BUFFER_WIDTH + 1; + return (pairCount + MAX_SKINNING_BUFFER_WIDTH - 1) / MAX_SKINNING_BUFFER_WIDTH; } inline size_t getSkinningBufferSize(size_t pairCount) noexcept { @@ -188,10 +188,16 @@ inline size_t getSkinningBufferSize(size_t pairCount) noexcept { UTILS_NOINLINE void updateDataAt(backend::DriverApi& driver, Handle handle, PixelDataFormat format, PixelDataType type, - const char* out, size_t elementSize, - size_t count, size_t size) { + const utils::FixedCapacityVector& pairs, + size_t count) { - size_t const textureWidth = getSkinningBufferWidth( count);//size); + size_t elementSize = sizeof(float2); + size_t size = getSkinningBufferSize(count); + auto* out = (float2*) malloc(size); + std::transform(pairs.begin(), pairs.begin() + count, out, + [](const float2& p) { return float2(p); }); + + size_t const textureWidth = getSkinningBufferWidth( count); size_t const lineCount = count / textureWidth; size_t const lastLineCount = count % textureWidth; @@ -203,17 +209,19 @@ void updateDataAt(backend::DriverApi& driver, if (lineCount) { // update the full-width lines if any driver.update3DImage(handle, 0, 0, 0, 0, - textureWidth, lineCount, 1, PixelBufferDescriptor::make( - out, (textureWidth * lineCount) * elementSize, + textureWidth, lineCount, 1, + PixelBufferDescriptor::make( + out, textureWidth * lineCount * elementSize, format, type,[allocation](void const*, size_t) {} )); - out += (lineCount * textureWidth) * elementSize; + out += lineCount * textureWidth; } if (lastLineCount) { // update the last partial line if any driver.update3DImage(handle, 0, 0, lineCount, 0, - lastLineCount, 1, 1, PixelBufferDescriptor::make( + lastLineCount, 1, 1, + PixelBufferDescriptor::make( out, lastLineCount * elementSize, format, type,[allocation](void const*, size_t) {} )); @@ -222,14 +230,14 @@ void updateDataAt(backend::DriverApi& driver, FSkinningBuffer::HandleIndicesAndWeights FSkinningBuffer::createIndicesAndWeightsHandle(FEngine& engine, size_t count) { backend::Handle samplerHandle; - backend::Handle textureHandle; // bone indices and weights + backend::Handle textureHandle; FEngine::DriverApi& driver = engine.getDriverApi(); - auto size = getSkinningBufferSize(count); // create a texture for skinning pairs data (bone index and weight) textureHandle = driver.createTexture(SamplerType::SAMPLER_2D, 1, TextureFormat::RG32F, 1, - getSkinningBufferWidth(size), getSkinningBufferHeight(size), 1, + getSkinningBufferWidth(count), + getSkinningBufferHeight(count), 1, TextureUsage::DEFAULT); samplerHandle = driver.createSamplerGroup(PerRenderPrimitiveSkinningSib::SAMPLER_COUNT); SamplerGroup samplerGroup(PerRenderPrimitiveSkinningSib::SAMPLER_COUNT); @@ -248,15 +256,9 @@ void FSkinningBuffer::setIndicesAndWeightsData(FEngine& engine, const utils::FixedCapacityVector& pairs, size_t count) { FEngine::DriverApi& driver = engine.getDriverApi(); - auto size = getSkinningBufferSize(count); - auto* out = (float2*) malloc(size); - std::transform(pairs.begin(), pairs.begin() + count, out, - [](const float2& p) { return float2(p); }); - updateDataAt(driver, textureHandle, Texture::Format::RG, Texture::Type::FLOAT, - (char const*)out, sizeof(float2), - count, size); + pairs, count); } } // namespace filament From 08b56aa94909d785488a94613488fb1605bd7dad Mon Sep 17 00:00:00 2001 From: brunojezek Date: Tue, 29 Aug 2023 17:57:42 +0200 Subject: [PATCH 15/24] Small fix: replace transform to memcpy --- filament/src/details/SkinningBuffer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/filament/src/details/SkinningBuffer.cpp b/filament/src/details/SkinningBuffer.cpp index 5769c756cfa..2600cf4351c 100644 --- a/filament/src/details/SkinningBuffer.cpp +++ b/filament/src/details/SkinningBuffer.cpp @@ -194,8 +194,7 @@ void updateDataAt(backend::DriverApi& driver, size_t elementSize = sizeof(float2); size_t size = getSkinningBufferSize(count); auto* out = (float2*) malloc(size); - std::transform(pairs.begin(), pairs.begin() + count, out, - [](const float2& p) { return float2(p); }); + std::memcpy(out, pairs.begin(), size); size_t const textureWidth = getSkinningBufferWidth( count); size_t const lineCount = count / textureWidth; From 4098bbbab7f44772343bdbcf313c21e70fac5cec Mon Sep 17 00:00:00 2001 From: brunojezek Date: Wed, 30 Aug 2023 12:09:49 +0200 Subject: [PATCH 16/24] Small corrections based on reviews --- filament/include/filament/VertexBuffer.h | 4 +- filament/src/components/RenderableManager.cpp | 122 +++++++++--------- filament/src/details/SkinningBuffer.cpp | 4 +- filament/src/details/VertexBuffer.cpp | 4 +- samples/helloskinningbuffer_morebones.cpp | 4 +- samples/skinningtest.cpp | 10 +- shaders/src/getters.vs | 2 +- 7 files changed, 77 insertions(+), 73 deletions(-) diff --git a/filament/include/filament/VertexBuffer.h b/filament/include/filament/VertexBuffer.h index 9c76e075da7..dd844c375a0 100644 --- a/filament/include/filament/VertexBuffer.h +++ b/filament/include/filament/VertexBuffer.h @@ -147,11 +147,13 @@ class UTILS_PUBLIC VertexBuffer : public FilamentAPI { * set in RenderableManager:Builder:boneIndicesAndWeights methods. * Works with or without buffer objects. * + * @param enabled If true, enables advanced skinning mode. False by default. + * * @return A reference to this Builder for chaining calls. * * @see RenderableManager:Builder:boneIndicesAndWeights */ - Builder& advancedSkinning() noexcept; + Builder& advancedSkinning(bool enabled) noexcept; /** * Creates the VertexBuffer object and returns a pointer to it. diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index b3e068c8f5c..7d7cdcbe75d 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -292,7 +292,7 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi entity.getId(), primitiveIndex); for (size_t iVertex = 0; iVertex < vertexCount; iVertex++) { auto bonesPerVertex = bonePairsForPrimitive[iVertex].size(); - maxPairsCount += bonesPerVertex; + maxPairsCount += bonesPerVertex; maxPairsCountPerVertex = max(bonesPerVertex, (uint) maxPairsCountPerVertex); } } @@ -302,71 +302,73 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi // final texture data, indices and weights mBoneIndicesAndWeights = utils::FixedCapacityVector(maxPairsCount); // temporary indices and weights for one vertex - std::unique_ptr tempPairs(new float2[maxPairsCountPerVertex]()); + std::unique_ptr tempPairs = std::make_unique + (maxPairsCountPerVertex); for (auto iBonePair = mBonePairs.begin(); iBonePair != mBonePairs.end(); ++iBonePair) { auto primitiveIndex = iBonePair->first; auto bonePairsForPrimitive = iBonePair->second; - if (bonePairsForPrimitive.size()) { - size_t vertexCount = mEntries[primitiveIndex].vertices->getVertexCount(); - std::unique_ptr skinJoints( - new uint16_t[4 * vertexCount]()); // temporary indices for one vertex - std::unique_ptr skinWeights( - new float[4 * vertexCount]()); // temporary weights for one vertex - for (size_t iVertex = 0; iVertex < vertexCount; iVertex++) { - size_t tempPairCount = 0; - float boneWeightsSum = 0; - for (size_t k = 0; k < bonePairsForPrimitive[iVertex].size(); k++) { - auto boneWeight = bonePairsForPrimitive[iVertex][k][1]; - auto boneIndex= bonePairsForPrimitive[iVertex][k][0]; - ASSERT_PRECONDITION(boneWeight >= 0, - "[entity=%u, primitive @ %u] bone weight (%f) of vertex=%u is negative ", - entity.getId(), primitiveIndex, boneWeight, iVertex); - if (boneWeight) { - ASSERT_PRECONDITION(boneIndex >= 0, - "[entity=%u, primitive @ %u] bone index (%i) of vertex=%u is negative ", - entity.getId(), primitiveIndex, (int) boneIndex, iVertex); - ASSERT_PRECONDITION(boneIndex < mSkinningBoneCount, - "[entity=%u, primitive @ %u] bone index (%i) of vertex=%u is bigger then bone count (%u) ", - entity.getId(), primitiveIndex, (int) boneIndex, iVertex, mSkinningBoneCount); - boneWeightsSum += boneWeight; - tempPairs[tempPairCount][0] = boneIndex; - tempPairs[tempPairCount][1] = boneWeight; - tempPairCount++; - } + if (!bonePairsForPrimitive.size()) { + continue; + } + size_t vertexCount = mEntries[primitiveIndex].vertices->getVertexCount(); + std::unique_ptr skinJoints = std::make_unique + (4 * vertexCount); // temporary indices for one vertex + std::unique_ptr skinWeights = std::make_unique + (4 * vertexCount); // temporary weights for one vertex + for (size_t iVertex = 0; iVertex < vertexCount; iVertex++) { + size_t tempPairCount = 0; + float boneWeightsSum = 0; + for (size_t k = 0; k < bonePairsForPrimitive[iVertex].size(); k++) { + auto boneWeight = bonePairsForPrimitive[iVertex][k][1]; + auto boneIndex = bonePairsForPrimitive[iVertex][k][0]; + ASSERT_PRECONDITION(boneWeight >= 0, + "[entity=%u, primitive @ %u] bone weight (%f) of vertex=%u is negative ", + entity.getId(), primitiveIndex, boneWeight, iVertex); + if (boneWeight) { + ASSERT_PRECONDITION(boneIndex >= 0, + "[entity=%u, primitive @ %u] bone index (%i) of vertex=%u is negative ", + entity.getId(), primitiveIndex, (int) boneIndex, iVertex); + ASSERT_PRECONDITION(boneIndex < mSkinningBoneCount, + "[entity=%u, primitive @ %u] bone index (%i) of vertex=%u is bigger then bone count (%u) ", + entity.getId(), primitiveIndex, (int) boneIndex, iVertex, mSkinningBoneCount); + boneWeightsSum += boneWeight; + tempPairs[tempPairCount][0] = boneIndex; + tempPairs[tempPairCount][1] = boneWeight; + tempPairCount++; } + } - ASSERT_PRECONDITION(boneWeightsSum > 0, - "[entity=%u, primitive @ %u] sum of bone weights of vertex=%u is %f, it should be positive.", - entity.getId(), primitiveIndex, iVertex, boneWeightsSum); - if (abs(boneWeightsSum - 1.f) > std::numeric_limits::epsilon()) { - utils::slog.w << "Warning of skinning: [entity=%" << entity.getId() - << ", primitive @ %" << primitiveIndex - << "] sum of bone weights of vertex=" << iVertex << " is " << boneWeightsSum - << ", it should be one. Weights will be normalized." << utils::io::endl; - } - // prepare data for vertex attributes - auto offset = iVertex * 4; - // set attributes, indices and weights, for <= 4 pairs - for (size_t j = 0, c = min(tempPairCount, 4ul); j < c; j++) { - skinJoints[j + offset] = tempPairs[j][0]; - skinWeights[j + offset] = tempPairs[j][1] / boneWeightsSum; - } - // prepare data for texture - if (tempPairCount > 4) { // set attributes, indices and weights, for > 4 pairs - skinWeights[3 + offset] = -(float) (pairsCount + 1); // negative offset to texture 0..-1, 1..-2 - skinJoints[3 + offset] = (uint16_t) tempPairCount; // number pairs per vertex in texture - for (size_t j = 3; j < tempPairCount; j++) { - mBoneIndicesAndWeights[pairsCount][0] = tempPairs[j][0]; - mBoneIndicesAndWeights[pairsCount][1] = tempPairs[j][1] / boneWeightsSum; - pairsCount++; - } + ASSERT_PRECONDITION(boneWeightsSum > 0, + "[entity=%u, primitive @ %u] sum of bone weights of vertex=%u is %f, it should be positive.", + entity.getId(), primitiveIndex, iVertex, boneWeightsSum); + if (abs(boneWeightsSum - 1.f) > std::numeric_limits::epsilon()) { + utils::slog.w << "Warning of skinning: [entity=%" << entity.getId() + << ", primitive @ %" << primitiveIndex + << "] sum of bone weights of vertex=" << iVertex << " is " << boneWeightsSum + << ", it should be one. Weights will be normalized." << utils::io::endl; + } + // prepare data for vertex attributes + auto offset = iVertex * 4; + // set attributes, indices and weights, for <= 4 pairs + for (size_t j = 0, c = min(tempPairCount, 4ul); j < c; j++) { + skinJoints[j + offset] = tempPairs[j][0]; + skinWeights[j + offset] = tempPairs[j][1] / boneWeightsSum; + } + // prepare data for texture + if (tempPairCount > 4) { // set attributes, indices and weights, for > 4 pairs + skinWeights[3 + offset] = -(float) (pairsCount + 1); // negative offset to texture 0..-1, 1..-2 + skinJoints[3 + offset] = (uint16_t) tempPairCount; // number pairs per vertex in texture + for (size_t j = 3; j < tempPairCount; j++) { + mBoneIndicesAndWeights[pairsCount][0] = tempPairs[j][0]; + mBoneIndicesAndWeights[pairsCount][1] = tempPairs[j][1] / boneWeightsSum; + pairsCount++; } - } // for all vertices per primitive - downcast(mEntries[primitiveIndex].vertices) - ->updateBoneIndicesAndWeights(downcast(engine), - std::move(skinJoints), - std::move(skinWeights)); - } + } + } // for all vertices per primitive + downcast(mEntries[primitiveIndex].vertices) + ->updateBoneIndicesAndWeights(downcast(engine), + std::move(skinJoints), + std::move(skinWeights)); } // for all primitives } mBoneIndicesAndWeightsCount = pairsCount; // only part of mBoneIndicesAndWeights is used for real data diff --git a/filament/src/details/SkinningBuffer.cpp b/filament/src/details/SkinningBuffer.cpp index 2600cf4351c..323a66ee97e 100644 --- a/filament/src/details/SkinningBuffer.cpp +++ b/filament/src/details/SkinningBuffer.cpp @@ -211,7 +211,7 @@ void updateDataAt(backend::DriverApi& driver, textureWidth, lineCount, 1, PixelBufferDescriptor::make( out, textureWidth * lineCount * elementSize, - format, type,[allocation](void const*, size_t) {} + format, type, [allocation](void const*, size_t) {} )); out += lineCount * textureWidth; } @@ -222,7 +222,7 @@ void updateDataAt(backend::DriverApi& driver, lastLineCount, 1, 1, PixelBufferDescriptor::make( out, lastLineCount * elementSize, - format, type,[allocation](void const*, size_t) {} + format, type, [allocation](void const*, size_t) {} )); } } diff --git a/filament/src/details/VertexBuffer.cpp b/filament/src/details/VertexBuffer.cpp index bd4ff95a0ad..f557e25d233 100644 --- a/filament/src/details/VertexBuffer.cpp +++ b/filament/src/details/VertexBuffer.cpp @@ -114,8 +114,8 @@ VertexBuffer::Builder& VertexBuffer::Builder::normalized(VertexAttribute attribu return *this; } -VertexBuffer::Builder& VertexBuffer::Builder::advancedSkinning() noexcept { - mImpl->mAdvancedSkinningEnabled = true; +VertexBuffer::Builder& VertexBuffer::Builder::advancedSkinning(bool enabled) noexcept { + mImpl->mAdvancedSkinningEnabled = enabled; return *this; } diff --git a/samples/helloskinningbuffer_morebones.cpp b/samples/helloskinningbuffer_morebones.cpp index a8e30fae37d..63bea07b165 100644 --- a/samples/helloskinningbuffer_morebones.cpp +++ b/samples/helloskinningbuffer_morebones.cpp @@ -104,7 +104,7 @@ int main(int argc, char** argv) { .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) - .advancedSkinning() + .advancedSkinning(true) .build(*engine); app.vb1->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr)); @@ -114,7 +114,7 @@ int main(int argc, char** argv) { .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) - .advancedSkinning() + .advancedSkinning(true) .build(*engine); app.vb2->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr)); diff --git a/samples/skinningtest.cpp b/samples/skinningtest.cpp index f0fbd0c6fe3..70d70e8326c 100644 --- a/samples/skinningtest.cpp +++ b/samples/skinningtest.cpp @@ -292,7 +292,7 @@ int main(int argc, char** argv) { VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) .enableBufferObjects() - .advancedSkinning() + .advancedSkinning(true) .build(*engine); app.bos[app.boCount] = BufferObject::Builder() .size(3 * sizeof(Vertex)) @@ -314,7 +314,7 @@ int main(int argc, char** argv) { VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) .enableBufferObjects() - .advancedSkinning() + .advancedSkinning(true) .build(*engine); app.bos[app.boCount] = BufferObject::Builder() .size(3 * sizeof(Vertex)) @@ -337,7 +337,7 @@ int main(int argc, char** argv) { VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) .enableBufferObjects() - .advancedSkinning() + .advancedSkinning(true) .build(*engine); app.bos[app.boCount] = BufferObject::Builder() .size(3 * sizeof(Vertex)) @@ -361,7 +361,7 @@ int main(int argc, char** argv) { VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) .enableBufferObjects() - .advancedSkinning() + .advancedSkinning(true) .build(*engine); app.bos[app.boCount] = BufferObject::Builder() .size(6 * sizeof(Vertex)) @@ -383,7 +383,7 @@ int main(int argc, char** argv) { VertexBuffer::AttributeType::UBYTE4, 8, 12) .normalized(VertexAttribute::COLOR) .enableBufferObjects() - .advancedSkinning() + .advancedSkinning(true) .build(*engine); app.bos[app.boCount] = BufferObject::Builder() .size(3 * sizeof(Vertex)) diff --git a/shaders/src/getters.vs b/shaders/src/getters.vs index b77dc053849..b5186c40213 100644 --- a/shaders/src/getters.vs +++ b/shaders/src/getters.vs @@ -78,7 +78,7 @@ void skinPosition(inout vec3 p, const uvec4 ids, const vec4 weights) { posSum += weights.z * mulBoneVertex(p, uint(ids.z)); uint pairIndex = uint(-weights.w - 1.); uint pairStop = pairIndex + uint(ids.w - 3u); - for (uint i = pairIndex; i < pairStop; i = i + 1u) { + for (uint i = pairIndex; i < pairStop; ++i) { ivec2 texcoord = ivec2(i % MAX_SKINNING_BUFFER_WIDTH, i / MAX_SKINNING_BUFFER_WIDTH); vec2 indexWeight = texelFetch(bonesBuffer_indicesAndWeights, texcoord, 0).rg; posSum += mulBoneVertex(p, uint(indexWeight.r)) * indexWeight.g; From 0ca29284e3bd47efd3d5279b15f6f7eb997e6203 Mon Sep 17 00:00:00 2001 From: fvbj Date: Mon, 4 Sep 2023 12:41:47 +0200 Subject: [PATCH 17/24] Commit after rebase --- filament/src/components/RenderableManager.cpp | 5 +- samples/CMakeLists.txt | 2 - samples/suzanneskinning.cpp | 288 ------------------ shaders/src/main.vs | 2 +- 4 files changed, 4 insertions(+), 293 deletions(-) delete mode 100644 samples/suzanneskinning.cpp diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 7d7cdcbe75d..452ad6a1ba3 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -73,8 +73,9 @@ struct RenderableManager::BuilderDetails { utils::FixedCapacityVector>> mBonePairs; explicit BuilderDetails(size_t count) - : mEntries(count), mCulling(true), mCastShadows(false), mReceiveShadows(true), - mScreenSpaceContactShadows(false), mSkinningBufferMode(false), mBonePairs(), mFogEnabled(true) { + : mEntries(count), mCulling(true), mCastShadows(false), + mReceiveShadows(true), mScreenSpaceContactShadows(false), + mSkinningBufferMode(false), mFogEnabled(true), mBonePairs() { } // this is only needed for the explicit instantiation below BuilderDetails() = default; diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index a50e5475826..00a17efee6f 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -250,7 +250,6 @@ if (NOT ANDROID) add_demo(skinningtest) add_demo(strobecolor) add_demo(suzanne) - add_demo(suzanneskinning) add_demo(texturedquad) add_demo(vbotest) add_demo(viewtest) @@ -266,7 +265,6 @@ if (NOT ANDROID) target_link_libraries(sample_cloth PRIVATE filameshio) target_link_libraries(sample_normal_map PRIVATE filameshio) target_link_libraries(suzanne PRIVATE filameshio suzanne-resources) - target_link_libraries(suzanneskinning PRIVATE filameshio suzanne-resources) if (FILAMENT_DISABLE_MATOPT) add_definitions(-DFILAMENT_DISABLE_MATOPT=1) diff --git a/samples/suzanneskinning.cpp b/samples/suzanneskinning.cpp deleted file mode 100644 index a1b2ef95cdb..00000000000 --- a/samples/suzanneskinning.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include - -#include -#include -#include - -#include - -#include - -#include - -#include - -#include "generated/resources/resources.h" -#include "generated/resources/monkey.h" - -using namespace filament; -using namespace ktxreader; -using utils::Entity; -using utils::EntityManager; -using namespace filament::math; - -struct App { - Material* material; - MaterialInstance* materialInstance; - filamesh::MeshReader::Mesh mesh; - mat4f transform; - Texture* albedo; - Texture* normal; - Texture* roughness; - Texture* metallic; - Texture* ao; - Entity renderable; - SkinningBuffer *sb; -}; - -mat4f transforms[] = {math::mat4f(1), - mat4f::translation(float3(1, 0, 0)), - mat4f::translation(float3(1, 1, 0)), - mat4f::translation(float3(0, 1, 0)), - mat4f::translation(float3(-1, 1, 0)), - mat4f::translation(float3(-1, 0, 0)), - mat4f::translation(float3(-1, -1, 0)), - mat4f::translation(float3(0, -1, 0)), - mat4f::translation(float3(1, -1, 0))}; - -utils::FixedCapacityVector> boneDataPerPrimitive(17785); //number of vertices -static const char* IBL_FOLDER = "assets/ibl/lightroom_14b"; - -static void printUsage(char* name) { - std::string exec_name(utils::Path(name).getName()); - std::string usage( - "SHOWCASE renders a Suzanne model with compressed textures.\n" - "Usage:\n" - " SHOWCASE [options]\n" - "Options:\n" - " --help, -h\n" - " Prints this message\n\n" - " --api, -a\n" - " Specify the backend API: opengl (default), vulkan, or metal\n" - ); - const std::string from("SHOWCASE"); - for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) { - usage.replace(pos, from.length(), exec_name); - } - std::cout << usage; -} - -static int handleCommandLineArguments(int argc, char* argv[], Config* config) { - static constexpr const char* OPTSTR = "ha:"; - static const struct option OPTIONS[] = { - { "help", no_argument, nullptr, 'h' }, - { "api", required_argument, nullptr, 'a' }, - { nullptr, 0, nullptr, 0 } - }; - int opt; - int option_index = 0; - while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) { - std::string arg(optarg ? optarg : ""); - switch (opt) { - default: - case 'h': - printUsage(argv[0]); - exit(0); - case 'a': - if (arg == "opengl") { - config->backend = Engine::Backend::OPENGL; - } else if (arg == "vulkan") { - config->backend = Engine::Backend::VULKAN; - } else if (arg == "metal") { - config->backend = Engine::Backend::METAL; - } else { - std::cerr << "Unrecognized backend. Must be 'opengl'|'vulkan'|'metal'.\n"; - } - break; - } - } - return optind; -} - -static Texture* loadNormalMap(Engine* engine, const uint8_t* normals, size_t nbytes) { - int w, h, n; - unsigned char* data = stbi_load_from_memory(normals, nbytes, &w, &h, &n, 3); - Texture* normalMap = Texture::Builder() - .width(uint32_t(w)) - .height(uint32_t(h)) - .levels(0xff) - .format(Texture::InternalFormat::RGB8) - .build(*engine); - Texture::PixelBufferDescriptor buffer(data, size_t(w * h * 3), - Texture::Format::RGB, Texture::Type::UBYTE, - (Texture::PixelBufferDescriptor::Callback) &stbi_image_free); - normalMap->setImage(*engine, 0, std::move(buffer)); - normalMap->generateMipmaps(*engine); - return normalMap; -} - -int main(int argc, char** argv) { - int boneCount = 9; - utils::FixedCapacityVector boneDataPerVertex(boneCount); - // index and weight for one vertex - for (size_t idx = 0; idx < boneCount; idx++) { - boneDataPerVertex[idx] = float2(idx, 1.f / boneCount); - } - for (size_t idx = 0; idx < boneDataPerPrimitive.size(); idx++) { - boneDataPerPrimitive[idx] = boneDataPerVertex; - } - - Config config; - config.title = "Suzanne model with unlimited bone skinning, example with 9 bones per vertex (#17785)"; - config.iblDirectory = FilamentApp::getRootAssetsPath() + IBL_FOLDER; - - handleCommandLineArguments(argc, argv, &config); - - App app; - auto setup = [config, &app](Engine* engine, View* view, Scene* scene) { - auto& tcm = engine->getTransformManager(); - auto& rcm = engine->getRenderableManager(); - auto& em = utils::EntityManager::get(); - - Ktx2Reader reader(*engine); - - reader.requestFormat(Texture::InternalFormat::DXT3_SRGBA); - reader.requestFormat(Texture::InternalFormat::DXT3_RGBA); - - // Uncompressed formats are lower priority, so they get added last. - reader.requestFormat(Texture::InternalFormat::SRGB8_A8); - reader.requestFormat(Texture::InternalFormat::RGBA8); - - constexpr auto sRGB = Ktx2Reader::TransferFunction::sRGB; - constexpr auto LINEAR = Ktx2Reader::TransferFunction::LINEAR; - - app.albedo = reader.load(MONKEY_ALBEDO_DATA, MONKEY_ALBEDO_SIZE, sRGB); - app.ao = reader.load(MONKEY_AO_DATA, MONKEY_AO_SIZE, LINEAR); - app.metallic = reader.load(MONKEY_METALLIC_DATA, MONKEY_METALLIC_SIZE, LINEAR); - app.roughness = reader.load(MONKEY_ROUGHNESS_DATA, MONKEY_ROUGHNESS_SIZE, LINEAR); - -#if !defined(NDEBUG) - using namespace utils; - slog.i << "Resolved format for albedo: " << app.albedo->getFormat() << io::endl; - slog.i << "Resolved format for ambient occlusion: " << app.ao->getFormat() << io::endl; - slog.i << "Resolved format for metallic: " << app.metallic->getFormat() << io::endl; - slog.i << "Resolved format for roughness: " << app.roughness->getFormat() << io::endl; -#endif - - app.normal = loadNormalMap(engine, MONKEY_NORMAL_DATA, MONKEY_NORMAL_SIZE); - TextureSampler sampler(TextureSampler::MinFilter::LINEAR_MIPMAP_LINEAR, - TextureSampler::MagFilter::LINEAR); - - // Instantiate material. - app.material = Material::Builder() - .package(RESOURCES_TEXTUREDLIT_DATA, RESOURCES_TEXTUREDLIT_SIZE).build(*engine); - app.materialInstance = app.material->createInstance(); - app.materialInstance->setParameter("albedo", app.albedo, sampler); - app.materialInstance->setParameter("ao", app.ao, sampler); - app.materialInstance->setParameter("metallic", app.metallic, sampler); - app.materialInstance->setParameter("normal", app.normal, sampler); - app.materialInstance->setParameter("roughness", app.roughness, sampler); - - auto ibl = FilamentApp::get().getIBL()->getIndirectLight(); - ibl->setIntensity(100000); - ibl->setRotation(mat3f::rotation(0.5f, float3{ 0, 1, 0 })); - - // Add geometry into the scene. - app.mesh = filamesh::MeshReader::loadMeshFromBuffer(engine, MONKEY_SUZANNE_DATA, nullptr, - nullptr, app.materialInstance); - auto ti = tcm.getInstance(app.mesh.renderable); - app.transform = mat4f{ mat3f(1), float3(0, 0, 0) } * tcm.getWorldTransform(ti); - - app.sb = SkinningBuffer::Builder() - .boneCount(256) - .initialize(true) - .build(*engine); - app.sb->setBones(*engine, transforms,9,0); - - app.renderable = EntityManager::get().create(); - RenderableManager::Builder(1) - .boundingBox({{ -2, -2, -2 }, { 2, 2, 2 }}) - .material(0, app.materialInstance) - .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.mesh.vertexBuffer, app.mesh.indexBuffer) - .receiveShadows(true) - .castShadows(false) - .enableSkinningBuffers(true) - .skinning(app.sb, 9, 0) - .boneIndicesAndWeights(0, boneDataPerPrimitive) - .build(*engine, app.renderable); - fprintf(stdout,"RenderableManager built done \n"); - - scene->addEntity(app.renderable); - tcm.setTransform(ti, app.transform); - }; - - auto cleanup = [&app](Engine* engine, View*, Scene*) { - engine->destroy(app.materialInstance); - engine->destroy(app.mesh.renderable); - engine->destroy(app.material); - engine->destroy(app.albedo); - engine->destroy(app.normal); - engine->destroy(app.roughness); - engine->destroy(app.metallic); - engine->destroy(app.ao); - engine->destroy(app.renderable); - engine->destroy(app.sb); - engine->destroy(app.mesh.vertexBuffer); - engine->destroy(app.mesh.indexBuffer); - }; - -FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { - - // Bone skinning animation for more than four bones per vertex - float t = now / 10.f; - float s1 = sin(t * f::PI * 4.f) * 10; - float s2 = sin(t * f::PI * 6.f) * 10; - float s3 = sin(t * f::PI * 8.f) * 10; - - // Create bone transformations - mat4f trans[] = { - mat4f::scaling(float3(s1 + 10, 1.f, 1.f)), - mat4f::scaling(float3(1.f, s2 + 10, 1.f)), - mat4f::scaling(float3(1.f, 1.f, s3 + 10)), - mat4f::rotation(t * f::PI * 16.f, float3(1, 0, 0)), - mat4f::rotation(t * f::PI * 4.f, float3(0, 1, 0)), - mat4f::rotation(t * f::PI * 8.f, float3(0, 0, 1)), - mat4f::translation(float3(s1, 0, 0)), - mat4f::translation(float3(0, s2, 0)), - mat4f::translation(float3(0, 0, s3)), - }; - - app.sb->setBones(*engine,trans,9,0); - }); - - FilamentApp::get().run(config, setup, cleanup); - - return 0; -} diff --git a/shaders/src/main.vs b/shaders/src/main.vs index a416bccc37b..5347362e233 100644 --- a/shaders/src/main.vs +++ b/shaders/src/main.vs @@ -80,7 +80,7 @@ void main() { #endif } - if ((object_uniforms.flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) { + if ((object_uniforms_flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) { skinNormalTangent(material.worldNormal, vertex_worldTangent.xyz, mesh_bone_indices, mesh_bone_weights); } #endif From bc600d48bef340bb83d9766058567ecf980944bc Mon Sep 17 00:00:00 2001 From: fvbj Date: Mon, 18 Sep 2023 19:22:16 +0200 Subject: [PATCH 18/24] Fix size of reserved bytes in RenderPass::PrimitiveInfo --- filament/src/RenderPass.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filament/src/RenderPass.h b/filament/src/RenderPass.h index abcba7288c2..4b671a648f9 100644 --- a/filament/src/RenderPass.h +++ b/filament/src/RenderPass.h @@ -240,7 +240,7 @@ class RenderPass { uint32_t skinningOffset = 0; // 4 bytes uint16_t instanceCount; // 2 bytes [MSb: user] Variant materialVariant; // 1 byte - uint8_t reserved[0] = {}; // 4 bytes +// uint8_t reserved[0] = {}; // 0 bytes static const uint16_t USER_INSTANCE_MASK = 0x8000u; static const uint16_t INSTANCE_COUNT_MASK = 0x7fffu; From 37d56225cdaddfc0abcae61afa860185963d9e3a Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 18 Sep 2023 21:07:30 -0700 Subject: [PATCH 19/24] attempt to fix build breakage --- shaders/src/main.vs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shaders/src/main.vs b/shaders/src/main.vs index 5347362e233..a52bc527d1d 100644 --- a/shaders/src/main.vs +++ b/shaders/src/main.vs @@ -80,7 +80,7 @@ void main() { #endif } - if ((object_uniforms_flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) { + if ((object_uniforms_flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0) { skinNormalTangent(material.worldNormal, vertex_worldTangent.xyz, mesh_bone_indices, mesh_bone_weights); } #endif From fe6b55d80db43398c6d6eec59668fa20f31564a1 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 18 Sep 2023 21:55:18 -0700 Subject: [PATCH 20/24] add missing header --- filament/src/details/VertexBuffer.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/filament/src/details/VertexBuffer.h b/filament/src/details/VertexBuffer.h index 29bae33a608..d9e78835186 100644 --- a/filament/src/details/VertexBuffer.h +++ b/filament/src/details/VertexBuffer.h @@ -26,9 +26,11 @@ #include #include + #include #include +#include #include namespace filament { From 3d43cfeb0b2c123858331bf9a0c3df831f9f57d0 Mon Sep 17 00:00:00 2001 From: fvbj Date: Tue, 19 Sep 2023 14:51:49 +0200 Subject: [PATCH 21/24] Fix build-windows --- filament/src/components/RenderableManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 452ad6a1ba3..dc685717fb8 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -292,9 +292,9 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi "[entity=%u, primitive @ %u] for advanced skinning set VertexBuffer::Builder::advancedSkinning()", entity.getId(), primitiveIndex); for (size_t iVertex = 0; iVertex < vertexCount; iVertex++) { - auto bonesPerVertex = bonePairsForPrimitive[iVertex].size(); + size_t bonesPerVertex = bonePairsForPrimitive[iVertex].size(); maxPairsCount += bonesPerVertex; - maxPairsCountPerVertex = max(bonesPerVertex, (uint) maxPairsCountPerVertex); + maxPairsCountPerVertex = std::max(bonesPerVertex, maxPairsCountPerVertex); } } @@ -351,7 +351,7 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi // prepare data for vertex attributes auto offset = iVertex * 4; // set attributes, indices and weights, for <= 4 pairs - for (size_t j = 0, c = min(tempPairCount, 4ul); j < c; j++) { + for (size_t j = 0, c = std::min(tempPairCount, 4ul); j < c; j++) { skinJoints[j + offset] = tempPairs[j][0]; skinWeights[j + offset] = tempPairs[j][1] / boneWeightsSum; } From 0b7dfee2431c8551dcf87d6b7e3d0d82c64d002c Mon Sep 17 00:00:00 2001 From: fvbj Date: Tue, 19 Sep 2023 19:00:49 +0200 Subject: [PATCH 22/24] Fix build-windows, type conversion --- filament/src/components/RenderableManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index dc685717fb8..7314f705d53 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -351,7 +351,7 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi // prepare data for vertex attributes auto offset = iVertex * 4; // set attributes, indices and weights, for <= 4 pairs - for (size_t j = 0, c = std::min(tempPairCount, 4ul); j < c; j++) { + for (size_t j = 0, c = std::min((int) tempPairCount, 4); j < c; j++) { skinJoints[j + offset] = tempPairs[j][0]; skinWeights[j + offset] = tempPairs[j][1] / boneWeightsSum; } From 0e4b5c2dc76b9d44e859a809826e01a2c9fc40e0 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 19 Sep 2023 14:03:27 -0700 Subject: [PATCH 23/24] attempt to fix windows build uint is not a standard type, use size_t instead --- samples/skinningtest.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/skinningtest.cpp b/samples/skinningtest.cpp index 70d70e8326c..7d148a14aee 100644 --- a/samples/skinningtest.cpp +++ b/samples/skinningtest.cpp @@ -141,7 +141,7 @@ int main(int argc, char** argv) { size_t boneCount = app.bonesPerVertex; float weight = 1.f / boneCount; FixedCapacityVector boneDataPerVertex(boneCount); - for (uint idx = 0; idx < boneCount; idx++) { + for (size_t idx = 0; idx < boneCount; idx++) { boneDataPerVertex[idx] = float2(idx, weight); boneDataArray[idx] = float2(idx, weight); boneDataArray[idx + boneCount] = float2(idx, weight); @@ -156,11 +156,11 @@ int main(int argc, char** argv) { app.boneDataPerPrimitive[idx++] = boneDataPerVertex; app.boneDataPerPrimitive[idx++] = boneDataPerVertex; - for (uint vertex_idx = 0; vertex_idx < 6; vertex_idx++) { + for (size_t vertex_idx = 0; vertex_idx < 6; vertex_idx++) { boneCount = vertex_idx % app.bonesPerVertex + 1; weight = 1.f / boneCount; FixedCapacityVector boneDataPerVertex1(boneCount); - for (uint idx = 0; idx < boneCount; idx++) { + for (size_t idx = 0; idx < boneCount; idx++) { boneDataPerVertex1[idx] = float2(idx, weight); } app.boneDataPerPrimitiveMulti[vertex_idx] = boneDataPerVertex1; @@ -607,14 +607,14 @@ int main(int argc, char** argv) { // Bone skinning animation for more than four bones per vertex float t = (float)(now - (int)now); - uint offset = ((uint)now) % 9; + size_t offset = ((size_t)now) % 9; float s = sin(t * f::PI * 2.f) * 10; mat4f trans[9] = {}; - for (uint i = 0; i < 9; i++) { + for (size_t i = 0; i < 9; i++) { trans[i] = filament::math::mat4f(1); } mat4f trans2[9] = {}; - for (uint i = 0; i < 9; i++) { + for (size_t i = 0; i < 9; i++) { trans2[i] = filament::math::mat4f(1); } mat4f transA[] = { From db5f0fff588f6b89aae0e64f268ce1b1898c4560 Mon Sep 17 00:00:00 2001 From: fvbj Date: Wed, 20 Sep 2023 00:06:21 +0200 Subject: [PATCH 24/24] attempt to fix windows build, uint removal --- samples/helloskinningbuffer.cpp | 4 ++-- samples/helloskinningbuffer_morebones.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/helloskinningbuffer.cpp b/samples/helloskinningbuffer.cpp index c31bf12f0ae..c69f962855d 100644 --- a/samples/helloskinningbuffer.cpp +++ b/samples/helloskinningbuffer.cpp @@ -209,7 +209,7 @@ int main(int argc, char** argv) { mat4f translate[] = {mat4f::translation(float3(s, c, 0))}; mat4f trans1of8[9] = {}; - for (uint i = 0; i < 9; i++) { + for (size_t i = 0; i < 9; i++) { trans1of8[i] = filament::math::mat4f(1); } s *= 5; @@ -223,7 +223,7 @@ int main(int argc, char** argv) { mat4f::translation(float3(0, -s, 0)), mat4f::translation(float3(s, -s, 0)), filament::math::mat4f(1)}; - uint offset = ((uint)now) % 8; + size_t offset = ((size_t)now) % 8; trans1of8[offset] = transA[offset]; // Set transformation of the first bone diff --git a/samples/helloskinningbuffer_morebones.cpp b/samples/helloskinningbuffer_morebones.cpp index 63bea07b165..48fe174e151 100644 --- a/samples/helloskinningbuffer_morebones.cpp +++ b/samples/helloskinningbuffer_morebones.cpp @@ -217,7 +217,7 @@ int main(int argc, char** argv) { mat4f translate[] = {mat4f::translation(float3(s, c, 0))}; mat4f trans[9] = {}; - for (uint i = 0; i < 9; i++) { + for (size_t i = 0; i < 9; i++) { trans[i] = filament::math::mat4f(1); } s *= 8; @@ -231,7 +231,7 @@ int main(int argc, char** argv) { mat4f::translation(float3(0, -s, 0)), mat4f::translation(float3(s, -s, 0)), filament::math::mat4f(1)}; - uint offset = ((uint)now) % 8; + size_t offset = ((size_t)now) % 8; trans[offset] = transA[offset]; // Set transformation of the first bone