4 Commits

Author SHA1 Message Date
fc6cc88dc5 feat(renderer): add moonlight and smooth day/night light blending 2026-06-18 21:35:28 +08:00
72011d2551 feat(renderer): compute ambient and sunlight colors based on sun height 2026-06-18 18:53:45 +08:00
83f1077ecd feat(renderer): add roughness-based specular lighting to blocks 2026-06-18 18:40:24 +08:00
8bba170984 feat(renderer): add PCSS shadow mode with configurable samples and softness
Implement Percentage Closer Soft Shadows (PCSS) as shadow mode 3.
Add a FindBlocker function and three Poisson disk arrays (8, 16, 32 samples).
Expose new uniforms (lightSizeUV, minRadius, maxRadius, samples) and provide
slider/combo controls in the dev panel for sample count, light size, and penumbra radius limits.
2026-06-18 17:47:23 +08:00
22 changed files with 381 additions and 63 deletions

View File

@@ -7,4 +7,5 @@ is_liquid = false
is_passable = true
is_transitional = false
is_transparent = true
name = 'air'
name = 'air'
roughness = 1.0

View File

@@ -7,4 +7,5 @@ is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'dirt'
name = 'dirt'
roughness = 1.0

View File

@@ -7,4 +7,5 @@ is_liquid = false
is_passable = true
is_transitional = false
is_transparent = true
name = 'grass'
name = 'grass'
roughness = 0.9

View File

@@ -7,4 +7,5 @@ is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'grass_block'
name = 'grass_block'
roughness = 0.9

View File

@@ -7,4 +7,5 @@ is_liquid = false
is_passable = false
is_transitional = false
is_transparent = true
name = 'leaf'
name = 'leaf'
roughness = 0.7

View File

@@ -7,4 +7,5 @@ is_liquid = false
is_passable = false
is_transitional = false
is_transparent = false
name = 'log'
name = 'log'
roughness = 0.7

View File

@@ -7,4 +7,5 @@ is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'sand'
name = 'sand'
roughness = 0.8

View File

@@ -7,4 +7,5 @@ is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'snowy_grass_block'
name = 'snowy_grass_block'
roughness = 0.9

View File

@@ -7,4 +7,5 @@ is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'stone'
name = 'stone'
roughness = 0.75

View File

@@ -8,3 +8,4 @@ is_transparent = false
is_discard = false
is_blend = false
is_transitional = false
roughness = 1.0

View File

@@ -7,4 +7,5 @@ is_liquid = true
is_passable = true
is_transitional = false
is_transparent = true
name = 'water'
name = 'water'
roughness = 0.02

View File

@@ -4,6 +4,7 @@ in vec2 tc;
in vec3 normal;
in vec3 vert_pos;
in vec4 FragPosLightSpace;
in float roughness;
flat in int tex_layer;
out vec4 color;
layout (binding = 0) uniform sampler2D shadowMap;
@@ -11,21 +12,123 @@ layout (binding = 1) uniform sampler2DArray samp;
uniform float ambientStrength;
uniform vec3 sunlightColor;
uniform vec3 ambientColor;
uniform vec3 sunlightDir;
uniform vec3 cameraPos;
uniform bool shader_on;
uniform int shadowMode;
uniform float specularStrength;
uniform float lightSizeUV;
uniform float minRadius;
uniform float maxRadius;
const vec2 poissonDisk32[32] = vec2[](
vec2(-0.975402, -0.071138),
vec2(-0.920347, -0.411420),
vec2(-0.883908, 0.217872),
vec2(-0.815442, -0.879125),
vec2(-0.775043, 0.543896),
vec2(-0.698126, -0.227570),
vec2(-0.682433, 0.801894),
vec2(-0.563905, 0.021517),
vec2(-0.443233, -0.975116),
vec2(-0.412231, 0.361307),
vec2(-0.264969, -0.418930),
vec2(-0.241888, 0.997065),
vec2(-0.094184, -0.929389),
vec2(-0.019101, 0.680997),
vec2( 0.143832, -0.141008),
vec2( 0.199841, 0.786414),
const vec2 poissonDisk[8] = vec2[](
vec2( 0.344959, 0.293878),
vec2( 0.443233, -0.475115),
vec2( 0.537430, -0.473734),
vec2( 0.589349, 0.569135),
vec2( 0.674281, -0.178897),
vec2( 0.791975, 0.190902),
vec2( 0.815442, 0.879125),
vec2( 0.896420, -0.613392),
vec2( 0.945586, -0.768907),
vec2( 0.974844, 0.756484),
vec2(-0.814100, 0.914376),
vec2(-0.382775, 0.276768),
vec2(-0.915886, 0.457714),
vec2( 0.537800, 0.912200),
vec2(-0.620000, -0.650000),
vec2( 0.120000, -0.780000)
);
const vec2 poissonDisk16[16] = vec2[](
vec2(-0.94201624, -0.39906216), vec2(0.94558609, -0.76890725),
vec2(-0.09418410, -0.92938870), vec2(0.34495938, 0.29387760),
vec2(-0.91588581, 0.45771432), vec2(-0.81544232, -0.87912464),
vec2(-0.38277543, 0.27676845), vec2(0.97484398, 0.75648379),
vec2(0.44323325, -0.97511554), vec2(0.53742981, -0.47373420),
vec2(-0.26496911, -0.41893023), vec2(0.79197514, 0.19090188),
vec2(-0.24188840, 0.99706507), vec2(-0.81409955, 0.91437590),
vec2(0.19984126, 0.78641367), vec2(0.14383161, -0.14100790)
);
const vec2 poissonDisk8[8] = vec2[](
vec2( 0.1440, 0.7659), vec2(-0.5761, 0.4479),
vec2(-0.3220, -0.6058), vec2( 0.5693, -0.4048),
vec2(-0.1276, 0.1657), vec2(-0.0649, -0.0165),
vec2( 0.2773, -0.0305), vec2(-0.1134, -0.2122)
);
uniform int samples;
float random(vec3 seed) {
return fract(sin(dot(seed, vec3(12.9898,78.233,45.5432))) * 43758.5453);
}
float FindBlocker(vec2 uv,
float zReceiver,
vec2 texelSize,
float bias,
float lightSizeUV)
{
float avgDepth = 0.0;
int blockers = 0;
float searchRadius = lightSizeUV * 0.5;
for(int i = 0; i < samples; i++)
{
vec2 offset;
if (samples == 32) {
offset =
poissonDisk32[i]
* searchRadius
* texelSize;
} else if (samples == 16) {
offset =
poissonDisk16[i]
* searchRadius
* texelSize;
} else if (samples == 8) {
offset =
poissonDisk8[i]
* searchRadius
* texelSize;
} else {
offset =
poissonDisk32[i]
* searchRadius
* texelSize;
}
float depth =
texture(shadowMap, uv + offset).r;
if(depth < zReceiver - bias)
{
avgDepth += depth;
blockers++;
}
}
if(blockers == 0)
return -1.0;
return avgDepth / blockers;
}
float ShadowCalculation(vec4 fragPosLightSpace, vec3 norm, vec3 lightDir)
{
@@ -40,10 +143,12 @@ float ShadowCalculation(vec4 fragPosLightSpace, vec3 norm, vec3 lightDir)
float currentDepth = projCoords.z;
vec2 texelSize = 1.0 / vec2(textureSize(shadowMap, 0));
float shadow = 0.0;
float bias =
max(
clamp(
0.001 * (1.0 - dot(norm, lightDir)),
0.0003,
0.001 * (1.0 - dot(norm, lightDir))
0.003
);
if (shadowMode == 0) {
@@ -51,13 +156,20 @@ float ShadowCalculation(vec4 fragPosLightSpace, vec3 norm, vec3 lightDir)
float angle = random(seed) * 6.2831853;; // 2*PI
float s = sin(angle), c = cos(angle);
mat2 rot = mat2(c, -s, s, c);
float radius = 0.7;
//float radius = 0.7;
float radius = mix(1.0, 4.0, currentDepth);
const int samples = 8;
for (int i = 0; i < samples; ++i) {
vec2 offset = rot * poissonDisk[i] * radius * texelSize;
vec2 offset;
if (samples == 32) {
offset = rot * poissonDisk32[i] * radius * texelSize;
} else if (samples == 16) {
offset = rot * poissonDisk16[i] * radius * texelSize;
} else if (samples == 8) {
offset = rot * poissonDisk8[i] * radius * texelSize;
} else {
offset = rot * poissonDisk32[i] * radius * texelSize;
}
float pcfDepth = texture(shadowMap, projCoords.xy + offset).r;
shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0);
}
@@ -80,6 +192,59 @@ float ShadowCalculation(vec4 fragPosLightSpace, vec3 norm, vec3 lightDir)
currentDepth - bias > pcfDepth
? 1.0
: 0.0;
} else if (shadowMode == 3) {
float avgBlockerDepth =
FindBlocker(
projCoords.xy,
currentDepth,
texelSize,
bias,
lightSizeUV
);
if(avgBlockerDepth < 0.0)
{
return 0.0;
}
vec3 seed = vert_pos * 37.0 + sin(vert_pos * 91.7) * 13.0;
float angle = random(seed) * 6.2831853;; // 2*PI
float s = sin(angle), c = cos(angle);
mat2 rot = mat2(c, -s, s, c);
/*
float penumbraRatio = (currentDepth - avgBlockerDepth);
float radius = clamp(
penumbraRatio * lightSizeUV,
minRadius,
maxRadius
);
*/
float radius =
mix(
minRadius,
maxRadius,
smoothstep(
0.0,
0.05,
currentDepth - avgBlockerDepth
)
);
for (int i = 0; i < samples; ++i) {
vec2 offset;
if (samples == 32) {
offset = rot * poissonDisk32[i] * radius * texelSize;
} else if (samples == 16) {
offset = rot * poissonDisk16[i] * radius * texelSize;
} else if (samples == 8) {
offset = rot * poissonDisk8[i] * radius * texelSize;
} else {
offset = rot * poissonDisk32[i] * radius * texelSize;
}
float pcfDepth = texture(shadowMap, projCoords.xy + offset).r;
shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0);
}
shadow /= float(samples);
} else {
float pcfDepth =
texture(shadowMap, projCoords.xy).r;
@@ -109,17 +274,56 @@ void main(void) {
vec3 lightDir = normalize(-sunlightDir);
vec3 ambient = ambientStrength * sunlightColor;
vec3 norm = normalize(normal);
vec3 V =
normalize(cameraPos - vert_pos);
vec3 H =
normalize(lightDir + V);
vec3 ambient = ambientStrength * ambientColor;
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * sunlightColor;
float r =
clamp(roughness, 0.0, 1.0);
float shininess =
mix(
512.0,
4.0,
r
);
float ks =
mix(
0.8,
0.02,
r
);
float spec = 0.0;
if(diff > 0.0)
{
spec =
ks *
pow(
max(dot(norm,H),0.0),
shininess
);
}
vec3 specular = spec * sunlightColor * specularStrength;
float shadow = ShadowCalculation(FragPosLightSpace, norm, lightDir);
color = vec4((ambient + (1.0 - shadow) * (diffuse)) * objectColor.rgb, objectColor.a);
color = vec4((ambient + (1.0 - shadow) * (diffuse)) * objectColor.rgb + (1.0-shadow) * specular, objectColor.a);
//color = varyingColor;
}

View File

@@ -4,11 +4,14 @@ layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in float layer;
layout (location = 3) in vec3 aNormal;
layout (location = 4) in float Roughness;
out vec2 tc;
out vec3 normal;
out vec3 vert_pos;
flat out int tex_layer;
out vec4 FragPosLightSpace;
out float roughness;
mat4 buildRotateX(float rad);
mat4 buildRotateY(float rad);
@@ -28,7 +31,7 @@ void main(void) {
tc = texCoord;
tex_layer = int(layer);
roughness = Roughness;
normal = mat3(norm_matrix) * aNormal;
FragPosLightSpace = lightSpaceMatrix * vec4(pos, 1.0);
gl_Position = proj_matrix * viewPos;

View File

@@ -47,6 +47,7 @@ private:
int m_pre_set_day_tick = 0;
int m_pre_set_tick_speed = 1;
bool m_tick_frezze = false;
int m_samples_idx = 1;
void show_about_table_bar();
void show_biome_table_bar();
void show_time_table_bar();

View File

@@ -51,13 +51,14 @@ struct BlockData {
bool is_discard = false;
bool is_blend = false;
bool is_transitional = false;
float roughness = 1.0f;
BlockData(BlockType b_id, std::string_view b_name, bool liquid,
bool passable, bool cross_plane, bool transparent, bool gas,
bool discard, bool blend, bool transitional)
bool discard, bool blend, bool transitional, float r)
: name(b_name), id(b_id), is_liquid(liquid), is_gas(gas),
is_passable(passable), is_cross_plane(cross_plane),
is_transparent(transparent), is_discard(discard), is_blend(blend),
is_transitional(transitional) {}
is_transitional(transitional), roughness(r) {}
};
class BlockManager {
@@ -79,6 +80,7 @@ public:
static bool is_discard(BlockType id);
static bool is_blend(BlockType id);
static bool is_transitional(BlockType id);
static float roughness(BlockType id);
static BlockType cross_plane_index(BlockType id);
private:

View File

@@ -224,6 +224,7 @@ struct Vertex3D {
float s = 0.0f, t = 0.0f;
float layer = 0.0f;
float nx = 0.0f, ny = 0.0f, nz = 0.0f;
float roughness = 1.0f;
};
struct Vertex2D {

View File

@@ -34,12 +34,23 @@ public:
bool& shader_on();
int& shadow_mode();
int& light_cull_face();
int& light_size_uv();
float& min_radius();
float& max_radius();
int& samples();
float& specular_strength();
private:
static constexpr glm::vec3 SUNLIGHT_COLOR{1.0f, 1.0f, 1.0f};
static constexpr glm::vec3 SUN_COLOR{1.00f, 0.95f, 0.80f};
static constexpr glm::vec3 MOON_COLOR{0.75f, 0.80f, 1.00f};
static constexpr glm::vec3 SKY_COLOR{0.529, 0.808, 0.922};
static constexpr glm::vec3 SUNSET_SUNLIGHT_COLOR{1.00f, 0.45f, 0.15f};
static constexpr glm::vec3 NOON_SUNLIGHT_COLOR{1.00f, 0.90f, 0.65f};
static constexpr glm::vec3 SUNSET_AMBIENT_COLOR{0.18f, 0.12f, 0.35f};
static constexpr glm::vec3 NOON_AMBIENT_COLOR{0.35f, 0.50f, 0.85f};
static constexpr glm::vec3 MOONLIGHT_COLOR{0.55f, 0.70f, 1.00f};
static constexpr glm::vec3 NIGHT_AMBIENT_COLOR{0.08f, 0.10f, 0.18f};
static constexpr float FAR_PLANE = 1000.0f;
static constexpr float NEAR_PLANE = 0.1f;
static constexpr float SUN_SIZE = 50.0f;
@@ -94,11 +105,21 @@ private:
glm::mat4 m_ui_m_matrix;
std::unordered_map<std::size_t, Shader> m_shaders;
glm::vec3 m_blend_from_sundir;
glm::vec3 m_blend_to_sundir;
glm::vec3 m_blend_from_lightdir;
glm::vec3 m_blend_to_lightdir;
float m_blend_t = 1.0f;
bool m_blend_initialized = false;
static constexpr float BLEND_DURATION = 0.15f;
int m_light_size_uv = 20;
float m_min_radius = 2.0f;
float m_max_radius = 20.0f;
int m_samples = 16;
float m_specular_strength = 0.5f;
float moon_intensity = 0.3f;
float sun_intensity = 1.00f;
/*
0 - quad vao
@@ -124,8 +145,8 @@ private:
glm::vec3 quantize_sun_direction(const glm::vec3& sundir,
float angle_step_deg) const;
glm::vec3 get_smoothed_shadow_sundir(const glm::vec3& raw_shadow_sundir,
float dt);
glm::vec3 get_smoothed_shadow_lightdir(const glm::vec3& raw_shadow_sundir,
float dt);
};
} // namespace Cubed

View File

@@ -111,6 +111,15 @@ bool BlockManager::is_transitional(BlockType id) {
}
return m_datas[id].is_transitional;
}
float BlockManager::roughness(BlockType id) {
if (id >= sums()) {
Logger::error("Id {}, is Over The Max Id", id, sums() - 1);
return m_datas[0].roughness;
}
return m_datas[id].roughness;
}
void BlockManager::init() {
fs::path data_path{block_data_dir};
@@ -149,9 +158,11 @@ void BlockManager::init() {
auto is_discard = safe_get_value(block, "is_discard", false);
auto is_blend = safe_get_value(block, "is_blend", false);
auto is_transitional = safe_get_value(block, "is_transitional", false);
auto roughness = safe_get_value(block, "roughness", 1.0);
m_datas.emplace_back(*id, *name, *is_liquid, *is_passable,
*is_cross_plane, *is_transparent, *is_gas,
*is_discard, *is_blend, *is_transitional);
*is_discard, *is_blend, *is_transitional,
static_cast<float>(*roughness));
}
std::sort(
m_datas.begin(), m_datas.end(),

View File

@@ -611,21 +611,43 @@ void DevPanel::show_items_tab_item() {
void DevPanel::show_shader_tab_item() {
static const char* shader_mode[] = {"Rotated Poisson Disk PCF",
"3x3 Square Grid PCF", "PCF off"};
static const char* shader_mode[] = {
"Rotated Poisson Disk PCF", "3x3 Square Grid PCF", "PCF off", "PCSS"};
static const char* cull_face_mode[] = {"Front", "Back"};
static const char* samples[] = {"8", "16", "32"};
if (ImGui::BeginTabItem("shader")) {
ImGui::Checkbox("Shader", &m_app.renderer().shader_on());
if (ImGui::SliderFloat("AmbientStrength",
&m_app.renderer().ambient_strength(), 0.0f,
0.35f))
;
ImGui::SliderFloat("SpecularStrength",
&m_app.renderer().specular_strength(), 0.0f, 2.0f);
ImGui::Checkbox("Discard Transparent",
&m_app.renderer().discard_transparent());
ImGui::Combo("ShaderMode", &m_app.renderer().shadow_mode(), shader_mode,
IM_ARRAYSIZE(shader_mode));
ImGui::Combo("LightCullFaceMode", &m_app.renderer().light_cull_face(),
cull_face_mode, IM_ARRAYSIZE(cull_face_mode));
if (ImGui::Combo("samples", &m_samples_idx, samples,
IM_ARRAYSIZE(samples))) {
if (m_samples_idx == 0) {
m_app.renderer().samples() = 8;
} else if (m_samples_idx == 1) {
m_app.renderer().samples() = 16;
} else if (m_samples_idx == 2) {
m_app.renderer().samples() = 32;
} else {
Logger::warn("Samples Index {} is invaild", m_samples_idx);
m_app.renderer().samples() = 16;
}
}
ImGui::SliderInt("LightSizeUV", &m_app.renderer().light_size_uv(), 0,
800);
ImGui::SliderFloat("MinRaduis", &m_app.renderer().min_radius(), 0.0f,
20.0f);
ImGui::SliderFloat("MaxRadius", &m_app.renderer().max_radius(), 0.0f,
100.0f);
ImGui::EndTabItem();
}
}

View File

@@ -377,7 +377,8 @@ void Chunk::gen_vertices(const OptionalBlockVectorArray& neighbor_block) {
NORMALS[face][i][0],
NORMALS[face][i][1],
NORMALS[face][i][2]
NORMALS[face][i][2],
BlockManager::roughness(cur_id)
};
if (BlockManager::is_transparent(cur_id)) {
@@ -427,7 +428,8 @@ void Chunk::gen_cross_plane_vertices(int world_x, int world_y, int world_z,
static_cast<float>(BlockManager::cross_plane_index(id)),
CROSS_NORMALS[face][i][0],
CROSS_NORMALS[face][i][1],
CROSS_NORMALS[face][i][2]
CROSS_NORMALS[face][i][2],
BlockManager::roughness(id)
};
m_vertex_data[1].m_vertices.emplace_back(vex);

View File

@@ -51,10 +51,13 @@ void VertexData::upload() {
(void*)offsetof(Vertex3D, layer));
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D),
(void*)offsetof(Vertex3D, nx));
glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex3D),
(void*)offsetof(Vertex3D, roughness));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);

View File

@@ -499,12 +499,16 @@ void Renderer::updata_framebuffer(int width, int height) {
m_width = width;
m_height = height;
}
#pragma region render_world
void Renderer::render_world() {
// shader map
glm::mat4 light_space_matrix;
auto& m_render_snapshots = m_world.render_snapshots();
auto& camera_pos = m_camera.get_camera_pos();
float texels_per_unit = 0.0f;
glm::vec3 sundir = glm::normalize(m_world.sunlight_dir());
float sun_height = (-sundir).y;
glm::vec3 lightdir = sundir;
if (m_shader_on) {
const auto& depth_shader = get_shader("depth_shader");
depth_shader.use();
@@ -515,16 +519,16 @@ void Renderer::render_world() {
glm::vec3 center = cam_pos + cam_fwd * (half_extent * 0.5f);
glm::vec3 sundir = glm::normalize(m_world.sunlight_dir());
glm::vec3 raw_shadow_sundir =
quantize_sun_direction(sundir, ANGLE_STEP_DEG);
glm::vec3 shadow_sundir =
get_smoothed_shadow_sundir(raw_shadow_sundir, m_delta_time);
glm::vec3 up = fabs(shadow_sundir.y) > 0.99f ? glm::vec3(0, 0, 1)
: glm::vec3(0, 1, 0);
glm::vec3 raw_shadow_lightdir =
quantize_sun_direction(lightdir, ANGLE_STEP_DEG);
glm::vec3 shadow_lightdir =
get_smoothed_shadow_lightdir(raw_shadow_lightdir, m_delta_time);
glm::vec3 up = fabs(shadow_lightdir.y) > 0.99f ? glm::vec3(0, 0, 1)
: glm::vec3(0, 1, 0);
glm::mat4 light_basis = glm::lookAt(glm::vec3(0.0f), shadow_sundir, up);
float texels_per_unit = DEPTH_MAP_SIZE / (half_extent * 2.0f);
glm::mat4 light_basis =
glm::lookAt(glm::vec3(0.0f), shadow_lightdir, up);
texels_per_unit = DEPTH_MAP_SIZE / (half_extent * 2.0f);
glm::vec3 ls_center = glm::vec3(light_basis * glm::vec4(center, 1.0f));
ls_center.x =
std::round(ls_center.x * texels_per_unit) / texels_per_unit;
@@ -536,7 +540,7 @@ void Renderer::render_world() {
float distance = half_extent * 1.5f;
float near_plane = 1.0f;
float far_plane = distance + half_extent * 2.0f;
glm::vec3 light_pos = snapped_center - shadow_sundir * distance;
glm::vec3 light_pos = snapped_center - shadow_lightdir * distance;
glm::mat4 light_view = glm::lookAt(light_pos, snapped_center, up);
glm::mat4 light_projection =
glm::ortho(-half_extent, half_extent, -half_extent, half_extent,
@@ -617,8 +621,24 @@ void Renderer::render_world() {
m_v_mat = m_camera.get_camera_lookat();
m_mv_mat = m_v_mat * m_m_mat;
m_norm_mat = glm::transpose(glm::inverse(m_mv_mat));
glm::vec3 light_dir_view =
glm::normalize(glm::mat3(m_v_mat) * m_world.sunlight_dir());
glm::vec3 light_dir_view = glm::normalize(glm::mat3(m_v_mat) * lightdir);
float daylight = glm::smoothstep(0.05f, 0.2f, sun_height);
glm::vec3 sun_color =
mix(SUNSET_SUNLIGHT_COLOR, NOON_SUNLIGHT_COLOR, daylight);
glm::vec3 ambient_color =
mix(SUNSET_AMBIENT_COLOR, NOON_AMBIENT_COLOR, daylight);
float day_factor = glm::smoothstep(-0.15f, 0.05f, sun_height);
float light_intensity =
glm::smoothstep(moon_intensity, sun_intensity, day_factor);
glm::vec3 directional_light_color =
glm::mix(MOON_COLOR, sun_color, day_factor) * light_intensity;
glm::vec3 finnal_ambient_color =
glm::mix(NIGHT_AMBIENT_COLOR, ambient_color, day_factor);
m_ambient_strength = glm::mix(0.45f, 0.25f, day_factor);
glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_mv_mat));
glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_p_mat));
@@ -628,11 +648,23 @@ void Renderer::render_world() {
glm::value_ptr(light_space_matrix));
glUniform1f(normal_block_shader.loc("ambientStrength"), m_ambient_strength);
glUniform3fv(normal_block_shader.loc("sunlightColor"), 1,
glm::value_ptr(SUNLIGHT_COLOR));
glm::value_ptr(directional_light_color));
glUniform3fv(normal_block_shader.loc("ambientColor"), 1,
glm::value_ptr(finnal_ambient_color));
glUniform3fv(normal_block_shader.loc("sunlightDir"), 1,
glm::value_ptr(light_dir_view));
glUniform1i(normal_block_shader.loc("shadowMode"), m_shadow_mode);
glUniform1i(normal_block_shader.loc("shader_on"), m_shader_on);
glUniform1f(normal_block_shader.loc("texelsPerUnit"), texels_per_unit);
glUniform1f(normal_block_shader.loc("lightSizeUV"),
static_cast<GLfloat>(m_light_size_uv));
glUniform1f(normal_block_shader.loc("minRadius"), m_min_radius);
glUniform1f(normal_block_shader.loc("maxRadius"), m_max_radius);
glUniform1i(normal_block_shader.loc("samples"), m_samples);
glUniform1f(normal_block_shader.loc("specularStrength"),
m_specular_strength);
glUniform3fv(normal_block_shader.loc("cameraPos"), 1,
glm::value_ptr(m_camera.get_camera_pos()));
m_mvp_mat = m_p_mat * m_mv_mat;
auto& m_planes = m_world.planes();
@@ -755,17 +787,17 @@ void Renderer::render_world() {
DebugCollector::get().report(
"rendered_chunk", "Rendered Chunk: " + std::to_string(rendered_sum));
}
#pragma endregion
void Renderer::render_dev_panel() {
glDisable(GL_DEPTH_TEST);
m_dev_panel.render();
glEnable(GL_DEPTH_TEST);
}
glm::vec3 Renderer::quantize_sun_direction(const glm::vec3& sundir,
glm::vec3 Renderer::quantize_sun_direction(const glm::vec3& lightdir,
float angle_step_deg) const {
float elevation = std::asin(glm::clamp(sundir.y, -1.0f, 1.0f));
float azimuth = std::atan2(sundir.z, sundir.x);
float elevation = std::asin(glm::clamp(lightdir.y, -1.0f, 1.0f));
float azimuth = std::atan2(lightdir.z, lightdir.x);
float step = glm::radians(angle_step_deg);
@@ -783,30 +815,30 @@ glm::vec3 Renderer::quantize_sun_direction(const glm::vec3& sundir,
}
glm::vec3
Renderer::get_smoothed_shadow_sundir(const glm::vec3& raw_shadow_sundir,
float dt) {
Renderer::get_smoothed_shadow_lightdir(const glm::vec3& raw_shadow_lightdir,
float dt) {
if (!m_blend_initialized) {
m_blend_from_sundir = raw_shadow_sundir;
m_blend_to_sundir = raw_shadow_sundir;
m_blend_from_lightdir = raw_shadow_lightdir;
m_blend_to_lightdir = raw_shadow_lightdir;
m_blend_t = 1.0f;
m_blend_initialized = true;
return raw_shadow_sundir;
return raw_shadow_lightdir;
}
if (raw_shadow_sundir != m_blend_to_sundir) {
if (raw_shadow_lightdir != m_blend_to_lightdir) {
glm::vec3 current_displayed = glm::normalize(
Math::slerp(m_blend_from_sundir, m_blend_to_sundir, m_blend_t));
Math::slerp(m_blend_from_lightdir, m_blend_to_lightdir, m_blend_t));
m_blend_from_sundir = current_displayed;
m_blend_to_sundir = raw_shadow_sundir;
m_blend_from_lightdir = current_displayed;
m_blend_to_lightdir = raw_shadow_lightdir;
m_blend_t = 0.0f;
}
m_blend_t = glm::min(m_blend_t + dt / BLEND_DURATION, 1.0f);
return glm::normalize(
Math::slerp(m_blend_from_sundir, m_blend_to_sundir, m_blend_t));
Math::slerp(m_blend_from_lightdir, m_blend_to_lightdir, m_blend_t));
}
float& Renderer::ambient_strength() { return m_ambient_strength; }
@@ -814,4 +846,9 @@ bool& Renderer::discard_transparent() { return m_discard_tranparent; }
bool& Renderer::shader_on() { return m_shader_on; }
int& Renderer::shadow_mode() { return m_shadow_mode; }
int& Renderer::light_cull_face() { return m_light_cull_face; }
int& Renderer::light_size_uv() { return m_light_size_uv; }
float& Renderer::min_radius() { return m_min_radius; }
float& Renderer::max_radius() { return m_max_radius; }
int& Renderer::samples() { return m_samples; }
float& Renderer::specular_strength() { return m_specular_strength; }
} // namespace Cubed