mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-11 22:11:51 +00:00
commit
d87190d68d
33 changed files with 698 additions and 92 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
<container size='668,418' color='#0F1E2DB2' context='menu'>
|
<container size='668,444' color='#0F1E2DB2' context='menu'>
|
||||||
<panel pos='6' size='250' color='0' interval='1'>
|
<panel pos='6' size='250' color='0' interval='1'>
|
||||||
<button id='s_aud' onclick='sections:set("audio")'>@Audio</button>
|
<button id='s_aud' onclick='sections:set("audio")'>@Audio</button>
|
||||||
<button id='s_dsp' onclick='sections:set("display")'>@Display</button>
|
<button id='s_dsp' onclick='sections:set("display")'>@Display</button>
|
||||||
|
|
|
||||||
|
|
@ -46,4 +46,5 @@ function on_open()
|
||||||
create_checkbox("graphics.advanced-render", "Advanced render", "graphics.advanced-render.tooltip")
|
create_checkbox("graphics.advanced-render", "Advanced render", "graphics.advanced-render.tooltip")
|
||||||
create_setting("graphics.ssao", "SSAO", 1, "", "graphics.ssao.tooltip")
|
create_setting("graphics.ssao", "SSAO", 1, "", "graphics.ssao.tooltip")
|
||||||
create_setting("graphics.shadows-quality", "Shadows quality", 1)
|
create_setting("graphics.shadows-quality", "Shadows quality", 1)
|
||||||
|
create_setting("graphics.clouds-quality", "Clouds quality", 1)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@
|
||||||
"translucent",
|
"translucent",
|
||||||
"background",
|
"background",
|
||||||
"skybox_gen",
|
"skybox_gen",
|
||||||
"shadows"
|
"shadows",
|
||||||
|
"clouds"
|
||||||
],
|
],
|
||||||
"post-effects": [
|
"post-effects": [
|
||||||
"default",
|
"default",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
{
|
{
|
||||||
"clouds": 0.8
|
"clouds": 1.0,
|
||||||
|
"clouds_tint": [0.6, 0.7, 0.8],
|
||||||
|
"sky_tint": [1.5, 1.5, 1.5],
|
||||||
|
"min_sky_light": [0.05, 0.07, 0.1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,6 @@
|
||||||
"fog_opacity": 0.98,
|
"fog_opacity": 0.98,
|
||||||
"fog_dencity": 3.6,
|
"fog_dencity": 3.6,
|
||||||
"fog_curve": 0.25,
|
"fog_curve": 0.25,
|
||||||
"clouds": 0.8
|
"clouds": 0.9,
|
||||||
|
"min_sky_light": [0.0, 0.0, 0.0]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,5 +19,8 @@
|
||||||
"fog_opacity": 0.5,
|
"fog_opacity": 0.5,
|
||||||
"fog_dencity": 1.7,
|
"fog_dencity": 1.7,
|
||||||
"fog_curve": 0.5,
|
"fog_curve": 0.5,
|
||||||
"clouds": 0.9
|
"clouds": 0.96,
|
||||||
|
"sky_tint": [2.0, 2.0, 2.0],
|
||||||
|
"clouds_tint": [0.6, 0.7, 0.8],
|
||||||
|
"min_sky_light": [0.05, 0.07, 0.1]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,8 @@
|
||||||
"fog_opacity": 0.8,
|
"fog_opacity": 0.8,
|
||||||
"fog_dencity": 2.5,
|
"fog_dencity": 2.5,
|
||||||
"fog_curve": 0.5,
|
"fog_curve": 0.5,
|
||||||
"clouds": 0.5
|
"clouds": 1.0,
|
||||||
|
"sky_tint": [1.9, 1.9, 1.9],
|
||||||
|
"clouds_tint": [0.7, 0.8, 0.9],
|
||||||
|
"min_sky_light": [0.05, 0.07, 0.1]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,5 +19,7 @@
|
||||||
"fog_dencity": 2.0,
|
"fog_dencity": 2.0,
|
||||||
"fog_curve": 0.5,
|
"fog_curve": 0.5,
|
||||||
"clouds": 0.7,
|
"clouds": 0.7,
|
||||||
"thunder_rate": 0.1
|
"thunder_rate": 0.1,
|
||||||
|
"clouds_tint": [0.3, 0.4, 0.5],
|
||||||
|
"min_sky_light": [0.0, 0.0, 0.0]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
31
res/shaders/clouds.glslf
Normal file
31
res/shaders/clouds.glslf
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
layout (location = 0) out vec4 f_color;
|
||||||
|
layout (location = 1) out vec4 f_position;
|
||||||
|
layout (location = 2) out vec4 f_normal;
|
||||||
|
layout (location = 3) out vec4 f_emission;
|
||||||
|
|
||||||
|
#include <world_fragment_header>
|
||||||
|
|
||||||
|
in vec4 a_torchLight;
|
||||||
|
|
||||||
|
uniform sampler2D u_texture0;
|
||||||
|
uniform vec3 u_sunDir;
|
||||||
|
|
||||||
|
// flags
|
||||||
|
uniform bool u_alphaClip;
|
||||||
|
uniform bool u_debugLights;
|
||||||
|
uniform bool u_debugNormals;
|
||||||
|
uniform vec4 u_tint;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
f_color.rgb = max(a_torchLight.rgb, a_skyLight);
|
||||||
|
f_color.a = 1.0;
|
||||||
|
f_color *= u_tint;
|
||||||
|
|
||||||
|
#ifndef ADVANCED_RENDER
|
||||||
|
vec3 fogColor = texture(u_skybox, a_dir).rgb;
|
||||||
|
f_color = mix(f_color, vec4(fogColor, 1.0), a_fog);
|
||||||
|
#endif
|
||||||
|
f_position = vec4(a_position, 1.0);
|
||||||
|
f_normal = vec4(a_normal, 1.0);
|
||||||
|
f_emission = vec4(vec3(a_emission), 1.0);
|
||||||
|
}
|
||||||
49
res/shaders/clouds.glslv
Normal file
49
res/shaders/clouds.glslv
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
#include <commons>
|
||||||
|
|
||||||
|
layout (location = 0) in vec3 v_position;
|
||||||
|
layout (location = 1) in vec2 v_texCoord;
|
||||||
|
layout (location = 2) in vec4 v_light;
|
||||||
|
layout (location = 3) in vec4 v_normal;
|
||||||
|
|
||||||
|
#include <world_vertex_header>
|
||||||
|
#include <lighting>
|
||||||
|
#include <fog>
|
||||||
|
#include <sky>
|
||||||
|
|
||||||
|
uniform float u_dayTime;
|
||||||
|
|
||||||
|
out vec4 a_torchLight;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
a_modelpos = u_model * vec4(v_position, 1.0f);
|
||||||
|
a_modelpos.x += sin(u_timer * 0.05 + a_modelpos.z * 0.002) * 1.5;
|
||||||
|
a_modelpos.z += sin(u_timer * 0.2 + a_modelpos.x * 0.002) * 1.5;
|
||||||
|
a_modelpos.y += sin(u_timer * 0.1 + (a_modelpos.x + a_modelpos.z) * 0.001) * 2.0;
|
||||||
|
|
||||||
|
vec3 pos3d = a_modelpos.xyz - u_cameraPos;
|
||||||
|
|
||||||
|
a_realnormal = v_normal.xyz * 2.0 - 1.0;
|
||||||
|
a_normal = calc_screen_normal(a_realnormal);
|
||||||
|
|
||||||
|
a_torchLight = vec4(calc_torch_light(
|
||||||
|
v_light.rgb, a_realnormal, a_modelpos.xyz, u_torchlightColor, u_gamma
|
||||||
|
), 1.0);
|
||||||
|
a_texCoord = v_texCoord;
|
||||||
|
|
||||||
|
a_dir = a_modelpos.xyz - u_cameraPos;
|
||||||
|
vec3 skyLightColor = pick_sky_color(u_skybox, u_dayTime, u_minSkyLight);
|
||||||
|
a_skyLight = skyLightColor.rgb*v_light.a;
|
||||||
|
|
||||||
|
mat4 viewmodel = u_view * u_model;
|
||||||
|
a_distance = length(viewmodel * vec4(pos3d, 0.0));
|
||||||
|
|
||||||
|
#ifndef ADVANCED_RENDER
|
||||||
|
a_fog = calc_fog(length(viewmodel * vec4(pos3d * FOG_POS_SCALE, 0.0)) / 256.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
a_emission = v_normal.w;
|
||||||
|
|
||||||
|
vec4 viewmodelpos = u_view * a_modelpos;
|
||||||
|
a_position = viewmodelpos.xyz;
|
||||||
|
gl_Position = u_proj * viewmodelpos;
|
||||||
|
}
|
||||||
|
|
@ -28,7 +28,7 @@ void main() {
|
||||||
a_texCoord = v_texCoord;
|
a_texCoord = v_texCoord;
|
||||||
|
|
||||||
a_dir = a_modelpos.xyz - u_cameraPos;
|
a_dir = a_modelpos.xyz - u_cameraPos;
|
||||||
vec3 skyLightColor = pick_sky_color(u_skybox, u_dayTime);
|
vec3 skyLightColor = pick_sky_color(u_skybox, u_dayTime, u_minSkyLight);
|
||||||
a_color.rgb = max(a_color.rgb, skyLightColor.rgb * v_light.a) * v_color;
|
a_color.rgb = max(a_color.rgb, skyLightColor.rgb * v_light.a) * v_color;
|
||||||
a_color.a = u_opacity;
|
a_color.a = u_opacity;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
// lighting
|
// lighting
|
||||||
#define SKY_LIGHT_MUL 2.5
|
#define SKY_LIGHT_MUL 2.5
|
||||||
#define SKY_LIGHT_TINT (vec3(1.0, 0.75, 0.6) * 2.0)
|
#define SKY_LIGHT_TINT (vec3(1.0, 0.75, 0.6) * 2.0)
|
||||||
#define MIN_SKY_LIGHT vec3(0.2, 0.25, 0.33)
|
|
||||||
|
|
||||||
// fog
|
// fog
|
||||||
#define FOG_POS_SCALE vec3(1.0, 0.2, 1.0)
|
#define FOG_POS_SCALE vec3(1.0, 0.2, 1.0)
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
|
|
||||||
#include <constants>
|
#include <constants>
|
||||||
|
|
||||||
vec3 pick_sky_color(samplerCube cubemap, float dayTime) {
|
vec3 pick_sky_color(samplerCube cubemap, float dayTime, vec3 minSkyLight) {
|
||||||
float elevation = sin(dayTime * PI2) * 0.2;
|
float elevation = sin(dayTime * PI2) * 0.2;
|
||||||
vec3 skyLightColor = texture(cubemap, vec3(0.0f, elevation, -0.4f)).rgb;
|
vec3 skyLightColor = texture(cubemap, vec3(0.0f, elevation, -0.4f)).rgb;
|
||||||
skyLightColor *= SKY_LIGHT_TINT;
|
skyLightColor *= SKY_LIGHT_TINT;
|
||||||
skyLightColor = min(vec3(1.0f), skyLightColor * SKY_LIGHT_MUL);
|
skyLightColor = min(vec3(1.0f), skyLightColor * SKY_LIGHT_MUL);
|
||||||
skyLightColor = max(MIN_SKY_LIGHT, skyLightColor);
|
skyLightColor = max(minSkyLight, skyLightColor);
|
||||||
return skyLightColor;
|
return skyLightColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,6 @@ uniform float u_timer;
|
||||||
uniform samplerCube u_skybox;
|
uniform samplerCube u_skybox;
|
||||||
uniform vec3 u_torchlightColor;
|
uniform vec3 u_torchlightColor;
|
||||||
uniform float u_torchlightDistance;
|
uniform float u_torchlightDistance;
|
||||||
|
uniform vec3 u_minSkyLight;
|
||||||
|
|
||||||
#endif // GLSL_WORLD_UNIFORMS_
|
#endif // GLSL_WORLD_UNIFORMS_
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ void main() {
|
||||||
a_texCoord = v_texCoord;
|
a_texCoord = v_texCoord;
|
||||||
|
|
||||||
a_dir = a_modelpos.xyz - u_cameraPos;
|
a_dir = a_modelpos.xyz - u_cameraPos;
|
||||||
vec3 skyLightColor = pick_sky_color(u_skybox, u_dayTime);
|
vec3 skyLightColor = pick_sky_color(u_skybox, u_dayTime, u_minSkyLight);
|
||||||
a_skyLight = skyLightColor.rgb*v_light.a;
|
a_skyLight = skyLightColor.rgb*v_light.a;
|
||||||
|
|
||||||
mat4 viewmodel = u_view * u_model;
|
mat4 viewmodel = u_view * u_model;
|
||||||
|
|
|
||||||
|
|
@ -241,6 +241,8 @@ uniform vec3 u_xaxis;
|
||||||
uniform vec3 u_yaxis;
|
uniform vec3 u_yaxis;
|
||||||
uniform vec3 u_zaxis;
|
uniform vec3 u_zaxis;
|
||||||
uniform vec3 u_lightDir;
|
uniform vec3 u_lightDir;
|
||||||
|
uniform vec3 u_tint;
|
||||||
|
uniform vec3 u_hightlight;
|
||||||
uniform int u_quality;
|
uniform int u_quality;
|
||||||
uniform float u_mie;
|
uniform float u_mie;
|
||||||
uniform float u_fog;
|
uniform float u_fog;
|
||||||
|
|
@ -295,5 +297,5 @@ void main() {
|
||||||
col = 1.0 - exp(-col);
|
col = 1.0 - exp(-col);
|
||||||
col = min(col, vec3(1.0));
|
col = min(col, vec3(1.0));
|
||||||
// Output to screen
|
// Output to screen
|
||||||
f_color = vec4(col, 1.0);
|
f_color = vec4(col * u_tint + u_hightlight, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ void main() {
|
||||||
a_texCoord = v_texCoord;
|
a_texCoord = v_texCoord;
|
||||||
|
|
||||||
a_dir = a_modelpos.xyz - u_cameraPos;
|
a_dir = a_modelpos.xyz - u_cameraPos;
|
||||||
vec3 skyLightColor = pick_sky_color(u_skybox, u_dayTime);
|
vec3 skyLightColor = pick_sky_color(u_skybox, u_dayTime, u_minSkyLight);
|
||||||
a_skyLight = skyLightColor.rgb*v_light.a;
|
a_skyLight = skyLightColor.rgb*v_light.a;
|
||||||
|
|
||||||
mat4 viewmodel = u_view * u_model;
|
mat4 viewmodel = u_view * u_model;
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,7 @@ settings.Windowed=Оконный
|
||||||
settings.Borderless=Безрамочный
|
settings.Borderless=Безрамочный
|
||||||
settings.Microphone=Микрофон
|
settings.Microphone=Микрофон
|
||||||
settings.microphone.None=Нет
|
settings.microphone.None=Нет
|
||||||
|
settings.Clouds quality=Качество облаков
|
||||||
|
|
||||||
# Управление
|
# Управление
|
||||||
chunks.reload=Перезагрузить Чанки
|
chunks.reload=Перезагрузить Чанки
|
||||||
|
|
|
||||||
|
|
@ -130,21 +130,22 @@ void Shadows::refresh(
|
||||||
const std::function<void(Camera&)>& renderShadowPass
|
const std::function<void(Camera&)>& renderShadowPass
|
||||||
) {
|
) {
|
||||||
static int frameid = 0;
|
static int frameid = 0;
|
||||||
if (shadows) {
|
if (!shadows) {
|
||||||
if (frameid % 2 == 0) {
|
return;
|
||||||
generateShadowsMap(
|
}
|
||||||
camera, pctx, *shadowMap, shadowCamera, 1.0f, renderShadowPass
|
if (frameid % 2 == 0) {
|
||||||
);
|
generateShadowsMap(
|
||||||
} else {
|
camera, pctx, *shadowMap, shadowCamera, 1.0f, renderShadowPass
|
||||||
generateShadowsMap(
|
);
|
||||||
camera,
|
} else {
|
||||||
pctx,
|
generateShadowsMap(
|
||||||
*wideShadowMap,
|
camera,
|
||||||
wideShadowCamera,
|
pctx,
|
||||||
3.0f,
|
*wideShadowMap,
|
||||||
renderShadowPass
|
wideShadowCamera,
|
||||||
);
|
3.0f,
|
||||||
}
|
renderShadowPass
|
||||||
|
);
|
||||||
}
|
}
|
||||||
frameid++;
|
frameid++;
|
||||||
}
|
}
|
||||||
|
|
@ -176,10 +177,7 @@ void Shadows::generateShadowsMap(
|
||||||
shadowCamera.setAspectRatio(1.0f);
|
shadowCamera.setAspectRatio(1.0f);
|
||||||
|
|
||||||
float t = worldInfo.daytime - 0.25f;
|
float t = worldInfo.daytime - 0.25f;
|
||||||
if (t < 0.0f) {
|
t = glm::mod(t < 0.0f ? t + 1.0f : t, 0.5f);
|
||||||
t += 1.0f;
|
|
||||||
}
|
|
||||||
t = fmod(t, 0.5f);
|
|
||||||
|
|
||||||
float sunCycleStep = 1.0f / 500.0f;
|
float sunCycleStep = 1.0f / 500.0f;
|
||||||
float sunAngle = glm::radians(
|
float sunAngle = glm::radians(
|
||||||
|
|
@ -206,15 +204,13 @@ void Shadows::generateShadowsMap(
|
||||||
|
|
||||||
shadowCamera.setProjection(glm::ortho(min.x, max.x, min.y, max.y, 0.1f, 1000.0f));
|
shadowCamera.setProjection(glm::ortho(min.x, max.x, min.y, max.y, 0.1f, 1000.0f));
|
||||||
|
|
||||||
{
|
auto sctx = pctx.sub();
|
||||||
auto sctx = pctx.sub();
|
sctx.setDepthTest(true);
|
||||||
sctx.setDepthTest(true);
|
sctx.setCullFace(true);
|
||||||
sctx.setCullFace(true);
|
sctx.setViewport({resolution, resolution});
|
||||||
sctx.setViewport({resolution, resolution});
|
shadowMap.bind();
|
||||||
shadowMap.bind();
|
if (renderShadowPass) {
|
||||||
if (renderShadowPass) {
|
renderShadowPass(shadowCamera);
|
||||||
renderShadowPass(shadowCamera);
|
|
||||||
}
|
|
||||||
shadowMap.unbind();
|
|
||||||
}
|
}
|
||||||
|
shadowMap.unbind();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
337
src/graphics/render/CloudsRenderer.cpp
Executable file
337
src/graphics/render/CloudsRenderer.cpp
Executable file
|
|
@ -0,0 +1,337 @@
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include "CloudsRenderer.hpp"
|
||||||
|
|
||||||
|
#include "assets/Assets.hpp"
|
||||||
|
#include "coders/imageio.hpp"
|
||||||
|
#include "debug/Logger.hpp"
|
||||||
|
#include "graphics/core/ImageData.hpp"
|
||||||
|
#include "graphics/core/Mesh.hpp"
|
||||||
|
#include "graphics/core/Shader.hpp"
|
||||||
|
#include "graphics/core/Texture.hpp"
|
||||||
|
#include "io/io.hpp"
|
||||||
|
#include "lighting/Lightmap.hpp"
|
||||||
|
#include "maths/FastNoiseLite.h"
|
||||||
|
#include "maths/FrustumCulling.hpp"
|
||||||
|
#include "maths/voxmaths.hpp"
|
||||||
|
#include "window/Camera.hpp"
|
||||||
|
#include "world/Weather.hpp"
|
||||||
|
|
||||||
|
#include <glm/ext.hpp>
|
||||||
|
#include <glm/gtx/norm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
|
static debug::Logger logger("clouds-render");
|
||||||
|
|
||||||
|
static inline constexpr int MAP_SIZE = 512;
|
||||||
|
static inline constexpr float CLOUD_VOXEL_SCALE = 8.0f;
|
||||||
|
static inline constexpr float CLOUDS_SPEED = 4.0f;
|
||||||
|
|
||||||
|
class CloudsMap {
|
||||||
|
public:
|
||||||
|
glm::ivec3 size;
|
||||||
|
const bool* voxels;
|
||||||
|
|
||||||
|
CloudsMap() = default;
|
||||||
|
|
||||||
|
CloudsMap(const glm::ivec3& size, const bool* voxels)
|
||||||
|
: size(size), voxels(voxels) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isOpen(int x, int y, int z) const {
|
||||||
|
if (x >= 0 && x < size.x && y >= 0 && y < size.y && z >= 0 && z < size.z) {
|
||||||
|
return !voxels[vox_index(x, y, z, size.x, size.z)];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class VolumeRenderer final {
|
||||||
|
public:
|
||||||
|
VolumeRenderer(size_t capacity)
|
||||||
|
: vertices(std::make_unique<ChunkVertex[]>(capacity)),
|
||||||
|
indexBuffer(std::make_unique<uint32_t[]>(capacity * 6)),
|
||||||
|
capacity(capacity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~VolumeRenderer() = default;
|
||||||
|
|
||||||
|
void build(CloudsMap volumeMap) {
|
||||||
|
this->map = std::move(volumeMap);
|
||||||
|
overflow = false;
|
||||||
|
offset = 0;
|
||||||
|
indexOffset = 0;
|
||||||
|
indexCount = 0;
|
||||||
|
|
||||||
|
int end = map.size.x * map.size.y * map.size.z;
|
||||||
|
for (int i = 0; i < end; i++) {
|
||||||
|
int x = i % map.size.x;
|
||||||
|
int y = i / (map.size.z * map.size.x);
|
||||||
|
int z = (i / map.size.x) % map.size.z;
|
||||||
|
const auto& vox = map.voxels[i];
|
||||||
|
if (!vox) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cube({x, y, z});
|
||||||
|
if (overflow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshData<ChunkVertex> createMesh() const {
|
||||||
|
return MeshData(
|
||||||
|
util::Buffer(vertices.get(), offset),
|
||||||
|
std::vector<util::Buffer<uint32_t>> {
|
||||||
|
util::Buffer(indexBuffer.get(), indexCount),
|
||||||
|
},
|
||||||
|
util::Buffer(
|
||||||
|
ChunkVertex::ATTRIBUTES,
|
||||||
|
sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<ChunkVertex[]> vertices;
|
||||||
|
std::unique_ptr<uint32_t[]> indexBuffer;
|
||||||
|
size_t capacity;
|
||||||
|
uint32_t indexOffset = 0;
|
||||||
|
uint32_t indexCount = 0;
|
||||||
|
uint32_t offset = 0;
|
||||||
|
bool overflow = false;
|
||||||
|
CloudsMap map {};
|
||||||
|
|
||||||
|
void vertex(
|
||||||
|
const glm::vec3& coord,
|
||||||
|
const glm::vec3& normal
|
||||||
|
) {
|
||||||
|
auto& vert = vertices[offset++];
|
||||||
|
vert.position = coord;
|
||||||
|
vert.uv = {};
|
||||||
|
vert.normal = {
|
||||||
|
static_cast<uint8_t>(normal.r * 127 + 128),
|
||||||
|
static_cast<uint8_t>(normal.g * 127 + 128),
|
||||||
|
static_cast<uint8_t>(normal.b * 127 + 128),
|
||||||
|
255
|
||||||
|
};
|
||||||
|
vert.color = {
|
||||||
|
0, 0, 0, static_cast<uint8_t>((coord.y / 8.0f * 0.25f + 0.75f) * 255)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void face(
|
||||||
|
const glm::vec3& coord,
|
||||||
|
const glm::vec3& X,
|
||||||
|
const glm::vec3& Y,
|
||||||
|
const glm::vec3& Z
|
||||||
|
) {
|
||||||
|
if (!isOpen(coord + Z)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (offset + 4 >= capacity) {
|
||||||
|
overflow = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float s = 0.5f;
|
||||||
|
vertex(coord + (-X - Y + Z) * s, Z);
|
||||||
|
vertex(coord + ( X - Y + Z) * s, Z);
|
||||||
|
vertex(coord + ( X + Y + Z) * s, Z);
|
||||||
|
vertex(coord + (-X + Y + Z) * s, Z);
|
||||||
|
|
||||||
|
const uint32_t indices[] {0, 1, 2, 0, 2, 3};
|
||||||
|
for (size_t i = 0; i < 6; i++) {
|
||||||
|
indexBuffer[indexCount++] = indexOffset + indices[i];
|
||||||
|
}
|
||||||
|
indexOffset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isOpen(const glm::ivec3& pos) const {
|
||||||
|
return pos.y < 0 || pos.y >= map.size.y ||
|
||||||
|
map.isOpen(pos.x, pos.y, pos.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cube(const glm::ivec3& coord) {
|
||||||
|
const glm::ivec3 X(1, 0, 0);
|
||||||
|
const glm::ivec3 Y(0, 1, 0);
|
||||||
|
const glm::ivec3 Z(0, 0, 1);
|
||||||
|
|
||||||
|
face(coord, X, Y, Z);
|
||||||
|
face(coord, -X, Y, -Z);
|
||||||
|
face(coord, X, -Z, Y);
|
||||||
|
face(coord, X, Z, -Y);
|
||||||
|
face(coord, -Z, Y, X);
|
||||||
|
face(coord, Z, Y, -X);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void generate_heightmap(
|
||||||
|
float* heightmap, fnl_state& state, int w, int dd, int layerid
|
||||||
|
) {
|
||||||
|
float pi2 = glm::two_pi<float>();
|
||||||
|
|
||||||
|
for (int lz = 0; lz < dd; lz++) {
|
||||||
|
for (int lx = 0; lx < w; lx++) {
|
||||||
|
float x = glm::sin(lx / static_cast<float>(w) * pi2) * w / pi2;
|
||||||
|
float y = -glm::cos(lx / static_cast<float>(w) * pi2) * w / pi2;
|
||||||
|
float z = lz;
|
||||||
|
float s = 1.5f;
|
||||||
|
auto n = fnlGetNoise3D(&state, x * s * 0.7, y * s, z * s * 0.7);
|
||||||
|
n += fnlGetNoise3D(&state, x * s + fnlGetNoise2D(&state, x * s * 4 + 2, z * s * 4) * 2.0f, y * s, z * 3.0f) * 0.5f;
|
||||||
|
n += fnlGetNoise3D(&state, x * s * 2, y * s * 2, z * s * 2) * 0.25f;
|
||||||
|
n += fnlGetNoise3D(&state, x * s * 4, y * s * 4, z * s * 4) * 0.125f * 2;
|
||||||
|
n += fnlGetNoise3D(&state, x * s * 8, y * s * 8, z * s * 8) * 0.125f * 0.5f * 2;
|
||||||
|
n += fnlGetNoise3D(&state, x * s * 16, y * s * 16, z * s * 16) * 0.125f * 0.25f * 3;
|
||||||
|
n = glm::max(0.0f, n);
|
||||||
|
n += -0.1f - layerid * 0.3f;
|
||||||
|
|
||||||
|
heightmap[lz * w + lx] = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sample_voxels(
|
||||||
|
bool* voxels,
|
||||||
|
const float* heightmap,
|
||||||
|
int height,
|
||||||
|
int segmentSize,
|
||||||
|
int segmentX,
|
||||||
|
int segmentZ
|
||||||
|
) {
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int z = 0; z < segmentSize; z++) {
|
||||||
|
for (int x = 0; x < segmentSize; x++) {
|
||||||
|
int gx = (segmentX * segmentSize) + x;
|
||||||
|
int gz = (segmentZ * segmentSize) + z;
|
||||||
|
|
||||||
|
float n = heightmap[gz * MAP_SIZE + gx];
|
||||||
|
if (gz < MAP_SIZE / 2) {
|
||||||
|
float t = gz / static_cast<float>(MAP_SIZE / 2);
|
||||||
|
n = n * t +
|
||||||
|
heightmap[(MAP_SIZE + gz) * MAP_SIZE + gx] * (1.0f - t);
|
||||||
|
}
|
||||||
|
bool solid = y <= n * height && y >= (0.5f - n * 0.5f) * height;
|
||||||
|
voxels[vox_index(x, y, z, segmentSize, segmentSize)] = solid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloudsRenderer::CloudsRenderer() {
|
||||||
|
VolumeRenderer volumeRenderer(1024 * 512);
|
||||||
|
|
||||||
|
const int diameter = 4;
|
||||||
|
const int segmentSize = MAP_SIZE / diameter;
|
||||||
|
|
||||||
|
const int w = MAP_SIZE;
|
||||||
|
const int h = 8;
|
||||||
|
const int d = MAP_SIZE;
|
||||||
|
const int dd = d * 1.5;
|
||||||
|
auto heightmap = std::make_unique<float[]>(w * dd);
|
||||||
|
|
||||||
|
for (int layerid = 0; layerid < 2; layerid++) {
|
||||||
|
auto& layer = layers[layerid];
|
||||||
|
layer.diameter = diameter;
|
||||||
|
layer.segmentSize = segmentSize;
|
||||||
|
|
||||||
|
fnl_state state = fnlCreateState();
|
||||||
|
state.seed = 5265 + layerid * 3521;
|
||||||
|
|
||||||
|
generate_heightmap(heightmap.get(), state, w, dd, layerid);
|
||||||
|
|
||||||
|
bool voxels[segmentSize * h * segmentSize];
|
||||||
|
for (int sz = 0; sz < diameter; sz++) {
|
||||||
|
for (int sx = 0; sx < diameter; sx++) {
|
||||||
|
sample_voxels(voxels, heightmap.get(), h, segmentSize, sx, sz);
|
||||||
|
|
||||||
|
CloudsMap map({segmentSize, h, segmentSize}, voxels);
|
||||||
|
|
||||||
|
volumeRenderer.build(map);
|
||||||
|
layer.meshes.push_back(std::make_unique<Mesh<ChunkVertex>>(
|
||||||
|
volumeRenderer.createMesh()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloudsRenderer::~CloudsRenderer() = default;
|
||||||
|
|
||||||
|
void CloudsRenderer::draw(
|
||||||
|
Layer& layer,
|
||||||
|
Frustum& frustum,
|
||||||
|
Shader& shader,
|
||||||
|
const Camera& camera,
|
||||||
|
float timer,
|
||||||
|
int layerId
|
||||||
|
) {
|
||||||
|
float scale = CLOUD_VOXEL_SCALE;
|
||||||
|
int totalDiameter = layer.segmentSize * scale;
|
||||||
|
|
||||||
|
int gcellX = floordiv(camera.position.x, totalDiameter);
|
||||||
|
int gcellZ = floordiv(camera.position.z, totalDiameter);
|
||||||
|
|
||||||
|
float speed = CLOUDS_SPEED;
|
||||||
|
float speedX = glm::sin(layerId * 0.3f + 0.4f) * speed / (layerId + 1);
|
||||||
|
float speedZ = -glm::cos(layerId * 0.3f + 0.4f) * speed / (layerId + 1);
|
||||||
|
|
||||||
|
int radius = 4;
|
||||||
|
|
||||||
|
for (int x = -radius; x <= radius; x++) {
|
||||||
|
for (int z = -radius; z <= radius; z++) {
|
||||||
|
int lcellX = gcellX - floordiv(glm::floor(timer * speedX), totalDiameter);
|
||||||
|
int lcellZ = gcellZ - floordiv(glm::floor(timer * speedZ), totalDiameter);
|
||||||
|
glm::vec3 position(
|
||||||
|
-128 * scale + (x + gcellX) * layer.segmentSize * scale +
|
||||||
|
glm::mod(timer * speedX, static_cast<float>(totalDiameter)),
|
||||||
|
250 + layerId * 200,
|
||||||
|
-128 * scale + (z + gcellZ) * layer.segmentSize * scale +
|
||||||
|
glm::mod(timer * speedZ, static_cast<float>(totalDiameter))
|
||||||
|
);
|
||||||
|
if (glm::distance2(
|
||||||
|
glm::vec2(
|
||||||
|
position.x + totalDiameter * 0.5f,
|
||||||
|
position.z + totalDiameter * 0.5f
|
||||||
|
),
|
||||||
|
glm::vec2(camera.position.x, camera.position.z)
|
||||||
|
) > 4e6) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!frustum.isBoxVisible(position, position + glm::vec3(layer.segmentSize * scale))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto matrix = glm::mat4(1.0f);
|
||||||
|
matrix = glm::translate(matrix, position);
|
||||||
|
matrix = glm::scale(matrix, glm::vec3(scale, scale, scale));
|
||||||
|
shader.uniformMatrix("u_model", matrix);
|
||||||
|
|
||||||
|
int lx = (x + radius + lcellX) % layer.diameter;
|
||||||
|
int lz = (z + radius + lcellZ) % layer.diameter;
|
||||||
|
if (lx < 0) lx += layer.diameter;
|
||||||
|
if (lz < 0) lz += layer.diameter;
|
||||||
|
|
||||||
|
layer.meshes[lz * layer.diameter + lx]->draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloudsRenderer::draw(
|
||||||
|
Shader& shader,
|
||||||
|
const Weather& weather,
|
||||||
|
float timer,
|
||||||
|
float fogFactor,
|
||||||
|
const Camera& camera,
|
||||||
|
int quality
|
||||||
|
) {
|
||||||
|
Frustum frustum;
|
||||||
|
frustum.update(camera.getProjView());
|
||||||
|
|
||||||
|
shader.uniform4f("u_tint", glm::vec4(weather.cloudsTint(), 1.0f));
|
||||||
|
shader.uniform1f("u_fogFactor", fogFactor * 0.03f);
|
||||||
|
shader.uniform1f("u_fogCurve", 0.7f - 0.3f);
|
||||||
|
|
||||||
|
for (int i = 0; i < std::min<int>(quality, layers.size()); i++) {
|
||||||
|
draw(layers[i], frustum, shader, camera, timer, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/graphics/render/CloudsRenderer.hpp
Executable file
44
src/graphics/render/CloudsRenderer.hpp
Executable file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Camera;
|
||||||
|
class Shader;
|
||||||
|
struct Weather;
|
||||||
|
class Frustum;
|
||||||
|
|
||||||
|
class CloudsRenderer final {
|
||||||
|
public:
|
||||||
|
CloudsRenderer();
|
||||||
|
~CloudsRenderer();
|
||||||
|
|
||||||
|
void draw(
|
||||||
|
Shader& shader,
|
||||||
|
const Weather& weather,
|
||||||
|
float timer,
|
||||||
|
float fogFactor,
|
||||||
|
const Camera& camera,
|
||||||
|
int quality
|
||||||
|
);
|
||||||
|
private:
|
||||||
|
struct Layer {
|
||||||
|
int diameter;
|
||||||
|
int segmentSize;
|
||||||
|
std::vector<std::unique_ptr<Mesh<ChunkVertex>>> meshes;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::array<Layer, 2> layers;
|
||||||
|
|
||||||
|
void draw(
|
||||||
|
Layer& layer,
|
||||||
|
Frustum& frustum,
|
||||||
|
Shader& shader,
|
||||||
|
const Camera& camera,
|
||||||
|
float timer,
|
||||||
|
int layerId
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -151,7 +151,7 @@ void PrecipitationRenderer::render(
|
||||||
glm::cross(glm::vec3(0, 1, 0), face.right),
|
glm::cross(glm::vec3(0, 1, 0), face.right),
|
||||||
FACE_SIZE,
|
FACE_SIZE,
|
||||||
light_at(chunks, pos.x, y, pos.z),
|
light_at(chunks, pos.x, y, pos.z),
|
||||||
glm::vec3(3.0f),
|
glm::vec3(1.0f),
|
||||||
calc_uv(pos, face.right, timer, weather)
|
calc_uv(pos, face.right, timer, weather)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,7 @@ void Skybox::draw(
|
||||||
drawStars(angle, opacity);
|
drawStars(angle, opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality) {
|
void Skybox::refresh(const DrawContext& pctx, float t, float mie, const glm::vec3& tint, const glm::vec3& hightlight, uint quality) {
|
||||||
frameid++;
|
frameid++;
|
||||||
float dayTime = t;
|
float dayTime = t;
|
||||||
DrawContext ctx = pctx.sub();
|
DrawContext ctx = pctx.sub();
|
||||||
|
|
@ -201,11 +201,13 @@ void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality)
|
||||||
|
|
||||||
shader.uniform1i("u_quality", quality);
|
shader.uniform1i("u_quality", quality);
|
||||||
shader.uniform1f("u_mie", mie);
|
shader.uniform1f("u_mie", mie);
|
||||||
|
shader.uniform3f("u_tint", tint);
|
||||||
|
shader.uniform3f("u_hightlight", hightlight);
|
||||||
shader.uniform1f("u_fog", mie - 1.0f);
|
shader.uniform1f("u_fog", mie - 1.0f);
|
||||||
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) >= 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);
|
||||||
}
|
}
|
||||||
|
|
@ -215,6 +217,7 @@ void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality)
|
||||||
}
|
}
|
||||||
prevMie = mie;
|
prevMie = mie;
|
||||||
prevT = t;
|
prevT = t;
|
||||||
|
prevHighlight = hightlight;
|
||||||
|
|
||||||
cubemap->unbind();
|
cubemap->unbind();
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ class Skybox {
|
||||||
float prevMie = -1.0f;
|
float prevMie = -1.0f;
|
||||||
float prevT = -1.0f;
|
float prevT = -1.0f;
|
||||||
float sunAltitude = 45.0f;
|
float sunAltitude = 45.0f;
|
||||||
|
glm::vec3 prevHighlight {1.0f};
|
||||||
glm::mat4 rotation;
|
glm::mat4 rotation;
|
||||||
|
|
||||||
void drawStars(float angle, float opacity);
|
void drawStars(float angle, float opacity);
|
||||||
|
|
@ -68,7 +69,7 @@ public:
|
||||||
float fog
|
float fog
|
||||||
);
|
);
|
||||||
|
|
||||||
void refresh(const DrawContext& pctx, float t, float mie, uint quality);
|
void refresh(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 {
|
bool isReady() const {
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@
|
||||||
#include "Skybox.hpp"
|
#include "Skybox.hpp"
|
||||||
#include "Emitter.hpp"
|
#include "Emitter.hpp"
|
||||||
#include "TextNote.hpp"
|
#include "TextNote.hpp"
|
||||||
|
#include "CloudsRenderer.hpp"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
@ -116,6 +117,7 @@ WorldRenderer::WorldRenderer(
|
||||||
);
|
);
|
||||||
shadowMapping = std::make_unique<Shadows>(level);
|
shadowMapping = std::make_unique<Shadows>(level);
|
||||||
debugLines = std::make_unique<DebugLinesRenderer>(level);
|
debugLines = std::make_unique<DebugLinesRenderer>(level);
|
||||||
|
cloudsRenderer = std::make_unique<CloudsRenderer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldRenderer::~WorldRenderer() = default;
|
WorldRenderer::~WorldRenderer() = default;
|
||||||
|
|
@ -124,6 +126,7 @@ static void setup_weather(Shader& shader, const Weather& weather) {
|
||||||
shader.uniform1f("u_weatherFogOpacity", weather.fogOpacity());
|
shader.uniform1f("u_weatherFogOpacity", weather.fogOpacity());
|
||||||
shader.uniform1f("u_weatherFogDencity", weather.fogDencity());
|
shader.uniform1f("u_weatherFogDencity", weather.fogDencity());
|
||||||
shader.uniform1f("u_weatherFogCurve", weather.fogCurve());
|
shader.uniform1f("u_weatherFogCurve", weather.fogCurve());
|
||||||
|
shader.uniform3f("u_minSkyLight", weather.minSkyLight());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_camera(Shader& shader, const Camera& camera) {
|
static void setup_camera(Shader& shader, const Camera& camera) {
|
||||||
|
|
@ -205,6 +208,7 @@ void WorldRenderer::renderOpaque(
|
||||||
particles->render(camera);
|
particles->render(camera);
|
||||||
|
|
||||||
auto& shader = assets.require<Shader>("main");
|
auto& shader = assets.require<Shader>("main");
|
||||||
|
auto& cloudsShader = assets.require<Shader>("clouds");
|
||||||
auto& linesShader = assets.require<Shader>("lines");
|
auto& linesShader = assets.require<Shader>("lines");
|
||||||
|
|
||||||
setupWorldShader(shader, camera, settings, fogFactor);
|
setupWorldShader(shader, camera, settings, fogFactor);
|
||||||
|
|
@ -212,6 +216,14 @@ void WorldRenderer::renderOpaque(
|
||||||
chunksRenderer->drawChunks(camera, shader);
|
chunksRenderer->drawChunks(camera, shader);
|
||||||
blockWraps->draw(ctx, player);
|
blockWraps->draw(ctx, player);
|
||||||
|
|
||||||
|
int cloudsQuality = settings.graphics.cloudsQuality.get();
|
||||||
|
if (cloudsQuality > 0) {
|
||||||
|
setupWorldShader(cloudsShader, camera, settings, fogFactor);
|
||||||
|
cloudsRenderer->draw(
|
||||||
|
cloudsShader, weather, timer, fogFactor, camera, cloudsQuality
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (hudVisible) {
|
if (hudVisible) {
|
||||||
renderLines(camera, linesShader, ctx);
|
renderLines(camera, linesShader, ctx);
|
||||||
}
|
}
|
||||||
|
|
@ -314,13 +326,19 @@ void WorldRenderer::renderFrame(
|
||||||
|
|
||||||
auto& mainShader = assets.require<Shader>("main");
|
auto& mainShader = assets.require<Shader>("main");
|
||||||
auto& entityShader = assets.require<Shader>("entity");
|
auto& entityShader = assets.require<Shader>("entity");
|
||||||
|
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();
|
||||||
|
|
||||||
Shader* affectedShaders[] {
|
Shader* affectedShaders[] {
|
||||||
&mainShader, &entityShader, &translucentShader, &deferredShader, nullptr
|
&mainShader,
|
||||||
|
&entityShader,
|
||||||
|
&cloudsShader,
|
||||||
|
&translucentShader,
|
||||||
|
&deferredShader,
|
||||||
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
refreshSettings(affectedShaders);
|
refreshSettings(affectedShaders);
|
||||||
|
|
@ -331,7 +349,15 @@ void WorldRenderer::renderFrame(
|
||||||
clouds = glm::max(worldInfo.fog, clouds);
|
clouds = glm::max(worldInfo.fog, clouds);
|
||||||
float mie = 1.0f + glm::max(worldInfo.fog, clouds * 0.5f) * 2.0f;
|
float mie = 1.0f + glm::max(worldInfo.fog, clouds * 0.5f) * 2.0f;
|
||||||
|
|
||||||
skybox->refresh(pctx, worldInfo.daytime, mie, 4);
|
float random = rand() / static_cast<float>(RAND_MAX);
|
||||||
|
skybox->refresh(
|
||||||
|
pctx,
|
||||||
|
worldInfo.daytime,
|
||||||
|
mie,
|
||||||
|
weather.skyTint(),
|
||||||
|
weather.highlight * random,
|
||||||
|
4
|
||||||
|
);
|
||||||
|
|
||||||
chunksRenderer->update();
|
chunksRenderer->update();
|
||||||
|
|
||||||
|
|
@ -369,7 +395,7 @@ void WorldRenderer::renderFrame(
|
||||||
if (gbufferPipeline) {
|
if (gbufferPipeline) {
|
||||||
postProcessing.bindDepthBuffer();
|
postProcessing.bindDepthBuffer();
|
||||||
} else {
|
} else {
|
||||||
postProcessing.getFramebuffer()->bind();
|
ctx.setFramebuffer(postProcessing.getFramebuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Background sky plane
|
// Background sky plane
|
||||||
|
|
@ -385,15 +411,14 @@ void WorldRenderer::renderFrame(
|
||||||
linesShader.uniformMatrix("u_projview", projView);
|
linesShader.uniformMatrix("u_projview", projView);
|
||||||
lineBatch->flush();
|
lineBatch->flush();
|
||||||
|
|
||||||
|
skybox->bind();
|
||||||
// Translucent blocks
|
// Translucent blocks
|
||||||
{
|
{
|
||||||
auto sctx = ctx.sub();
|
auto sctx = ctx.sub();
|
||||||
sctx.setCullFace(true);
|
sctx.setCullFace(true);
|
||||||
skybox->bind();
|
|
||||||
translucentShader.use();
|
translucentShader.use();
|
||||||
setupWorldShader(translucentShader, camera, settings, fogFactor);
|
setupWorldShader(translucentShader, camera, settings, fogFactor);
|
||||||
chunksRenderer->drawSortedMeshes(camera, translucentShader);
|
chunksRenderer->drawSortedMeshes(camera, translucentShader);
|
||||||
skybox->unbind();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weather effects
|
// Weather effects
|
||||||
|
|
@ -412,6 +437,7 @@ void WorldRenderer::renderFrame(
|
||||||
precipitation->render(camera, *weather);
|
precipitation->render(camera, *weather);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
skybox->unbind();
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
@ -448,43 +474,45 @@ void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) {
|
||||||
int y = std::floor(player.currentCamera->position.y);
|
int y = std::floor(player.currentCamera->position.y);
|
||||||
int z = std::floor(player.currentCamera->position.z);
|
int z = std::floor(player.currentCamera->position.z);
|
||||||
auto block = player.chunks->get(x, y, z);
|
auto block = player.chunks->get(x, y, z);
|
||||||
if (block && block->id) {
|
|
||||||
const auto& def = level.content.getIndices()->blocks.require(block->id);
|
|
||||||
if (def.overlayTexture.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto textureRegion = util::get_texture_region(
|
|
||||||
assets, def.overlayTexture, "blocks:notfound"
|
|
||||||
);
|
|
||||||
DrawContext ctx = wctx.sub();
|
|
||||||
ctx.setDepthTest(false);
|
|
||||||
ctx.setCullFace(false);
|
|
||||||
|
|
||||||
auto& shader = assets.require<Shader>("ui3d");
|
if (block == nullptr || block->id == BLOCK_AIR || block->id == BLOCK_VOID) {
|
||||||
shader.use();
|
return;
|
||||||
batch3d->begin();
|
|
||||||
shader.uniformMatrix("u_projview", glm::mat4(1.0f));
|
|
||||||
shader.uniformMatrix("u_apply", glm::mat4(1.0f));
|
|
||||||
auto light = player.chunks->getLight(x, y, z);
|
|
||||||
float s = Lightmap::extract(light, 3) / 15.0f;
|
|
||||||
glm::vec4 tint(
|
|
||||||
glm::min(1.0f, Lightmap::extract(light, 0) / 15.0f + s),
|
|
||||||
glm::min(1.0f, Lightmap::extract(light, 1) / 15.0f + s),
|
|
||||||
glm::min(1.0f, Lightmap::extract(light, 2) / 15.0f + s),
|
|
||||||
1.0f
|
|
||||||
);
|
|
||||||
batch3d->texture(textureRegion.texture);
|
|
||||||
batch3d->sprite(
|
|
||||||
glm::vec3(),
|
|
||||||
glm::vec3(0, 1, 0),
|
|
||||||
glm::vec3(1, 0, 0),
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
textureRegion.region,
|
|
||||||
tint
|
|
||||||
);
|
|
||||||
batch3d->flush();
|
|
||||||
}
|
}
|
||||||
|
const auto& def = level.content.getIndices()->blocks.require(block->id);
|
||||||
|
if (def.overlayTexture.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto textureRegion = util::get_texture_region(
|
||||||
|
assets, def.overlayTexture, "blocks:notfound"
|
||||||
|
);
|
||||||
|
DrawContext ctx = wctx.sub();
|
||||||
|
ctx.setDepthTest(false);
|
||||||
|
ctx.setCullFace(false);
|
||||||
|
|
||||||
|
auto& shader = assets.require<Shader>("ui3d");
|
||||||
|
shader.use();
|
||||||
|
batch3d->begin();
|
||||||
|
shader.uniformMatrix("u_projview", glm::mat4(1.0f));
|
||||||
|
shader.uniformMatrix("u_apply", glm::mat4(1.0f));
|
||||||
|
auto light = player.chunks->getLight(x, y, z);
|
||||||
|
float s = Lightmap::extract(light, 3) / 15.0f;
|
||||||
|
glm::vec4 tint(
|
||||||
|
glm::min(1.0f, Lightmap::extract(light, 0) / 15.0f + s),
|
||||||
|
glm::min(1.0f, Lightmap::extract(light, 1) / 15.0f + s),
|
||||||
|
glm::min(1.0f, Lightmap::extract(light, 2) / 15.0f + s),
|
||||||
|
1.0f
|
||||||
|
);
|
||||||
|
batch3d->texture(textureRegion.texture);
|
||||||
|
batch3d->sprite(
|
||||||
|
glm::vec3(),
|
||||||
|
glm::vec3(0, 1, 0),
|
||||||
|
glm::vec3(1, 0, 0),
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
textureRegion.region,
|
||||||
|
tint
|
||||||
|
);
|
||||||
|
batch3d->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldRenderer::clear() {
|
void WorldRenderer::clear() {
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ class Shader;
|
||||||
class Shadows;
|
class Shadows;
|
||||||
class Skybox;
|
class Skybox;
|
||||||
class TextsRenderer;
|
class TextsRenderer;
|
||||||
|
class CloudsRenderer;
|
||||||
struct EngineSettings;
|
struct EngineSettings;
|
||||||
|
|
||||||
struct CompileTimeShaderSettings {
|
struct CompileTimeShaderSettings {
|
||||||
|
|
@ -57,6 +58,7 @@ class WorldRenderer {
|
||||||
std::unique_ptr<Shadows> shadowMapping;
|
std::unique_ptr<Shadows> shadowMapping;
|
||||||
std::unique_ptr<DebugLinesRenderer> debugLines;
|
std::unique_ptr<DebugLinesRenderer> debugLines;
|
||||||
std::unique_ptr<PrecipitationRenderer> precipitation;
|
std::unique_ptr<PrecipitationRenderer> precipitation;
|
||||||
|
std::unique_ptr<CloudsRenderer> cloudsRenderer;
|
||||||
Weather weather {};
|
Weather weather {};
|
||||||
|
|
||||||
float timer = 0.0f;
|
float timer = 0.0f;
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
||||||
builder.add("shadows-quality", &settings.graphics.shadowsQuality);
|
builder.add("shadows-quality", &settings.graphics.shadowsQuality);
|
||||||
builder.add("dense-render-distance", &settings.graphics.denseRenderDistance);
|
builder.add("dense-render-distance", &settings.graphics.denseRenderDistance);
|
||||||
builder.add("soft-lighting", &settings.graphics.softLighting);
|
builder.add("soft-lighting", &settings.graphics.softLighting);
|
||||||
|
builder.add("clouds-quality", &settings.graphics.cloudsQuality);
|
||||||
|
|
||||||
builder.addSection("ui");
|
builder.addSection("ui");
|
||||||
builder.add("language", &settings.ui.language);
|
builder.add("language", &settings.ui.language);
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,9 @@ dv::value WeatherPreset::serialize() const {
|
||||||
root["fog_opacity"] = fogOpacity;
|
root["fog_opacity"] = fogOpacity;
|
||||||
root["fog_dencity"] = fogDencity;
|
root["fog_dencity"] = fogDencity;
|
||||||
root["fog_curve"] = fogCurve;
|
root["fog_curve"] = fogCurve;
|
||||||
|
root["sky_tint"] = dv::to_value(skyTint);
|
||||||
|
root["clouds_tint"] = dv::to_value(cloudsTint);
|
||||||
|
root["min_sky_light"] = dv::to_value(minSkyLight);
|
||||||
root["clouds"] = clouds;
|
root["clouds"] = clouds;
|
||||||
root["thunder_rate"] = thunderRate;
|
root["thunder_rate"] = thunderRate;
|
||||||
|
|
||||||
|
|
@ -51,6 +54,9 @@ void WeatherPreset::deserialize(const dv::value& src) {
|
||||||
src.at("fog_opacity").get(fogOpacity);
|
src.at("fog_opacity").get(fogOpacity);
|
||||||
src.at("fog_dencity").get(fogDencity);
|
src.at("fog_dencity").get(fogDencity);
|
||||||
src.at("fog_curve").get(fogCurve);
|
src.at("fog_curve").get(fogCurve);
|
||||||
|
dv::get_vec(src, "sky_tint", skyTint);
|
||||||
|
dv::get_vec(src, "clouds_tint", cloudsTint);
|
||||||
|
dv::get_vec(src, "min_sky_light", minSkyLight);
|
||||||
src.at("clouds").get(clouds);
|
src.at("clouds").get(clouds);
|
||||||
src.at("thunder_rate").get(thunderRate);
|
src.at("thunder_rate").get(thunderRate);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,15 @@ struct WeatherPreset : Serializable {
|
||||||
/// @brief Weather effects intensity
|
/// @brief Weather effects intensity
|
||||||
float intensity = 0.0f;
|
float intensity = 0.0f;
|
||||||
|
|
||||||
|
/// @brief Skybox color multiplier
|
||||||
|
glm::vec3 skyTint {1.0f, 1.0f, 1.0f};
|
||||||
|
|
||||||
|
/// @brief Clouds color multiplier
|
||||||
|
glm::vec3 cloudsTint {1.0f, 1.0f, 1.0f};
|
||||||
|
|
||||||
|
/// @brief Minimal sky-emitted lights (moon light)
|
||||||
|
glm::vec3 minSkyLight {0.2f, 0.25f, 0.33f};
|
||||||
|
|
||||||
dv::value serialize() const override;
|
dv::value serialize() const override;
|
||||||
void deserialize(const dv::value& src) override;
|
void deserialize(const dv::value& src) override;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,8 @@ struct GraphicsSettings {
|
||||||
IntegerSetting denseRenderDistance {56, 0, 10'000};
|
IntegerSetting denseRenderDistance {56, 0, 10'000};
|
||||||
/// @brief Soft lighting for blocks
|
/// @brief Soft lighting for blocks
|
||||||
FlagSetting softLighting {true};
|
FlagSetting softLighting {true};
|
||||||
|
/// @brief Clouds quality level
|
||||||
|
IntegerSetting cloudsQuality {2, 0, 2};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PathfindingSettings {
|
struct PathfindingSettings {
|
||||||
|
|
|
||||||
55
src/voxels/VoxelsVolume.cpp
Normal file
55
src/voxels/VoxelsVolume.cpp
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include "VoxelsVolume.hpp"
|
||||||
|
|
||||||
|
#include "constants.hpp"
|
||||||
|
#include "content/Content.hpp"
|
||||||
|
#include "voxels/Block.hpp"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
void VoxelsVolume::compressInto(VoxelsVolume& dst, const Content& content) const {
|
||||||
|
assert(dst.w < w && dst.h < h && dst.d < d);
|
||||||
|
assert(w % dst.w == 0 && h % dst.h == 0 && d % dst.d == 0);
|
||||||
|
|
||||||
|
int stepW = w / dst.w;
|
||||||
|
int stepH = h / dst.h;
|
||||||
|
int stepD = d / dst.d;
|
||||||
|
int height = dst.h;
|
||||||
|
int depth = dst.d;
|
||||||
|
int width = dst.w;
|
||||||
|
|
||||||
|
auto dstVoxels = dst.getVoxels();
|
||||||
|
auto dstLights = dst.getLights();
|
||||||
|
|
||||||
|
const auto& blockDefs = content.getIndices()->blocks;
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int z = 0; z < depth; z++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
voxel selectedVoxel {BLOCK_AIR, {}};
|
||||||
|
light_t light = 0;
|
||||||
|
for (int ly = 0; ly < stepH; ly++) {
|
||||||
|
for (int lz = 0; lz < stepD; lz++) {
|
||||||
|
for (int lx = 0; lx < stepW; lx++) {
|
||||||
|
size_t srcIndex = vox_index(
|
||||||
|
x * stepW + lx, y * stepH + ly, z * stepD, w, d
|
||||||
|
);
|
||||||
|
auto vox = voxels[srcIndex];
|
||||||
|
if (vox.id == BLOCK_VOID) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto& def = blockDefs.require(vox.id);
|
||||||
|
if (def.rt.solid) {
|
||||||
|
selectedVoxel = std::move(vox);
|
||||||
|
} else if (light == 0) {
|
||||||
|
light = lights[srcIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size_t dstIndex = vox_index(x, y, z, dst.w, dst.d);
|
||||||
|
dstLights[dstIndex] = light;
|
||||||
|
dstVoxels[dstIndex] = std::move(selectedVoxel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,15 +6,17 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
class Content;
|
||||||
|
|
||||||
class VoxelsVolume {
|
class VoxelsVolume {
|
||||||
public:
|
public:
|
||||||
static inline constexpr size_t MAX_VOXELS = CHUNK_VOL * 2;
|
|
||||||
|
|
||||||
VoxelsVolume(int w, int h, int d)
|
VoxelsVolume(int w, int h, int d)
|
||||||
: VoxelsVolume(0, 0, 0, w, h, d) {}
|
: VoxelsVolume(0, 0, 0, w, h, d) {}
|
||||||
|
|
||||||
VoxelsVolume(int x, int y, int z, int w, int h, int d)
|
VoxelsVolume(int x, int y, int z, int w, int h, int d)
|
||||||
: x(x), y(y), z(z), w(w), h(h), d(d) {
|
: x(x), y(y), z(z), w(w), h(h), d(d),
|
||||||
|
voxels(std::make_unique<voxel[]>(w * h * d)),
|
||||||
|
lights(std::make_unique<light_t[]>(w * h * d)) {
|
||||||
std::memset(voxels.get(), 0xFF, sizeof(voxel) * w * h * d);
|
std::memset(voxels.get(), 0xFF, sizeof(voxel) * w * h * d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,10 +54,18 @@ public:
|
||||||
return voxels.get();
|
return voxels.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const voxel* getVoxels() const {
|
||||||
|
return voxels.get();
|
||||||
|
}
|
||||||
|
|
||||||
light_t* getLights() {
|
light_t* getLights() {
|
||||||
return lights.get();
|
return lights.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const light_t* getLights() const {
|
||||||
|
return lights.get();
|
||||||
|
}
|
||||||
|
|
||||||
inline blockid_t pickBlockId(int bx, int by, int bz) const {
|
inline blockid_t pickBlockId(int bx, int by, int bz) const {
|
||||||
if (bx < x || by < y || bz < z || bx >= x + w || by >= y + h ||
|
if (bx < x || by < y || bz < z || bx >= x + w || by >= y + h ||
|
||||||
bz >= z + d) {
|
bz >= z + d) {
|
||||||
|
|
@ -80,6 +90,8 @@ public:
|
||||||
}
|
}
|
||||||
return lights[vox_index(bx - x, by - y, bz - z, w, d)];
|
return lights[vox_index(bx - x, by - y, bz - z, w, d)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void compressInto(VoxelsVolume& dst, const Content& content) const;
|
||||||
private:
|
private:
|
||||||
int x, y, z;
|
int x, y, z;
|
||||||
int w, h, d;
|
int w, h, d;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ struct Weather : Serializable {
|
||||||
std::string nameB;
|
std::string nameB;
|
||||||
float t = 1.0f;
|
float t = 1.0f;
|
||||||
float speed = 0.0f;
|
float speed = 0.0f;
|
||||||
|
glm::vec3 highlight {};
|
||||||
|
|
||||||
void update(float delta) {
|
void update(float delta) {
|
||||||
t += delta * speed;
|
t += delta * speed;
|
||||||
|
|
@ -51,6 +52,18 @@ struct Weather : Serializable {
|
||||||
return b.clouds * sqrtT + a.clouds * (1.0f - sqrtT);
|
return b.clouds * sqrtT + a.clouds * (1.0f - sqrtT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 skyTint() const {
|
||||||
|
return b.skyTint * t + a.skyTint * (1.0f - t);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 cloudsTint() const {
|
||||||
|
return b.cloudsTint * t + a.cloudsTint * (1.0f - t);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 minSkyLight() const {
|
||||||
|
return b.minSkyLight * t + a.minSkyLight * (1.0f - t);
|
||||||
|
}
|
||||||
|
|
||||||
dv::value serialize() const override;
|
dv::value serialize() const override;
|
||||||
void deserialize(const dv::value& src) override;
|
void deserialize(const dv::value& src) override;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue