Add basic lens flare implementation

This commit is contained in:
Vsevolod Kremianskii 2021-05-03 22:48:46 +07:00
parent c287a57472
commit d78bd29e6d
10 changed files with 139 additions and 15 deletions

View file

@ -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

View 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

View file

@ -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));
}
}
}

View file

@ -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 {

View file

@ -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);

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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()));
}

View file

@ -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(