test environment (sky)

This commit is contained in:
MihailRis 2026-05-12 02:02:06 +03:00
parent c4d5812b4f
commit a7ad219261
14 changed files with 421 additions and 196 deletions

View file

@ -9,6 +9,10 @@
#include <stdexcept> #include <stdexcept>
#include <unordered_map> #include <unordered_map>
#ifdef VC_ENABLE_REFLECTION
#include "util/EnumMetadata.hpp"
#endif
namespace util { namespace util {
template<class T> class Buffer; template<class T> class Buffer;
} }
@ -70,6 +74,14 @@ namespace dv {
return ptr != nullptr; return ptr != nullptr;
} }
inline value* operator->() noexcept {
return ptr;
}
inline const value* operator->() const noexcept {
return ptr;
}
inline value& operator*() noexcept { inline value& operator*() noexcept {
return *ptr; return *ptr;
} }
@ -78,6 +90,11 @@ namespace dv {
return *ptr; return *ptr;
} }
#ifdef VC_ENABLE_REFLECTION
template <typename T>
bool get(T& dst, const util::EnumMetadata<T>& mt) const;
#endif
bool get(std::string& dst) const; bool get(std::string& dst) const;
bool get(bool& dst) const; bool get(bool& dst) const;
bool get(char& dst) const; bool get(char& dst) const;
@ -552,6 +569,17 @@ namespace dv {
} }
return false; return false;
} }
#ifdef VC_ENABLE_REFLECTION
template <typename T>
inline bool optionalvalue::get(T& dst, const util::EnumMetadata<T>& mt) const {
if (ptr) {
return mt.getItem(ptr->asString(), dst);
}
return false;
}
#endif
inline bool optionalvalue::get(std::string& dst) const { inline bool optionalvalue::get(std::string& dst) const {
if (ptr) { if (ptr) {
dst = ptr->asString(); dst = ptr->asString();

View file

@ -4,7 +4,7 @@
#include <GL/glew.h> #include <GL/glew.h>
Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat) Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat)
: Texture(0, width, height) : Texture(0U, width, height, imageFormat)
{ {
glGenTextures(1, &id); glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_CUBE_MAP, id); glBindTexture(GL_TEXTURE_CUBE_MAP, id);
@ -14,7 +14,6 @@ Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat)
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
uint format = gl::to_glenum(imageFormat);
for (uint face = 0; face < 6; face++) { for (uint face = 0; face < 6; face++) {
glTexImage2D( glTexImage2D(
GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
@ -37,3 +36,23 @@ void Cubemap::bind() const {
void Cubemap::unbind() const { void Cubemap::unbind() const {
glBindTexture(GL_TEXTURE_CUBE_MAP, 0); glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
} }
void Cubemap::reload(const ubyte* data, uint width, uint height) {
this->width = width;
this->height = height;
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
for (uint face = 0; face < 6; face++) {
glTexImage2D(
GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
0,
format,
width,
height,
0,
format,
GL_UNSIGNED_BYTE,
data
);
}
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}

View file

@ -9,4 +9,5 @@ public:
virtual void bind() const override; virtual void bind() const override;
virtual void unbind() const override; virtual void unbind() const override;
virtual void reload(const ubyte* data, uint w, uint h) override;
}; };

View file

@ -1,14 +1,14 @@
#include "Framebuffer.hpp" #include "Framebuffer.hpp"
#include <GL/glew.h> #include <GL/glew.h>
#include "Texture.hpp" #include "Texture.hpp"
#include "debug/Logger.hpp" #include "debug/Logger.hpp"
static debug::Logger logger("gl-framebuffer"); static debug::Logger logger("gl-framebuffer");
Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture) Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture)
: fbo(fbo), depth(depth), texture(std::move(texture)) : fbo(fbo), depth(depth), texture(std::move(texture)) {
{
if (this->texture) { if (this->texture) {
width = this->texture->getWidth(); width = this->texture->getWidth();
height = this->texture->getHeight(); height = this->texture->getHeight();
@ -18,35 +18,55 @@ Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture)
} }
} }
static std::unique_ptr<Texture> create_texture(int width, int height, int format) { static std::unique_ptr<Texture> create_texture(
GLuint tex; int width, int height, bool alpha
glGenTextures(1, &tex); ) {
glBindTexture(GL_TEXTURE_2D, tex); GLenum glformat = alpha ? GL_RGBA : GL_RGB;
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr);
GLuint textureid;
glGenTextures(1, &textureid);
glBindTexture(GL_TEXTURE_2D, textureid);
glTexImage2D(
GL_TEXTURE_2D,
0,
glformat,
width,
height,
0,
glformat,
GL_UNSIGNED_BYTE,
nullptr
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); glFramebufferTexture2D(
return std::make_unique<Texture>(tex, width, height); GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid, 0
);
return std::make_unique<Texture>(
textureid,
width,
height,
alpha ? ImageFormat::RGBA8888 : ImageFormat::RGB888
);
} }
Framebuffer::Framebuffer(uint width, uint height, bool alpha) Framebuffer::Framebuffer(uint width, uint height, bool alpha)
: width(width), height(height) : width(width), height(height) {
{
glGenFramebuffers(1, &fbo); glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
format = alpha ? GL_RGBA : GL_RGB;
// Setup color attachment (texture) // Setup color attachment (texture)
texture = create_texture(width, height, format); texture = create_texture(width, height, alpha);
// Setup depth attachment // Setup depth attachment
glGenRenderbuffers(1, &depth); glGenRenderbuffers(1, &depth);
glBindRenderbuffer(GL_RENDERBUFFER, depth); glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth
);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
logger.error() << "framebuffer is not complete!"; logger.error() << "framebuffer is not complete!";
@ -60,6 +80,10 @@ Framebuffer::~Framebuffer() {
glDeleteRenderbuffers(1, &depth); glDeleteRenderbuffers(1, &depth);
} }
void Framebuffer::setTexture(std::unique_ptr<Texture> texture) {
this->texture = std::move(texture);
}
void Framebuffer::bind() { void Framebuffer::bind() {
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
} }
@ -81,7 +105,7 @@ void Framebuffer::resize(uint width, uint height) {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0);
texture = create_texture(width, height, format); texture->resize(width, height);
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }

View file

@ -12,13 +12,14 @@ class Framebuffer : public Bindable {
uint depth; uint depth;
uint width; uint width;
uint height; uint height;
uint format;
std::shared_ptr<Texture> texture; std::shared_ptr<Texture> texture;
public: public:
Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture); Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture);
Framebuffer(uint width, uint height, bool alpha=false); Framebuffer(uint width, uint height, bool alpha=false);
~Framebuffer(); ~Framebuffer();
void setTexture(std::unique_ptr<Texture> texture);
/// @brief Use framebuffer /// @brief Use framebuffer
void bind() override; void bind() override;

View file

@ -7,8 +7,8 @@
uint Texture::MAX_RESOLUTION = 1024; // Window.initialize overrides it uint Texture::MAX_RESOLUTION = 1024; // Window.initialize overrides it
Texture::Texture(uint id, uint width, uint height) Texture::Texture(uint id, uint width, uint height, ImageFormat imageFormat)
: id(id), width(width), height(height) { : id(id), width(width), height(height), format(gl::to_glenum(imageFormat)) {
} }
Texture::Texture(const ubyte* data, uint width, uint height, ImageFormat imageFormat) Texture::Texture(const ubyte* data, uint width, uint height, ImageFormat imageFormat)
@ -17,7 +17,7 @@ Texture::Texture(const ubyte* data, uint width, uint height, ImageFormat imageFo
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLenum format = gl::to_glenum(imageFormat); format = gl::to_glenum(imageFormat);
glTexImage2D( glTexImage2D(
GL_TEXTURE_2D, 0, format, width, height, 0, GL_TEXTURE_2D, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, static_cast<const GLvoid*>(data) format, GL_UNSIGNED_BYTE, static_cast<const GLvoid*>(data)
@ -41,23 +41,27 @@ void Texture::unbind() const {
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
} }
void Texture::resize(uint width, uint height) {
reload(nullptr, width, height);
}
void Texture::reload(const ImageData& image) { void Texture::reload(const ImageData& image) {
width = image.getWidth();
height = image.getHeight();
reload(image.getData(), width, height); reload(image.getData(), width, height);
} }
void Texture::reload(const ubyte* data, uint width, uint height) { void Texture::reload(const ubyte* data, uint width, uint height) {
this->width = width;
this->height = height;
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, static_cast<const GLvoid*>(data)); format, GL_UNSIGNED_BYTE, static_cast<const GLvoid*>(data));
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
} }
void Texture::reloadPartial(const ImageData& image, uint x, uint y, uint w, uint h) { void Texture::reloadPartial(const ImageData& image, uint x, uint y, uint w, uint h) {
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image.getData()); glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, image.getData());
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
} }

View file

@ -11,19 +11,21 @@ protected:
uint id; uint id;
uint width; uint width;
uint height; uint height;
uint format;
public: public:
Texture(uint id, uint width, uint height); Texture(uint id, uint width, uint height, ImageFormat imageFormat);
Texture(const ubyte* data, uint width, uint height, ImageFormat format); Texture(const ubyte* data, uint width, uint height, ImageFormat format);
virtual ~Texture(); virtual ~Texture();
virtual void bind() const; virtual void bind() const;
virtual void unbind() const; virtual void unbind() const;
void reload(const ubyte* data, uint w, uint h); virtual void reload(const ubyte* data, uint w, uint h);
void reloadPartial(const ImageData& image, uint x, uint y, uint w, uint h); void reloadPartial(const ImageData& image, uint x, uint y, uint w, uint h);
void setNearestFilter(); void setNearestFilter();
void reload(const ImageData& image); void reload(const ImageData& image);
virtual void resize(uint w, uint h);
void setMipMapping(bool flag, bool pixelated); void setMipMapping(bool flag, bool pixelated);

View file

@ -1,47 +1,44 @@
#include "Skybox.hpp" #include "Skybox.hpp"
#include "assets/Assets.hpp"
#include "graphics/core/Shader.hpp" #include <GL/glew.h>
#include "graphics/core/Mesh.hpp"
#include "graphics/core/Batch3D.hpp"
#include "graphics/core/Texture.hpp"
#include "graphics/core/Cubemap.hpp"
#include "graphics/core/Framebuffer.hpp"
#include "graphics/core/DrawContext.hpp"
#include "window/Window.hpp"
#include "window/Camera.hpp"
#include "maths/UVRegion.hpp"
#include <cmath> #include <cmath>
#include <iostream>
#include <GL/glew.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/constants.hpp> #include <glm/gtc/constants.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <limits>
#include "assets/Assets.hpp"
#include "graphics/core/Batch3D.hpp"
#include "graphics/core/Cubemap.hpp"
#include "graphics/core/DrawContext.hpp"
#include "graphics/core/Framebuffer.hpp"
#include "graphics/core/Mesh.hpp"
#include "graphics/core/Shader.hpp"
#include "graphics/core/Texture.hpp"
#include "maths/UVRegion.hpp"
#include "window/Camera.hpp"
#include "window/Window.hpp"
using namespace advanced_pipeline; using namespace advanced_pipeline;
const int STARS_COUNT = 3000; const int STARS_COUNT = 3000;
const int STARS_SEED = 632; const int STARS_SEED = 632;
Skybox::Skybox(uint size, Shader& shader) Skybox::Skybox(uint size, const Assets& assets)
: size(size), : size(size),
shader(shader), assets(assets),
batch3d(std::make_unique<Batch3D>(4096)) shader(assets.require<Shader>("skybox_gen")),
{ batch3d(std::make_unique<Batch3D>(4096)) {
auto cubemap = std::make_unique<Cubemap>(size, size, ImageFormat::RGB888);
uint fboid; SkyboxVertex vertices[] {
glGenFramebuffers(1, &fboid);
fbo = std::make_unique<Framebuffer>(fboid, 0, std::move(cubemap));
SkyboxVertex vertices[]{
{{-1.0f, -1.0f}}, {{-1.0f, -1.0f}},
{{-1.0f, 1.0f}}, {{-1.0f, 1.0f}},
{{1.0f, 1.0f}}, {{1.0f, 1.0f}},
{{-1.0f, -1.0f}}, {{-1.0f, -1.0f}},
{{1.0f, 1.0f}}, {{1.0f, 1.0f}},
{{1.0f, -1.0f}} {{1.0f, -1.0f}}};
};
mesh = std::make_unique<Mesh<SkyboxVertex>>(vertices, 6); mesh = std::make_unique<Mesh<SkyboxVertex>>(vertices, 6);
@ -68,20 +65,20 @@ Skybox::Skybox(uint size, Shader& shader)
true, true,
glm::pi<float>() * 0.25f, glm::pi<float>() * 0.25f,
}); });
setMode(mode);
} }
Skybox::~Skybox() = default; Skybox::~Skybox() = default;
void Skybox::drawBackground( void Skybox::drawBackground(const Camera& camera, int width, int height) {
const Camera& camera, const Assets& assets, int width, int height
) {
auto backShader = assets.get<Shader>("background"); auto backShader = assets.get<Shader>("background");
backShader->use(); backShader->use();
backShader->uniformMatrix("u_view", camera.getView(false)); backShader->uniformMatrix("u_view", camera.getView(false));
backShader->uniform1f( backShader->uniform1f(
"u_zoom", camera.zoom * camera.getFov() / glm::half_pi<float>() "u_zoom", camera.zoom * camera.getFov() / glm::half_pi<float>()
); );
backShader->uniform1f("u_ar", float(width)/float(height)); backShader->uniform1f("u_ar", float(width) / float(height));
backShader->uniform1i("u_skybox", 1); backShader->uniform1i("u_skybox", 1);
bind(); bind();
mesh->draw(); mesh->draw();
@ -93,9 +90,7 @@ void Skybox::drawStars(float angle, float opacity) {
random.setSeed(STARS_SEED); random.setSeed(STARS_SEED);
glm::mat4 rotation = glm::rotate( glm::mat4 rotation = glm::rotate(
glm::mat4(1.0f), glm::mat4(1.0f), -angle + glm::pi<float>() * 0.5f, glm::vec3(0, 0, -1)
-angle + glm::pi<float>() * 0.5f,
glm::vec3(0, 0, -1)
); );
rotation = glm::rotate(rotation, sunAltitude, glm::vec3(1, 0, 0)); rotation = glm::rotate(rotation, sunAltitude, glm::vec3(1, 0, 0));
@ -108,41 +103,20 @@ void Skybox::drawStars(float angle, float opacity) {
glm::vec3 pos = glm::vec4(rx, ry, rz, 1) * rotation; glm::vec3 pos = glm::vec4(rx, ry, rz, 1) * rotation;
float sopacity = random.randFloat(); float sopacity = random.randFloat();
if (pos.y < 0.0f) if (pos.y < 0.0f) continue;
continue;
sopacity *= (0.2f + std::sqrt(std::cos(angle)) * 0.5f) - 0.05f; sopacity *= (0.2f + std::sqrt(std::cos(angle)) * 0.5f) - 0.05f;
glm::vec4 tint (1,1,1, sopacity * opacity); glm::vec4 tint(1, 1, 1, sopacity * opacity);
batch3d->point(pos * depth, tint); batch3d->point(pos * depth, tint);
} }
batch3d->flushPoints(); batch3d->flushPoints();
} }
void Skybox::draw( void Skybox::drawSkySprites(
const DrawContext& pctx,
const Camera& camera,
const Assets& assets,
float daytime, float daytime,
float fog) float angle,
{ float opacity
const glm::uvec2& viewport = pctx.getViewport(); ) {
glActiveTexture(GL_TEXTURE0);
drawBackground(camera, assets, viewport.x, viewport.y);
DrawContext ctx = pctx.sub();
ctx.setBlendMode(BlendMode::addition);
auto shader = assets.get<Shader>("ui3d");
shader->use();
shader->uniformMatrix("u_projview", camera.getProjView(false));
shader->uniformMatrix("u_apply", glm::mat4(1.0f));
batch3d->begin();
float angle = daytime * glm::pi<float>() * 2.0f;
float opacity = glm::pow(1.0f - fog, 7.0f);
float depthScale = 2e3; float depthScale = 2e3;
for (auto& sprite : sprites) { for (auto& sprite : sprites) {
batch3d->texture(assets.get<Texture>(sprite.texture)); batch3d->texture(assets.get<Texture>(sprite.texture));
@ -159,39 +133,132 @@ void Skybox::draw(
glm::vec3 pos = glm::vec4(0, distance, 0, 1) * rotation; glm::vec3 pos = glm::vec4(0, distance, 0, 1) * rotation;
glm::vec3 up = glm::vec4(depthScale, 0, 0, 1) * rotation; glm::vec3 up = glm::vec4(depthScale, 0, 0, 1) * rotation;
glm::vec3 right = glm::vec4(0, 0, depthScale, 1) * rotation; glm::vec3 right = glm::vec4(0, 0, depthScale, 1) * rotation;
glm::vec4 tint (1,1,1, opacity); glm::vec4 tint(1, 1, 1, opacity);
if (!sprite.emissive) { if (!sprite.emissive) {
tint *= 0.6f + std::cos(angle)*0.4; tint *= 0.6f + std::cos(angle) * 0.4;
} }
batch3d->sprite(pos, right, batch3d->sprite(pos, right, up, 1, 1, UVRegion(), tint);
up, 1, 1, UVRegion(), tint);
} }
batch3d->flush(); batch3d->flush();
drawStars(angle, opacity);
} }
void Skybox::refresh(const DrawContext& pctx, float t, float mie, const glm::vec3& tint, const glm::vec3& hightlight, uint quality) { void Skybox::draw(
const Environment& environment,
const DrawContext& pctx,
const Camera& camera,
float daytime,
float fog
) {
const glm::uvec2& viewport = pctx.getViewport();
glActiveTexture(GL_TEXTURE0);
drawBackground(camera, viewport.x, viewport.y);
float angle = daytime * glm::pi<float>() * 2.0f;
float opacity = glm::pow(1.0f - fog, 7.0f);
DrawContext ctx = pctx.sub();
ctx.setBlendMode(BlendMode::addition);
if (!environment.sky.sprites && !environment.sky.stars) {
return;
}
auto shader = assets.get<Shader>("ui3d");
shader->use();
shader->uniformMatrix("u_projview", camera.getProjView(false));
shader->uniformMatrix("u_apply", glm::mat4(1.0f));
batch3d->begin();
if (environment.sky.sprites) {
drawSkySprites(daytime, angle, opacity);
}
if (environment.sky.stars) {
drawStars(angle, opacity);
}
}
void Skybox::setMode(SkyMode mode) {
if (this->mode == mode && fbo) {
return;
}
this->mode = mode;
uint size = mode == SkyMode::BOX ? this->size : 1U;
prevT = std::numeric_limits<float>().min();
uint fboid;
glGenFramebuffers(1, &fboid);
fbo = std::make_unique<Framebuffer>(
fboid,
false,
std::make_unique<Cubemap>(size, size, ImageFormat::RGB888)
);
}
void Skybox::refresh(
const Environment& environment,
const DrawContext& pctx,
float dayTime,
float mie,
const glm::vec3& tint,
const glm::vec3& hightlight,
uint quality
) {
setMode(environment.sky.mode);
if (mode == SkyMode::NONE) {
return;
} else if (mode == SkyMode::SOLID) {
DrawContext ctx = pctx.sub();
ctx.setDepthMask(false);
ctx.setDepthTest(false);
ctx.setFramebuffer(fbo.get());
ctx.setViewport({fbo->getWidth(), fbo->getHeight()});
auto cubemap = dynamic_cast<Cubemap*>(fbo->getTexture());
assert(cubemap != nullptr);
glActiveTexture(GL_TEXTURE0 + TARGET_SKYBOX);
cubemap->bind();
for (int face = 0; face < 6; face++) {
glFramebufferTexture2D(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
cubemap->getId(),
0
);
glClearColor(tint.r, tint.g, tint.b, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
cubemap->unbind();
return;
}
frameid++; frameid++;
float dayTime = t;
DrawContext ctx = pctx.sub(); DrawContext ctx = pctx.sub();
ctx.setDepthMask(false); ctx.setDepthMask(false);
ctx.setDepthTest(false); ctx.setDepthTest(false);
ctx.setFramebuffer(fbo.get()); ctx.setFramebuffer(fbo.get());
ctx.setViewport({size, size}); ctx.setViewport({fbo->getWidth(), fbo->getHeight()});
auto cubemap = dynamic_cast<Cubemap*>(fbo->getTexture()); auto cubemap = dynamic_cast<Cubemap*>(fbo->getTexture());
assert(cubemap != nullptr); assert(cubemap != nullptr);
ready = true;
glActiveTexture(GL_TEXTURE0 + TARGET_SKYBOX); glActiveTexture(GL_TEXTURE0 + TARGET_SKYBOX);
cubemap->bind(); cubemap->bind();
shader.use(); shader.use();
t *= glm::two_pi<float>();
float t = dayTime * glm::two_pi<float>();
lightDir = glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f)); lightDir = glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f));
float sunAngle = glm::radians((t / glm::two_pi<float>() - 0.25f) * 360.0f); float sunAngle = glm::radians((dayTime - 0.25f) * 360.0f);
float x = -glm::cos(sunAngle + glm::pi<float>() * 0.5f) * glm::radians(sunAltitude); float x = -glm::cos(sunAngle + glm::pi<float>() * 0.5f) *
glm::radians(sunAltitude);
float y = sunAngle - glm::pi<float>() * 0.5f; float y = sunAngle - glm::pi<float>() * 0.5f;
float z = glm::radians(0.0f); float z = glm::radians(0.0f);
rotation = glm::rotate(glm::mat4(1.0f), y, glm::vec3(0, 1, 0)); rotation = glm::rotate(glm::mat4(1.0f), y, glm::vec3(0, 1, 0));
@ -207,7 +274,9 @@ void Skybox::refresh(const DrawContext& pctx, float t, float mie, const glm::vec
shader.uniform3f("u_lightDir", lightDir); shader.uniform3f("u_lightDir", lightDir);
shader.uniform1f("u_dayTime", dayTime); shader.uniform1f("u_dayTime", dayTime);
if (glm::abs(mie-prevMie) + glm::abs(t-prevT) + glm::abs(prevHighlight.r - hightlight.r) >= 0.01) { if (glm::abs(mie - prevMie) + glm::abs(t - prevT) +
glm::abs(prevHighlight.r - hightlight.r) >=
0.01) {
for (uint face = 0; face < 6; face++) { for (uint face = 0; face < 6; face++) {
refreshFace(face, cubemap); refreshFace(face, cubemap);
} }

View file

@ -1,14 +1,18 @@
#pragma once #pragma once
#include <glm/glm.hpp>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include <glm/glm.hpp>
#include "typedefs.hpp"
#include "maths/fastmaths.hpp"
#include "graphics/core/MeshData.hpp"
template<typename VertexStructure> class Mesh; #include "graphics/core/MeshData.hpp"
#include "maths/fastmaths.hpp"
#include "typedefs.hpp"
#include "world/Environment.hpp"
template <typename VertexStructure>
class Mesh;
class Shader; class Shader;
class Assets; class Assets;
class Camera; class Camera;
@ -21,8 +25,7 @@ struct SkyboxVertex {
glm::vec2 position; glm::vec2 position;
static constexpr VertexAttribute ATTRIBUTES[] { static constexpr VertexAttribute ATTRIBUTES[] {
{VertexAttribute::Type::FLOAT, false, 2}, {VertexAttribute::Type::FLOAT, false, 2}, {{}, 0}};
{{}, 0}};
}; };
struct SkySprite { struct SkySprite {
@ -34,10 +37,11 @@ struct SkySprite {
}; };
class Skybox { class Skybox {
std::unique_ptr<Framebuffer> fbo; SkyMode mode = SkyMode::SOLID;
uint size; uint size;
std::unique_ptr<Framebuffer> fbo;
const Assets& assets;
Shader& shader; Shader& shader;
bool ready = false;
FastRandom random; FastRandom random;
glm::vec3 lightDir; glm::vec3 lightDir;
@ -53,30 +57,36 @@ class Skybox {
glm::mat4 rotation; glm::mat4 rotation;
void drawStars(float angle, float opacity); void drawStars(float angle, float opacity);
void drawBackground( void drawBackground(const Camera& camera, int width, int height);
const Camera& camera, const Assets& assets, int width, int height void drawSkySprites(float daytime, float angle, float opacity);
);
void refreshFace(uint face, Cubemap* cubemap); void refreshFace(uint face, Cubemap* cubemap);
public: public:
Skybox(uint size, Shader& shader); Skybox(uint size, const Assets& assets);
~Skybox(); ~Skybox();
void setMode(SkyMode mode);
void draw( void draw(
const Environment& environment,
const DrawContext& pctx, const DrawContext& pctx,
const Camera& camera, const Camera& camera,
const Assets& assets,
float daytime, float daytime,
float fog float fog
); );
void refresh(const DrawContext& pctx, float t, float mie, const glm::vec3& tint, const glm::vec3& hightlight, uint quality); void refresh(
const Environment& environment,
const DrawContext& pctx,
float t,
float mie,
const glm::vec3& tint,
const glm::vec3& hightlight,
uint quality
);
void bind() const; void bind() const;
void unbind() const; void unbind() const;
bool isReady() const {
return ready;
}
const glm::vec3 getLightDir() const { const glm::vec3& getLightDir() const {
return lightDir; return lightDir;
} }
}; };

View file

@ -1,12 +1,45 @@
#include "WorldRenderer.hpp" #include "WorldRenderer.hpp"
#include <assert.h>
#include <algorithm>
#include <glm/ext.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <memory>
#include "BlockWrapsRenderer.hpp"
#include "ChunksRenderer.hpp"
#include "CloudsRenderer.hpp"
#include "DebugLinesRenderer.hpp"
#include "Emitter.hpp"
#include "HandsRenderer.hpp"
#include "ModelBatch.hpp"
#include "NamedSkeletons.hpp"
#include "ParticlesRenderer.hpp"
#include "PrecipitationRenderer.hpp"
#include "Skybox.hpp"
#include "TextNote.hpp"
#include "TextsRenderer.hpp"
#include "assets/Assets.hpp" #include "assets/Assets.hpp"
#include "assets/assets_util.hpp" #include "assets/assets_util.hpp"
#include "coders/GLSLExtension.hpp"
#include "content/Content.hpp" #include "content/Content.hpp"
#include "engine/Engine.hpp" #include "engine/Engine.hpp"
#include "coders/GLSLExtension.hpp"
#include "frontend/LevelFrontend.hpp"
#include "frontend/ContentGfxCache.hpp" #include "frontend/ContentGfxCache.hpp"
#include "frontend/LevelFrontend.hpp"
#include "graphics/commons/Model.hpp"
#include "graphics/core/Atlas.hpp"
#include "graphics/core/Batch3D.hpp"
#include "graphics/core/DrawContext.hpp"
#include "graphics/core/Font.hpp"
#include "graphics/core/Framebuffer.hpp"
#include "graphics/core/GBuffer.hpp"
#include "graphics/core/LineBatch.hpp"
#include "graphics/core/Mesh.hpp"
#include "graphics/core/PostProcessing.hpp"
#include "graphics/core/Shader.hpp"
#include "graphics/core/Shadows.hpp"
#include "graphics/core/Texture.hpp"
#include "items/Inventory.hpp" #include "items/Inventory.hpp"
#include "items/ItemDef.hpp" #include "items/ItemDef.hpp"
#include "items/ItemStack.hpp" #include "items/ItemStack.hpp"
@ -25,38 +58,6 @@
#include "world/Level.hpp" #include "world/Level.hpp"
#include "world/LevelEvents.hpp" #include "world/LevelEvents.hpp"
#include "world/World.hpp" #include "world/World.hpp"
#include "graphics/commons/Model.hpp"
#include "graphics/core/Atlas.hpp"
#include "graphics/core/Batch3D.hpp"
#include "graphics/core/DrawContext.hpp"
#include "graphics/core/LineBatch.hpp"
#include "graphics/core/Mesh.hpp"
#include "graphics/core/PostProcessing.hpp"
#include "graphics/core/Framebuffer.hpp"
#include "graphics/core/Shader.hpp"
#include "graphics/core/Texture.hpp"
#include "graphics/core/Font.hpp"
#include "graphics/core/Shadows.hpp"
#include "graphics/core/GBuffer.hpp"
#include "BlockWrapsRenderer.hpp"
#include "ParticlesRenderer.hpp"
#include "PrecipitationRenderer.hpp"
#include "HandsRenderer.hpp"
#include "NamedSkeletons.hpp"
#include "TextsRenderer.hpp"
#include "ChunksRenderer.hpp"
#include "DebugLinesRenderer.hpp"
#include "ModelBatch.hpp"
#include "Skybox.hpp"
#include "Emitter.hpp"
#include "TextNote.hpp"
#include "CloudsRenderer.hpp"
#include <assert.h>
#include <algorithm>
#include <glm/ext.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <memory>
using namespace advanced_pipeline; using namespace advanced_pipeline;
@ -105,8 +106,7 @@ WorldRenderer::WorldRenderer(
[this](LevelEventType, Chunk* chunk) { chunksRenderer->unload(chunk); } [this](LevelEventType, Chunk* chunk) { chunksRenderer->unload(chunk); }
); );
skybox = std::make_unique<Skybox>( skybox = std::make_unique<Skybox>(
settings.graphics.skyboxResolution.get(), settings.graphics.skyboxResolution.get(), assets
assets.require<Shader>("skybox_gen")
); );
const auto& content = level.content; const auto& content = level.content;
@ -179,6 +179,11 @@ void WorldRenderer::setupWorldShader(
} }
} }
float WorldRenderer::calcFogFactor() const {
const auto& settings = engine.getSettings();
return 15.0f / static_cast<float>(settings.chunks.loadDistance.get() - 2);
}
void WorldRenderer::renderOpaque( void WorldRenderer::renderOpaque(
const DrawContext& ctx, const DrawContext& ctx,
const Camera& camera, const Camera& camera,
@ -187,14 +192,13 @@ void WorldRenderer::renderOpaque(
) { ) {
texts->render(ctx, camera, settings, hudVisible, false); texts->render(ctx, camera, settings, hudVisible, false);
bool culling = engine.getSettings().graphics.frustumCulling.get(); float fogFactor = calcFogFactor();
float fogFactor =
15.0f / static_cast<float>(settings.chunks.loadDistance.get() - 2);
auto& entityShader = assets.require<Shader>("entity"); auto& entityShader = assets.require<Shader>("entity");
setupWorldShader(entityShader, camera, settings, fogFactor); setupWorldShader(entityShader, camera, settings, fogFactor);
skybox->bind(); skybox->bind();
bool culling = engine.getSettings().graphics.frustumCulling.get();
if (culling) { if (culling) {
frustumCulling->update(camera.getProjView()); frustumCulling->update(camera.getProjView());
} }
@ -213,22 +217,24 @@ void WorldRenderer::renderOpaque(
auto& shader = assets.require<Shader>("main"); auto& shader = assets.require<Shader>("main");
auto& cloudsShader = assets.require<Shader>("clouds"); auto& cloudsShader = assets.require<Shader>("clouds");
auto& linesShader = assets.require<Shader>("lines");
setupWorldShader(shader, camera, settings, fogFactor); setupWorldShader(shader, camera, settings, fogFactor);
chunksRenderer->drawChunks(camera, shader); chunksRenderer->drawChunks(camera, shader);
blockWraps->draw(ctx); blockWraps->draw(ctx);
int cloudsQuality = settings.graphics.cloudsQuality.get(); if (level.environment.sky.clouds) {
if (cloudsQuality > 0) { int cloudsQuality = settings.graphics.cloudsQuality.get();
setupWorldShader(cloudsShader, camera, settings, fogFactor); if (cloudsQuality > 0) {
cloudsRenderer->draw( setupWorldShader(cloudsShader, camera, settings, fogFactor);
cloudsShader, weather, timer, fogFactor, camera, cloudsQuality cloudsRenderer->draw(
); cloudsShader, weather, timer, fogFactor, camera, cloudsQuality
);
}
} }
if (hudVisible) { if (hudVisible) {
auto& linesShader = assets.require<Shader>("lines");
renderLines(camera, linesShader, ctx); renderLines(camera, linesShader, ctx);
} }
skybox->unbind(); skybox->unbind();
@ -290,17 +296,15 @@ void WorldRenderer::refreshSettings(Shader** shaders) {
CompileTimeShaderSettings currentSettings { CompileTimeShaderSettings currentSettings {
gbufferPipeline, gbufferPipeline,
shadowsQuality != 0, shadowsQuality != 0,
graphics.ssao.get() && gbufferPipeline graphics.ssao.get() && gbufferPipeline};
}; if (prevCTShaderSettings.advancedRender != currentSettings.advancedRender ||
if (
prevCTShaderSettings.advancedRender != currentSettings.advancedRender ||
prevCTShaderSettings.shadows != currentSettings.shadows || prevCTShaderSettings.shadows != currentSettings.shadows ||
prevCTShaderSettings.ssao != currentSettings.ssao prevCTShaderSettings.ssao != currentSettings.ssao) {
) {
std::vector<std::string> defines; std::vector<std::string> defines;
if (currentSettings.shadows) defines.emplace_back("ENABLE_SHADOWS"); if (currentSettings.shadows) defines.emplace_back("ENABLE_SHADOWS");
if (currentSettings.ssao) defines.emplace_back("ENABLE_SSAO"); if (currentSettings.ssao) defines.emplace_back("ENABLE_SSAO");
if (currentSettings.advancedRender) defines.emplace_back("ADVANCED_RENDER"); if (currentSettings.advancedRender)
defines.emplace_back("ADVANCED_RENDER");
for (size_t i = 0; shaders[i]; i++) { for (size_t i = 0; shaders[i]; i++) {
shaders[i]->recompile(defines); shaders[i]->recompile(defines);
@ -332,7 +336,8 @@ void WorldRenderer::renderFrame(
auto& entityShader = assets.require<Shader>("entity"); auto& entityShader = assets.require<Shader>("entity");
auto& cloudsShader = assets.require<Shader>("clouds"); auto& cloudsShader = assets.require<Shader>("clouds");
auto& translucentShader = assets.require<Shader>("translucent"); auto& translucentShader = assets.require<Shader>("translucent");
auto& deferredShader = assets.require<PostEffect>("deferred_lighting").getShader(); auto& deferredShader =
assets.require<PostEffect>("deferred_lighting").getShader();
const auto& settings = engine.getSettings(); const auto& settings = engine.getSettings();
@ -342,8 +347,7 @@ void WorldRenderer::renderFrame(
&cloudsShader, &cloudsShader,
&translucentShader, &translucentShader,
&deferredShader, &deferredShader,
nullptr nullptr};
};
refreshSettings(affectedShaders); refreshSettings(affectedShaders);
@ -355,6 +359,7 @@ void WorldRenderer::renderFrame(
float random = rand() / static_cast<float>(RAND_MAX); float random = rand() / static_cast<float>(RAND_MAX);
skybox->refresh( skybox->refresh(
level.environment,
pctx, pctx,
worldInfo.daytime, worldInfo.daytime,
mie, mie,
@ -385,8 +390,7 @@ void WorldRenderer::renderFrame(
texts->render(pctx, camera, settings, hudVisible, true); texts->render(pctx, camera, settings, hudVisible, true);
} }
skybox->bind(); skybox->bind();
float fogFactor = float fogFactor = calcFogFactor();
15.0f / static_cast<float>(settings.chunks.loadDistance.get() - 2);
if (gbufferPipeline) { if (gbufferPipeline) {
deferredShader.use(); deferredShader.use();
setupWorldShader(deferredShader, camera, settings, fogFactor); setupWorldShader(deferredShader, camera, settings, fogFactor);
@ -403,7 +407,9 @@ void WorldRenderer::renderFrame(
} }
// Background sky plane // Background sky plane
skybox->draw(ctx, camera, assets, worldInfo.daytime, clouds); skybox->draw(
level.environment, ctx, camera, worldInfo.daytime, clouds
);
auto& linesShader = assets.require<Shader>("lines"); auto& linesShader = assets.require<Shader>("lines");
linesShader.use(); linesShader.use();
@ -429,14 +435,17 @@ void WorldRenderer::renderFrame(
entityShader.use(); entityShader.use();
setupWorldShader(entityShader, camera, settings, fogFactor); setupWorldShader(entityShader, camera, settings, fogFactor);
std::array<const WeatherPreset*, 2> weatherInstances {&weather.a, &weather.b}; std::array<const WeatherPreset*, 2> weatherInstances {
&weather.a, &weather.b};
for (const auto& weather : weatherInstances) { for (const auto& weather : weatherInstances) {
float maxIntensity = weather->fall.maxIntensity; float maxIntensity = weather->fall.maxIntensity;
float zero = weather->fall.minOpacity; float zero = weather->fall.minOpacity;
float one = weather->fall.maxOpacity; float one = weather->fall.maxOpacity;
float t = (weather->intensity * (one - zero)) * maxIntensity + zero; float t = (weather->intensity * (one - zero)) * maxIntensity + zero;
entityShader.uniform1i("u_alphaClip", weather->fall.opaque); entityShader.uniform1i("u_alphaClip", weather->fall.opaque);
entityShader.uniform1f("u_opacity", weather->fall.opaque ? t * t : t); entityShader.uniform1f(
"u_opacity", weather->fall.opaque ? t * t : t
);
if (weather->intensity > 1.e-3f && !weather->fall.texture.empty()) { if (weather->intensity > 1.e-3f && !weather->fall.texture.empty()) {
precipitation->render(camera, *weather); precipitation->render(camera, *weather);
} }
@ -486,9 +495,8 @@ void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) {
if (def.overlayTexture.empty()) { if (def.overlayTexture.empty()) {
return; return;
} }
auto textureRegion = util::get_texture_region( auto textureRegion =
assets, def.overlayTexture, "blocks:notfound" util::get_texture_region(assets, def.overlayTexture, "blocks:notfound");
);
DrawContext ctx = wctx.sub(); DrawContext ctx = wctx.sub();
ctx.setDepthTest(false); ctx.setDepthTest(false);
ctx.setCullFace(false); ctx.setCullFace(false);

View file

@ -99,6 +99,8 @@ class WorldRenderer {
); );
void refreshSettings(Shader** shaders); void refreshSettings(Shader** shaders);
float calcFogFactor() const;
public: public:
std::unique_ptr<ParticlesRenderer> particles; std::unique_ptr<ParticlesRenderer> particles;
std::unique_ptr<TextsRenderer> texts; std::unique_ptr<TextsRenderer> texts;

25
src/world/Environment.cpp Normal file
View file

@ -0,0 +1,25 @@
#define VC_ENABLE_REFLECTION
#include "Environment.hpp"
#include "data/dv.hpp"
#include "data/dv_util.hpp"
dv::value Environment::serialize() const {
return dv::object({
{"sky", dv::object({
{"mode", SkyModeMeta.getNameString(sky.mode)},
{"stars", sky.stars},
{"clouds", sky.clouds},
{"sprites", sky.sprites},
})},
});
}
void Environment::deserialize(const dv::value& src) {
if (auto skyItem = src.at("sky")) {
skyItem->at("mode").get(sky.mode, SkyModeMeta);
skyItem->at("stars").get(sky.stars);
skyItem->at("clouds").get(sky.clouds);
skyItem->at("sprites").get(sky.sprites);
}
}

30
src/world/Environment.hpp Normal file
View file

@ -0,0 +1,30 @@
#pragma once
#include "interfaces/Serializable.hpp"
#include "util/EnumMetadata.hpp"
enum class SkyMode {
NONE, SOLID, BOX
};
VC_ENUM_METADATA(SkyMode)
{"none", SkyMode::NONE},
{"solid", SkyMode::SOLID},
{"box", SkyMode::BOX},
VC_ENUM_END
class Environment : public Serializable {
public:
struct {
SkyMode mode = SkyMode::BOX;
bool stars = true;
bool clouds = true;
bool sprites = true;
} sky;
Environment() = default;
dv::value serialize() const override;
void deserialize(const dv::value& src) override;
private:
};

View file

@ -6,6 +6,7 @@
#include <unordered_map> #include <unordered_map>
#include "typedefs.hpp" #include "typedefs.hpp"
#include "Environment.hpp"
class Content; class Content;
class World; class World;
@ -36,6 +37,7 @@ public:
std::unique_ptr<Players> players; std::unique_ptr<Players> players;
std::unique_ptr<voxels::Pathfinding> pathfinding; std::unique_ptr<voxels::Pathfinding> pathfinding;
std::vector<std::shared_ptr<Camera>> cameras; // move somewhere? std::vector<std::shared_ptr<Camera>> cameras; // move somewhere?
Environment environment {};
Level( Level(
std::unique_ptr<World> world, std::unique_ptr<World> world,