From c4985f8684d85a2f97140f35586fd7d8623f3abc Mon Sep 17 00:00:00 2001 From: Vsevolod Kremianskii Date: Sun, 16 May 2021 14:08:25 +0700 Subject: [PATCH] Disable back-face culling for particles, grass and etc. --- CMakeLists.txt | 1 - src/engine/graphics/statemanager.cpp | 19 +++- src/engine/graphics/statemanager.h | 7 +- src/engine/scene/node/emitternode.cpp | 73 ++++++++++++--- src/engine/scene/node/emitternode.h | 14 --- .../scene/node/emitternode_particle.cpp | 93 ------------------- src/engine/scene/pipeline/world.cpp | 7 +- src/engine/scene/scenegraph.cpp | 5 + 8 files changed, 87 insertions(+), 132 deletions(-) delete mode 100644 src/engine/scene/node/emitternode_particle.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c6c5fd0c..7e80e7b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -308,7 +308,6 @@ set(SCENE_HEADERS set(SCENE_SOURCES src/engine/scene/node/cameranode.cpp src/engine/scene/node/emitternode.cpp - src/engine/scene/node/emitternode_particle.cpp src/engine/scene/node/grassnode.cpp src/engine/scene/node/lightnode.cpp src/engine/scene/node/meshnode.cpp diff --git a/src/engine/graphics/statemanager.cpp b/src/engine/graphics/statemanager.cpp index 6a51bafe..11e68c7c 100644 --- a/src/engine/graphics/statemanager.cpp +++ b/src/engine/graphics/statemanager.cpp @@ -64,13 +64,13 @@ void StateManager::withDepthTest(const function &block) { } void StateManager::setDepthTestEnabled(bool enabled) { - if (_depthTestEnabled != enabled) { + if (_depthTest != enabled) { if (enabled) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } - _depthTestEnabled = enabled; + _depthTest = enabled; } } @@ -107,9 +107,20 @@ void StateManager::withLightenBlending(const function &block) { } void StateManager::withBackFaceCulling(const function &block) { - glEnable(GL_CULL_FACE); + setBackFaceCullingEnabled(true); block(); - glDisable(GL_CULL_FACE); + setBackFaceCullingEnabled(false); +} + +void StateManager::setBackFaceCullingEnabled(bool enabled) { + if (_backFaceCulling != enabled) { + if (enabled) { + glEnable(GL_CULL_FACE); + } else { + glDisable(GL_CULL_FACE); + } + _backFaceCulling = enabled; + } } void StateManager::setActiveTextureUnit(int n) { diff --git a/src/engine/graphics/statemanager.h b/src/engine/graphics/statemanager.h index 4be96c03..98540f84 100644 --- a/src/engine/graphics/statemanager.h +++ b/src/engine/graphics/statemanager.h @@ -39,14 +39,15 @@ public: void withLightenBlending(const std::function &block); void withBackFaceCulling(const std::function &block); + void setDepthTestEnabled(bool enabled); + void setBackFaceCullingEnabled(bool enabled); void setActiveTextureUnit(int n); private: + bool _depthTest { false }; + bool _backFaceCulling { false }; int _textureUnit { 0 }; - bool _depthTestEnabled { false }; uint32_t _polygonMode { 0 }; - - void setDepthTestEnabled(bool enabled); }; diff --git a/src/engine/scene/node/emitternode.cpp b/src/engine/scene/node/emitternode.cpp index 1689afae..0882378e 100644 --- a/src/engine/scene/node/emitternode.cpp +++ b/src/engine/scene/node/emitternode.cpp @@ -77,9 +77,6 @@ EmitterSceneNode::EmitterSceneNode(const ModelSceneNode *model, shared_ptr camera(_sceneGraph->activeCamera()); - if (!camera) return; - removeExpiredParticles(dt); spawnParticles(dt); @@ -89,19 +86,16 @@ void EmitterSceneNode::update(float dt) { } void EmitterSceneNode::removeExpiredParticles(float dt) { - for (auto it = _particles.begin(); it != _particles.end(); ) { - auto &particle = (*it); - if (isParticleExpired(*particle)) { - it = _particles.erase(it); - } else { - ++it; - } - } + auto expiredParticles = find_if(_particles.begin(), _particles.end(), [this](auto &particle) { return isParticleExpired(*particle); }); + _particles.erase(expiredParticles, _particles.end()); +} + +bool EmitterSceneNode::isParticleExpired(Particle &particle) const { + return _lifeExpectancy != -1.0f && particle.lifetime >= _lifeExpectancy; } void EmitterSceneNode::spawnParticles(float dt) { shared_ptr emitter(_modelNode->emitter()); - switch (emitter->updateMode) { case ModelNode::Emitter::UpdateMode::Fountain: if (_birthrate != 0.0f) { @@ -194,6 +188,61 @@ void EmitterSceneNode::detonate() { doSpawnParticle(); } +void EmitterSceneNode::initParticle(Particle &particle) { + if (_fps > 0.0f) { + particle.animLength = (_frameEnd - _frameStart + 1) / _fps; + } + particle.frame = _frameStart; +} + +void EmitterSceneNode::updateParticle(Particle &particle, float dt) { + shared_ptr emitter(_modelNode->emitter()); + + if (_lifeExpectancy != -1.0f) { + particle.lifetime = glm::min(particle.lifetime + dt, _lifeExpectancy); + } else if (particle.lifetime == particle.animLength) { + particle.lifetime = 0.0f; + } else { + particle.lifetime = glm::min(particle.lifetime + dt, particle.animLength); + } + + if (!isParticleExpired(particle)) { + particle.position.z += particle.velocity * dt; + updateParticleAnimation(particle, dt); + } +} + +template +static T interpolateConstraints(const EmitterSceneNode::Constraints &constraints, float t) { + T result; + if (t < 0.5f) { + float tt = 2.0f * t; + result = (1.0f - tt) * constraints.start + tt * constraints.mid; + } else { + float tt = 2.0f * (t - 0.5f); + result = (1.0f - tt) * constraints.mid + tt * constraints.end; + } + return result; +} + +void EmitterSceneNode::updateParticleAnimation(Particle &particle, float dt) { + shared_ptr emitter(_modelNode->emitter()); + + float maturity; + if (_lifeExpectancy != -1.0f) { + maturity = particle.lifetime / static_cast(_lifeExpectancy); + } else if (particle.animLength > 0.0f) { + maturity = particle.lifetime / particle.animLength; + } else { + maturity = 0.0f; + } + + particle.frame = static_cast(glm::ceil(_frameStart + maturity * (_frameEnd - _frameStart))); + particle.size = interpolateConstraints(_particleSize, maturity); + particle.color = interpolateConstraints(_color, maturity); + particle.alpha = interpolateConstraints(_alpha, maturity); +} + } // namespace scene } // namespace reone diff --git a/src/engine/scene/node/emitternode.h b/src/engine/scene/node/emitternode.h index b2f8d4ca..2ea726c5 100644 --- a/src/engine/scene/node/emitternode.h +++ b/src/engine/scene/node/emitternode.h @@ -17,10 +17,6 @@ #pragma once -#include - -#include "glm/vec3.hpp" - #include "../../common/timer.h" #include "../../graphics/model/modelnode.h" @@ -56,12 +52,6 @@ public: EmitterSceneNode(const ModelSceneNode *model, std::shared_ptr modelNode, SceneGraph *sceneGraph); void update(float dt) override; - - /** - * Renders the specified particles. - * - * @param particles subset of this emitters particles - */ void drawParticles(const std::vector &particles); void detonate(); @@ -94,15 +84,11 @@ private: void removeExpiredParticles(float dt); void doSpawnParticle(); - // Particles - void initParticle(Particle &particle); void updateParticle(Particle &particle, float dt); void updateParticleAnimation(Particle &particle, float dt); bool isParticleExpired(Particle &particle) const; - - // END Particles }; } // namespace scene diff --git a/src/engine/scene/node/emitternode_particle.cpp b/src/engine/scene/node/emitternode_particle.cpp deleted file mode 100644 index 13dfb01b..00000000 --- a/src/engine/scene/node/emitternode_particle.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2020-2021 The reone project contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "emitternode.h" - -using namespace std; - -using namespace reone::graphics; - -namespace reone { - -namespace scene { - -void EmitterSceneNode::initParticle(Particle &particle) { - shared_ptr emitter(_modelNode->emitter()); - - if (_fps > 0) { - particle.animLength = (_frameEnd - _frameStart + 1) / static_cast(_fps); - } - - particle.frame = _frameStart; -} - -void EmitterSceneNode::updateParticle(Particle &particle, float dt) { - shared_ptr emitter(_modelNode->emitter()); - - if (_lifeExpectancy != -1) { - particle.lifetime = glm::min(particle.lifetime + dt, static_cast(_lifeExpectancy)); - } else if (particle.lifetime == particle.animLength) { - particle.lifetime = 0.0f; - } else { - particle.lifetime = glm::min(particle.lifetime + dt, particle.animLength); - } - - if (!isParticleExpired(particle)) { - particle.position.z += particle.velocity * dt; - updateParticleAnimation(particle, dt); - } -} - -template -static T interpolateConstraints(const EmitterSceneNode::Constraints &constraints, float t) { - T result; - if (t < 0.5f) { - float tt = 2.0f * t; - result = (1.0f - tt) * constraints.start + tt * constraints.mid; - } else { - float tt = 2.0f * (t - 0.5f); - result = (1.0f - tt) * constraints.mid + tt * constraints.end; - } - return result; -} - -void EmitterSceneNode::updateParticleAnimation(Particle &particle, float dt) { - shared_ptr emitter(_modelNode->emitter()); - - float maturity; - if (_lifeExpectancy != -1) { - maturity = particle.lifetime / static_cast(_lifeExpectancy); - } else if (particle.animLength > 0.0f) { - maturity = particle.lifetime / particle.animLength; - } else { - maturity = 0.0f; - } - - particle.frame = static_cast(glm::ceil(_frameStart + maturity * (_frameEnd - _frameStart))); - particle.size = interpolateConstraints(_particleSize, maturity); - particle.color = interpolateConstraints(_color, maturity); - particle.alpha = interpolateConstraints(_alpha, maturity); -} - -bool EmitterSceneNode::isParticleExpired(Particle &particle) const { - shared_ptr emitter(_modelNode->emitter()); - return _lifeExpectancy != -1 && particle.lifetime >= _lifeExpectancy; -} - -} // namespace scene - -} // namespace reone diff --git a/src/engine/scene/pipeline/world.cpp b/src/engine/scene/pipeline/world.cpp index c3858678..6d352434 100644 --- a/src/engine/scene/pipeline/world.cpp +++ b/src/engine/scene/pipeline/world.cpp @@ -136,11 +136,8 @@ void WorldRenderPipeline::render() { computeLightSpaceMatrices(); - StateManager::instance().withBackFaceCulling([this]() { - drawShadows(); - drawGeometry(); - }); - + drawShadows(); + drawGeometry(); applyHorizontalBlur(); applyVerticalBlur(); drawResult(); diff --git a/src/engine/scene/scenegraph.cpp b/src/engine/scene/scenegraph.cpp index 03c727ad..e957f9dd 100644 --- a/src/engine/scene/scenegraph.cpp +++ b/src/engine/scene/scenegraph.cpp @@ -22,6 +22,7 @@ #include "glm/gtx/transform.hpp" #include "../graphics/mesh/meshes.h" +#include "../graphics/statemanager.h" #include "node/cameranode.h" #include "node/emitternode.h" @@ -311,6 +312,8 @@ void SceneGraph::draw(bool shadowPass) { return; } + StateManager::instance().setBackFaceCullingEnabled(true); + // Render opaque meshes for (auto &mesh : _opaqueMeshes) { mesh->drawSingle(false); @@ -334,6 +337,8 @@ void SceneGraph::draw(bool shadowPass) { mesh->drawSingle(false); } + StateManager::instance().setBackFaceCullingEnabled(false); + // Render grass for (auto &grass : _grassClusters) { grass.first->drawClusters(grass.second);