Adding a simple manual exposure control to configure the tonemapping and expose it to js. Add a convenient way to access the Job._concept._data with template

This commit is contained in:
samcake 2015-12-15 18:18:42 -08:00
parent 2bbd5d86b8
commit d2ebaef69e
18 changed files with 165 additions and 12 deletions

View file

@ -109,6 +109,11 @@ panel.newCheckbox("Network/Physics status",
function(value) { return (value & showNetworkStatusFlag) > 0; } function(value) { return (value & showNetworkStatusFlag) > 0; }
); );
panel.newSlider("Tone Mapping Exposure", -10, 10,
function (value) { Scene.setEngineToneMappingExposure(value); },
function() { return Scene.getEngineToneMappingExposure(); },
function (value) { return (value); });
var tickTackPeriod = 500; var tickTackPeriod = 500;
function updateCounters() { function updateCounters() {

View file

@ -3691,6 +3691,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
renderContext._occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugAmbientOcclusion); renderContext._occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugAmbientOcclusion);
renderContext._fxaaStatus = Menu::getInstance()->isOptionChecked(MenuOption::Antialiasing); renderContext._fxaaStatus = Menu::getInstance()->isOptionChecked(MenuOption::Antialiasing);
renderContext._toneMappingExposure = sceneInterface->getEngineToneMappingExposure();
renderArgs->_shouldRender = LODManager::shouldRender; renderArgs->_shouldRender = LODManager::shouldRender;
renderContext.args = renderArgs; renderContext.args = renderArgs;

View file

@ -311,6 +311,12 @@ void Batch::blit(const FramebufferPointer& src, const Vec4i& srcViewport,
_params.push_back(dstViewport.w); _params.push_back(dstViewport.w);
} }
void Batch::generateTextureMipmap(const TexturePointer& texture) {
ADD_COMMAND(generateTextureMipmap);
_params.push_back(_textures.cache(texture));
}
void Batch::beginQuery(const QueryPointer& query) { void Batch::beginQuery(const QueryPointer& query) {
ADD_COMMAND(beginQuery); ADD_COMMAND(beginQuery);

View file

@ -211,6 +211,9 @@ public:
// with xy and zw the bounding corners of the rect region. // with xy and zw the bounding corners of the rect region.
void blit(const FramebufferPointer& src, const Vec4i& srcRect, const FramebufferPointer& dst, const Vec4i& dstRect); void blit(const FramebufferPointer& src, const Vec4i& srcRect, const FramebufferPointer& dst, const Vec4i& dstRect);
// Generate the mipmap for a texture
void generateTextureMipmap(const TexturePointer& texture);
// Query Section // Query Section
void beginQuery(const QueryPointer& query); void beginQuery(const QueryPointer& query);
void endQuery(const QueryPointer& query); void endQuery(const QueryPointer& query);
@ -292,6 +295,7 @@ public:
COMMAND_setFramebuffer, COMMAND_setFramebuffer,
COMMAND_clearFramebuffer, COMMAND_clearFramebuffer,
COMMAND_blit, COMMAND_blit,
COMMAND_generateTextureMipmap,
COMMAND_beginQuery, COMMAND_beginQuery,
COMMAND_endQuery, COMMAND_endQuery,

View file

@ -52,6 +52,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
(&::gpu::GLBackend::do_setFramebuffer), (&::gpu::GLBackend::do_setFramebuffer),
(&::gpu::GLBackend::do_clearFramebuffer), (&::gpu::GLBackend::do_clearFramebuffer),
(&::gpu::GLBackend::do_blit), (&::gpu::GLBackend::do_blit),
(&::gpu::GLBackend::do_generateTextureMipmap),
(&::gpu::GLBackend::do_beginQuery), (&::gpu::GLBackend::do_beginQuery),
(&::gpu::GLBackend::do_endQuery), (&::gpu::GLBackend::do_endQuery),

View file

@ -376,12 +376,16 @@ protected:
// Resource Stage // Resource Stage
void do_setResourceTexture(Batch& batch, size_t paramOffset); void do_setResourceTexture(Batch& batch, size_t paramOffset);
// update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s
void releaseResourceTexture(uint32_t slot); void releaseResourceTexture(uint32_t slot);
void resetResourceStage(); void resetResourceStage();
struct ResourceStageState { struct ResourceStageState {
Textures _textures; Textures _textures;
int findEmptyTextureSlot() const;
ResourceStageState(): ResourceStageState():
_textures(MAX_NUM_RESOURCE_TEXTURES, nullptr) _textures(MAX_NUM_RESOURCE_TEXTURES, nullptr)
{} {}
@ -432,6 +436,7 @@ protected:
void do_setFramebuffer(Batch& batch, size_t paramOffset); void do_setFramebuffer(Batch& batch, size_t paramOffset);
void do_clearFramebuffer(Batch& batch, size_t paramOffset); void do_clearFramebuffer(Batch& batch, size_t paramOffset);
void do_blit(Batch& batch, size_t paramOffset); void do_blit(Batch& batch, size_t paramOffset);
void do_generateTextureMipmap(Batch& batch, size_t paramOffset);
// Synchronize the state cache of this Backend with the actual real state of the GL Context // Synchronize the state cache of this Backend with the actual real state of the GL Context
void syncOutputStateCache(); void syncOutputStateCache();

View file

@ -361,4 +361,4 @@ void GLBackend::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, co
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
(void) CHECK_GL_ERROR(); (void) CHECK_GL_ERROR();
} }

View file

@ -231,6 +231,7 @@ void GLBackend::releaseResourceTexture(uint32_t slot) {
} }
} }
void GLBackend::resetResourceStage() { void GLBackend::resetResourceStage() {
for (uint32_t i = 0; i < _resource._textures.size(); i++) { for (uint32_t i = 0; i < _resource._textures.size(); i++) {
releaseResourceTexture(i); releaseResourceTexture(i);
@ -268,3 +269,13 @@ void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) {
} }
} }
int GLBackend::ResourceStageState::findEmptyTextureSlot() const {
// start from the end of the slots, try to find an empty one that can be used
for (auto i = MAX_NUM_RESOURCE_TEXTURES - 1; i > 0; i--) {
if (!_textures[i]) {
return i;
}
}
return -1;
}

View file

@ -404,8 +404,9 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) {
if (bytes && texture.isAutogenerateMips()) { if (bytes && texture.isAutogenerateMips()) {
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
} else if (texture.isAutogenerateMips()) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
} }
object->_target = GL_TEXTURE_2D; object->_target = GL_TEXTURE_2D;
syncSampler(texture.getSampler(), texture.getType(), object); syncSampler(texture.getSampler(), texture.getType(), object);
@ -588,3 +589,37 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTextur
glTexParameterf(object->_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); glTexParameterf(object->_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());
} }
void GLBackend::do_generateTextureMipmap(Batch& batch, size_t paramOffset) {
TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
if (!resourceTexture) {
return;
}
GLTexture* object = GLBackend::syncGPUObject(*resourceTexture);
if (!object) {
return;
}
// IN 4.1 we still need to find an available slot
auto freeSlot = _resource.findEmptyTextureSlot();
auto bindingSlot = (freeSlot < 0 ? 0 : freeSlot);
glActiveTexture(GL_TEXTURE0 + bindingSlot);
glBindTexture(object->_target, object->_texture);
glGenerateMipmap(object->_target);
if (freeSlot < 0) {
// If had to use slot 0 then restore state
GLTexture* boundObject = GLBackend::syncGPUObject(*_resource._textures[0]);
if (boundObject) {
glBindTexture(boundObject->_target, boundObject->_texture);
}
} else {
// clean up
glBindTexture(object->_target, 0);
}
(void)CHECK_GL_ERROR();
}

View file

@ -49,7 +49,7 @@ static const std::string FUNCTIONS_PLACEHOLDER { "/*FUNCTIONS_PLACEHOLDER*/" };
std::string DebugDeferredBuffer::getCode(Modes mode) { std::string DebugDeferredBuffer::getCode(Modes mode) {
switch (mode) { switch (mode) {
case DiffuseMode: { case DiffuseMode: {
QString code = "return vec4(texture(%1, uv).xyz, 1.0);"; QString code = "return vec4(pow(texture(%1, uv).xyz, vec3(1.0 / 2.2)), 1.0);";
return code.arg(SLOT_NAMES[Diffuse].c_str()).toStdString(); return code.arg(SLOT_NAMES[Diffuse].c_str()).toStdString();
} }
case AlphaMode: { case AlphaMode: {
@ -73,7 +73,7 @@ std::string DebugDeferredBuffer::getCode(Modes mode) {
return code.arg(SLOT_NAMES[Depth].c_str()).toStdString(); return code.arg(SLOT_NAMES[Depth].c_str()).toStdString();
} }
case LightingMode: { case LightingMode: {
QString code = "return vec4(texture(%1, uv).xyz, 1.0);"; QString code = "return vec4(pow(texture(%1, uv).xyz, vec3(1.0 / 2.2)), 1.0);";
return code.arg(SLOT_NAMES[Lighting].c_str()).toStdString(); return code.arg(SLOT_NAMES[Lighting].c_str()).toStdString();
} }
case CustomMode: case CustomMode:

View file

@ -87,9 +87,11 @@ void FramebufferCache::createPrimaryFramebuffer() {
auto tex = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width * 0.5, height * 0.5, defaultSampler)); auto tex = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width * 0.5, height * 0.5, defaultSampler));
_selfieFramebuffer->setRenderBuffer(0, tex); _selfieFramebuffer->setRenderBuffer(0, tex);
auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR);
//_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, defaultSampler)); //_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, defaultSampler));
//lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::R11G11B10), width, height, defaultSampler)); //lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::R11G11B10), width, height, defaultSampler));
_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, defaultSampler)); _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, smoothSampler));
_lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
_lightingFramebuffer->setRenderBuffer(0, _lightingTexture); _lightingFramebuffer->setRenderBuffer(0, _lightingTexture);
_lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); _lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);

View file

@ -104,6 +104,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
// Lighting Buffer ready for tone mapping // Lighting Buffer ready for tone mapping
_jobs.push_back(Job(new ToneMappingDeferred::JobModel("ToneMapping"))); _jobs.push_back(Job(new ToneMappingDeferred::JobModel("ToneMapping")));
_toneMappingJobIndex = _jobs.size() - 1;
// Debugging Deferred buffer job // Debugging Deferred buffer job
_jobs.push_back(Job(new DebugDeferredBuffer::JobModel("DebugDeferredBuffer"))); _jobs.push_back(Job(new DebugDeferredBuffer::JobModel("DebugDeferredBuffer")));
@ -164,6 +165,8 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend
setAntialiasingStatus(renderContext->_fxaaStatus); setAntialiasingStatus(renderContext->_fxaaStatus);
setToneMappingExposure(renderContext->_toneMappingExposure);
renderContext->args->_context->syncCache(); renderContext->args->_context->syncCache();
for (auto job : _jobs) { for (auto job : _jobs) {
@ -390,3 +393,18 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const
}); });
args->_batch = nullptr; args->_batch = nullptr;
} }
void RenderDeferredTask::setToneMappingExposure(float exposure) {
if (_toneMappingJobIndex >= 0) {
_jobs[_toneMappingJobIndex].edit<ToneMappingDeferred>()._toneMappingEffect.setExposure(exposure);
}
}
float RenderDeferredTask::getToneMappingExposure() const {
if (_toneMappingJobIndex >= 0) {
_jobs[_toneMappingJobIndex].get<ToneMappingDeferred>()._toneMappingEffect.getExposure();
} else {
return 0.0f;
}
}

View file

@ -129,6 +129,11 @@ public:
void setAntialiasingStatus(bool draw) { if (_antialiasingJobIndex >= 0) { _jobs[_antialiasingJobIndex].setEnabled(draw); } } void setAntialiasingStatus(bool draw) { if (_antialiasingJobIndex >= 0) { _jobs[_antialiasingJobIndex].setEnabled(draw); } }
bool doAntialiasingStatus() const { if (_antialiasingJobIndex >= 0) { return _jobs[_antialiasingJobIndex].isEnabled(); } else { return false; } } bool doAntialiasingStatus() const { if (_antialiasingJobIndex >= 0) { return _jobs[_antialiasingJobIndex].isEnabled(); } else { return false; } }
int _toneMappingJobIndex = -1;
void setToneMappingExposure(float exposure);
float getToneMappingExposure() const;
virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);

View file

@ -20,7 +20,8 @@
ToneMappingEffect::ToneMappingEffect() { ToneMappingEffect::ToneMappingEffect() {
Parameters parameters;
_parametersBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Parameters), (const gpu::Byte*) &parameters));
} }
void ToneMappingEffect::init() { void ToneMappingEffect::init() {
@ -38,6 +39,16 @@ void ToneMappingEffect::init() {
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
struct ToneMappingParams {
vec4 _exp_2powExp_s0_s1;
};
uniform toneMappingParamsBuffer {
ToneMappingParams params;
};
float getTwoPowExposure() {
return params._exp_2powExp_s0_s1.y;
}
uniform sampler2D colorMap; uniform sampler2D colorMap;
@ -45,16 +56,24 @@ void ToneMappingEffect::init() {
out vec4 outFragColor; out vec4 outFragColor;
void main(void) { void main(void) {
vec4 fragColor = texture(colorMap, varTexCoord0); vec4 fragColorRaw = textureLod(colorMap, varTexCoord0, 0);
vec3 fragColor = fragColorRaw.xyz;
/* vec4 fragColorAverage = textureLod(colorMap, varTexCoord0, 10);
float averageIntensity = length(fragColorAverage.xyz);
vec3 fragColor = fragColorRaw.xyz / averageIntensity;
*/
fragColor *= getTwoPowExposure();
// if (gl_FragCoord.x > 1000) { // if (gl_FragCoord.x > 1000) {
// Manually gamma correct from Ligthing BUffer to color buffer // Manually gamma correct from Ligthing BUffer to color buffer
// outFragColor.xyz = pow( fragColor.xyz , vec3(1.0 / 2.2) ); // outFragColor.xyz = pow( fragColor.xyz , vec3(1.0 / 2.2) );
fragColor *= 2.0; // Hardcoded Exposure Adjustment
vec3 x = max(vec3(0.0),fragColor.xyz-0.004); vec3 x = max(vec3(0.0),fragColor.xyz-0.004);
vec3 retColor = (x*(6.2*x+.5))/(x*(6.2*x+1.7)+0.06); vec3 retColor = (x*(6.2*x+.5))/(x*(6.2*x+1.7)+0.06);
// fragColor *= 8; // Hardcoded Exposure Adjustment
// fragColor = fragColor/(1.0+fragColor); // fragColor = fragColor/(1.0+fragColor);
// vec3 retColor = pow(fragColor.xyz,vec3(1/2.2)); // vec3 retColor = pow(fragColor.xyz,vec3(1/2.2));
@ -70,12 +89,19 @@ void ToneMappingEffect::init() {
auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(blitVS, blitPS)); auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(blitVS, blitPS));
//auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); //auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS);
gpu::Shader::makeProgram(*blitProgram); gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("toneMappingParamsBuffer"), 3));
gpu::Shader::makeProgram(*blitProgram, slotBindings);
auto blitState = std::make_shared<gpu::State>(); auto blitState = std::make_shared<gpu::State>();
blitState->setColorWriteMask(true, true, true, true); blitState->setColorWriteMask(true, true, true, true);
_blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState)); _blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState));
} }
void ToneMappingEffect::setExposure(float exposure) {
_parametersBuffer.edit<Parameters>()._exposure = exposure;
_parametersBuffer.edit<Parameters>()._twoPowExposure = pow(2.0, exposure);
}
void ToneMappingEffect::render(RenderArgs* args) { void ToneMappingEffect::render(RenderArgs* args) {
if (!_blitLightBuffer) { if (!_blitLightBuffer) {
@ -89,6 +115,9 @@ void ToneMappingEffect::render(RenderArgs* args) {
auto lightingBuffer = framebufferCache->getLightingTexture(); auto lightingBuffer = framebufferCache->getLightingTexture();
auto destFbo = framebufferCache->getPrimaryFramebuffer(); auto destFbo = framebufferCache->getPrimaryFramebuffer();
batch.setFramebuffer(destFbo); batch.setFramebuffer(destFbo);
batch.generateTextureMipmap(lightingBuffer);
batch.setViewportTransform(args->_viewport); batch.setViewportTransform(args->_viewport);
batch.setProjectionTransform(glm::mat4()); batch.setProjectionTransform(glm::mat4());
batch.setViewTransform(Transform()); batch.setViewTransform(Transform());
@ -104,6 +133,7 @@ void ToneMappingEffect::render(RenderArgs* args) {
batch.setModelTransform(model); batch.setModelTransform(model);
} }
batch.setUniformBuffer(3, _parametersBuffer);
batch.setResourceTexture(0, lightingBuffer); batch.setResourceTexture(0, lightingBuffer);
batch.draw(gpu::TRIANGLE_STRIP, 4); batch.draw(gpu::TRIANGLE_STRIP, 4);

View file

@ -27,6 +27,9 @@ public:
void render(RenderArgs* args); void render(RenderArgs* args);
void setExposure(float exposure);
float getExposure() const { return _parametersBuffer.get<Parameters>()._exposure; }
private: private:
gpu::PipelinePointer _blitLightBuffer; gpu::PipelinePointer _blitLightBuffer;
@ -34,7 +37,10 @@ private:
// Class describing the uniform buffer with all the parameters common to the tone mapping shaders // Class describing the uniform buffer with all the parameters common to the tone mapping shaders
class Parameters { class Parameters {
public: public:
float _exposure = 0.0f;
float _twoPowExposure = 1.0f;
glm::vec2 spare;
Parameters() {} Parameters() {}
}; };
typedef gpu::BufferView UniformBufferView; typedef gpu::BufferView UniformBufferView;

View file

@ -84,6 +84,23 @@ public:
const Varying getInput() const { return _concept->getInput(); } const Varying getInput() const { return _concept->getInput(); }
const Varying getOutput() const { return _concept->getOutput(); } const Varying getOutput() const { return _concept->getOutput(); }
template <class T> T& edit() {
auto theConcept = std::dynamic_pointer_cast<typename T::JobModel>(_concept);
if (theConcept) {
return theConcept->_data;
}
assert(false);
return T();
}
template <class T> const T& get() const {
auto theConcept = std::dynamic_pointer_cast<typename T::JobModel>(_concept);
if (theConcept) {
return theConcept->_data;
}
assert(false);
return T();
}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
PerformanceTimer perfTimer(getName().c_str()); PerformanceTimer perfTimer(getName().c_str());
PROFILE_RANGE(getName().c_str()); PROFILE_RANGE(getName().c_str());

View file

@ -61,6 +61,8 @@ public:
bool _occlusionStatus = false; bool _occlusionStatus = false;
bool _fxaaStatus = false; bool _fxaaStatus = false;
float _toneMappingExposure = 0.0;
RenderContext() {} RenderContext() {}
}; };
typedef std::shared_ptr<RenderContext> RenderContextPointer; typedef std::shared_ptr<RenderContext> RenderContextPointer;

View file

@ -118,6 +118,9 @@ public:
Q_INVOKABLE void setEngineDisplayHitEffect(bool display) { _drawHitEffect = display; } Q_INVOKABLE void setEngineDisplayHitEffect(bool display) { _drawHitEffect = display; }
Q_INVOKABLE bool doEngineDisplayHitEffect() { return _drawHitEffect; } Q_INVOKABLE bool doEngineDisplayHitEffect() { return _drawHitEffect; }
Q_INVOKABLE void setEngineToneMappingExposure(float exposure) { _engineToneMappingExposure = exposure; }
Q_INVOKABLE float getEngineToneMappingExposure() { return _engineToneMappingExposure; }
signals: signals:
void shouldRenderAvatarsChanged(bool shouldRenderAvatars); void shouldRenderAvatarsChanged(bool shouldRenderAvatars);
void shouldRenderEntitiesChanged(bool shouldRenderEntities); void shouldRenderEntitiesChanged(bool shouldRenderEntities);
@ -154,6 +157,7 @@ protected:
bool _drawHitEffect = false; bool _drawHitEffect = false;
float _engineToneMappingExposure = 0.0f;
}; };
#endif // hifi_SceneScriptingInterface_h #endif // hifi_SceneScriptingInterface_h