1#include "InstancedMeshBuilderSystem.h"
2#include "Components/Core/InstancedMeshRenderComponent.h"
4#include "Systems/Core/CameraSystem.h"
5#include "Systems/Core/TransformSystem.h"
7#include "Resources/Mesh.h"
8#include "Resources/MeshManager.h"
9#include "Resources/VertexFormats.h"
11#include "Services/DPIService.h"
13#include "Foundation/HashSequence.h"
14#include "Foundation/Geometry/Glm.hpp"
22 void buildMatrices(std::span<glm::mat4> matrices,
23 std::span<const glm::vec3> positions,
24 std::span<const glm::quat> rotations,
25 std::span<const glm::vec3> scales,
28 for (
size_t i = 0; i < instanceCount; ++i) {
29 const glm::vec3 position = !positions.empty() ? positions[i] : glm::vec3(0.0f);
30 const glm::quat rotation = !rotations.empty() ? rotations[i] : glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
31 const glm::vec3 scale = !scales.empty() ? scales[i] : glm::vec3(1.0f);
32 matrices[i] = glm::translate(glm::mat4(1.0f), position) * glm::mat4_cast(rotation) * glm::scale(glm::mat4(1.0f), scale);
36 size_t scaleMatrices(std::span<glm::mat4> matricesOut,
37 std::span<glm::vec4> colorsOut,
38 std::span<const glm::mat4> matricesIn,
39 std::span<const glm::vec4> colorsIn,
40 const glm::mat4& localToWorld,
41 const glm::mat4& viewMatrix,
42 const glm::mat4& rawProjectionMatrix,
43 const float viewportHeight,
45 const float maxDistance)
47 assert(matricesOut.size() == matricesIn.size());
48 assert(colorsOut.size() == colorsIn.size());
50 const glm::mat4 M = viewMatrix * localToWorld;
51 const glm::vec4 M_row2 = glm::transpose(M)[2];
52 const glm::vec4 PM_row3 = glm::transpose(rawProjectionMatrix * M)[3];
53 const float pixelScale = 2.0f * dpiScale / (rawProjectionMatrix[1][1] * viewportHeight);
55 size_t activeCount = 0;
56 for (
size_t i = 0, N = matricesIn.size(); i < N; i++) {
57 glm::mat4 m = matricesIn[i];
58 const glm::vec4 pos = glm::vec4(glm::vec3(m[3]), 1.0f);
60 const float camZ = dot(M_row2, pos);
61 if (0 < maxDistance && camZ < -maxDistance)
continue;
63 const float clipW = glm::dot(PM_row3, pos);
64 const float scale = pixelScale * clipW;
65 if (scale <= 0.f)
continue;
67 matricesOut[activeCount] = glm::mat4(scale*m[0], scale*m[1], scale*m[2], m[3]);
68 if (!colorsIn.empty()) {
69 colorsOut[activeCount] = colorsIn[i];
87 bool forceUpdate =
false;
89 if (comp.hasChanged()) {
90 size_t positionCount = comp.positions.size();
91 size_t rotationCount = comp.rotations.size();
92 size_t scaleCount = comp.scales.size();
93 size_t colorCount = comp.colors.size();
95 data.instanceCount = 0;
96 for (
size_t count : { positionCount, rotationCount, scaleCount, colorCount }) {
98 data.instanceCount = data.instanceCount ? std::min(data.instanceCount, count) : count;
102 if (data.instanceCount == 0) {
104 data.useMatrix =
false;
105 data.usePositions =
false;
106 data.useColors =
false;
107 data.dynamicScaling =
false;
108 data.matrices.resize(0,
false);
111 if (!data.instanceMesh) {
112 data.instanceMesh =
context->meshManager->create();
114 data.instanceMesh->clear();
116 data.useColors = colorCount;
117 data.dynamicScaling = comp.fixedSize;
118 if (data.dynamicScaling) {
119 data.useMatrix =
true;
120 data.usePositions =
false;
121 data.matrices.resize(
sizeof(glm::mat4)*data.instanceCount,
false);
122 buildMatrices(std::span(
static_cast<glm::mat4*
>(data.matrices.data()), data.instanceCount),
123 std::span(comp.positions.data(), comp.positions.size()),
124 std::span(comp.rotations.data(), comp.rotations.size()),
125 std::span(comp.scales.data(), comp.scales.size()),
130 data.useMatrix = rotationCount > 0 || scaleCount > 0;
131 data.usePositions = !data.useMatrix && positionCount;
132 if (data.useMatrix) {
133 MappedStream<glm::mat4> matrices = data.instanceMesh->map<glm::mat4>(VertexDataType::Positions, VertexFormats::InstanceMat4f, 0, data.instanceCount,
true);
134 buildMatrices(std::span(matrices.
data, data.instanceCount),
135 std::span(comp.positions.data(), comp.positions.size()),
136 std::span(comp.rotations.data(), comp.rotations.size()),
137 std::span(comp.scales.data(), comp.scales.size()),
140 if (data.usePositions) {
141 data.instanceMesh->setInstancePositions(std::span<const glm::vec3>(comp.positions.data(), data.instanceCount));
143 if (data.useColors) {
144 data.instanceMesh->setInstanceColors(std::span<const glm::vec4>(comp.colors.data(), data.instanceCount));
146 data.instanceMesh->setInstanceCount(data.instanceCount);
151 if (data.dynamicScaling) {
152 assert(data.matrices.size() ==
sizeof(glm::mat4)*data.instanceCount);
155 const glm::mat4& localToWorld =
context->transformSystem->getLocalToWorld(trComp);
157 mainCamData.viewMatrix,
159 mainCamData.viewportSize.y,
162 if (forceUpdate || data.viewStateHash != viewStateHash) {
163 data.viewStateHash = viewStateHash;
165 size_t currentInstanceCount = 0;
166 MappedStream<glm::mat4> outMatrices = data.instanceMesh->map<glm::mat4>(VertexDataType::Positions, VertexFormats::InstanceMat4f, 0, data.instanceCount,
true);
167 if (data.useColors) {
168 MappedStream<glm::vec4> outColors = data.instanceMesh->map<glm::vec4>(VertexDataType::Colors0, VertexFormats::InstanceColor4f, 0, data.instanceCount,
true);
169 currentInstanceCount = scaleMatrices(std::span<glm::mat4>(outMatrices.
data, data.instanceCount),
170 std::span<glm::vec4>(outColors.
data, data.instanceCount),
171 std::span<const glm::mat4>(
static_cast<const glm::mat4*
>(data.matrices.data()), data.instanceCount),
172 std::span<const glm::vec4>(comp.colors.data(), data.instanceCount),
174 mainCamData.viewMatrix,
176 mainCamData.viewportSize.y,
178 comp.fixedSizeMaxDistance);
181 currentInstanceCount = scaleMatrices(std::span<glm::mat4>(outMatrices.
data, data.instanceCount),
182 std::span<glm::vec4>(),
183 std::span<const glm::mat4>(
static_cast<const glm::mat4*
>(data.matrices.data()), data.instanceCount),
184 std::span<const glm::vec4>(),
186 mainCamData.viewMatrix,
188 mainCamData.viewportSize.y,
190 comp.fixedSizeMaxDistance);
192 data.instanceMesh->setCount(currentInstanceCount);
193 data.instanceMesh->setInstanceCount(currentInstanceCount);
205 renderComp->
material->setVariant(
"InstancedMatrix", data.useMatrix);
206 renderComp->
material->setVariant(
"InstancedPositions", data.usePositions);
207 renderComp->
material->setVariant(
"InstancedColors", data.useColors);
void setChanged()
Sets the component to the ComponentFlags::Changed state with carry.
ComponentType * getComponent() const
Context * context
Pointer to the Context instance the system lives in.
void update()
Updates the system state to that of the current frame.
ComponentPool< ComponentType > pool
Pool of components managed by the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Renders a mesh using instancing.
MaterialInstanceHandle material
Material instance used to render the mesh.
std::unique_ptr< class DPIService > dpiService
DPI service instance.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr size_t hashSequence(const T &t, const U &u)
Hash the last two items in a sequence of objects.
Contains data describing a Camera instance and its derived data structured such as matrix data and vi...
glm::mat4 rawProjectionMatrix
Projection matrix that has not been adjusted by the renderer, and is thus appropriate for direct scre...
Wrapper for mapped stream data automatically updating the Mesh resource mapped from when destructed.
Element * data
Pointer to the element data mapped from the Mesh data stream.
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.