Add basic lens flare implementation
This commit is contained in:
parent
c287a57472
commit
d78bd29e6d
10 changed files with 139 additions and 15 deletions
|
@ -179,6 +179,7 @@ set(RENDER_HEADERS
|
|||
src/render/model/animatedproperty.h
|
||||
src/render/model/animation.h
|
||||
src/render/model/emitter.h
|
||||
src/render/model/lensflare.h
|
||||
src/render/model/mdlreader.h
|
||||
src/render/model/model.h
|
||||
src/render/model/modelmesh.h
|
||||
|
|
39
src/render/model/lensflare.h
Normal file
39
src/render/model/lensflare.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "glm/vec3.hpp"
|
||||
|
||||
#include "../texture.h"
|
||||
|
||||
namespace reone {
|
||||
|
||||
namespace render {
|
||||
|
||||
struct LensFlare {
|
||||
std::shared_ptr<Texture> texture;
|
||||
glm::vec3 colorShift { 0.0f };
|
||||
float position { 0.0f };
|
||||
float size { 0.0f };
|
||||
};
|
||||
|
||||
} // namespace render
|
||||
|
||||
} // namespace reone
|
|
@ -754,6 +754,7 @@ void MdlReader::readLight(ModelNode &node) {
|
|||
node._light->dynamicType = dynamicType;
|
||||
node._light->affectDynamic = static_cast<bool>(affectDynamic);
|
||||
node._light->shadow = static_cast<bool>(shadow);
|
||||
node._light->flareRadius = flareRadius;
|
||||
|
||||
int numFlares = static_cast<int>(flareTexturesArrayDef.count);
|
||||
if (numFlares > 0) {
|
||||
|
@ -777,12 +778,12 @@ void MdlReader::readLight(ModelNode &node) {
|
|||
}
|
||||
|
||||
for (int i = 0; i < numFlares; ++i) {
|
||||
ModelNode::LightFlare lightFlare;
|
||||
lightFlare.texture = flareTextures[i];
|
||||
lightFlare.colorShift = colorShifts[i];
|
||||
lightFlare.position = flarePositions[i];
|
||||
lightFlare.size = flareSizes[i];
|
||||
node._light->flares.push_back(move(lightFlare));
|
||||
LensFlare lensFlare;
|
||||
lensFlare.texture = flareTextures[i];
|
||||
lensFlare.colorShift = colorShifts[i];
|
||||
lensFlare.position = flarePositions[i];
|
||||
lensFlare.size = flareSizes[i];
|
||||
node._light->flares.push_back(move(lensFlare));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "aabbnode.h"
|
||||
#include "animatedproperty.h"
|
||||
#include "emitter.h"
|
||||
#include "lensflare.h"
|
||||
#include "modelmesh.h"
|
||||
|
||||
namespace reone {
|
||||
|
@ -51,13 +52,6 @@ class Model;
|
|||
*/
|
||||
class ModelNode : boost::noncopyable {
|
||||
public:
|
||||
struct LightFlare {
|
||||
std::shared_ptr<Texture> texture;
|
||||
glm::vec3 colorShift { 0.0f };
|
||||
float position { 0.0f };
|
||||
float size { 0.0f };
|
||||
};
|
||||
|
||||
struct Light {
|
||||
int priority { 0 };
|
||||
int dynamicType { 0 };
|
||||
|
@ -65,7 +59,7 @@ public:
|
|||
bool affectDynamic { false };
|
||||
bool shadow { false };
|
||||
float flareRadius { 0.0f };
|
||||
std::vector<LightFlare> flares;
|
||||
std::vector<LensFlare> flares;
|
||||
};
|
||||
|
||||
struct Reference {
|
||||
|
|
|
@ -640,6 +640,27 @@ void main() {
|
|||
}
|
||||
)END";
|
||||
|
||||
static constexpr GLchar kShaderVertexBillboard[] = R"END(
|
||||
layout(location = 0) in vec3 aPosition;
|
||||
layout(location = 2) in vec2 aTexCoords;
|
||||
|
||||
out vec2 fragTexCoords;
|
||||
|
||||
void main() {
|
||||
vec3 cameraRight = vec3(uGeneral.view[0][0], uGeneral.view[1][0], uGeneral.view[2][0]);
|
||||
vec3 cameraUp = vec3(uGeneral.view[0][1], uGeneral.view[1][1], uGeneral.view[2][1]);
|
||||
|
||||
vec4 P = vec4(
|
||||
vec3(uGeneral.model[3]) +
|
||||
cameraRight * aPosition.x * uGeneral.model[0][0] +
|
||||
cameraUp * aPosition.y * uGeneral.model[1][1],
|
||||
1.0);
|
||||
|
||||
gl_Position = uGeneral.projection * uGeneral.view * P;
|
||||
fragTexCoords = aTexCoords;
|
||||
}
|
||||
)END";
|
||||
|
||||
static constexpr GLchar kShaderGeometryDepth[] = R"END(
|
||||
layout(triangles) in;
|
||||
layout(triangle_strip, max_vertices=18) out;
|
||||
|
@ -1172,6 +1193,7 @@ void Shaders::init() {
|
|||
initShader(ShaderName::VertexParticle, GL_VERTEX_SHADER, { kShaderBaseHeader, kShaderVertexParticle });
|
||||
initShader(ShaderName::VertexGrass, GL_VERTEX_SHADER, { kShaderBaseHeader, kShaderVertexGrass });
|
||||
initShader(ShaderName::VertexText, GL_VERTEX_SHADER, { kShaderBaseHeader, kShaderVertexText });
|
||||
initShader(ShaderName::VertexBillboard, GL_VERTEX_SHADER, { kShaderBaseHeader, kShaderVertexBillboard });
|
||||
initShader(ShaderName::GeometryDepth, GL_GEOMETRY_SHADER, { kShaderBaseHeader, kShaderGeometryDepth });
|
||||
initShader(ShaderName::FragmentColor, GL_FRAGMENT_SHADER, { kShaderBaseHeader, kShaderFragmentColor });
|
||||
initShader(ShaderName::FragmentDepth, GL_FRAGMENT_SHADER, { kShaderBaseHeader, kShaderFragmentDepth });
|
||||
|
@ -1203,6 +1225,7 @@ void Shaders::init() {
|
|||
initProgram(ShaderProgram::ParticleParticle, { ShaderName::VertexParticle, ShaderName::FragmentParticle });
|
||||
initProgram(ShaderProgram::GrassGrass, { ShaderName::VertexGrass, ShaderName::FragmentGrass });
|
||||
initProgram(ShaderProgram::TextText, { ShaderName::VertexText, ShaderName::FragmentText });
|
||||
initProgram(ShaderProgram::BillboardGUI, { ShaderName::VertexBillboard, ShaderName::FragmentGUI });
|
||||
|
||||
glGenBuffers(1, &_uboCombined);
|
||||
glGenBuffers(1, &_uboText);
|
||||
|
|
|
@ -50,7 +50,8 @@ enum class ShaderProgram {
|
|||
ModelPBR,
|
||||
ParticleParticle,
|
||||
GrassGrass,
|
||||
TextText
|
||||
TextText,
|
||||
BillboardGUI
|
||||
};
|
||||
|
||||
struct UniformFeatureFlags {
|
||||
|
@ -225,6 +226,7 @@ private:
|
|||
VertexParticle,
|
||||
VertexGrass,
|
||||
VertexText,
|
||||
VertexBillboard,
|
||||
GeometryDepth,
|
||||
FragmentColor,
|
||||
FragmentDepth,
|
||||
|
|
|
@ -17,8 +17,21 @@
|
|||
|
||||
#include "lightnode.h"
|
||||
|
||||
#include "glm/ext.hpp"
|
||||
|
||||
#include "../../render/meshes.h"
|
||||
#include "../../render/shaders.h"
|
||||
#include "../../render/stateutil.h"
|
||||
#include "../../render/window.h"
|
||||
|
||||
#include "../scenegraph.h"
|
||||
|
||||
#include "cameranode.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
using namespace reone::render;
|
||||
|
||||
namespace reone {
|
||||
|
||||
namespace scene {
|
||||
|
@ -28,6 +41,28 @@ LightSceneNode::LightSceneNode(int priority, SceneGraph *sceneGraph) :
|
|||
_priority(priority) {
|
||||
}
|
||||
|
||||
void LightSceneNode::drawLensFlares(const LensFlare &flare) {
|
||||
shared_ptr<CameraSceneNode> camera(_sceneGraph->activeCamera());
|
||||
if (!camera) return;
|
||||
|
||||
setActiveTextureUnit(0);
|
||||
flare.texture->bind();
|
||||
|
||||
glm::mat4 transform(1.0f);
|
||||
transform = glm::translate(transform, glm::vec3(_absoluteTransform[3]));
|
||||
transform = glm::scale(transform, glm::vec3(flare.texture->height()));
|
||||
|
||||
ShaderUniforms uniforms(_sceneGraph->uniformsPrototype());
|
||||
uniforms.combined.general.model = move(transform);
|
||||
uniforms.combined.general.color = glm::vec4(flare.colorShift, 1.0f);
|
||||
|
||||
Shaders::instance().activate(ShaderProgram::BillboardGUI, uniforms);
|
||||
|
||||
withAdditiveBlending([]() {
|
||||
Meshes::instance().getQuadNDC()->draw();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
|
||||
} // namespace reone
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "../types.h"
|
||||
|
||||
#include "../../render/model/lensflare.h"
|
||||
|
||||
#include "scenenode.h"
|
||||
|
||||
namespace reone {
|
||||
|
@ -29,6 +31,8 @@ class LightSceneNode : public SceneNode {
|
|||
public:
|
||||
LightSceneNode(int priority, SceneGraph *sceneGraph);
|
||||
|
||||
void drawLensFlares(const render::LensFlare &flare);
|
||||
|
||||
bool isShadow() const { return _shadow; }
|
||||
bool isAmbientOnly() const { return _ambientOnly; }
|
||||
bool isDirectional() const { return _directional; }
|
||||
|
@ -37,6 +41,8 @@ public:
|
|||
int priority() const { return _priority; }
|
||||
float multiplier() const { return _multiplier; }
|
||||
float radius() const { return _radius; }
|
||||
float flareRadius() const { return _flareRadius; }
|
||||
const std::vector<render::LensFlare> &flares() const { return _flares; }
|
||||
|
||||
void setColor(glm::vec3 color) { _color = std::move(color); }
|
||||
void setMultiplier(float multiplier) { _multiplier = multiplier; }
|
||||
|
@ -44,6 +50,8 @@ public:
|
|||
void setShadow(bool shadow) { _shadow = shadow; }
|
||||
void setAmbientOnly(bool ambientOnly) { _ambientOnly = ambientOnly; }
|
||||
void setDirectional(bool directional) { _directional = directional; }
|
||||
void setFlareRadius(float radius) { _flareRadius = radius; }
|
||||
void setFlares(std::vector<render::LensFlare> flares) { _flares = std::move(flares); }
|
||||
|
||||
private:
|
||||
int _priority;
|
||||
|
@ -54,6 +62,13 @@ private:
|
|||
bool _shadow { false };
|
||||
bool _ambientOnly { false };
|
||||
bool _directional { false };
|
||||
|
||||
// Light flares
|
||||
|
||||
float _flareRadius { 0.0f };
|
||||
std::vector<render::LensFlare> _flares;
|
||||
|
||||
// END Light flares
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
|
|
|
@ -126,6 +126,9 @@ void ModelSceneNode::initModelNodes() {
|
|||
lightNode->setShadow(light->shadow);
|
||||
lightNode->setAmbientOnly(light->ambientOnly);
|
||||
lightNode->setDirectional(directional);
|
||||
lightNode->setFlareRadius(light->flareRadius);
|
||||
lightNode->setFlares(light->flares);
|
||||
|
||||
childNode->addChild(lightNode);
|
||||
_lightNodeByNumber.insert(make_pair(modelNode->nodeNumber(), lightNode.get()));
|
||||
}
|
||||
|
|
|
@ -327,6 +327,17 @@ void SceneGraph::draw(bool shadowPass) {
|
|||
for (auto &pair : _particles) {
|
||||
pair.first->drawParticles(pair.second);
|
||||
}
|
||||
|
||||
// Render lens flares
|
||||
for (auto &light : _lights) {
|
||||
// Ignore lights that are too far away or outside of camera frustums
|
||||
if (_activeCamera->getDistanceTo2(*light) > light->flareRadius() * light->flareRadius() ||
|
||||
!_activeCamera->isInFrustum(light->absoluteTransform()[3])) continue;
|
||||
|
||||
for (auto &flare : light->flares()) {
|
||||
light->drawLensFlares(flare);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneGraph::getLightsAt(
|
||||
|
|
Loading…
Reference in a new issue