mirror of
https://github.com/overte-org/overte.git
synced 2025-04-23 03:53:34 +02:00
INtroducing the tonemapping job in its separate file and clean DeferredLightingEffect
This commit is contained in:
parent
c55c1e0d7f
commit
5d207d0c9c
6 changed files with 209 additions and 120 deletions
|
@ -82,7 +82,7 @@ gpu::PipelinePointer DeferredLightingEffect::getPipeline(SimpleProgramKey config
|
|||
return pipeline;
|
||||
}
|
||||
|
||||
void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
||||
void DeferredLightingEffect::init() {
|
||||
auto VS = gpu::Shader::createVertex(std::string(simple_vert));
|
||||
auto PS = gpu::Shader::createPixel(std::string(simple_textured_frag));
|
||||
auto PSEmissive = gpu::Shader::createPixel(std::string(simple_textured_emisive_frag));
|
||||
|
@ -95,7 +95,7 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
|||
gpu::Shader::makeProgram(*_simpleShader, slotBindings);
|
||||
gpu::Shader::makeProgram(*_emissiveShader, slotBindings);
|
||||
|
||||
_viewState = viewState;
|
||||
|
||||
_directionalLightLocations = std::make_shared<LightLocations>();
|
||||
_directionalAmbientSphereLightLocations = std::make_shared<LightLocations>();
|
||||
_directionalSkyboxLightLocations = std::make_shared<LightLocations>();
|
||||
|
@ -112,49 +112,6 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
|||
loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations);
|
||||
loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations);
|
||||
|
||||
{
|
||||
//auto VSFS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
//auto PSBlit = gpu::StandardShaderLib::getDrawTexturePS();
|
||||
const char BlitTextureGamma_frag[] = R"SCRIBE(#version 410 core
|
||||
// Generated on Sat Oct 24 09:34:37 2015
|
||||
//
|
||||
// Draw texture 0 fetched at texcoord.xy
|
||||
//
|
||||
// Created by Sam Gateau on 6/22/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
uniform sampler2D colorMap;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
outFragColor = texture(colorMap, varTexCoord0);
|
||||
// if (gl_FragCoord.x > 1000) {
|
||||
// Manually gamma correct from Ligthing BUffer to color buffer
|
||||
outFragColor.xyz = pow( outFragColor.xyz , vec3(1.0 / 2.2) );
|
||||
// }
|
||||
}
|
||||
|
||||
)SCRIBE";
|
||||
auto blitPS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(BlitTextureGamma_frag)));
|
||||
|
||||
//auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS);
|
||||
auto blitVS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(blitVS, blitPS));
|
||||
|
||||
//auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS);
|
||||
gpu::Shader::makeProgram(*blitProgram);
|
||||
auto blitState = std::make_shared<gpu::State>();
|
||||
blitState->setColorWriteMask(true, true, true, true);
|
||||
_blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState));
|
||||
}
|
||||
|
||||
// Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light
|
||||
_globalLights.push_back(0);
|
||||
_allocatedLights.push_back(std::make_shared<model::Light>());
|
||||
|
@ -694,37 +651,6 @@ void DeferredLightingEffect::render(RenderArgs* args) {
|
|||
}
|
||||
|
||||
|
||||
void DeferredLightingEffect::copyBack(RenderArgs* args) {
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
QSize framebufferSize = framebufferCache->getFrameBufferSize();
|
||||
|
||||
auto lightingBuffer = framebufferCache->getLightingTexture();
|
||||
auto destFbo = framebufferCache->getPrimaryFramebufferDepthColor();
|
||||
batch.setFramebuffer(destFbo);
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setProjectionTransform(glm::mat4());
|
||||
batch.setViewTransform(Transform());
|
||||
{
|
||||
float sMin = args->_viewport.x / (float)framebufferSize.width();
|
||||
float sWidth = args->_viewport.z / (float)framebufferSize.width();
|
||||
float tMin = args->_viewport.y / (float)framebufferSize.height();
|
||||
float tHeight = args->_viewport.w / (float)framebufferSize.height();
|
||||
Transform model;
|
||||
batch.setPipeline(_blitLightBuffer);
|
||||
model.setTranslation(glm::vec3(sMin, tMin, 0.0));
|
||||
model.setScale(glm::vec3(sWidth, tHeight, 1.0));
|
||||
batch.setModelTransform(model);
|
||||
}
|
||||
|
||||
batch.setResourceTexture(0, lightingBuffer);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
args->_context->render(batch);
|
||||
});
|
||||
}
|
||||
|
||||
void DeferredLightingEffect::setupTransparent(RenderArgs* args, int lightBufferUnit) {
|
||||
auto globalLight = _allocatedLights[_globalLights.front()];
|
||||
args->_batch->setUniformBuffer(lightBufferUnit, globalLight->getSchemaBuffer());
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "model/Stage.h"
|
||||
#include "model/Geometry.h"
|
||||
|
||||
class AbstractViewStateInterface;
|
||||
class RenderArgs;
|
||||
class SimpleProgramKey;
|
||||
struct LightLocations;
|
||||
|
@ -78,7 +77,6 @@ public:
|
|||
|
||||
void prepare(RenderArgs* args);
|
||||
void render(RenderArgs* args);
|
||||
void copyBack(RenderArgs* args);
|
||||
|
||||
void setupTransparent(RenderArgs* args, int lightBufferUnit);
|
||||
|
||||
|
@ -101,9 +99,7 @@ private:
|
|||
gpu::ShaderPointer _simpleShader;
|
||||
gpu::ShaderPointer _emissiveShader;
|
||||
QHash<SimpleProgramKey, gpu::PipelinePointer> _simplePrograms;
|
||||
|
||||
gpu::PipelinePointer _blitLightBuffer;
|
||||
|
||||
|
||||
gpu::PipelinePointer _directionalSkyboxLight;
|
||||
LightLocationsPtr _directionalSkyboxLightLocations;
|
||||
|
||||
|
@ -143,8 +139,6 @@ private:
|
|||
std::vector<int> _globalLights;
|
||||
std::vector<int> _pointLights;
|
||||
std::vector<int> _spotLights;
|
||||
|
||||
AbstractViewStateInterface* _viewState;
|
||||
|
||||
int _ambientLightMode = 0;
|
||||
model::AtmospherePointer _atmosphere;
|
||||
|
|
|
@ -44,67 +44,85 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo
|
|||
DependencyManager::get<DeferredLightingEffect>()->render(renderContext->args);
|
||||
}
|
||||
|
||||
void ResolveDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
PerformanceTimer perfTimer("ResolveDeferred");
|
||||
DependencyManager::get<DeferredLightingEffect>()->copyBack(renderContext->args);
|
||||
void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
PerformanceTimer perfTimer("ToneMappingDeferred");
|
||||
_toneMappingEffect.render(renderContext->args);
|
||||
}
|
||||
|
||||
RenderDeferredTask::RenderDeferredTask() : Task() {
|
||||
_jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred")));
|
||||
// CPU only, create the list of renderedOpaques items
|
||||
_jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque",
|
||||
FetchItems(
|
||||
[] (const RenderContextPointer& context, int count) {
|
||||
context->_numFeedOpaqueItems = count;
|
||||
}
|
||||
[](const RenderContextPointer& context, int count) {
|
||||
context->_numFeedOpaqueItems = count;
|
||||
}
|
||||
)
|
||||
)));
|
||||
)));
|
||||
_jobs.push_back(Job(new CullItemsOpaque::JobModel("CullOpaque", _jobs.back().getOutput())));
|
||||
_jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortOpaque", _jobs.back().getOutput())));
|
||||
auto& renderedOpaques = _jobs.back().getOutput();
|
||||
_jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", _jobs.back().getOutput())));
|
||||
|
||||
// CPU only, create the list of renderedTransparents items
|
||||
_jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent",
|
||||
FetchItems(
|
||||
ItemFilter::Builder::transparentShape().withoutLayered(),
|
||||
[](const RenderContextPointer& context, int count) {
|
||||
context->_numFeedTransparentItems = count;
|
||||
}
|
||||
)
|
||||
)));
|
||||
_jobs.push_back(Job(new CullItemsTransparent::JobModel("CullTransparent", _jobs.back().getOutput())));
|
||||
_jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false))));
|
||||
auto& renderedTransparents = _jobs.back().getOutput();
|
||||
|
||||
// GPU Jobs: Start preparing the deferred and lighting buffer
|
||||
_jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred")));
|
||||
|
||||
// Render opaque objects in DeferredBuffer
|
||||
_jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", renderedOpaques)));
|
||||
|
||||
// Once opaque is all rendered create stencil background
|
||||
_jobs.push_back(Job(new DrawStencilDeferred::JobModel("DrawOpaqueStencil")));
|
||||
|
||||
// Use Stencil and start drawing background in Lighting buffer
|
||||
_jobs.push_back(Job(new DrawBackgroundDeferred::JobModel("DrawBackgroundDeferred")));
|
||||
|
||||
// Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now.
|
||||
_jobs.push_back(Job(new DrawLight::JobModel("DrawLight")));
|
||||
_jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred")));
|
||||
_jobs.push_back(Job(new ResolveDeferred::JobModel("ResolveDeferred")));
|
||||
_jobs.push_back(Job(new AmbientOcclusion::JobModel("AmbientOcclusion")));
|
||||
|
||||
// DeferredBuffer is complete, now let's shade it into the LightingBuffer
|
||||
_jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred")));
|
||||
|
||||
// AO job, to be revisited
|
||||
_jobs.push_back(Job(new AmbientOcclusion::JobModel("AmbientOcclusion")));
|
||||
_jobs.back().setEnabled(false);
|
||||
_occlusionJobIndex = _jobs.size() - 1;
|
||||
|
||||
// AA job to be revisited
|
||||
_jobs.push_back(Job(new Antialiasing::JobModel("Antialiasing")));
|
||||
|
||||
_jobs.back().setEnabled(false);
|
||||
_antialiasingJobIndex = _jobs.size() - 1;
|
||||
|
||||
_jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent",
|
||||
FetchItems(
|
||||
ItemFilter::Builder::transparentShape().withoutLayered(),
|
||||
[] (const RenderContextPointer& context, int count) {
|
||||
context->_numFeedTransparentItems = count;
|
||||
}
|
||||
)
|
||||
)));
|
||||
_jobs.push_back(Job(new CullItemsTransparent::JobModel("CullTransparent", _jobs.back().getOutput())));
|
||||
|
||||
|
||||
_jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false))));
|
||||
_jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", _jobs.back().getOutput())));
|
||||
// Render transparent objects forward in LigthingBuffer
|
||||
_jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", renderedTransparents)));
|
||||
|
||||
// Lighting Buffer ready for tone mapping
|
||||
_jobs.push_back(Job(new ToneMappingDeferred::JobModel("ToneMapping")));
|
||||
|
||||
// Debugging Deferred buffer job
|
||||
_jobs.push_back(Job(new DebugDeferredBuffer::JobModel("DebugDeferredBuffer")));
|
||||
_jobs.back().setEnabled(false);
|
||||
_drawDebugDeferredBufferIndex = _jobs.size() - 1;
|
||||
|
||||
// Grab a texture map representing the different status icons and assign that to the drawStatsuJob
|
||||
auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg";
|
||||
|
||||
auto statusIconMap = DependencyManager::get<TextureCache>()->getImageTexture(iconMapPath);
|
||||
_jobs.push_back(Job(new render::DrawStatus::JobModel("DrawStatus", renderedOpaques, DrawStatus(statusIconMap))));
|
||||
|
||||
_jobs.back().setEnabled(false);
|
||||
_drawStatusJobIndex = _jobs.size() - 1;
|
||||
// Status icon rendering job
|
||||
{
|
||||
// Grab a texture map representing the different status icons and assign that to the drawStatsuJob
|
||||
auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg";
|
||||
auto statusIconMap = DependencyManager::get<TextureCache>()->getImageTexture(iconMapPath);
|
||||
_jobs.push_back(Job(new render::DrawStatus::JobModel("DrawStatus", renderedOpaques, DrawStatus(statusIconMap))));
|
||||
_jobs.back().setEnabled(false);
|
||||
_drawStatusJobIndex = _jobs.size() - 1;
|
||||
}
|
||||
|
||||
_jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D")));
|
||||
|
||||
|
@ -112,7 +130,6 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
|||
_jobs.back().setEnabled(false);
|
||||
_drawHitEffectJobIndex = _jobs.size() -1;
|
||||
|
||||
|
||||
// Give ourselves 3 frmaes of timer queries
|
||||
_timerQueries.push_back(std::make_shared<gpu::Query>());
|
||||
_timerQueries.push_back(std::make_shared<gpu::Query>());
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include "gpu/Pipeline.h"
|
||||
|
||||
#include "ToneMappingEffect.h"
|
||||
|
||||
class SetupDeferred {
|
||||
public:
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
|
@ -38,11 +40,13 @@ public:
|
|||
typedef render::Job::Model<RenderDeferred> JobModel;
|
||||
};
|
||||
|
||||
class ResolveDeferred {
|
||||
class ToneMappingDeferred {
|
||||
public:
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
|
||||
typedef render::Job::Model<ResolveDeferred> JobModel;
|
||||
ToneMappingEffect _toneMappingEffect;
|
||||
|
||||
typedef render::Job::Model<ToneMappingDeferred> JobModel;
|
||||
};
|
||||
|
||||
class DrawOpaqueDeferred {
|
||||
|
|
102
libraries/render-utils/src/ToneMappingEffect.cpp
Normal file
102
libraries/render-utils/src/ToneMappingEffect.cpp
Normal file
|
@ -0,0 +1,102 @@
|
|||
//
|
||||
// ToneMappingEffect.cpp
|
||||
// libraries/render-utils/src
|
||||
//
|
||||
// Created by Sam Gateau on 12/7/2015.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ToneMappingEffect.h"
|
||||
|
||||
#include <gpu/Context.h>
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include <RenderArgs.h>
|
||||
|
||||
#include "FramebufferCache.h"
|
||||
|
||||
|
||||
ToneMappingEffect::ToneMappingEffect() {
|
||||
|
||||
}
|
||||
|
||||
void ToneMappingEffect::init() {
|
||||
//auto VSFS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
//auto PSBlit = gpu::StandardShaderLib::getDrawTexturePS();
|
||||
const char BlitTextureGamma_frag[] = R"SCRIBE(#version 410 core
|
||||
// Generated on Sat Oct 24 09:34:37 2015
|
||||
//
|
||||
// Draw texture 0 fetched at texcoord.xy
|
||||
//
|
||||
// Created by Sam Gateau on 6/22/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
uniform sampler2D colorMap;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
outFragColor = texture(colorMap, varTexCoord0);
|
||||
// if (gl_FragCoord.x > 1000) {
|
||||
// Manually gamma correct from Ligthing BUffer to color buffer
|
||||
outFragColor.xyz = pow( outFragColor.xyz , vec3(1.0 / 2.2) );
|
||||
// }
|
||||
}
|
||||
|
||||
)SCRIBE";
|
||||
auto blitPS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(BlitTextureGamma_frag)));
|
||||
|
||||
//auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS);
|
||||
auto blitVS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(blitVS, blitPS));
|
||||
|
||||
//auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS);
|
||||
gpu::Shader::makeProgram(*blitProgram);
|
||||
auto blitState = std::make_shared<gpu::State>();
|
||||
blitState->setColorWriteMask(true, true, true, true);
|
||||
_blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState));
|
||||
}
|
||||
|
||||
|
||||
void ToneMappingEffect::render(RenderArgs* args) {
|
||||
if (!_blitLightBuffer) {
|
||||
init();
|
||||
}
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
QSize framebufferSize = framebufferCache->getFrameBufferSize();
|
||||
|
||||
auto lightingBuffer = framebufferCache->getLightingTexture();
|
||||
auto destFbo = framebufferCache->getPrimaryFramebufferDepthColor();
|
||||
batch.setFramebuffer(destFbo);
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setProjectionTransform(glm::mat4());
|
||||
batch.setViewTransform(Transform());
|
||||
{
|
||||
float sMin = args->_viewport.x / (float)framebufferSize.width();
|
||||
float sWidth = args->_viewport.z / (float)framebufferSize.width();
|
||||
float tMin = args->_viewport.y / (float)framebufferSize.height();
|
||||
float tHeight = args->_viewport.w / (float)framebufferSize.height();
|
||||
Transform model;
|
||||
batch.setPipeline(_blitLightBuffer);
|
||||
model.setTranslation(glm::vec3(sMin, tMin, 0.0));
|
||||
model.setScale(glm::vec3(sWidth, tHeight, 1.0));
|
||||
batch.setModelTransform(model);
|
||||
}
|
||||
|
||||
batch.setResourceTexture(0, lightingBuffer);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
args->_context->render(batch);
|
||||
});
|
||||
}
|
46
libraries/render-utils/src/ToneMappingEffect.h
Normal file
46
libraries/render-utils/src/ToneMappingEffect.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// ToneMappingEffect.h
|
||||
// libraries/render-utils/src
|
||||
//
|
||||
// Created by Sam Gateau on 12/7/2015.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ToneMappingEffect_h
|
||||
#define hifi_ToneMappingEffect_h
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
#include <gpu/Resource.h>
|
||||
#include <gpu/Pipeline.h>
|
||||
|
||||
class RenderArgs;
|
||||
|
||||
class ToneMappingEffect {
|
||||
public:
|
||||
ToneMappingEffect();
|
||||
virtual ~ToneMappingEffect() {}
|
||||
|
||||
void render(RenderArgs* args);
|
||||
|
||||
private:
|
||||
|
||||
gpu::PipelinePointer _blitLightBuffer;
|
||||
|
||||
// Class describing the uniform buffer with all the parameters common to the tone mapping shaders
|
||||
class Parameters {
|
||||
public:
|
||||
|
||||
Parameters() {}
|
||||
};
|
||||
typedef gpu::BufferView UniformBufferView;
|
||||
gpu::BufferView _parametersBuffer;
|
||||
|
||||
void init();
|
||||
};
|
||||
|
||||
#endif // hifi_ToneMappingEffect_h
|
Loading…
Reference in a new issue