Cogs.Core
TerrainRenderer.cpp
1#include "TerrainRenderer.h"
2
3#include "RenderContext.h"
4#include "Terrain.h"
5
6#include "Systems/Core/TransformSystem.h"
7#include "Systems/Core/CameraSystem.h"
8
9#include "Components/Core/RenderComponent.h"
10
11#include "Resources/MaterialManager.h"
12
13#include "Renderer/RenderStateUpdater.h"
14#include "Renderer/RenderMaterialInstance.h"
15#include "Renderer/RenderEffect.h"
16#include "Renderer/RenderTarget.h"
17#include "Renderer/Tasks/RenderListTask.h"
18#include "Renderer/Tasks/GenerateListTask.h"
19
20#include "Context.h"
21
22#include "TerrainSystem.h"
23#include "OceanSystem.h"
24
25#include "Renderer/IRenderer.h"
26
27Cogs::Core::TerrainRenderer::~TerrainRenderer()
28{
29}
31{
32 this->device = device;
33 this->context = context;
34
35 terrainSystem = ExtensionRegistry::getExtensionSystem<TerrainSystem>(context);
36}
37
38void Cogs::Core::TerrainRenderer::handleEvent(uint32_t eventId, const DrawContext * renderingContext)
39{
40 if (!renderingContext) return;
41
42 switch (eventId) {
44 for (auto & terrain : terrainSystem->pool) {
45 preRender(terrain, renderingContext);
46 }
47 break;
49 for (auto & terrain : terrainSystem->pool) {
50 postRender(terrain, renderingContext);
51 }
52 break;
53 default:
54 break;
55 }
56}
57
58namespace Cogs
59{
60 namespace Core
61 {
62 void updateTerrainContext(TerrainData & terrainData, const RenderTaskContext * renderingContext, const RenderTarget * renderTarget, const CameraData & cameraData)
63 {
64 auto & renderContext = terrainData.renderContext;
65
66 renderContext.renderTarget = renderTarget->renderTargetHandle;
67 renderContext.depthStencilTarget = renderTarget->depthTargetHandle;
68
69 renderContext.isOIT = renderingContext->renderer->getSettings().transparencyAlgorithm == RenderSettings::TransparencyAlgorithm::OIT;
70
71 renderContext.offsetEnabled = false;
72 renderContext.device = renderingContext->renderer->getDevice();
73 renderContext.context = renderingContext->renderer->getDevice()->getImmediateContext();
74 if (terrainData.viewportFromTarget) {
75 renderContext.width = static_cast<uint16_t>(renderTarget->width);
76 renderContext.height = static_cast<uint16_t>(renderTarget->height);
77 renderContext.viewportX = 0;
78 renderContext.viewportY = 0;
79 }
80 else {
81 renderContext.width = static_cast<uint16_t>(cameraData.viewportSize.x);
82 renderContext.height = static_cast<uint16_t>(cameraData.viewportSize.y);
83 renderContext.viewportX = static_cast<uint16_t>(cameraData.viewportOrigin.x);
84 renderContext.viewportY = static_cast<uint16_t>(cameraData.viewportOrigin.y);
85 }
86 renderContext.cullVolume.frustum = cameraData.frustum;
87
88 renderContext.origin = renderingContext->context->transformSystem->getOrigin();
89 renderContext.cullOrigin = renderContext.origin;
90 renderContext.offset = terrainData.offset;
91
92 renderContext.scene.projectionMatrix = cameraData.projectionMatrix;
93 renderContext.scene.viewMatrix = cameraData.viewMatrix;
94 renderContext.scene.viewMatrixInverse = cameraData.inverseViewMatrix;
95
96 renderContext.wireframe = renderingContext->renderer->getMode() == RenderMode::Wireframe;
97
98 renderContext.maxAppliedTilesPerFrame = terrainData.maxTilesPerFrame;
99 renderContext.offsetEnabled = false;
100
101 renderContext.reverseDepth = renderingContext->context->variables->get("renderer.reverseDepth", false);
102
103 renderContext.rayPickIndex = cameraData.rayPickId;
104 }
105 }
106}
107
108void Cogs::Core::TerrainRenderer::generateCommands(const RenderTaskContext * renderingContext, RenderList * renderList)
109{
110 for (auto & terrain : terrainSystem->pool) {
111 auto & terrainData = terrainSystem->getData(&terrain);
112
113 if (!terrainData.initialized) continue;
114
115 auto renderComponent = terrain.getComponent<RenderComponent>();
116
117 terrainData.visible = renderComponent->isVisible();
118
119 float dummy = 0.f;
120 terrainData.getBounds->getBounds(context, terrainData.bbox, dummy);
121
122 auto & terrainItem = renderList->createCustom(&terrainData.terrainStreamsLayout);
123 terrainItem.materialInstance = terrain.material.resolve();
124
125 if (terrainItem.materialInstance) {
126 terrainItem.drawOrder = terrainItem.materialInstance->options.drawOrder;
127 }
128 getTransparencyState(*renderingContext->states, terrainItem.materialInstance, terrainItem);
129 if (terrainItem.blendState != static_cast<uint16_t>(BlendMode::None)) {
130 terrainItem.flags |= RenderItemFlags::Transparent;
131 }
132 terrainItem.layer = renderComponent->layer;
133 terrainItem.flags |= RenderItemFlags::Custom;
134 terrainItem.flags |= renderComponent->castShadows() ? RenderItemFlags::CastShadows : RenderItemFlags::None;
135 terrainItem.objectId = renderComponent->objectId;
136 terrainItem.setBounds(&terrainData.bbox);
137
138 terrainItem.setCallbackData(&terrainData);
139 terrainItem.callback = [](RenderTaskContext * renderingContext, DrawContext * drawContext, const RenderItem * terrainItem)
140 {
141 TerrainData & terrainData = *terrainItem->getCallbackData<TerrainData>();
142
143 RenderMaterialInstance * renderMaterial = renderingContext->renderer->getRenderResources().getRenderMaterialInstance(terrainItem->materialInstance);
144 RenderMaterialInstance * depthRenderMaterial = renderingContext->renderer->getRenderResources().getRenderMaterialInstance(terrainData.depthMaterial);
145
146 if (!renderMaterial || !depthRenderMaterial) return;
147
148 auto bindings = drawContext->binding;
149 auto forwardPermutation = renderingContext->renderer->getEnginePermutations().get("Forward");
150
151 RenderPassOptions passOptions = drawContext->cameraData->passOptions ? *drawContext->cameraData->passOptions : RenderPassOptions{};
152 passOptions.updateHash();
153
154 const EffectBinding* depthBindings = depthRenderMaterial->checkReady(terrainData.terrainStreamsLayout, forwardPermutation, passOptions, ClipShapeType(0), drawContext->renderTarget);
155 if (!depthBindings) {
156 return;
157 }
158
159 if (!bindings->renderEffect->isActive() || !depthBindings->renderEffect->isActive()) return;
160 if (!HandleIsValid(bindings->sceneBufferBinding) || !HandleIsValid(depthBindings->sceneBufferBinding)) return;
161
162 updateTerrainContext(terrainData, renderingContext, drawContext->renderTarget, *drawContext->cameraData);
163
164 const size_t permutation = drawContext->permutationIndex;
165 terrainData.renderContext.permutation = permutation;
166 auto & permutationRenderContextData = terrainData.renderContext.getPermutationDependentRenderContextData(permutation);
167 permutationRenderContextData.clipmapEffect = bindings->renderEffect->effectHandle;
168 permutationRenderContextData.clipmapDepthEffect = depthBindings->renderEffect->effectHandle;
169
170 auto pass = drawContext->cameraData->renderPass;
171 switch (pass) {
172 case RenderPass::Refraction:
173 terrainData.renderContext.renderPass = TerrainRenderPass::Refraction;
174 break;
175 case RenderPass::Reflection:
176 terrainData.renderContext.renderPass = TerrainRenderPass::Reflection;
177 break;
178 case RenderPass::Other:
179 terrainData.renderContext.renderPass = TerrainRenderPass::Other;
180 break;
181 default:
182 terrainData.renderContext.renderPass = TerrainRenderPass::Main;
183 break;
184 }
185
186 terrainData.renderContext.callback = [&](Cogs::EffectHandle effect) {
187 const bool isRegularPass = effect == bindings->renderEffect->effectHandle;
188
189 if (isRegularPass) {
190 drawContext->deviceContext->setBlendState(drawContext->renderer->getRenderStates().blendStates[terrainItem->blendState].handle);
191
192 updateSceneBindings(drawContext, drawContext->cameraData, bindings);
193 drawContext->task->applyMaterial(*drawContext, *terrainItem, bindings);
194 updateMaterialBindings(drawContext, renderMaterial, bindings, true);
195 applyMaterialPerObject(drawContext, renderMaterial, *terrainItem, bindings);
196 } else {
197 drawContext->deviceContext->setBlendState(drawContext->renderer->getRenderStates().blendStates[size_t(BlendMode::None)].handle);
198
199 updateSceneBindings(drawContext, drawContext->cameraData, depthBindings);
200 applyMaterialPerObject(drawContext, depthRenderMaterial, *terrainItem, depthBindings);
201 }
202 };
203
204 if (terrainData.visible) {
205 if (terrainData.renderContext.renderPass == TerrainRenderPass::Main) {
206 auto & camSystem = renderingContext->context->cameraSystem;
207 auto mainCam = camSystem->getMainCamera();
208
209 auto oldData = drawContext->cameraData;
210 for (auto & cameraComponent : camSystem->pool) {
211 if (mainCam == &cameraComponent) continue;
212 if ((cameraComponent.flags & CameraFlags::EnablePicking) == 0) continue;
213
214 auto & cameraData = renderingContext->context->cameraSystem->getData(&cameraComponent);
215 drawContext->cameraData = &cameraData;
216
217 updateEngineBuffers(renderingContext, drawContext->renderTarget, &cameraData, nullptr);
218 updateTerrainContext(terrainData, renderingContext, drawContext->renderTarget, cameraData);
219 terrainDepthRender(terrainData.context, &terrainData.renderContext);
220 }
221
222 drawContext->cameraData = oldData;
223 updateEngineBuffers(renderingContext, drawContext->renderTarget, drawContext->cameraData, nullptr);
224 updateTerrainContext(terrainData, renderingContext, drawContext->renderTarget, *drawContext->cameraData);
225 }
226
227 terrainDepthRender(terrainData.context, &terrainData.renderContext);
228 terrainRender(terrainData.context, &terrainData.renderContext);
229 }
230 else {
231 if (terrainData.oceanData) {
232 // If ocean is visible we still need pre-render.
233 auto oceanRenderComponent = terrainData.oceanData->oceanComponent->getComponent<RenderComponent>();
234
235 if (oceanRenderComponent && oceanRenderComponent->isVisible()) {
236 terrainDepthRender(terrainData.context, &terrainData.renderContext);
237 }
238 }
239 }
240 };
241
242 if (terrainData.renderContext.oceanEnabled) {
243 auto & oceanData = *terrainData.oceanData;
244
245 if (!oceanData.initialized) break;
246
247 auto renderComponent_ = oceanData.oceanComponent->getComponent<RenderComponent>();
248
249 if (!renderComponent_->isVisible()) continue;
250
251 auto & oceanItem = renderList->createCustom(&oceanData.streamsLayout);
252 oceanItem.layer = RenderLayers::Ocean;
253
254 oceanItem.flags |= RenderItemFlags::Transparent;
255 oceanItem.blendState = (uint16_t)BlendMode::Blend;
256 if ((terrainItem.flags & RenderItemFlags::Transparent) != 0) {
257 oceanItem.drawOrder = terrainItem.drawOrder + 1;
258 }
259 else {
260 oceanItem.drawOrder = 0;
261 }
262 oceanItem.materialInstance = oceanData.material.resolve();
263 oceanItem.objectId = renderComponent_->objectId;
264
265 float dummy_ = 0.f;
266 oceanData.bounds->getBounds(context, oceanData.bbox, dummy_);
267
268 oceanItem.setBounds(&oceanData.bbox);
269
270 oceanItem.setCallbackData(&oceanData);
271 oceanItem.callback = [](RenderTaskContext * renderingContext, DrawContext * drawContext, const RenderItem * oceanItem)
272 {
273 auto & oceanData = *oceanItem->getCallbackData<OceanData>();
274
275 if (drawContext->permutation->isShadowPass()) return;
276
277 RenderMaterialInstance * oceanRenderMaterial = renderingContext->renderer->getRenderResources().getRenderMaterialInstance(oceanData.material);
278
279 if (!oceanRenderMaterial) return;
280
281 const EffectBinding * oceanBindings = drawContext->binding;
282
283 if (!oceanBindings || !oceanBindings->renderEffect) return;
284
285 if (oceanBindings->renderEffect->isDelayed()) {
286 oceanBindings->renderEffect->requestLoad();
287
288 return;
289 }
290
291 if (!oceanBindings->renderEffect->isActive()) return;
292 if (!HandleIsValid(oceanBindings->sceneBufferBinding)) return;
293
294 auto & terrainData = *oceanData.terrainData;
295
296 updateTerrainContext(terrainData, renderingContext, drawContext->renderTarget, *drawContext->cameraData);
297
298 const size_t permutation = drawContext->permutationIndex;
299 terrainData.renderContext.permutation = permutation;
300 auto & permutationRenderContextData = terrainData.renderContext.getPermutationDependentRenderContextData(permutation);
301 permutationRenderContextData.oceanEffect = oceanBindings->renderEffect->effectHandle;
302
303 terrainData.renderContext.oceanCallback = [&](Cogs::EffectHandle /*effect*/) {
304 drawContext->task->applyMaterial(*drawContext, *oceanItem, oceanBindings);
305 updateMaterialBindings(drawContext, oceanRenderMaterial, oceanBindings, false);
306 updateSceneBindings(drawContext, drawContext->cameraData, oceanBindings);
307 applyMaterialPerObject(drawContext, oceanRenderMaterial, *oceanItem, oceanBindings);
308 };
309
310 oceanRender(terrainData.context, &terrainData.renderContext);
311 };
312 }
313 }
314}
315
316void Cogs::Core::TerrainRenderer::preRender(TerrainComponent & terrain, const DrawContext * drawContext)
317{
318 // Only pre-render for main camera.
319 if (drawContext->cameraData != &context->cameraSystem->getMainCameraData()) return;
320
321 auto & terrainData = terrainSystem->getData(&terrain);
322
323 if (!terrainData.initialized) return;
324
325 auto renderComponent = terrain.getComponent<RenderComponent>();
326
327 if (!renderComponent->isVisible()) {
328 if (terrainData.oceanData) {
329 // If ocean is visible we still need pre-render.
330 auto renderComponent_ = terrainData.oceanData->oceanComponent->getComponent<RenderComponent>();
331
332 if (!renderComponent_->isVisible()) return;
333 }
334 else {
335 return;
336 }
337 }
338
339 updateTerrainContext(terrainData, drawContext->taskContext, drawContext->renderTarget, *drawContext->cameraData);
340
341 terrainPreRender(terrainData.context, &terrainData.renderContext);
342}
343void Cogs::Core::TerrainRenderer::postRender(TerrainComponent & terrain, const DrawContext * renderingContext)
344{
345 auto & terrainData = terrainSystem->getData(&terrain);
346
347 if (!terrainData.initialized) return;
348 if (!terrainData.visible && !terrainData.oceanData) return;
349 if (!terrainData.renderContext.context) return;
350
351 terrainPostRender(terrainData.context, &terrainData.renderContext);
352
353 if (terrainRequiresRedraw(terrainData.context)) {
354 renderingContext->context->engine->setDirty();
355 }
356}
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
std::unique_ptr< class Variables > variables
Variables service instance.
Definition: Context.h:180
IGraphicsDevice * getDevice() override
Get the graphics device used by the renderer.
Definition: Renderer.h:46
RenderMode getMode() const override
Get the Rendering mode used by the renderer.
Definition: Renderer.h:40
const RenderSettings & getSettings() const override
Get the settings of the renderer.
Definition: Renderer.h:47
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.
glm::dvec3 getOrigin() const
Gets the Origin offset of the scene.
Represents a graphics device used to manage graphics resources and issue drawing commands.
virtual IContext * getImmediateContext()=0
Get a pointer to the immediate context used to issue commands to the graphics device.
ClipShapeType
Specifices what kind of shape a clip shape has.
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
@ EnablePicking
Supports picking.
@ Blend
Render with regular alpha blending.
@ None
No blending enabled for opaque shapes, defaults to Blend for transparent shapes.
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
Contains data describing a Camera instance and its derived data structured such as matrix data and vi...
Definition: CameraSystem.h:67
@ 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