Cogs.Core
PotreeRenderer.cpp
1#include "ExtensionRegistry.h"
2#include "Renderer/Renderer.h"
3#include "Renderer/RenderList.h"
4#include "Renderer/RenderStateUpdater.h"
5#include "Renderer/RenderTarget.h"
6#include "Renderer/Tasks/RenderListTask.h"
7#include "Renderer/Tasks/FilterListTask.h"
8#include "Renderer/Tasks/GenerateListTask.h"
9#include "Renderer/CustomRenderer/DebugGeometryRenderers.h"
10
11#include "PotreeRenderer.h"
12#include "PotreeSystem.h"
13
14#include "Rendering/IGraphicsDevice.h"
15
16#include "Foundation/Logging/Logger.h"
17
18#include <glm/glm.hpp>
19
20#include <array>
21
22using namespace Cogs;
23using namespace Cogs::Core;
24
25namespace {
27
28 bool setRenderItemState(float& scale, RenderTaskContext* taskContext, DrawContext* drawContext, const RenderItem* renderItem)
29 {
30 const auto* camData = drawContext->cameraData;
31 if (camData == nullptr) return false;
32
33 scale = 1.f;
34 float w = camData->viewportSize.x;
35 float h = camData->viewportSize.y;
36 if (drawContext->task->viewportFromTarget && drawContext->renderTarget) {
37 w = float(drawContext->renderTarget->width);
38 h = float(drawContext->renderTarget->height);
39 scale = 0.5f*(w / std::max(1.f, camData->viewportSize.x) + h / std::max(1.f, camData->viewportSize.y));
40 }
41
42 Renderer* renderer = taskContext->renderer;
43
44 auto* device = renderer->getDevice();
45 auto* iContext = device->getImmediateContext();
46
47 iContext->setViewport(camData->viewportOrigin.x, camData->viewportOrigin.y, w, h);
48 iContext->setDepthStencilState(taskContext->states->commonDepthStates[renderItem->depthState]);
49 iContext->setBlendState(taskContext->states->blendStates[renderItem->blendState].handle);
50
51 const RenderPassOptions passOptions = initRenderPassOptions(*camData, renderItem->materialInstance);
52 iContext->setRasterizerState(taskContext->states->rasterizerStateHandles[getRasterizerState(renderer, *renderItem, passOptions, camData->flipWindingOrder, true)]);
53
54 const ClipShapeCache::Item& clipShape = drawContext->clipShapeCache->data[renderItem->clipShapeIx];
55 updateViewportBuffer(taskContext, taskContext->engineBuffers->sceneBufferHandle, taskContext->engineBuffers->viewBufferHandle, drawContext->renderTarget, renderItem->viewportData ? renderItem->viewportData : drawContext->cameraData, &clipShape.clipEquations);
56
57 // Invokes updateSceneBindings
58 // Invokes updateMaterialBindings(instance=false)
59 applyMaterialPermutation(taskContext, drawContext, renderItem->binding, renderItem->renderMaterialInstance);
60
61 // INvokes updateEnvironmentBindings,
62 // Updates permutation->constant buffers
63 drawContext->task->applyMaterial(*drawContext, *renderItem);
64
65 // Invokes updateMaterialBindings -> applyMaterialProperties
66 applyMaterialInstance(drawContext, renderItem->binding, renderItem->renderMaterialInstance);
67
68 updateSceneBindings(drawContext, drawContext->cameraData, renderItem->binding);
69
70 updateMaterialBindings(drawContext, renderItem->renderMaterialInstance, renderItem->binding, true);
71
72 // applyMaterialPerObject, but worldMatrix is stuffed with callback pointer
73 const auto bindings = renderItem->binding;
74 auto& engineBuffers = *drawContext->engineBuffers;
75 auto* potreeData = static_cast<PotreeData*>(renderItem->callbackData);
76 // assert(HandleIsValid(bindings->objectBufferBinding));
77 if(!HandleIsValid(bindings->objectBufferBinding)) return false;
78 {
79 Cogs::MappedBuffer<ObjectBuffer> objectBuffer(iContext, engineBuffers.objectBufferHandle, Cogs::MapMode::WriteDiscard);
80 if (objectBuffer) {
81 objectBuffer->worldMatrix = potreeData->worldFromOcttreeFrame;
82 objectBuffer->objectId = renderItem->objectId;
83 }
84 }
85 iContext->setConstantBuffer(bindings->objectBufferBinding, engineBuffers.objectBufferHandle);
86
87 return true;
88 }
89
90
91 void potreeCallback(RenderTaskContext* taskContext, DrawContext* drawContext, const RenderItem* renderItem)
92 {
93 auto* potreeData = static_cast<PotreeData*>(renderItem->callbackData);
94 if (potreeData->state != PotreeState::Running) return;
95
96 float scale = 1.f;
97 if (!setRenderItemState(scale, taskContext, drawContext, renderItem)) return;
98
99 // We use camera viewport to control rendering for consistent look during dynamic render resolution,
100 // we pass the scaling factor so that pointsize sent to the rendering API can be adjusted.
101 const float w = drawContext->cameraData->viewportSize.x;
102 const float h = drawContext->cameraData->viewportSize.y;
103
104 Cogs::Core::Renderer* renderer = taskContext->renderer;
105 Cogs::IGraphicsDevice* device = renderer->getDevice();
106 Cogs::IContext* iContext = device->getImmediateContext();
107
108 if (!HandleIsValid(potreeData->octtreeTexture)) {
109 return;
110 }
111
112 iContext->setTexture("octtree", 0, potreeData->octtreeTexture);
113 iContext->setSamplerState("octtreeSampler", 0, renderer->getRenderStates().commonSamplerStates[3]);
114
115 float viewScale = std::cbrt(glm::determinant(glm::mat3(potreeData->worldFromOcttreeFrame) * glm::mat3(drawContext->cameraData->viewMatrix)));
116
118 passControl.push_back(glm::vec4(viewScale * potreeData->modelSpaceRadius,
119 w * viewScale * potreeData->modelSpaceRadius,
120 2.f / (w * scale), 2.f / (h * scale)));
121 for (size_t i = 0; i < potreeData->clipPlaneCount; i++) {
122 passControl.push_back(potreeData->clipPlanes[i] * drawContext->cameraData->inverseViewProjectionMatrix);
123 }
124 glm::vec4 pointControl[2] = {
125 glm::vec4(potreeData->densitySized.levelScale,
126 potreeData->densitySized.scale,
127 potreeData->densitySized.bias,
128 0.5f),
129 glm::vec4(scale, 0.f, 0.f, 0.f)
130 };
131 // assert(HandleIsValid(potreeData->pointParametersBuffer));
132 if(!HandleIsValid(potreeData->pointParametersBuffer)) return;
133 {
134 Cogs::MappedBuffer<PointParameters> buffer(iContext, potreeData->pointParametersBuffer, Cogs::MapMode::WriteDiscard);
135 if(buffer){ // TODO can this buffer be prefilled outside the render loop?
136 buffer->passControl[0] = passControl[0];
137 for (size_t i = 1; i <= potreeData->clipPlaneCount; i++) {
138 buffer->passControl[i] = passControl[i];
139 }
140 buffer->pointControl[0] = pointControl[0];
141 buffer->pointControl[1] = pointControl[1];
142 }
143 }
144 iContext->setConstantBuffer("PointParameters", potreeData->pointParametersBuffer);
145
146 for (auto* cell : potreeData->activeCells) {
147 if (cell->pointCount && HandleIsValid(cell->pointData)) {
148 iContext->setVertexBuffers(&cell->pointData, 1);
149 iContext->draw(Cogs::PrimitiveType::PointList, 0, cell->pointCount);
150 }
151 }
152 }
153
154 void potreeBoxCallback(RenderTaskContext* taskContext, DrawContext* drawContext, const RenderItem* renderItem)
155 {
156 auto* potreeData = static_cast<PotreeData*>(renderItem->callbackData);
157 if (potreeData->state != PotreeState::Running) return;
158
159 float scale = 1.f;
160 if (!setRenderItemState(scale, taskContext, drawContext, renderItem)) return;
161
162 auto* renderer = taskContext->renderer;
163 auto* device = renderer->getDevice();
164 auto* iContext = device->getImmediateContext();
165
166 auto* potreeRenderer = static_cast<PotreeRenderer*>(renderItem->callbackData2);
167
168 iContext->setVertexBuffers(&potreeRenderer->boxVertices, 1);
169 iContext->setIndexBuffer(potreeRenderer->boxEdgeIndices, 2, 0);
170
171 for (auto* cell : potreeData->activeCells) {
172 if (cell->kind != PotreeCell::Kind::RegularNode) continue;
173 if (potreeData->debugBoxes == PotreeDebugBoxes::ActiveLeafCells && (cell->texOffset == 0xffffu || potreeData->octtreeTextureData[cell->texOffset].r != 0)) continue;
174
175 auto color = cell->owningSubtree->l + cell->l;// cell->owningSubtree->subtreeId * 4091;
176
177 glm::vec4 boxControl[3] = {
178 glm::vec4(cell->tbmin, 1.f),
179 glm::vec4(cell->tbmax - cell->tbmin, 1.f),
180 //glm::vec4(((color >> 0) & 0x3) / 15.f, ((color >> 2) & 0x3) / 15.f,((color >> 2) & 0x3) / 3.f,1.f)
181 glm::vec4(((color >> 0) & 0x1), ((color >> 1) & 0x1), ((color >> 2) & 0x1), 1.f)
182 };
183 if(!HandleIsValid(cell->boxParametersBuffer)){
184 auto* buffers = device->getBuffers();
185 cell->boxParametersBuffer = buffers->loadBuffer(nullptr, sizeof(BoxParameters), Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
186 }
187 //assert(HandleIsValid(cell->boxParametersBuffer));
188 if(!HandleIsValid(cell->boxParametersBuffer)) continue;
189 {
190 Cogs::MappedBuffer<BoxParameters> buffer(iContext, cell->boxParametersBuffer, Cogs::MapMode::WriteDiscard);
191 if(buffer){ // TODO can this buffer be prefilled outside the render loop?
192 buffer->boxControl[0] = boxControl[0];
193 buffer->boxControl[1] = boxControl[1];
194 buffer->boxControl[2] = boxControl[2];
195 }
196 }
197 iContext->setConstantBuffer("BoxParameters", cell->boxParametersBuffer);
198
199 iContext->drawIndexed(Cogs::PrimitiveType::LineList, 0, potreeRenderer->boxEdgeIndexPrimitives);
200 }
201
202 const glm::mat4 M = drawContext->cameraData->viewProjection * potreeData->frustum;
203 drawOneOneWireBox(taskContext, drawContext, nullptr, M, 0);
204 }
205}
206
208{
209 this->device = device;
210 this->context = context;
211 potreeSystem = ExtensionRegistry::getExtensionSystem<PotreeSystem>(context);
212
213
214 std::array<Cogs::VertexElement,1> elements = {
215 Cogs::VertexElement{0, Cogs::DataFormat::R32G32B32_FLOAT, Cogs::ElementSemantic::Position, 0, Cogs::InputType::VertexData, 0}
216 };
217
218 boxStreamsLayout.vertexFormats[0] = VertexFormats::createVertexFormat(elements.data(), elements.size());
219 boxStreamsLayout.numStreams = 1;
220 boxStreamsLayout.updateHash();
221
222 auto* buffers = device->getBuffers();
223
224 // Create wireframe unit box geometry
225 static const float boxVertexData[] = {
226 0.f, 0.f, 0.f,
227 1.f, 0.f, 0.f,
228 1.f, 1.f, 0.f,
229 0.f, 1.f, 0.f,
230 0.f, 0.f, 1.f,
231 1.f, 0.f, 1.f,
232 1.f, 1.f, 1.f,
233 0.f, 1.f, 1.f,
234 };
235 boxVertices = buffers->loadVertexBuffer(boxVertexData, sizeof(boxVertexData) / sizeof(boxVertexData[0]), boxStreamsLayout.vertexFormats[0]);
236
237 static const uint16_t boxEdgeIndexData[] = {
238 0, 1, 1, 2, 2, 3, 3, 0,
239 4, 5, 5, 6, 6, 7, 7, 4,
240 0, 4, 1, 5, 2, 6, 3, 7
241 };
242 boxEdgeIndexPrimitives = static_cast<unsigned>(sizeof(boxEdgeIndexData) / sizeof(boxEdgeIndexData[0]));
243 boxEdgeIndices = buffers->loadIndexBuffer(boxEdgeIndexData, boxEdgeIndexPrimitives, sizeof(boxEdgeIndexData[0]));
244
245}
246
247void Cogs::Core::PotreeRenderer::handleEvent(uint32_t eventId, const DrawContext * renderingContext)
248{
249 if (!renderingContext) return;
250
251 switch (eventId) {
253 IBuffers* buffers = renderingContext->device->getBuffers();
254 ITextures* textures = renderingContext->device->getTextures();
255 for (auto& poComp : potreeSystem->pool) {
256 PotreeDataHolder& poDataHolder = potreeSystem->getData(&poComp);
257 PotreeData* poData = poDataHolder.poData.get();
258 assert(poData);
259
260 if(!HandleIsValid(poData->pointParametersBuffer)){
261 poData->pointParametersBuffer = buffers->loadBuffer(nullptr, sizeof(PointParameters), Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
262 }
263
264 if (HandleIsValid(poData->octtreeTexture)) {
265 textures->releaseTexture(poData->octtreeTexture);
266 poData->octtreeTexture = Cogs::TextureHandle::NoHandle;
267 }
268
269 if (poData->octtreeTextureData.size()) {
270 TextureDescription desc{};
271 desc.target = Cogs::ResourceDimensions::Texture2D;
272 desc.width = static_cast<uint32_t>(poData->octtreeTextureData.size());
273 desc.height = 1;
274 desc.format = Cogs::TextureFormat::R8G8B8A8_UNORM;
275 desc.flags = Cogs::TextureFlags::Default;
276
277 TextureData data(poData->octtreeTextureData.data(), TextureExtent{ desc.width, 1, 1 }, 1, 1, 1, desc.format);
278 poData->octtreeTexture = textures->loadTexture(desc, &data);
279 }
280 }
281 break;
282 }
284 break;
285
286 default:
287 break;
288 }
289}
290
291void Cogs::Core::PotreeRenderer::generateCommands(const RenderTaskContext * renderingContext, RenderList * renderList)
292{
293 if (!renderingContext) return;
294
295 for (auto & poComp : potreeSystem->pool) {
296 if (!poComp.isVisible()) continue;
297
298 PotreeDataHolder& poDataHolder = potreeSystem->getData(&poComp);
299 PotreeData* poData = poDataHolder.poData.get();
300 assert(poData);
301
302 if (poData->state != PotreeState::Running) continue;
303
304 // Just skip instance if we haven't gotten metadata yet
305 if (poData->streamsLayout.numStreams == 0) continue;
306
307 MaterialInstance* pointMaterialInstance = poData->pointMaterial.instance.resolve();
308 if (pointMaterialInstance) {
309
310 assert(!HandleIsValid(poComp.pointMaterial) || poComp.pointMaterial == poData->pointMaterial.instance);
311
312 RenderItem& renderItem = renderList->createCustom(&poData->streamsLayout);
313
314 if (!poComp.clipShapeComponent.Empty()) {
315 renderItem.clipShapeIx = renderList->clipShapeCache->getIndex(context, poComp.clipShapeComponent);
316 }
317
318 renderItem.lod = poComp.lod;
319 renderItem.layer = poComp.layer;
320 renderItem.cullingIndex = ~0u;;
321 renderItem.objectId = poComp.objectId;
322 renderItem.flags |= (pointMaterialInstance->instanceFlags & MaterialFlags::CustomBucket) != 0 ? RenderItemFlags::CustomBucket : RenderItemFlags::None;
323 renderItem.flags |= pointMaterialInstance->hasTransparency() ? RenderItemFlags::Transparent : RenderItemFlags::None;
324 renderItem.flags |= pointMaterialInstance->isBackdrop() ? RenderItemFlags::Backdrop : RenderItemFlags::None;
325 renderItem.flags |= poComp.castShadows() ? RenderItemFlags::CastShadows : RenderItemFlags::None;
326 renderItem.materialInstance = pointMaterialInstance;
327 getTransparencyState(renderingContext->renderer->getRenderStates(), pointMaterialInstance, renderItem);
328 renderItem.drawOrder = pointMaterialInstance->options.drawOrder != 0 ? pointMaterialInstance->options.drawOrder : poComp.drawOrder;
329 renderItem.setCallbackData(poData);
330 renderItem.callback = potreeCallback;
331 }
332
333 if (poComp.debugBoxes != PotreeDebugBoxes::None) {
334 MaterialInstance* boxMaterialInstance = poData->boxMaterial.instance.resolve();
335 if (boxMaterialInstance) {
336
337 assert(!HandleIsValid(poComp.boxMaterial) || poComp.boxMaterial == poData->boxMaterial.instance);
338
339 RenderItem& renderItem = renderList->createCustom(&boxStreamsLayout);
340 renderItem.lod = poComp.lod;
341 renderItem.layer = poComp.layer;
342 renderItem.cullingIndex = ~0u;;
343 renderItem.objectId = poComp.objectId;
344 renderItem.flags |= (boxMaterialInstance->instanceFlags & MaterialFlags::CustomBucket) != 0 ? RenderItemFlags::CustomBucket : RenderItemFlags::None;
345 renderItem.flags |= boxMaterialInstance->hasTransparency() ? RenderItemFlags::Transparent : RenderItemFlags::None;
346 renderItem.flags |= boxMaterialInstance->isBackdrop() ? RenderItemFlags::Backdrop : RenderItemFlags::None;
347 renderItem.flags |= poComp.castShadows() ? RenderItemFlags::CastShadows : RenderItemFlags::None;
348 renderItem.materialInstance = boxMaterialInstance;
349 getTransparencyState(renderingContext->renderer->getRenderStates(), boxMaterialInstance, renderItem);
350 renderItem.drawOrder = boxMaterialInstance->options.drawOrder != 0 ? boxMaterialInstance->options.drawOrder : poComp.drawOrder;
351 renderItem.setCallbackData(poData);
352 renderItem.setCallbackData2(this);
353 renderItem.callback = potreeBoxCallback;
354 }
355 }
356
357 }
358}
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
Core renderer system.
Definition: Renderer.h:28
RenderStates & getRenderStates() override
Get the reference to the RenderStates structure.
Definition: Renderer.h:68
IGraphicsDevice * getDevice() override
Get the graphics device used by the renderer.
Definition: Renderer.h:45
Represents a graphics device used to manage graphics resources and issue drawing commands.
virtual ITextures * getTextures()=0
Get a pointer to the texture management interface.
virtual IContext * getImmediateContext()=0
Get a pointer to the immediate context used to issue commands to the graphics device.
virtual IBuffers * getBuffers()=0
Get a pointer to the buffer management interface.
Log implementation class.
Definition: LogManager.h:140
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
@ None
No debug node outlines.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
@ VertexData
Per vertex data.
@ PointList
List of points.
@ LineList
List of lines.
@ Position
Position semantic.
@ Write
The buffer can be mapped and written to by the CPU after creation.
Definition: Flags.h:50
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
Definition: Flags.h:72
@ CustomBucket
Items with this flag should be put in Custom rendering buckets.
Definition: Material.h:64
Material instances represent a specialized Material combined with state for all its buffers and prope...
bool hasTransparency() const
Get if this instance has any transparency and should be rendered with blending enabled.
bool isBackdrop() const
Get if geometry rendered with this material instance is to be treated as backdrops.
MaterialOptions options
Material rendering options used by this instance.
uint16_t instanceFlags
Material instance flags.
VertexFormatHandle vertexFormats[maxStreams]
COGSCORE_DLL_API void updateHash()
void initialize(Context *context, IGraphicsDevice *device) override
Initialize the extension using the given context and device.
void handleEvent(uint32_t eventId, const DrawContext *renderingContext) override
Called when rendering events occur.
int32_t drawOrder
Ordering of draw items within a bucket.
Definition: RenderList.h:172
uint32_t objectId
Lower 6 of upper 8 bits are instance id bits, lower 24 bits are object id.
Definition: RenderList.h:174
RenderLayers layer
Visibility mask.
Definition: RenderList.h:170
@ PostRender
Rendering has finished for a given rendering context.
Definition: IRenderer.h:101
@ PreRender
Pre rendering happening for a given rendering context.
Definition: IRenderer.h:93
ResourceType * resolve() const
Resolve the handle, returning a pointer to the actual resource.
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78
Provides buffer management functionality.
Definition: IBuffers.h:13
virtual BufferHandle loadBuffer(const void *data, const size_t size, Usage::EUsage usage, uint32_t accessMode, uint32_t bindFlags, uint32_t stride=0)=0
Loads a new buffer using the given data to populate the buffer.
Represents a graphics device context which can receive rendering commands.
Definition: IContext.h:43
virtual void setTexture(const StringView &name, unsigned int unit, TextureHandle textureHandle)=0
Sets the texture slot given by unit with the given name to contain the given texture.
virtual void drawIndexed(PrimitiveType primitiveType, const size_t startIndex, const size_t numIndexes, const size_t startVertex=0)=0
Draws indexed, non-instanced primitives.
virtual void setIndexBuffer(IndexBufferHandle bufferHandle, uint32_t stride=4, uint32_t offset=0)=0
Sets the current index buffer.
virtual void setConstantBuffer(const StringView &name, const BufferHandle bufferHandle, const uint32_t offset=0, const uint32_t size=~0u)=0
Sets a constant buffer to be bound to the given name and slot.
virtual void setViewport(const float x, const float y, const float width, const float height)=0
Sets the current viewport to the given location and dimensions.
virtual void draw(PrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes)=0
Draws non-indexed, non-instanced primitives.
virtual void setSamplerState(const StringView &name, unsigned int unit, SamplerStateHandle samplerStateHandle)=0
Sets the sampler slot given by unit with the given name to contain the given sampler state.
virtual void setVertexBuffers(const VertexBufferHandle *vertexBufferHandles, const size_t count, const uint32_t *strides, const uint32_t *offsets)=0
Sets the current vertex buffers.
Provides texture management functionality.
Definition: ITextures.h:40
virtual void releaseTexture(TextureHandle textureHandle)=0
Release the texture with the given textureHandle.
virtual TextureHandle loadTexture(const unsigned char *bytes, unsigned int width, unsigned int height, TextureFormat format, unsigned int flags=0)=0
Load a texture using the given data to populate the texture contents.
@ WriteDiscard
Write access. When unmapping the graphics system will discard the old contents of the resource.
Definition: Flags.h:103
Provides RAII style mapping of a buffer resource.
Definition: IBuffers.h:160
@ Default
Default usage, the texture can be loaded once and bound and sampled in shaders.
Definition: Flags.h:116
@ Dynamic
Buffer will be loaded and modified with some frequency.
Definition: Flags.h:30
Vertex element structure used to describe a single data element in a vertex for the input assembler.
Definition: VertexFormat.h:38