Cogs.Core
TwinVisualsSystem.cpp
1#include "Foundation/Logging/Logger.h"
2#include "Foundation/Reflection/TypeDatabase.h"
3
4#include "Components/Core/EnvironmentComponent.h"
5
6#include "Resources/TextureManager.h"
7
8#include "Context.h"
9#include "ViewContext.h"
10#include "Services/Variables.h"
11#include "Services/Time.h"
12#include "Engine.h"
13#include "EntityStore.h"
14#include "Systems/Core/EnvironmentSystem.h"
15#include "Rendering/ICapabilities.h"
16#include "Rendering/IGraphicsDevice.h"
17
18#include "TwinVisualsComponent.h"
19#include "TwinVisualsSystem.h"
20
21namespace {
22 using Cogs::StringView;
23 using namespace Cogs::Core;
24 Cogs::Logging::Log logger = Cogs::Logging::getLogger("TwinVisuals");
25
26 // Variables that are modified with default values. See comments for where the default values were found.
27 struct ManagedVariables {
28 StringView pipeline;
29 bool clearDepth = true;
30 bool clearColor = false;
31 float debugView_outline = 1.f; // ShowTriangleSizes.pipeline(12)
32 StringView renderer_tonemapper = "Filmic"; // Renderer.cpp(412)
33 bool renderer_shadowsEnabled = true; // Renderer.cpp(410)
34 StringView renderer_filterPermutation = ""; // Advanced.pipeline
35 StringView shadows_softShadows = "Default"; // LightSystem.cpp(535)
36 int shadows_cascadeShadowResolution = 1024; // LightSystem.cpp(546)
37 StringView shadows_cascadeShadowFormat = "D16_UNORM";
38 bool postProcess_ambientOcclusion_enabled = true; // ForwardHdrCore.pipeline(38)
39 StringView postProcess_ambientOcclusion_type = "SSAO"; // ForwardHdrCore.pipeline(13)
40 bool postProcess_autoExposure_enabled = true; // ForwardHdrCore.pipeline(34)
41 float postProcess_basicAmbientOcclusion_contrast = 2.f; // BasicAmbientOcclusion.pipeline(22)
42 float postProcess_basicAmbientOcclusion_maxScreenRadiusPercentage = 1.5f; // BasicAmbientOcclusion.pipeline(21)
43 float postProcess_basicAmbientOcclusion_resolutionFactor = 2.f; // BasicAmbientOcclusion.pipeline(25)
44 float postProcess_basicAmbientOcclusion_strength = 0.7f; // BasicAmbientOcclusion.pipeline(23)
45 float postProcess_basicAmbientOcclusion_worldSpaceRadius = 0.05f; // BasicAmbientOcclusion.pipeline(20)
46 bool postProcess_bloom_enabled = true; // ForwardHdrCore.pipeline(46)
47 float postProcess_bloom_intensity = 0.02f; // PhysicallyBasedBloom.pipeline(18)
48 bool postProcess_fxaa_enabled = true; // ForwardHdrCore.pipeline(54)
49 float postProcess_fxaa_qualityEdgeThreshold = 0.166f; // FXAACore.pipeline(26)
50 float postProcess_fxaa_qualityEdgeThresholdMin = 0.0833f; // FXAACore.pipeline(31)
51 float postProcess_fxaa_qualitySubpix = 0.5f; // FXAACore.pipeline(19)
52 bool postProcess_multiSampleForwardPass = false; // ForwardHdrCore.pipeline(30) settings.pp_HBAO_dirCount = 5;
53 int postProcess_HBAO_dirCount = 5; // HBAO.pipeline(17)
54 float postProcess_HBAO_power = 1.2f;
55 int postProcess_HBAO_stepsPerDir = 15;
56 float postProcess_HBAO_strength = 0.8f;
57 float postProcess_HBAO_contrast = 0.8f;
58 float postProcess_HBAO_worldSpaceRadius = 50.f;
59 float postProcess_HBAO_maxScreenRadiusPercentage = 15.f;
60 float postProcess_HBAO_thicknessWS = 1.f;
61 float renderer_exposureCompensation = 0.f; // AutoExposure.pipeline(68)
62 float renderer_exposureDecreaseSpeed = 50.f; // AutoExposure.pipeline(73)
63 float renderer_exposureIncreaseSpeed = 100.f; // AutoExposure.pipeline(72)
64 int postProcess_autoExposure_updateInterval = 10; // Twin specific default
65 float postProcess_autoExposure_sampleArea_x = 0.3f; // AutoExposure.pipeline(41)
66 float postProcess_autoExposure_sampleArea_y = 0.3f; // AutoExposure.pipeline(42)
67 float renderer_exposureMaximum = 10.f; // AutoExposure.pipeline(70)
68 float renderer_exposureMinimum = 0.00000001f; // AutoExposure.pipeline(69)
69 float renderer_lightScale = 1.f; // AutoExposure.pipeline(71)
70 float renderer_maxShadowDistance = 30000.f; // LightSystem.cpp(510)
71 float renderer_UpscaleHeight = 1.0;
72 float renderer_UpscaleWidth = 1.0;
73 float renderer_postProcess_blur_radius = 8.f; // DepthOfField.pipeline(8)
74 bool renderer_postProcess_depthOfField_enabled = false; // UseDepthOfField.pipeline(13)
75 float renderer_postProcess_depthOfField_startDistance = 50.f; // DepthOfField.pipeline(6)
76 float renderer_postProcess_depthOfField_smoothing = 1000.f; // DepthOfField.pipeline(7)
77 int renderer_samples = 4; // What we get in WebGL (tested on nvidia and edge)
78 bool twinVisuals_highlightRegions_enabled = false; // TwinVisuals
79 bool twinVisuals_groundPlane_enabled = false; // TwinVisuals
80 bool renderer_multiSampleForwardPass = true; // Set to false on devices where multisampling is unreliable
81 };
82
83 void setVariables(Context* context, const ManagedVariables& variables)
84 {
85 context->variables->set("renderer.pipeline", variables.pipeline);
86 context->variables->set("renderer.filterPermutation", variables.renderer_filterPermutation);
87 context->variables->set("clearColor", variables.clearColor);
88 context->variables->set("clearDepth", variables.clearDepth);
89 context->variables->set("debugView.outline", variables.debugView_outline);
90 context->variables->set("renderer.tonemapper", variables.renderer_tonemapper);
91 context->variables->set("renderer.shadowsEnabled", variables.renderer_shadowsEnabled);
92 context->variables->set("shadows.softShadows", variables.shadows_softShadows);
93 context->variables->set("shadows.cascadeShadowResolution", variables.shadows_cascadeShadowResolution);
94 context->variables->set("shadows.cascadeShadowFormat", variables.shadows_cascadeShadowFormat);
95 context->variables->set("postProcess.ambientOcclusion.enabled", variables.postProcess_ambientOcclusion_enabled);
96 context->variables->set("postProcess.ambientOcclusion.type", variables.postProcess_ambientOcclusion_type);
97 context->variables->set("postProcess.autoExposure.enabled", variables.postProcess_autoExposure_enabled);
98 context->variables->set("postProcess.basicAmbientOcclusion.contrast", variables.postProcess_basicAmbientOcclusion_contrast);
99 context->variables->set("postProcess.basicAmbientOcclusion.maxScreenRadiusPercentage", variables.postProcess_basicAmbientOcclusion_maxScreenRadiusPercentage);
100 context->variables->set("postProcess.basicAmbientOcclusion.resolutionFactor", variables.postProcess_basicAmbientOcclusion_resolutionFactor);
101 context->variables->set("postProcess.basicAmbientOcclusion.strength", variables.postProcess_basicAmbientOcclusion_strength);
102 context->variables->set("postProcess.basicAmbientOcclusion.worldSpaceRadius", variables.postProcess_basicAmbientOcclusion_worldSpaceRadius);
103 context->variables->set("postProcess.bloom.enabled", variables.postProcess_bloom_enabled);
104 context->variables->set("postProcess.fxaa.enabled", variables.postProcess_fxaa_enabled);
105 context->variables->set("postProcess.fxaa.qualityEdgeThreshold", variables.postProcess_fxaa_qualityEdgeThreshold);
106 context->variables->set("postProcess.fxaa.qualityEdgeThresholdMin", variables.postProcess_fxaa_qualityEdgeThresholdMin);
107 context->variables->set("postProcess.fxaa.qualitySubpix", variables.postProcess_fxaa_qualitySubpix);
108 context->variables->set("postProcess.HBAO.dirCount", variables.postProcess_HBAO_dirCount);
109 context->variables->set("postProcess.HBAO.power", variables.postProcess_HBAO_power);
110 context->variables->set("postProcess.HBAO.stepsPerDir", variables.postProcess_HBAO_stepsPerDir);
111 context->variables->set("postProcess.HBAO.strength", variables.postProcess_HBAO_strength);
112 context->variables->set("postProcess.HBAO.contrast", variables.postProcess_HBAO_contrast);
113 context->variables->set("postProcess.HBAO.worldSpaceRadius", variables.postProcess_HBAO_worldSpaceRadius);
114 context->variables->set("postProcess.HBAO.maxScreenRadiusPercentage", variables.postProcess_HBAO_maxScreenRadiusPercentage);
115 context->variables->set("postProcess.HBAO.thicknessWS", variables.postProcess_HBAO_thicknessWS);
116 context->variables->set("postProcess.multiSampleForwardPass", variables.postProcess_multiSampleForwardPass);
117 context->variables->set("renderer.exposureCompensation", variables.renderer_exposureCompensation);
118 context->variables->set("renderer.exposureDecreaseSpeed", variables.renderer_exposureDecreaseSpeed);
119 context->variables->set("renderer.exposureIncreaseSpeed", variables.renderer_exposureIncreaseSpeed);
120 context->variables->set("renderer.UpscaleHeight", variables.renderer_UpscaleHeight);
121 context->variables->set("renderer.UpscaleWidth", variables.renderer_UpscaleWidth);
122 context->variables->set("renderer.postProcess.autoExposure.updateInterval", variables.postProcess_autoExposure_updateInterval);
123 context->variables->set("renderer.postProcess.autoExposure.sampleArea_x", variables.postProcess_autoExposure_sampleArea_x);
124 context->variables->set("renderer.postProcess.autoExposure.sampleArea_y", variables.postProcess_autoExposure_sampleArea_y);
125 context->variables->set("renderer.exposureMaximum", variables.renderer_exposureMaximum);
126 context->variables->set("renderer.exposureMinimum", variables.renderer_exposureMinimum);
127 context->variables->set("renderer.lightScale", variables.renderer_lightScale);
128 context->variables->set("renderer.maxShadowDistance", variables.renderer_maxShadowDistance);
129 context->variables->set("renderer.postProcess.blur.radius", variables.renderer_postProcess_blur_radius);
130 context->variables->set("renderer.postProcess.depthOfField.enabled", variables.renderer_postProcess_depthOfField_enabled);
131 context->variables->set("renderer.postProcess.depthOfField.smoothing", variables.renderer_postProcess_depthOfField_smoothing);
132 context->variables->set("renderer.postProcess.depthOfField.startDistance", variables.renderer_postProcess_depthOfField_startDistance);
133 context->variables->set("renderer.samples", variables.renderer_samples);
134 context->variables->set("twinVisuals.highlightRegions.enabled", variables.twinVisuals_highlightRegions_enabled);
135 context->variables->set("twinVisuals.groundPlane.enabled", variables.twinVisuals_groundPlane_enabled);
136 context->variables->set("renderer.multiSampleForwardPass", variables.renderer_multiSampleForwardPass);
137 }
138
139}
140
142{
143 for (const TwinVisualsComponent& visualsComp : pool) {
144
145 // Check if biosphere has been (re-)specified
146 if (visualsComp.hasChanged()) {
147 TwinVisualsData& visualsData = getData(&visualsComp);
148
149 if (visualsData.biosphere != visualsComp.biosphere) {
150 visualsData.biosphere = visualsComp.biosphere;
151 if (visualsData.biosphere.empty()) {
152 visualsData.ggx.clear(context, visualsData);
153 visualsData.lut.clear(context, visualsData);
154 visualsData.lambertian.clear(context, visualsData);
155 visualsData.skybox.clear(context, visualsData);
156 }
157 else {
158 visualsData.ggx.issue(context, visualsData, visualsData.biosphere + "/GGX.ktx2");
159 visualsData.lut.issue(context, visualsData, visualsData.biosphere + "/LUT.png");
160 visualsData.lambertian.issue(context, visualsData, visualsData.biosphere + "/Lambertian.ktx2");
161 visualsData.skybox.issue(context, visualsData, visualsData.biosphere + "/skybox.ktx2");
162 }
163 }
164 }
165 }
166}
167
169{
170 bool forceUpdate = false;
171
172 for (const TwinVisualsComponent& visualsComp : pool) {
173 TwinVisualsData& visualsData = getData(&visualsComp);
174
175 // Try to avoid overwriting all the variables all the time so it is still possible to manually experiment with them
176 bool update = forceUpdate || visualsData.firstrun;
177 visualsData.firstrun = false;
178
179 //const glm::vec2 upscaleFactor = glm::vec2(1.f);
180 const TwinVisualsDynamicRenderResolution drrPreset = visualsComp.dynamicRenderResolution;
181 const bool useLowResolution = visualsComp.useLowResolution && drrPreset != TwinVisualsDynamicRenderResolution::FullQuality;
182
183 // Automatically detect highlight-region-enable when there are any highlightregioncomponents.
184 // To avoid pulling in a dependency on the highlightregion extension we just check if there
185 // are any components on the system, not anything more fancy.
186 bool highlightRegionEnable = false;
187 if (visualsComp.highlightRegionEnable) {
188 if (const Reflection::Type& type = Reflection::TypeDatabase::getType("HighlightRegionComponent"); type.isValid()) {
189 if (auto* system = reinterpret_cast<ComponentSystem*>(context->getExtensionSystem(type.getTypeId())); system) {
190 if (system->pool.size()) {
191 highlightRegionEnable = true;
192 }
193 }
194 }
195 }
196
197 // Auto exposure needs about a second to correct the exposure.
198 if (visualsComp.mode == TwinVisualsMode::Advanced || visualsComp.mode == TwinVisualsMode::DarkFocus || visualsComp.mode == TwinVisualsMode::SurfaceDarkFocus) {
199 uint32_t framesSinceDirty = context->time->getFrame() - context->engine->getLastDirtyFrame();
200 if (framesSinceDirty <= 60) {
201 context->engine->triggerUpdate();
202 }
203 }
204
205 bool pbrEnvironmentEnabled = false;
206 EnvironmentComponent *env = context->environmentSystem->getGlobalEnvironment();
207 if (env) {
208 pbrEnvironmentEnabled = env->PBR;
209 }
210 bool enableGroundPlane = visualsComp.groundPlaneEnabled;
211
212 update = update
213 || (visualsData.mode != visualsComp.mode)
214 || (visualsData.texAtlasStyle != visualsComp.texAtlasStyle)
215 || (visualsData.qualityPreset != visualsComp.qualityPreset)
216 || (visualsData.tonemapper != visualsComp.tonemapper)
217 || (visualsData.shadowsEnabled != visualsComp.shadowsEnabled)
218 || (visualsData.highlightRegionEnabled != highlightRegionEnable)
219 || (visualsData.pbrEnvironmentEnabled != pbrEnvironmentEnabled)
220 || (visualsData.drrPreset != drrPreset)
221 || (visualsData.useLowRes != useLowResolution)
222 || (visualsData.brightness != visualsComp.brightness)
223 || (visualsData.groundPlaneEnabled != enableGroundPlane);
224
225 visualsData.tonemapper = visualsComp.tonemapper;
226 visualsData.shadowsEnabled = visualsComp.shadowsEnabled;
227 visualsData.drrPreset = drrPreset;
228 visualsData.useLowRes = useLowResolution;
229 visualsData.highlightRegionEnabled = highlightRegionEnable;
230 visualsData.mode = visualsComp.mode;
231 visualsData.texAtlasStyle = visualsComp.texAtlasStyle;
232 visualsData.qualityPreset = visualsComp.qualityPreset;
233 visualsData.pbrEnvironmentEnabled = pbrEnvironmentEnabled;
234 visualsData.brightness = visualsComp.brightness;
235 visualsData.groundPlaneEnabled = enableGroundPlane;
236 float upscaleFactor = 1.f;
237 switch (drrPreset) {
238 case TwinVisualsDynamicRenderResolution::FullQuality:
239 upscaleFactor = 1.f;
240 break;
241 case TwinVisualsDynamicRenderResolution::Balanced:
242 upscaleFactor = useLowResolution ? 4.f / 3.f : 1.f;
243 break;
244 case TwinVisualsDynamicRenderResolution::Fast:
245 upscaleFactor = useLowResolution ? 16.f / 9.f : 4.f / 3.f;
246 break;
247 case TwinVisualsDynamicRenderResolution::FullAndSmooth:
248 upscaleFactor = useLowResolution ? 19.f / 9.f : 1.f;
249 break;
250 default:
251 break;
252 }
253
254 if (update) {
255 ManagedVariables variables;
256 variables.twinVisuals_groundPlane_enabled = enableGroundPlane;
257 if (context->device->getCapabilities()->getDeviceCapabilities().MaxSamples == 1) {
258 variables.renderer_multiSampleForwardPass = false;
259 }
260 variables.renderer_shadowsEnabled = visualsData.shadowsEnabled;
261 variables.renderer_UpscaleHeight = upscaleFactor;
262 variables.renderer_UpscaleWidth = upscaleFactor;
263 variables.twinVisuals_highlightRegions_enabled = visualsData.highlightRegionEnabled;
264 switch (visualsComp.mode) {
265 case TwinVisualsMode::Balanced:
266
267 // New pipeline/task supports with and without ground, this is for easy side-by-side comparison of pipelines
268 if(visualsComp.groundPlaneEnabled) {
269 variables.pipeline = "TwinVisuals/Pipelines/TexAtlas/BalancedWithTexAtlas.pipeline";
270 }
271 else {
272 variables.pipeline = "TwinVisuals/Pipelines/Balanced/Balanced.pipeline";
273 }
274 variables.clearDepth = true;
275 variables.clearColor = false; // Should probably be true.
276 variables.renderer_maxShadowDistance = 150.f;
277 variables.shadows_softShadows = "Low";
278 break;
279
280 case TwinVisualsMode::Advanced:
281 variables.pipeline = "TwinVisuals/Pipelines/Advanced/Advanced.pipeline";
282 variables.clearDepth = true;
283 variables.clearColor = false; // Should probably be true.
284 variables.postProcess_ambientOcclusion_enabled = true;
285 variables.postProcess_autoExposure_enabled = false;
286 variables.postProcess_basicAmbientOcclusion_contrast = 0.9f;
287 variables.postProcess_basicAmbientOcclusion_maxScreenRadiusPercentage = 0.6f;
288 variables.postProcess_basicAmbientOcclusion_resolutionFactor = 1.f;
289 variables.postProcess_basicAmbientOcclusion_strength = 0.7f;
290 variables.postProcess_basicAmbientOcclusion_worldSpaceRadius = 50.f;
291 variables.postProcess_HBAO_dirCount = 3;
292 variables.postProcess_HBAO_power = 3;
293 variables.postProcess_HBAO_stepsPerDir = 20;
294
295 variables.postProcess_bloom_enabled = true;
296 variables.postProcess_bloom_intensity = 0.005f;
297 variables.postProcess_fxaa_enabled = true;
298 variables.postProcess_fxaa_qualityEdgeThreshold = 0.063f;
299 variables.postProcess_fxaa_qualityEdgeThresholdMin = 0.0312f;
300 variables.postProcess_fxaa_qualitySubpix = 1.f;
301 variables.postProcess_multiSampleForwardPass = true;
302 variables.renderer_exposureDecreaseSpeed = 6.f;
303 variables.renderer_exposureIncreaseSpeed = 6.f;
304 variables.renderer_exposureMaximum = 8.f;
305 variables.renderer_exposureMinimum = 0.3f;
306 variables.renderer_lightScale = 0.5f + visualsData.brightness;
307 variables.renderer_maxShadowDistance = 150.f;
308 variables.shadows_softShadows = "Low";
309 variables.renderer_samples = 8;
310 break;
311
312 case TwinVisualsMode::Glass:
313 variables.pipeline = "TwinVisuals/Pipelines/Glass/GlassMode.pipeline";
314 variables.clearDepth = true;
315 variables.clearColor = false; // Should probably be true.
316 variables.renderer_lightScale = 0.5f + visualsData.brightness;
317 break;
318
319 case TwinVisualsMode::Sketch:
320 variables.pipeline = "TwinVisuals/Pipelines/Sketch/BasicNPRUpscale.pipeline";
321 variables.clearDepth = true;
322 variables.clearColor = false; // Should probably be true.
323 variables.renderer_lightScale = 0.5f + visualsData.brightness;
324 break;
325
326 case TwinVisualsMode::DepthOfField:
327 variables.pipeline = drrPreset == TwinVisualsDynamicRenderResolution::FullQuality ? "Pipelines/DepthOfField/UseDepthOfField.pipeline" : "Pipelines/DepthOfField/UseDepthOfFieldUpscale.pipeline";
328 variables.renderer_postProcess_depthOfField_enabled = true;
329 variables.renderer_postProcess_blur_radius = 5.f;
330 variables.renderer_postProcess_depthOfField_smoothing = 50.f;
331 variables.renderer_postProcess_depthOfField_startDistance = 10.f;
332 variables.renderer_lightScale = 0.5f + visualsData.brightness;
333 break;
334
335 case TwinVisualsMode::Preview3DTriangleSize:
336 variables.pipeline = "Pipelines/DebugView/ShowTriangleSizes.pipeline";
337 variables.debugView_outline = 0.f;
338 break;
339
340 case TwinVisualsMode::DarkFocus:
341 variables.pipeline = "TwinVisuals/Pipelines/Advanced/Advanced.pipeline";
342 variables.clearDepth = true;
343 variables.clearColor = false; // Should probably be true.
344 variables.postProcess_ambientOcclusion_enabled = true;
345 variables.postProcess_ambientOcclusion_type = "SSAO";
346 variables.postProcess_autoExposure_enabled = true;
347 variables.postProcess_basicAmbientOcclusion_contrast = 0.9f;
348 variables.postProcess_basicAmbientOcclusion_maxScreenRadiusPercentage = 5.0f;
349 variables.postProcess_basicAmbientOcclusion_resolutionFactor = 1.f;
350 variables.postProcess_basicAmbientOcclusion_strength = 1.0f;
351 variables.postProcess_basicAmbientOcclusion_worldSpaceRadius = 50.f;
352 variables.postProcess_bloom_enabled = true;
353 variables.postProcess_bloom_intensity = 0.007f;
354 variables.postProcess_fxaa_enabled = true;
355 variables.postProcess_fxaa_qualityEdgeThreshold = 0.063f;
356 variables.postProcess_fxaa_qualityEdgeThresholdMin = 0.0312f;
357 variables.postProcess_fxaa_qualitySubpix = 1.f;
358 variables.postProcess_multiSampleForwardPass = true;
359 variables.renderer_exposureCompensation = 4.f* visualsData.brightness - 2.f;
360 variables.renderer_exposureDecreaseSpeed = 6.f;
361 variables.renderer_exposureIncreaseSpeed = 6.f;
362 variables.renderer_exposureMaximum = 2.5f;
363 variables.renderer_exposureMinimum = 0.3f;
364 variables.renderer_lightScale = 1.f;
365 variables.renderer_maxShadowDistance = 150.f;
366 variables.renderer_samples = 8;
367 variables.shadows_softShadows = "Low";
368 variables.shadows_cascadeShadowResolution = 4096;
369 break;
370
371 case TwinVisualsMode::SurfaceCAD:
372 variables.pipeline = "TwinVisuals/Pipelines/Surface/Surface.pipeline";
373 variables.clearDepth = true;
374 variables.clearColor = false; // Should probably be true.
375 variables.postProcess_ambientOcclusion_enabled = true;
376 variables.postProcess_ambientOcclusion_type = "SSAO";
377 variables.postProcess_autoExposure_enabled = false;
378 variables.postProcess_basicAmbientOcclusion_contrast = 0.9f;
379 variables.postProcess_basicAmbientOcclusion_maxScreenRadiusPercentage = 0.6f;
380 variables.postProcess_basicAmbientOcclusion_resolutionFactor = 1.f;
381 variables.postProcess_basicAmbientOcclusion_strength = 0.7f;
382 variables.postProcess_basicAmbientOcclusion_worldSpaceRadius = 50.f;
383 variables.postProcess_bloom_enabled = false;
384 variables.postProcess_fxaa_enabled = true;
385 variables.postProcess_fxaa_qualityEdgeThreshold = 0.063f;
386 variables.postProcess_fxaa_qualityEdgeThresholdMin = 0.0312f;
387 variables.postProcess_fxaa_qualitySubpix = 1.f;
388 variables.postProcess_multiSampleForwardPass = true;
389 variables.renderer_maxShadowDistance = 150.f;
390 variables.shadows_softShadows = "Low";
391 variables.renderer_samples = 4;
392 variables.renderer_lightScale = 0.5f + visualsData.brightness;
393 break;
394
395 case TwinVisualsMode::SurfaceDefault:
396 variables.pipeline = "TwinVisuals/Pipelines/Surface/Surface.pipeline";
397 variables.clearDepth = true;
398 variables.clearColor = false; // Should probably be true.
399 variables.postProcess_ambientOcclusion_enabled = true;
400 variables.postProcess_ambientOcclusion_type = "HBAO";
401 variables.postProcess_autoExposure_enabled = false;
402 variables.postProcess_basicAmbientOcclusion_contrast = 0.9f;
403 variables.postProcess_basicAmbientOcclusion_maxScreenRadiusPercentage = 0.6f;
404 variables.postProcess_basicAmbientOcclusion_resolutionFactor = 1.f;
405 variables.postProcess_basicAmbientOcclusion_strength = 0.7f;
406 variables.postProcess_basicAmbientOcclusion_worldSpaceRadius = 50.f;
407 variables.postProcess_HBAO_dirCount = useLowResolution ? 3 : 5;
408 variables.postProcess_HBAO_power = 3;
409 variables.postProcess_HBAO_stepsPerDir = useLowResolution ? 15 : 25;
410
411 variables.postProcess_bloom_enabled = true;
412 variables.postProcess_bloom_intensity = 0.005f;
413 variables.postProcess_fxaa_enabled = true;
414 variables.postProcess_fxaa_qualityEdgeThreshold = 0.063f;
415 variables.postProcess_fxaa_qualityEdgeThresholdMin = 0.0312f;
416 variables.postProcess_fxaa_qualitySubpix = 1.f;
417 variables.postProcess_multiSampleForwardPass = true;
418 variables.renderer_exposureDecreaseSpeed = 6.f;
419 variables.renderer_exposureIncreaseSpeed = 6.f;
420 variables.renderer_exposureMaximum = 8.f;
421 variables.renderer_exposureMinimum = 0.3f;
422 variables.renderer_lightScale = 0.5f + visualsData.brightness;
423 variables.renderer_maxShadowDistance = 150.f;
424 variables.shadows_softShadows = "Low";
425 variables.renderer_samples = 8;
426
427 break;
428 case TwinVisualsMode::SurfaceHyper:
429 variables.pipeline = "TwinVisuals/Pipelines/Surface/Surface.pipeline";
430 variables.clearDepth = true;
431 variables.clearColor = false; // Should probably be true.
432 variables.postProcess_ambientOcclusion_enabled = true;
433 variables.postProcess_ambientOcclusion_type = "HBAO";
434 variables.postProcess_autoExposure_enabled = false;
435 variables.postProcess_basicAmbientOcclusion_contrast = 0.9f;
436 variables.postProcess_basicAmbientOcclusion_maxScreenRadiusPercentage = 5.0f;
437 variables.postProcess_basicAmbientOcclusion_resolutionFactor = 1.f;
438 variables.postProcess_basicAmbientOcclusion_strength = 1.0f;
439 variables.postProcess_basicAmbientOcclusion_worldSpaceRadius = 50.f;
440 variables.postProcess_bloom_enabled = true;
441 variables.postProcess_fxaa_enabled = true;
442 variables.postProcess_fxaa_qualityEdgeThreshold = 0.063f;
443 variables.postProcess_fxaa_qualityEdgeThresholdMin = 0.0312f;
444 variables.postProcess_fxaa_qualitySubpix = 1.f;
445 variables.postProcess_HBAO_dirCount = 5;
446 variables.postProcess_HBAO_stepsPerDir = 25;
447 variables.postProcess_HBAO_power = 3.0f;
448 variables.postProcess_HBAO_strength = 0.7f;
449 variables.postProcess_HBAO_contrast = 0.7f;
450 variables.postProcess_multiSampleForwardPass = true;
451 variables.renderer_lightScale = 0.5f + visualsData.brightness;
452 variables.renderer_maxShadowDistance = 150.f;
453 variables.renderer_samples = 8;
454 variables.shadows_softShadows = "Low";
455 variables.shadows_cascadeShadowResolution = 4096;
456 break;
457
458 case TwinVisualsMode::SurfaceGlass:
459 variables.pipeline = "TwinVisuals/Pipelines/Surface/SurfaceGlass.pipeline";
460 variables.clearDepth = true;
461 variables.clearColor = false; // Should probably be true.
462 variables.renderer_lightScale = 0.5f + visualsData.brightness;
463 break;
464
465 case TwinVisualsMode::SurfaceSketch:
466 variables.pipeline = "TwinVisuals/Pipelines/Surface/SurfaceSketch.pipeline";
467 variables.clearDepth = true;
468 variables.clearColor = false; // Should probably be true.
469 variables.renderer_lightScale = 0.5f + visualsData.brightness;
470 break;
471
472 case TwinVisualsMode::SurfaceDarkFocus:
473 variables.pipeline = "TwinVisuals/Pipelines/Surface/Surface.pipeline";
474 variables.clearDepth = true;
475 variables.clearColor = false; // Should probably be true.
476 variables.postProcess_ambientOcclusion_enabled = true;
477 variables.postProcess_ambientOcclusion_type = "SSAO";
478 variables.postProcess_autoExposure_enabled = false;
479 variables.postProcess_basicAmbientOcclusion_contrast = 0.9f;
480 variables.postProcess_basicAmbientOcclusion_maxScreenRadiusPercentage = 5.0f;
481 variables.postProcess_basicAmbientOcclusion_resolutionFactor = 1.f;
482 variables.postProcess_basicAmbientOcclusion_strength = 1.0f;
483 variables.postProcess_basicAmbientOcclusion_worldSpaceRadius = 50.f;
484 variables.postProcess_bloom_enabled = true;
485 variables.postProcess_bloom_intensity = 0.007f;
486 variables.postProcess_fxaa_enabled = true;
487 variables.postProcess_fxaa_qualityEdgeThreshold = 0.063f;
488 variables.postProcess_fxaa_qualityEdgeThresholdMin = 0.0312f;
489 variables.postProcess_fxaa_qualitySubpix = 1.f;
490 variables.postProcess_multiSampleForwardPass = true;
491 variables.renderer_exposureCompensation = 4.f* visualsData.brightness - 2.f;
492 variables.renderer_exposureDecreaseSpeed = 6.f;
493 variables.renderer_exposureIncreaseSpeed = 6.f;
494 variables.renderer_exposureMaximum = 2.5f;
495 variables.renderer_exposureMinimum = 0.3f;
496 variables.renderer_lightScale = 1.f;
497 variables.renderer_maxShadowDistance = 150.f;
498 variables.renderer_samples = 8;
499 variables.shadows_softShadows = "Low";
500 variables.shadows_cascadeShadowResolution = 4096;
501 break;
502 case TwinVisualsMode::SurfaceClay:
503 variables.pipeline = "TwinVisuals/Pipelines/Surface/Clay.pipeline";
504 variables.clearDepth = true;
505 variables.clearColor = false; // Should probably be true.
506 variables.postProcess_ambientOcclusion_enabled = true;
507 variables.postProcess_ambientOcclusion_type = "HBAO";
508 variables.postProcess_ambientOcclusion_enabled = true;
509 variables.postProcess_autoExposure_enabled = false;
510 variables.postProcess_bloom_enabled = false;
511 variables.postProcess_fxaa_enabled = true;
512 variables.postProcess_fxaa_qualityEdgeThreshold = 0.063f;
513 variables.postProcess_fxaa_qualityEdgeThresholdMin = 0.0312f;
514 variables.postProcess_fxaa_qualitySubpix = 1.f;
515 variables.postProcess_multiSampleForwardPass = true;
516 {
517 // Should probably be smoother. 0.5 is neutral and should map to 1.0.
518 float x = std::max(0.0f, std::min(1.0f, visualsData.brightness));
519 if (x <= 0.5f)
520 {
521 variables.renderer_lightScale = 1.8f * x + 0.1f;
522 }
523 else
524 {
525 variables.renderer_lightScale = 6.f * x - 2.f;
526 }
527 }
528 variables.renderer_maxShadowDistance = 150.f;
529 variables.renderer_samples = 4;
530 variables.shadows_softShadows = "Low";
531 variables.shadows_cascadeShadowResolution = 256;
532 switch (visualsComp.qualityPreset) {
533 case TwinVisualsQualityPreset::Low:
534 variables.pipeline = "TwinVisuals/Pipelines/Surface/ClayLow.pipeline";
535 variables.postProcess_ambientOcclusion_type = "HBAOv2";
536 variables.renderer_shadowsEnabled = false;
537 variables.postProcess_ambientOcclusion_enabled = true;
538 variables.postProcess_fxaa_enabled = false; // Not present in Clay - Low pipeline, so disabling has no effect.
539 break;
540 case TwinVisualsQualityPreset::Medium:
541 variables.renderer_shadowsEnabled = false;
542 variables.postProcess_HBAO_dirCount = 4;
543 variables.postProcess_HBAO_power = 1.75;
544 variables.postProcess_HBAO_stepsPerDir = 7;
545 variables.postProcess_HBAO_strength = 0.75;
546 variables.postProcess_HBAO_thicknessWS = 6;
547 variables.postProcess_HBAO_maxScreenRadiusPercentage = 3.0;
548 break;
549 case TwinVisualsQualityPreset::High:
550 variables.postProcess_HBAO_dirCount = 5;
551 variables.postProcess_HBAO_power = 3;
552 variables.postProcess_HBAO_stepsPerDir = 30;
553 variables.postProcess_HBAO_strength = 0.8f;
554 variables.postProcess_HBAO_thicknessWS = 1.0;
555 variables.shadows_cascadeShadowResolution = 2048;
556 break;
557 case TwinVisualsQualityPreset::Ultra:
558 variables.postProcess_HBAO_dirCount = 7;
559 variables.postProcess_HBAO_power = 3;
560 variables.postProcess_HBAO_stepsPerDir = 30;
561 variables.postProcess_HBAO_strength = 0.8f;
562 variables.postProcess_HBAO_thicknessWS = 1.0f;
563 variables.shadows_softShadows = "High";
564 variables.shadows_cascadeShadowResolution = 4096;
565 break;
566 default:
567 assert(false && "Invalid enum value");
568 break;
569 }
570 variables.renderer_filterPermutation = variables.postProcess_ambientOcclusion_type == "HBAOv2" ? "ForwardWithStructureBuffer" : "ForwardWithNormals";
571
572 break;
573
574 default:
575
576 assert(false && "Invalid enum value");
577 break;
578 }
579 variables.postProcess_bloom_intensity /= (upscaleFactor * upscaleFactor); // Bloom intensity needs to be divided by the upscale factor to get similar result when upscaling is enabled.
580 switch (visualsComp.tonemapper) {
581 case TwinVisualsTonemapper::Reinhard:
582 variables.renderer_tonemapper = "Reinhard";
583 break;
584 case TwinVisualsTonemapper::Filmic:
585 variables.renderer_tonemapper = "Filmic";
586 break;
587 case TwinVisualsTonemapper::ACESLuminance:
588 variables.renderer_tonemapper = "ACESLuminance";
589 break;
590 case TwinVisualsTonemapper::PBRNeutral:
591 variables.renderer_tonemapper = "PBRNeutral";
592 break;
593 default:
594 assert(false && "Invalid enum value");
595 break;
596 }
597
598 setVariables(context, variables);
599 }
600
601 // Update texture fetching state
602 visualsData.ggx.check(context, visualsData);
603 visualsData.lut.check(context, visualsData);
604 visualsData.lambertian.check(context, visualsData);
605 visualsData.skybox.check(context, visualsData);
606
607 // See if we are good to go for texture presenting
608 if (visualsData.presentTextures) {
609 if (EnvironmentComponent* envComp = context->environmentSystem->getGlobalEnvironment(); envComp) {
610 envComp->radiance = visualsData.ggx.present;
611 envComp->irradiance = visualsData.lambertian.present;
612 envComp->brdfLUT = visualsData.lut.present;
613 envComp->skyDome = visualsData.skybox.present;
614 }
615 }
616
617 }
618}
619
621{
622 for (const TwinVisualsComponent& visualsComp : pool) {
623 TwinVisualsData& visualsData = getData(&visualsComp);
624
625 visualsData.presentTextures = false;
626 if (visualsData.prevTextureLoadingState != visualsData.currTextureLoadingState) { // State change
627 switch (visualsData.currTextureLoadingState) {
628 case TextureLoadingState::Ready:
629 visualsData.presentTextures = true;
630 context->engine->triggerUpdate(); // Force another frame so textures get presented
631 context->engine->invokeComponentNotifyCallback(visualsComp, (int)TwinVisualsNotification::TexturesReady, nullptr, 0);
632 break;
633 case TextureLoadingState::Loading:
634 context->engine->invokeComponentNotifyCallback(visualsComp, (int)TwinVisualsNotification::TexturesLoading, nullptr, 0);
635 break;
636 case TextureLoadingState::Failed:
637 context->engine->invokeComponentNotifyCallback(visualsComp, (int)TwinVisualsNotification::TexturesFailed, nullptr, 0);
638 break;
639 }
640 }
641
642 visualsData.prevTextureLoadingState = visualsData.currTextureLoadingState;
643 visualsData.currTextureLoadingState = TextureLoadingState::Ready; // We are ready until some texture wrapper tells us we're not
644 }
645}
646
648{
649 ComponentHandle handle = base::createComponent();
650 if (globalTwinVisualsComponent == nullptr) {
651 globalTwinVisualsComponent = handle.resolveComponent<TwinVisualsComponent>();
652 }
653 return handle;
654}
655
657{
658 if (globalTwinVisualsComponent == handle.resolveComponent<TwinVisualsComponent>()) {
659 globalTwinVisualsComponent = nullptr;
660 }
661 base::destroyComponent(handle);
662}
663
664void Cogs::Core::TwinVisualsTextureWrapper::clear(Context* /*context*/, TwinVisualsData& visualsData)
665{
666 present = TextureHandle::NoHandle;
668 if (visualsData.currTextureLoadingState != TextureLoadingState::Failed) { // Failed state is sticky
669 visualsData.currTextureLoadingState = TextureLoadingState::Loading;
670 }
671}
672
673void Cogs::Core::TwinVisualsTextureWrapper::issue(Context* context, TwinVisualsData& visualsData, const StringView path)
674{
675 issued = context->textureManager->loadTexture(path, NoResourceId, TextureLoadFlags::None);
676 LOG_DEBUG(logger, "Frame %u: Issue fetch for %.*s", context->time->getFrame(), StringViewFormat(issued->getSource()));
677 if (visualsData.currTextureLoadingState != TextureLoadingState::Failed) { // Failed state is sticky
678 visualsData.currTextureLoadingState = TextureLoadingState::Loading;
679 }
680}
681
682bool Cogs::Core::TwinVisualsTextureWrapper::check(Context* context, TwinVisualsData& visualsData)
683{
684 if (HandleIsValid(issued)) {
685 if (issued->hasFailedLoad()) {
686 visualsData.currTextureLoadingState = TextureLoadingState::Failed;
687 }
688 else if (!issued->isResident()) {
689 if (visualsData.currTextureLoadingState != TextureLoadingState::Failed) { // Failed state is sticky
690 visualsData.currTextureLoadingState = TextureLoadingState::Loading;
691 }
692 }
693 else if(present != issued) {
694 present = issued;
695 LOG_DEBUG(logger, "Frame %u: Resident texture %.*s", context->time->getFrame(), StringViewFormat(issued->getSource()));
696 }
697 }
698 return visualsData.presentTextures;
699}
Context * context
Pointer to the Context instance the system lives in.
void postUpdate()
Perform post update logic in the system.
void update()
Updates the system state to that of the current frame.
void preUpdate()
Run the pre-update method of the system.
Typed component system managing a pool of components with the given ComponentType.
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.
Definition: Context.h:83
class ComponentSystemBase * getExtensionSystem(const uint16_t id)
Retrieve the system with the given id.
Definition: Context.cpp:416
std::unique_ptr< class Variables > variables
Variables service instance.
Definition: Context.h:180
std::unique_ptr< class Time > time
Time service instance.
Definition: Context.h:198
std::unique_ptr< class Engine > engine
Engine instance.
Definition: Context.h:222
Log implementation class.
Definition: LogManager.h:140
static const Type & getType()
Get the Type of the given template argument.
Definition: TypeDatabase.h:168
Represents a discrete type definition, describing a native type class.
Definition: Type.h:89
constexpr bool isValid() const
Gets if the type is considered a valid, registered type.
Definition: Type.h:328
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:50
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.
@ TexturesFailed
One or more new textures have started fetching.
@ TexturesReady
All textures required have been fetched successfully, will be used next frame.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Handle to a Component instance.
Definition: Component.h:67
ComponentType * resolveComponent() const
Definition: Component.h:90
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
ComponentHandle createComponent() override
void destroyComponent(ComponentHandle handle) override