mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-06-21 18:17:03 +08:00
feat: lighting effects (#18)
* feat(rendering): add basic diffuse and ambient lighting to block rendering * feat(world): add day/night cycle with server tick system * feat(renderer): make ambient strength adjustable via dev panel * fix(game_time): use unsigned tick type and enforce positive tick speed * feat(renderer): add shadow mapping with PCF soft shadows Introduce shadow mapping using a dedicated depth framebuffer and shader. The block fragment shader now performs percentage-closer filtering (PCF) with Poisson disk sampling and random rotation for soft shadows. The vertex shader outputs light-space coordinates. A new depth shader pair handles rendering from the light's perspective, discarding transparent fragments. The renderer sets up the light projection based on the camera position and sun direction, and applies the shadow factor to diffuse lighting. Day/night cycle can now be toggled off in the world server thread. * perf(shadow): increase depth map resolution and refine PCF sampling * feat(dev-panel): add tick freeze toggle and fix TickType sign Add checkbox to freeze tick advancement in dev panel. Change TickType from unsigned long long to signed long long to prevent underflow. * chore(world): add missing <numbers> include * feat(renderer): add runtime shader and shadow mode controls Introduce user-controllable shader on/off, shadow mode (rotated Poisson disk, 3x3 grid, or off), light cull face, and discard transparent in depth pass. Expose all settings in new dev panel "shader" tab. Move ambient strength slider to the new tab. * fix(texture): set texture wrap mode to clamp to edge * feat(renderer): smooth shadow sun direction transitions using quantized directions and slerp * 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. * feat(renderer): add roughness-based specular lighting to blocks * feat(renderer): compute ambient and sunlight colors based on sun height * feat(renderer): add moonlight and smooth day/night light blending * refactor(renderer): extract day/night calculation and add billboard shaders Add a new ParallelLight struct to encapsulate lighting parameters. Move day-night cycle computation from render_world() to a new day_night_calculation() method. Update sky shaders to use procedural colors based on sun position. Add separate billboard shaders for sun/moon. * feat(sky): add animated clouds to sky shader with speed control * feat(renderer): add configurable cloud thresholds and white mix
This commit is contained in:
@@ -7,4 +7,5 @@ is_liquid = false
|
|||||||
is_passable = true
|
is_passable = true
|
||||||
is_transitional = false
|
is_transitional = false
|
||||||
is_transparent = true
|
is_transparent = true
|
||||||
name = 'air'
|
name = 'air'
|
||||||
|
roughness = 1.0
|
||||||
@@ -7,4 +7,5 @@ is_liquid = false
|
|||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = true
|
is_transitional = true
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'dirt'
|
name = 'dirt'
|
||||||
|
roughness = 1.0
|
||||||
@@ -7,4 +7,5 @@ is_liquid = false
|
|||||||
is_passable = true
|
is_passable = true
|
||||||
is_transitional = false
|
is_transitional = false
|
||||||
is_transparent = true
|
is_transparent = true
|
||||||
name = 'grass'
|
name = 'grass'
|
||||||
|
roughness = 0.9
|
||||||
@@ -7,4 +7,5 @@ is_liquid = false
|
|||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = true
|
is_transitional = true
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'grass_block'
|
name = 'grass_block'
|
||||||
|
roughness = 0.9
|
||||||
@@ -7,4 +7,5 @@ is_liquid = false
|
|||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = false
|
is_transitional = false
|
||||||
is_transparent = true
|
is_transparent = true
|
||||||
name = 'leaf'
|
name = 'leaf'
|
||||||
|
roughness = 0.7
|
||||||
@@ -7,4 +7,5 @@ is_liquid = false
|
|||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = false
|
is_transitional = false
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'log'
|
name = 'log'
|
||||||
|
roughness = 0.7
|
||||||
@@ -7,4 +7,5 @@ is_liquid = false
|
|||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = true
|
is_transitional = true
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'sand'
|
name = 'sand'
|
||||||
|
roughness = 0.8
|
||||||
@@ -7,4 +7,5 @@ is_liquid = false
|
|||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = true
|
is_transitional = true
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'snowy_grass_block'
|
name = 'snowy_grass_block'
|
||||||
|
roughness = 0.9
|
||||||
@@ -7,4 +7,5 @@ is_liquid = false
|
|||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = true
|
is_transitional = true
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'stone'
|
name = 'stone'
|
||||||
|
roughness = 0.75
|
||||||
@@ -8,3 +8,4 @@ is_transparent = false
|
|||||||
is_discard = false
|
is_discard = false
|
||||||
is_blend = false
|
is_blend = false
|
||||||
is_transitional = false
|
is_transitional = false
|
||||||
|
roughness = 1.0
|
||||||
@@ -7,4 +7,5 @@ is_liquid = true
|
|||||||
is_passable = true
|
is_passable = true
|
||||||
is_transitional = false
|
is_transitional = false
|
||||||
is_transparent = true
|
is_transparent = true
|
||||||
name = 'water'
|
name = 'water'
|
||||||
|
roughness = 0.02
|
||||||
11
assets/shaders/billboard_f_shader.glsl
Normal file
11
assets/shaders/billboard_f_shader.glsl
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
out vec4 frag_color;
|
||||||
|
|
||||||
|
uniform vec3 color;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
|
||||||
|
frag_color = vec4(color, 1.0);
|
||||||
|
|
||||||
|
}
|
||||||
10
assets/shaders/billboard_v_shader.glsl
Normal file
10
assets/shaders/billboard_v_shader.glsl
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
layout (location = 0) in vec3 vertices_pos;
|
||||||
|
|
||||||
|
uniform mat4 mv_matrix;
|
||||||
|
uniform mat4 proj_matrix;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
gl_Position = proj_matrix * mv_matrix * vec4(vertices_pos, 1.0);
|
||||||
|
}
|
||||||
@@ -1,15 +1,329 @@
|
|||||||
#version 460
|
#version 460
|
||||||
|
|
||||||
in vec2 tc;
|
in vec2 tc;
|
||||||
|
in vec3 normal;
|
||||||
|
in vec3 vert_pos;
|
||||||
|
in vec4 FragPosLightSpace;
|
||||||
|
in float roughness;
|
||||||
flat in int tex_layer;
|
flat in int tex_layer;
|
||||||
out vec4 color;
|
out vec4 color;
|
||||||
|
layout (binding = 0) uniform sampler2D shadowMap;
|
||||||
|
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),
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
|
||||||
|
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||||
|
|
||||||
|
projCoords = projCoords * 0.5 + 0.5;
|
||||||
|
if (projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
||||||
|
projCoords.y < 0.0 || projCoords.y > 1.0 ||
|
||||||
|
projCoords.z < 0.0 || projCoords.z > 1.0) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
float currentDepth = projCoords.z;
|
||||||
|
vec2 texelSize = 1.0 / vec2(textureSize(shadowMap, 0));
|
||||||
|
float shadow = 0.0;
|
||||||
|
|
||||||
|
float bias =
|
||||||
|
clamp(
|
||||||
|
0.001 * (1.0 - dot(norm, lightDir)),
|
||||||
|
0.0003,
|
||||||
|
0.003
|
||||||
|
);
|
||||||
|
|
||||||
|
if (shadowMode == 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 radius = 0.7;
|
||||||
|
float radius = mix(1.0, 4.0, currentDepth);
|
||||||
|
|
||||||
|
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 if (shadowMode == 1) {
|
||||||
|
for (int x = -1; x <= 1; ++x) {
|
||||||
|
for (int y = -1; y <= 1; ++y) {
|
||||||
|
vec2 offset = vec2(x, y) * texelSize;
|
||||||
|
float pcfDepth = texture(shadowMap, projCoords.xy + offset).r;
|
||||||
|
shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shadow /= 9.0;
|
||||||
|
} else if (shadowMode == 2) {
|
||||||
|
// pcf off
|
||||||
|
float pcfDepth =
|
||||||
|
texture(shadowMap, projCoords.xy).r;
|
||||||
|
|
||||||
|
shadow =
|
||||||
|
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;
|
||||||
|
|
||||||
|
shadow =
|
||||||
|
currentDepth - bias > pcfDepth
|
||||||
|
? 1.0
|
||||||
|
: 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return shadow;
|
||||||
|
}
|
||||||
|
|
||||||
layout (binding = 0) uniform sampler2DArray samp;
|
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
color = texture(samp, vec3(tc, tex_layer));
|
vec4 objectColor = texture(samp, vec3(tc, tex_layer));
|
||||||
if (color.a < 0.8) {
|
|
||||||
|
if (objectColor.a < 0.8) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
|
if (!shader_on) {
|
||||||
|
color = objectColor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vec3 lightDir = normalize(-sunlightDir);
|
||||||
|
|
||||||
|
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 + (1.0-shadow) * specular, objectColor.a);
|
||||||
|
|
||||||
//color = varyingColor;
|
//color = varyingColor;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,15 @@
|
|||||||
layout (location = 0) in vec3 pos;
|
layout (location = 0) in vec3 pos;
|
||||||
layout (location = 1) in vec2 texCoord;
|
layout (location = 1) in vec2 texCoord;
|
||||||
layout (location = 2) in float layer;
|
layout (location = 2) in float layer;
|
||||||
|
layout (location = 3) in vec3 aNormal;
|
||||||
|
layout (location = 4) in float Roughness;
|
||||||
|
|
||||||
out vec2 tc;
|
out vec2 tc;
|
||||||
|
out vec3 normal;
|
||||||
|
out vec3 vert_pos;
|
||||||
flat out int tex_layer;
|
flat out int tex_layer;
|
||||||
|
out vec4 FragPosLightSpace;
|
||||||
|
out float roughness;
|
||||||
|
|
||||||
mat4 buildRotateX(float rad);
|
mat4 buildRotateX(float rad);
|
||||||
mat4 buildRotateY(float rad);
|
mat4 buildRotateY(float rad);
|
||||||
@@ -13,13 +20,21 @@ mat4 buildTranslate(float x, float y, float z);
|
|||||||
|
|
||||||
uniform mat4 mv_matrix;
|
uniform mat4 mv_matrix;
|
||||||
uniform mat4 proj_matrix;
|
uniform mat4 proj_matrix;
|
||||||
|
uniform mat4 norm_matrix;
|
||||||
|
uniform mat4 lightSpaceMatrix;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
gl_Position = proj_matrix * mv_matrix * vec4(pos, 1.0);
|
vec4 viewPos = mv_matrix * vec4(pos, 1.0);
|
||||||
|
|
||||||
|
vert_pos = pos;
|
||||||
|
|
||||||
tc = texCoord;
|
tc = texCoord;
|
||||||
|
|
||||||
tex_layer = int(layer);
|
tex_layer = int(layer);
|
||||||
|
roughness = Roughness;
|
||||||
|
normal = mat3(norm_matrix) * aNormal;
|
||||||
|
FragPosLightSpace = lightSpaceMatrix * vec4(pos, 1.0);
|
||||||
|
gl_Position = proj_matrix * viewPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4 buildTranslate(float x, float y, float z) {
|
mat4 buildTranslate(float x, float y, float z) {
|
||||||
|
|||||||
16
assets/shaders/depth_fragment_shader.glsl
Normal file
16
assets/shaders/depth_fragment_shader.glsl
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
in vec2 tc;
|
||||||
|
flat in int tex_layer;
|
||||||
|
layout (binding = 1) uniform sampler2DArray samp;
|
||||||
|
|
||||||
|
uniform bool is_discard_tranparent;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
if (is_discard_tranparent) {
|
||||||
|
vec4 texColor = texture(samp, vec3(tc, tex_layer));
|
||||||
|
if (texColor.a < 0.8)
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
//gl_FragDepth = gl_FragCoord.z;
|
||||||
|
}
|
||||||
12
assets/shaders/depth_shader.glsl
Normal file
12
assets/shaders/depth_shader.glsl
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#version 460
|
||||||
|
layout (location = 0) in vec3 pos;
|
||||||
|
layout (location = 1) in vec2 texCoord;
|
||||||
|
layout (location = 2) in float layer;
|
||||||
|
uniform mat4 lightSpaceMatrix;
|
||||||
|
out vec2 tc;
|
||||||
|
flat out int tex_layer;
|
||||||
|
void main() {
|
||||||
|
tc = texCoord;
|
||||||
|
tex_layer = int(layer);
|
||||||
|
gl_Position = lightSpaceMatrix * vec4(pos, 1.0);
|
||||||
|
}
|
||||||
@@ -1,9 +1,95 @@
|
|||||||
#version 460
|
#version 460
|
||||||
|
|
||||||
|
in vec3 dir;
|
||||||
|
|
||||||
out vec4 frag_color;
|
out vec4 frag_color;
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
|
|
||||||
frag_color = vec4(0.529, 0.808, 0.922, 1.0);
|
|
||||||
|
|
||||||
|
uniform vec3 skyTop;
|
||||||
|
uniform vec3 skyBottom;
|
||||||
|
|
||||||
|
uniform vec3 sunDir;
|
||||||
|
uniform vec3 sunColor;
|
||||||
|
|
||||||
|
uniform float horizonSharpness;
|
||||||
|
uniform float cloudWhiteMix;
|
||||||
|
|
||||||
|
uniform float cloudThresholdLow;
|
||||||
|
uniform float cloudThresholdHigh;
|
||||||
|
|
||||||
|
uniform float time;
|
||||||
|
|
||||||
|
|
||||||
|
float hash(vec2 p) {
|
||||||
|
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
float noise(vec2 p) {
|
||||||
|
vec2 i = floor(p);
|
||||||
|
vec2 f = fract(p);
|
||||||
|
f = f * f * (3.0 - 2.0 * f);
|
||||||
|
float a = hash(i);
|
||||||
|
float b = hash(i + vec2(1.0, 0.0));
|
||||||
|
float c = hash(i + vec2(0.0, 1.0));
|
||||||
|
float d = hash(i + vec2(1.0, 1.0));
|
||||||
|
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
float fbm(vec2 p) {
|
||||||
|
float v = 0.0;
|
||||||
|
float amp = 0.5;
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
v += amp * noise(p);
|
||||||
|
p *= 2.0;
|
||||||
|
amp *= 0.5;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
vec3 sund = normalize(sunDir);
|
||||||
|
|
||||||
|
float t =
|
||||||
|
clamp(
|
||||||
|
dir.y * 0.5 + 0.5,
|
||||||
|
0.0,
|
||||||
|
1.0
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
vec3 sky =
|
||||||
|
mix(
|
||||||
|
skyBottom,
|
||||||
|
skyTop,
|
||||||
|
pow(t, horizonSharpness)
|
||||||
|
);
|
||||||
|
|
||||||
|
// cloud
|
||||||
|
if (dir.y > 0.0) {
|
||||||
|
vec2 cloud_uv = dir.xz / (dir.y + 0.15) * 0.5 + vec2(time * 0.005, time * 0.002);
|
||||||
|
float cloud_density = fbm(cloud_uv * 2.0);
|
||||||
|
float safeLow = cloudThresholdLow;
|
||||||
|
float safeHigh = max(cloudThresholdHigh, cloudThresholdLow + 0.001);
|
||||||
|
cloud_density = smoothstep(safeLow,safeHigh, cloud_density);
|
||||||
|
|
||||||
|
|
||||||
|
float fade = smoothstep(0.0, 0.3, dir.y) * (1.0 - smoothstep(0.85, 1.0, dir.y));
|
||||||
|
cloud_density *= fade;
|
||||||
|
|
||||||
|
vec3 cloud_color = mix(skyBottom, vec3(1.0), cloudWhiteMix);
|
||||||
|
sky = mix(sky, cloud_color, cloud_density * 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
float sunAmount = max(dot(dir, sund), 0.0);
|
||||||
|
|
||||||
|
//float glow = pow(sunAmount, 8.0) * 0.15;
|
||||||
|
|
||||||
|
float glow = pow(sunAmount, 8.0) * 0.15 + pow(sunAmount, 32.0) * 0.3;
|
||||||
|
|
||||||
|
sky += glow * sunColor;
|
||||||
|
|
||||||
|
frag_color = vec4(sky, 1.0);
|
||||||
|
//frag_color = vec4(vec3(sunAmount), 1.0);
|
||||||
|
//frag_color = vec4(t,0,0,1);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,12 @@ layout (location = 0) in vec3 vertices_pos;
|
|||||||
uniform mat4 mv_matrix;
|
uniform mat4 mv_matrix;
|
||||||
uniform mat4 proj_matrix;
|
uniform mat4 proj_matrix;
|
||||||
|
|
||||||
|
out vec3 dir;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
|
// Our skybox mesh uses [0,1] coordinates instead of the usual [-1,1].
|
||||||
|
// Shift to the cube center before normalizing to obtain the correct
|
||||||
|
// view direction for atmospheric calculations.
|
||||||
|
dir = normalize(vertices_pos - vec3(0.5));
|
||||||
gl_Position = proj_matrix * mv_matrix * vec4(vertices_pos, 1.0);
|
gl_Position = proj_matrix * mv_matrix * vec4(vertices_pos, 1.0);
|
||||||
}
|
}
|
||||||
@@ -32,6 +32,7 @@ public:
|
|||||||
const glm::vec3& get_camera_pos() const;
|
const glm::vec3& get_camera_pos() const;
|
||||||
|
|
||||||
bool is_under_water() const;
|
bool is_under_water() const;
|
||||||
|
glm::vec3 get_camera_front() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ constexpr float DEFAULT_MAX_RUN_SPEED = 7.0f;
|
|||||||
constexpr float DEFAULT_ACCELERATION = 10.0f;
|
constexpr float DEFAULT_ACCELERATION = 10.0f;
|
||||||
constexpr float DEFAULT_DECELERATION = 15.0f;
|
constexpr float DEFAULT_DECELERATION = 15.0f;
|
||||||
constexpr float DEFAULT_G = 22.5f;
|
constexpr float DEFAULT_G = 22.5f;
|
||||||
static constexpr int SIZE_X = CHUNK_SIZE;
|
constexpr int SIZE_X = CHUNK_SIZE;
|
||||||
static constexpr int SIZE_Y = WORLD_SIZE_Y;
|
constexpr int SIZE_Y = WORLD_SIZE_Y;
|
||||||
static constexpr int SIZE_Z = CHUNK_SIZE;
|
constexpr int SIZE_Z = CHUNK_SIZE;
|
||||||
|
|
||||||
constexpr ChunkPos CHUNK_DIR[]{{1, 0}, {-1, 0}, {0, 1}, {0, -1},
|
constexpr ChunkPos CHUNK_DIR[]{{1, 0}, {-1, 0}, {0, 1}, {0, -1},
|
||||||
{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
|
{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
|
||||||
|
|||||||
@@ -44,14 +44,20 @@ private:
|
|||||||
bool m_need_save_config = false;
|
bool m_need_save_config = false;
|
||||||
bool m_gen_thread_running = true;
|
bool m_gen_thread_running = true;
|
||||||
int m_theme = 0;
|
int m_theme = 0;
|
||||||
|
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_about_table_bar();
|
||||||
void show_biome_table_bar();
|
void show_biome_table_bar();
|
||||||
|
void show_time_table_bar();
|
||||||
void show_cave_table_bar();
|
void show_cave_table_bar();
|
||||||
void show_river_table_bar();
|
void show_river_table_bar();
|
||||||
void show_settings_tab_item();
|
void show_settings_tab_item();
|
||||||
void show_world_tab_item();
|
void show_world_tab_item();
|
||||||
void show_player_tab_item();
|
void show_player_tab_item();
|
||||||
void show_items_tab_item();
|
void show_items_tab_item();
|
||||||
|
void show_shader_tab_item();
|
||||||
|
|
||||||
void update_config_view();
|
void update_config_view();
|
||||||
void update_player_profile();
|
void update_player_profile();
|
||||||
|
|||||||
@@ -51,13 +51,14 @@ struct BlockData {
|
|||||||
bool is_discard = false;
|
bool is_discard = false;
|
||||||
bool is_blend = false;
|
bool is_blend = false;
|
||||||
bool is_transitional = false;
|
bool is_transitional = false;
|
||||||
|
float roughness = 1.0f;
|
||||||
BlockData(BlockType b_id, std::string_view b_name, bool liquid,
|
BlockData(BlockType b_id, std::string_view b_name, bool liquid,
|
||||||
bool passable, bool cross_plane, bool transparent, bool gas,
|
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),
|
: name(b_name), id(b_id), is_liquid(liquid), is_gas(gas),
|
||||||
is_passable(passable), is_cross_plane(cross_plane),
|
is_passable(passable), is_cross_plane(cross_plane),
|
||||||
is_transparent(transparent), is_discard(discard), is_blend(blend),
|
is_transparent(transparent), is_discard(discard), is_blend(blend),
|
||||||
is_transitional(transitional) {}
|
is_transitional(transitional), roughness(r) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class BlockManager {
|
class BlockManager {
|
||||||
@@ -79,6 +80,7 @@ public:
|
|||||||
static bool is_discard(BlockType id);
|
static bool is_discard(BlockType id);
|
||||||
static bool is_blend(BlockType id);
|
static bool is_blend(BlockType id);
|
||||||
static bool is_transitional(BlockType id);
|
static bool is_transitional(BlockType id);
|
||||||
|
static float roughness(BlockType id);
|
||||||
static BlockType cross_plane_index(BlockType id);
|
static BlockType cross_plane_index(BlockType id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
10
include/Cubed/gameplay/game_time.hpp
Normal file
10
include/Cubed/gameplay/game_time.hpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Prevent unsigned underflow issues in subtraction
|
||||||
|
using TickType = long long;
|
||||||
|
|
||||||
|
constexpr int DEFAULT_PER_TICK_TIME = 50;
|
||||||
|
|
||||||
|
constexpr TickType DAY_TIME = 24000;
|
||||||
|
|
||||||
|
constexpr TickType PER_HOUR = 1000;
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
class World;
|
class World;
|
||||||
struct VertexData {
|
struct VertexData {
|
||||||
std::vector<Vertex> m_vertices;
|
std::vector<Vertex3D> m_vertices;
|
||||||
GLuint m_vbo = 0;
|
GLuint m_vbo = 0;
|
||||||
GLuint m_vao = 0;
|
GLuint m_vao = 0;
|
||||||
std::atomic<std::size_t> m_sum{0};
|
std::atomic<std::size_t> m_sum{0};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "Cubed/AABB.hpp"
|
#include "Cubed/AABB.hpp"
|
||||||
#include "Cubed/gameplay/cave_carver.hpp"
|
#include "Cubed/gameplay/cave_carver.hpp"
|
||||||
#include "Cubed/gameplay/chunk.hpp"
|
#include "Cubed/gameplay/chunk.hpp"
|
||||||
|
#include "Cubed/gameplay/game_time.hpp"
|
||||||
#include "Cubed/gameplay/river_worm.hpp"
|
#include "Cubed/gameplay/river_worm.hpp"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@@ -39,12 +40,21 @@ private:
|
|||||||
std::unordered_map<ChunkPos, const Chunk*, ChunkPos::Hash>;
|
std::unordered_map<ChunkPos, const Chunk*, ChunkPos::Hash>;
|
||||||
using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>;
|
using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>;
|
||||||
using ChunkHashMap = std::unordered_map<ChunkPos, Chunk, ChunkPos::Hash>;
|
using ChunkHashMap = std::unordered_map<ChunkPos, Chunk, ChunkPos::Hash>;
|
||||||
|
|
||||||
glm::vec3 m_gen_player_pos{0.0f, 0.0f, 0.0f};
|
glm::vec3 m_gen_player_pos{0.0f, 0.0f, 0.0f};
|
||||||
ChunkHashMap m_chunks;
|
ChunkHashMap m_chunks;
|
||||||
std::unordered_map<std::size_t, Player> m_players;
|
std::unordered_map<std::size_t, Player> m_players;
|
||||||
std::vector<glm::vec4> m_planes;
|
std::vector<glm::vec4> m_planes;
|
||||||
|
|
||||||
std::thread m_gen_thread;
|
std::thread m_gen_thread;
|
||||||
|
std::thread m_server_thread;
|
||||||
|
|
||||||
|
std::stop_source m_server_stop_source;
|
||||||
|
|
||||||
|
std::atomic<int> m_per_tick_time = DEFAULT_PER_TICK_TIME; // ms
|
||||||
|
|
||||||
|
std::atomic<TickType> m_day_tick = 6000;
|
||||||
|
|
||||||
mutable std::mutex m_chunks_mutex;
|
mutable std::mutex m_chunks_mutex;
|
||||||
std::mutex m_gen_signal_mutex;
|
std::mutex m_gen_signal_mutex;
|
||||||
std::mutex m_new_chunk_queue_mutex;
|
std::mutex m_new_chunk_queue_mutex;
|
||||||
@@ -59,8 +69,12 @@ private:
|
|||||||
std::atomic<bool> m_is_rebuilding{false};
|
std::atomic<bool> m_is_rebuilding{false};
|
||||||
std::atomic<bool> m_chunk_gen_finished{false};
|
std::atomic<bool> m_chunk_gen_finished{false};
|
||||||
std::atomic<bool> m_could_gen{true};
|
std::atomic<bool> m_could_gen{true};
|
||||||
|
std::atomic<bool> m_tick_running{true};
|
||||||
std::atomic<int> m_rendering_distance{24};
|
std::atomic<int> m_rendering_distance{24};
|
||||||
std::atomic<float> m_chunk_gen_fraction{0.0f};
|
std::atomic<float> m_chunk_gen_fraction{0.0f};
|
||||||
|
|
||||||
|
std::atomic<TickType> m_game_ticks{0};
|
||||||
|
|
||||||
std::vector<ChunkPos> m_dirty_queue;
|
std::vector<ChunkPos> m_dirty_queue;
|
||||||
std::vector<ChunkRenderSnapshot> m_render_snapshots;
|
std::vector<ChunkRenderSnapshot> m_render_snapshots;
|
||||||
std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk;
|
std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk;
|
||||||
@@ -119,12 +133,25 @@ public:
|
|||||||
int rendering_distance() const;
|
int rendering_distance() const;
|
||||||
void rendering_distance(int rendering_distance);
|
void rendering_distance(int rendering_distance);
|
||||||
void start_gen_thread();
|
void start_gen_thread();
|
||||||
|
void start_server_thread();
|
||||||
void stop_gen_thread();
|
void stop_gen_thread();
|
||||||
|
void stop_server_thread();
|
||||||
|
void serever_run(std::stop_token stoken);
|
||||||
|
|
||||||
CaveCarver& cave_carcer();
|
CaveCarver& cave_carcer();
|
||||||
RiverWorm& river_worm();
|
RiverWorm& river_worm();
|
||||||
std::vector<glm::vec4>& planes();
|
std::vector<glm::vec4>& planes();
|
||||||
std::vector<ChunkRenderSnapshot>& render_snapshots();
|
std::vector<ChunkRenderSnapshot>& render_snapshots();
|
||||||
|
|
||||||
|
glm::vec3 sunlight_dir() const;
|
||||||
|
TickType game_tick() const;
|
||||||
|
TickType day_tick() const;
|
||||||
|
void day_tick(TickType tick);
|
||||||
|
int per_tick_time() const;
|
||||||
|
void per_tick_time(int ms);
|
||||||
|
|
||||||
|
bool is_tick_running() const;
|
||||||
|
void tick_running(bool run);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
|
|||||||
@@ -91,6 +91,51 @@ constexpr float TEX_COORDS[6][6][2] = {
|
|||||||
{0.0f, 1.0f}, // back left
|
{0.0f, 1.0f}, // back left
|
||||||
{0.0f, 0.0f}} // front left
|
{0.0f, 0.0f}} // front left
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr float NORMALS[6][6][3] = {
|
||||||
|
// ===== front (z = +1) =====
|
||||||
|
{{0.0f, 0.0f, 1.0f},
|
||||||
|
{0.0f, 0.0f, 1.0f},
|
||||||
|
{0.0f, 0.0f, 1.0f},
|
||||||
|
{0.0f, 0.0f, 1.0f},
|
||||||
|
{0.0f, 0.0f, 1.0f},
|
||||||
|
{0.0f, 0.0f, 1.0f}},
|
||||||
|
// ===== right (x = +1) =====
|
||||||
|
{{1.0f, 0.0f, 0.0f},
|
||||||
|
{1.0f, 0.0f, 0.0f},
|
||||||
|
{1.0f, 0.0f, 0.0f},
|
||||||
|
{1.0f, 0.0f, 0.0f},
|
||||||
|
{1.0f, 0.0f, 0.0f},
|
||||||
|
{1.0f, 0.0f, 0.0f}},
|
||||||
|
// ===== back (z = -1) =====
|
||||||
|
{{0.0f, 0.0f, -1.0f},
|
||||||
|
{0.0f, 0.0f, -1.0f},
|
||||||
|
{0.0f, 0.0f, -1.0f},
|
||||||
|
{0.0f, 0.0f, -1.0f},
|
||||||
|
{0.0f, 0.0f, -1.0f},
|
||||||
|
{0.0f, 0.0f, -1.0f}},
|
||||||
|
// ===== left (x = -1) =====
|
||||||
|
{{-1.0f, 0.0f, 0.0f},
|
||||||
|
{-1.0f, 0.0f, 0.0f},
|
||||||
|
{-1.0f, 0.0f, 0.0f},
|
||||||
|
{-1.0f, 0.0f, 0.0f},
|
||||||
|
{-1.0f, 0.0f, 0.0f},
|
||||||
|
{-1.0f, 0.0f, 0.0f}},
|
||||||
|
// ===== top (y = +1) =====
|
||||||
|
{{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f}},
|
||||||
|
// ===== bottom (y = -1) =====
|
||||||
|
{{0.0f, -1.0f, 0.0f},
|
||||||
|
{0.0f, -1.0f, 0.0f},
|
||||||
|
{0.0f, -1.0f, 0.0f},
|
||||||
|
{0.0f, -1.0f, 0.0f},
|
||||||
|
{0.0f, -1.0f, 0.0f},
|
||||||
|
{0.0f, -1.0f, 0.0f}}};
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
constexpr float CUBE_VER[24] = {0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0,
|
constexpr float CUBE_VER[24] = {0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0,
|
||||||
0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0,
|
0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0,
|
||||||
@@ -148,6 +193,24 @@ constexpr float CROSS_TEX_COORDS[2][6][2] = {
|
|||||||
{1.0f, 1.0f}, // bottom right
|
{1.0f, 1.0f}, // bottom right
|
||||||
{0.0f, 1.0f}}, // bottom left
|
{0.0f, 1.0f}}, // bottom left
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr float CROSS_NORMALS[2][6][3] = {
|
||||||
|
// ===== Plane 1: upward =====
|
||||||
|
{{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f}},
|
||||||
|
|
||||||
|
// ===== Plane 2: upward =====
|
||||||
|
{{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f},
|
||||||
|
{0.0f, 1.0f, 0.0f}}};
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
constexpr float QUAD_VERTICES[] = {
|
constexpr float QUAD_VERTICES[] = {
|
||||||
@@ -156,10 +219,12 @@ constexpr float QUAD_VERTICES[] = {
|
|||||||
|
|
||||||
-1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f};
|
-1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f};
|
||||||
|
|
||||||
struct Vertex {
|
struct Vertex3D {
|
||||||
float x = 0.0f, y = 0.0f, z = 0.0f;
|
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||||
float s = 0.0f, t = 0.0f;
|
float s = 0.0f, t = 0.0f;
|
||||||
float layer = 0.0f;
|
float layer = 0.0f;
|
||||||
|
float nx = 0.0f, ny = 0.0f, nz = 0.0f;
|
||||||
|
float roughness = 1.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Vertex2D {
|
struct Vertex2D {
|
||||||
|
|||||||
@@ -28,22 +28,71 @@ public:
|
|||||||
void update_fov(float fov);
|
void update_fov(float fov);
|
||||||
void update_proj_matrix(float aspect, float width, float height);
|
void update_proj_matrix(float aspect, float width, float height);
|
||||||
void updata_framebuffer(int width, int height);
|
void updata_framebuffer(int width, int height);
|
||||||
|
float& ambient_strength();
|
||||||
|
|
||||||
|
bool& discard_transparent();
|
||||||
|
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();
|
||||||
|
float& cloud_speed();
|
||||||
|
float& cloud_threshold_low();
|
||||||
|
float& cloud_threshold_high();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct ParallelLight {
|
||||||
|
glm::vec3 sundir;
|
||||||
|
glm::vec3 lightdir;
|
||||||
|
float sun_height = 0.0f;
|
||||||
|
float day_light = 0.0f;
|
||||||
|
float day_factor = 0.0f;
|
||||||
|
glm::vec3 sun_color;
|
||||||
|
glm::vec3 directional_light_color;
|
||||||
|
glm::vec3 finnal_ambient_color;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 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;
|
||||||
|
static constexpr float MOON_SIZE = 50.0f;
|
||||||
|
static constexpr float DEPTH_MAP_SIZE = 4096.0f;
|
||||||
|
static constexpr float ANGLE_STEP_DEG = 0.5f;
|
||||||
|
float m_ambient_strength = 0.1f;
|
||||||
|
|
||||||
const Camera& m_camera;
|
const Camera& m_camera;
|
||||||
DevPanel& m_dev_panel;
|
DevPanel& m_dev_panel;
|
||||||
const TextureManager& m_texture_manager;
|
const TextureManager& m_texture_manager;
|
||||||
World& m_world;
|
World& m_world;
|
||||||
|
|
||||||
|
bool m_discard_tranparent = true;
|
||||||
|
bool m_shader_on = true;
|
||||||
|
int m_shadow_mode = 0;
|
||||||
|
int m_light_cull_face = 0;
|
||||||
float m_aspect = 0.0f;
|
float m_aspect = 0.0f;
|
||||||
float m_fov = DEFAULT_FOV;
|
float m_fov = DEFAULT_FOV;
|
||||||
|
|
||||||
float m_delta_time = 0.0f;
|
float m_delta_time = 0.0f;
|
||||||
|
|
||||||
|
float m_cloud_time = 0.0f;
|
||||||
|
float m_cloud_speed = 5.0f;
|
||||||
|
|
||||||
float m_width = 0.0f;
|
float m_width = 0.0f;
|
||||||
float m_height = 0.0f;
|
float m_height = 0.0f;
|
||||||
|
|
||||||
glm::mat4 m_p_mat, m_v_mat, m_m_mat, m_mv_mat, m_mvp_mat;
|
glm::mat4 m_p_mat, m_v_mat, m_m_mat, m_mv_mat, m_mvp_mat, m_norm_mat;
|
||||||
|
|
||||||
GLuint m_mv_loc = 0;
|
GLuint m_mv_loc = 0;
|
||||||
GLuint m_proj_loc = 0;
|
GLuint m_proj_loc = 0;
|
||||||
@@ -62,18 +111,43 @@ private:
|
|||||||
GLuint m_accum_texture = 0;
|
GLuint m_accum_texture = 0;
|
||||||
GLuint m_reveal_texture = 0;
|
GLuint m_reveal_texture = 0;
|
||||||
GLuint m_oit_depth_render_buffer = 0;
|
GLuint m_oit_depth_render_buffer = 0;
|
||||||
|
|
||||||
|
GLuint m_depth_map_fbo = 0;
|
||||||
|
GLuint m_depth_map_texture = 0;
|
||||||
|
|
||||||
GLuint m_quad_vbo = 0;
|
GLuint m_quad_vbo = 0;
|
||||||
|
|
||||||
glm::mat4 m_ui_proj;
|
glm::mat4 m_ui_proj;
|
||||||
glm::mat4 m_ui_m_matrix;
|
glm::mat4 m_ui_m_matrix;
|
||||||
std::unordered_map<std::size_t, Shader> m_shaders;
|
std::unordered_map<std::size_t, Shader> m_shaders;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
float m_cloud_threshold_low = 0.5f;
|
||||||
|
float m_cloud_threshold_high = 0.75f;
|
||||||
|
|
||||||
|
ParallelLight m_parallel_light;
|
||||||
/*
|
/*
|
||||||
0 - quad vao
|
0 - quad vao
|
||||||
1 - sky vao
|
1 - sky vao
|
||||||
2 - outline vao
|
2 - outline vao
|
||||||
3 - ui vao
|
3 - ui vao
|
||||||
4 - text vao
|
4 - text vao
|
||||||
|
|
||||||
*/
|
*/
|
||||||
std::vector<GLuint> m_vao;
|
std::vector<GLuint> m_vao;
|
||||||
std::vector<Vertex2D> m_ui;
|
std::vector<Vertex2D> m_ui;
|
||||||
@@ -81,6 +155,8 @@ private:
|
|||||||
void init_quad();
|
void init_quad();
|
||||||
void init_text();
|
void init_text();
|
||||||
|
|
||||||
|
void day_night_calculation();
|
||||||
|
|
||||||
void render_outline();
|
void render_outline();
|
||||||
void render_sky();
|
void render_sky();
|
||||||
void render_text();
|
void render_text();
|
||||||
@@ -88,6 +164,11 @@ private:
|
|||||||
void render_world();
|
void render_world();
|
||||||
void render_underwater();
|
void render_underwater();
|
||||||
void render_dev_panel();
|
void render_dev_panel();
|
||||||
|
|
||||||
|
glm::vec3 quantize_sun_direction(const glm::vec3& sundir,
|
||||||
|
float angle_step_deg) const;
|
||||||
|
glm::vec3 get_smoothed_shadow_lightdir(const glm::vec3& raw_shadow_sundir,
|
||||||
|
float dt);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -12,6 +12,8 @@ float smootherstep(float edge0, float edge1, float x);
|
|||||||
bool is_aabb_in_frustum(const glm::vec3& center, const glm::vec3& half_extents,
|
bool is_aabb_in_frustum(const glm::vec3& center, const glm::vec3& half_extents,
|
||||||
const std::vector<glm::vec4>& planes);
|
const std::vector<glm::vec4>& planes);
|
||||||
float deterministic_random(int x, int z, uint64_t seed);
|
float deterministic_random(int x, int z, uint64_t seed);
|
||||||
|
glm::vec3 slerp(const glm::vec3& from, const glm::vec3& to, float t);
|
||||||
|
|
||||||
} // namespace Math
|
} // namespace Math
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -111,6 +111,15 @@ bool BlockManager::is_transitional(BlockType id) {
|
|||||||
}
|
}
|
||||||
return m_datas[id].is_transitional;
|
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() {
|
void BlockManager::init() {
|
||||||
fs::path data_path{block_data_dir};
|
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_discard = safe_get_value(block, "is_discard", false);
|
||||||
auto is_blend = safe_get_value(block, "is_blend", false);
|
auto is_blend = safe_get_value(block, "is_blend", false);
|
||||||
auto is_transitional = safe_get_value(block, "is_transitional", 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,
|
m_datas.emplace_back(*id, *name, *is_liquid, *is_passable,
|
||||||
*is_cross_plane, *is_transparent, *is_gas,
|
*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(
|
std::sort(
|
||||||
m_datas.begin(), m_datas.end(),
|
m_datas.begin(), m_datas.end(),
|
||||||
|
|||||||
@@ -60,4 +60,6 @@ const glm::vec3& Camera::get_camera_pos() const { return m_camera_pos; }
|
|||||||
|
|
||||||
bool Camera::is_under_water() const { return m_under_water; }
|
bool Camera::is_under_water() const { return m_under_water; }
|
||||||
|
|
||||||
|
glm::vec3 Camera::get_camera_front() const { return m_player->get_front(); }
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ void DevPanel::render() {
|
|||||||
show_world_tab_item();
|
show_world_tab_item();
|
||||||
show_player_tab_item();
|
show_player_tab_item();
|
||||||
show_items_tab_item();
|
show_items_tab_item();
|
||||||
|
show_shader_tab_item();
|
||||||
show_about_table_bar();
|
show_about_table_bar();
|
||||||
|
|
||||||
ImGui::EndTabBar();
|
ImGui::EndTabBar();
|
||||||
@@ -107,6 +108,7 @@ void DevPanel::show_about_table_bar() {
|
|||||||
ImGui::Text("FreeType");
|
ImGui::Text("FreeType");
|
||||||
ImGui::Text("toml++");
|
ImGui::Text("toml++");
|
||||||
ImGui::Text("Dear ImGui");
|
ImGui::Text("Dear ImGui");
|
||||||
|
ImGui::Text("Tbb");
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Text("Special Thanks");
|
ImGui::Text("Special Thanks");
|
||||||
ImGui::Text("TANGERIME");
|
ImGui::Text("TANGERIME");
|
||||||
@@ -263,6 +265,31 @@ void DevPanel::show_biome_table_bar() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DevPanel::show_time_table_bar() {
|
||||||
|
World& world = m_app.world();
|
||||||
|
ImGui::Text("Game Tick %llu", world.game_tick());
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("Day Tick %llu", world.day_tick());
|
||||||
|
m_tick_frezze = !world.is_tick_running();
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Checkbox("Tick Frezze", &m_tick_frezze)) {
|
||||||
|
world.tick_running(!m_tick_frezze);
|
||||||
|
}
|
||||||
|
if (ImGui::SliderInt("SetDayTick", &m_pre_set_day_tick, 0, DAY_TIME)) {
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Set##DayTick")) {
|
||||||
|
world.day_tick(static_cast<TickType>(m_pre_set_day_tick));
|
||||||
|
}
|
||||||
|
ImGui::Text("MSPT %d", world.per_tick_time());
|
||||||
|
if (ImGui::SliderInt("SetMSPT", &m_pre_set_tick_speed, 1, 200)) {
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Set##MSPT")) {
|
||||||
|
world.per_tick_time(m_pre_set_tick_speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DevPanel::show_cave_table_bar() {
|
void DevPanel::show_cave_table_bar() {
|
||||||
auto& cave_carcer = m_app.world().cave_carcer();
|
auto& cave_carcer = m_app.world().cave_carcer();
|
||||||
|
|
||||||
@@ -336,6 +363,7 @@ void DevPanel::show_settings_tab_item() {
|
|||||||
static_cast<double>(m_config.mouse_sensitivity));
|
static_cast<double>(m_config.mouse_sensitivity));
|
||||||
m_player->hot_reload();
|
m_player->hot_reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::SliderInt("Distance", &m_config.rendering_distance, 2,
|
if (ImGui::SliderInt("Distance", &m_config.rendering_distance, 2,
|
||||||
128)) {
|
128)) {
|
||||||
Config::get().set("world.rendering_distance",
|
Config::get().set("world.rendering_distance",
|
||||||
@@ -457,6 +485,10 @@ void DevPanel::show_world_tab_item() {
|
|||||||
ImGui::Text("Chunk Build Progress\n");
|
ImGui::Text("Chunk Build Progress\n");
|
||||||
ImGui::ProgressBar(m_app.world().chunk_gen_fraction());
|
ImGui::ProgressBar(m_app.world().chunk_gen_fraction());
|
||||||
if (ImGui::BeginTabBar("World Settings")) {
|
if (ImGui::BeginTabBar("World Settings")) {
|
||||||
|
if (ImGui::BeginTabItem("Time")) {
|
||||||
|
show_time_table_bar();
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
if (ImGui::BeginTabItem("Cave")) {
|
if (ImGui::BeginTabItem("Cave")) {
|
||||||
show_cave_table_bar();
|
show_cave_table_bar();
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
@@ -577,6 +609,58 @@ 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", "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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_app.renderer().shadow_mode() == 3) {
|
||||||
|
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::SliderFloat("Cloud Speed", &m_app.renderer().cloud_speed(), 1.0f,
|
||||||
|
100.0f);
|
||||||
|
ImGui::SliderFloat("Cloud Threshold Low",
|
||||||
|
&m_app.renderer().cloud_threshold_low(), 0.0f, 1.0f);
|
||||||
|
ImGui::SliderFloat("Cloud Threshold High",
|
||||||
|
&m_app.renderer().cloud_threshold_high(), 0.0f,
|
||||||
|
1.0f);
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DevPanel::update_config_view() {
|
void DevPanel::update_config_view() {
|
||||||
auto config = Config::get();
|
auto config = Config::get();
|
||||||
m_config.fov =
|
m_config.fov =
|
||||||
|
|||||||
@@ -366,13 +366,19 @@ void Chunk::gen_vertices(const OptionalBlockVectorArray& neighbor_block) {
|
|||||||
cur_id);
|
cur_id);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
Vertex vex = {
|
Vertex3D vex = {
|
||||||
VERTICES_POS[face][i][0] + (float)world_x * 1.0f,
|
VERTICES_POS[face][i][0] + (float)world_x * 1.0f,
|
||||||
VERTICES_POS[face][i][1] + (float)world_y * 1.0f,
|
VERTICES_POS[face][i][1] + (float)world_y * 1.0f,
|
||||||
VERTICES_POS[face][i][2] + (float)world_z * 1.0f,
|
VERTICES_POS[face][i][2] + (float)world_z * 1.0f,
|
||||||
TEX_COORDS[face][i][0],
|
TEX_COORDS[face][i][0],
|
||||||
TEX_COORDS[face][i][1],
|
TEX_COORDS[face][i][1],
|
||||||
static_cast<float>(cur_id * 6 + face)
|
|
||||||
|
static_cast<float>(cur_id * 6 + face),
|
||||||
|
|
||||||
|
NORMALS[face][i][0],
|
||||||
|
NORMALS[face][i][1],
|
||||||
|
NORMALS[face][i][2],
|
||||||
|
BlockManager::roughness(cur_id)
|
||||||
|
|
||||||
};
|
};
|
||||||
if (BlockManager::is_transparent(cur_id)) {
|
if (BlockManager::is_transparent(cur_id)) {
|
||||||
@@ -413,13 +419,17 @@ void Chunk::gen_cross_plane_vertices(int world_x, int world_y, int world_z,
|
|||||||
}
|
}
|
||||||
for (int face = 0; face < 2; face++) {
|
for (int face = 0; face < 2; face++) {
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
Vertex vex = {
|
Vertex3D vex = {
|
||||||
CROSS_VERTICES_POS[face][i][0] + (float)world_x * 1.0f,
|
CROSS_VERTICES_POS[face][i][0] + (float)world_x * 1.0f,
|
||||||
CROSS_VERTICES_POS[face][i][1] + (float)world_y * 1.0f,
|
CROSS_VERTICES_POS[face][i][1] + (float)world_y * 1.0f,
|
||||||
CROSS_VERTICES_POS[face][i][2] + (float)world_z * 1.0f,
|
CROSS_VERTICES_POS[face][i][2] + (float)world_z * 1.0f,
|
||||||
CROSS_TEX_COORDS[face][i][0],
|
CROSS_TEX_COORDS[face][i][0],
|
||||||
CROSS_TEX_COORDS[face][i][1],
|
CROSS_TEX_COORDS[face][i][1],
|
||||||
static_cast<float>(BlockManager::cross_plane_index(id))
|
static_cast<float>(BlockManager::cross_plane_index(id)),
|
||||||
|
CROSS_NORMALS[face][i][0],
|
||||||
|
CROSS_NORMALS[face][i][1],
|
||||||
|
CROSS_NORMALS[face][i][2],
|
||||||
|
BlockManager::roughness(id)
|
||||||
|
|
||||||
};
|
};
|
||||||
m_vertex_data[1].m_vertices.emplace_back(vex);
|
m_vertex_data[1].m_vertices.emplace_back(vex);
|
||||||
|
|||||||
@@ -41,18 +41,23 @@ void VertexData::upload() {
|
|||||||
}
|
}
|
||||||
glBindVertexArray(m_vao);
|
glBindVertexArray(m_vao);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, m_vertices.size() * sizeof(Vertex),
|
glBufferData(GL_ARRAY_BUFFER, m_vertices.size() * sizeof(Vertex3D),
|
||||||
m_vertices.data(), GL_DYNAMIC_DRAW);
|
m_vertices.data(), GL_DYNAMIC_DRAW);
|
||||||
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), (void*)0);
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex3D),
|
||||||
(void*)offsetof(Vertex, s));
|
(void*)offsetof(Vertex3D, s));
|
||||||
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex),
|
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex3D),
|
||||||
(void*)offsetof(Vertex, layer));
|
(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(0);
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
glEnableVertexAttribArray(2);
|
glEnableVertexAttribArray(2);
|
||||||
|
glEnableVertexAttribArray(3);
|
||||||
|
glEnableVertexAttribArray(4);
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
#include "Cubed/tools/cubed_hash.hpp"
|
#include "Cubed/tools/cubed_hash.hpp"
|
||||||
|
|
||||||
#include <execution>
|
#include <execution>
|
||||||
|
#include <glm/gtc/constants.hpp>
|
||||||
|
#include <numbers>
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
@@ -18,6 +21,7 @@ World::World() {}
|
|||||||
|
|
||||||
World::~World() {
|
World::~World() {
|
||||||
stop_gen_thread();
|
stop_gen_thread();
|
||||||
|
stop_server_thread();
|
||||||
m_chunks.clear();
|
m_chunks.clear();
|
||||||
{
|
{
|
||||||
std::lock_guard lk(m_delete_vbo_mutex);
|
std::lock_guard lk(m_delete_vbo_mutex);
|
||||||
@@ -86,6 +90,8 @@ void World::init_world() {
|
|||||||
auto d = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
|
auto d = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
|
||||||
Logger::info("Chunk Block Init Finish, Time Consuming: {}", d);
|
Logger::info("Chunk Block Init Finish, Time Consuming: {}", d);
|
||||||
|
|
||||||
|
start_server_thread();
|
||||||
|
|
||||||
Logger::info("TestPlayer Create Finish");
|
Logger::info("TestPlayer Create Finish");
|
||||||
}
|
}
|
||||||
void World::init_chunks() {
|
void World::init_chunks() {
|
||||||
@@ -727,6 +733,11 @@ void World::start_gen_thread() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::start_server_thread() {
|
||||||
|
m_server_thread = std::thread(
|
||||||
|
[this]() { serever_run(m_server_stop_source.get_token()); });
|
||||||
|
}
|
||||||
|
|
||||||
void World::stop_gen_thread() {
|
void World::stop_gen_thread() {
|
||||||
m_gen_running = false;
|
m_gen_running = false;
|
||||||
m_gen_cv.notify_all();
|
m_gen_cv.notify_all();
|
||||||
@@ -736,6 +747,25 @@ void World::stop_gen_thread() {
|
|||||||
Logger::info("Gen Thread Stopped");
|
Logger::info("Gen Thread Stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::stop_server_thread() {
|
||||||
|
m_server_stop_source.request_stop();
|
||||||
|
if (m_server_thread.joinable()) {
|
||||||
|
m_server_thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::serever_run(std::stop_token stoken) {
|
||||||
|
Logger::info("Server Thread Started!");
|
||||||
|
while (!stoken.stop_requested()) {
|
||||||
|
std::this_thread::sleep_for(milliseconds(m_per_tick_time));
|
||||||
|
if (m_tick_running) {
|
||||||
|
++m_game_ticks;
|
||||||
|
m_day_tick = (m_day_tick + 1) % DAY_TIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Logger::info("Server Thread Stopped!");
|
||||||
|
}
|
||||||
|
|
||||||
void World::need_gen() {
|
void World::need_gen() {
|
||||||
if (!m_could_gen) {
|
if (!m_could_gen) {
|
||||||
Logger::warn("It is generating or consuming new chunks");
|
Logger::warn("It is generating or consuming new chunks");
|
||||||
@@ -1006,4 +1036,49 @@ std::vector<glm::vec4>& World::planes() { return m_planes; }
|
|||||||
std::vector<ChunkRenderSnapshot>& World::render_snapshots() {
|
std::vector<ChunkRenderSnapshot>& World::render_snapshots() {
|
||||||
return m_render_snapshots;
|
return m_render_snapshots;
|
||||||
};
|
};
|
||||||
|
/*
|
||||||
|
glm::vec3 World::sunlight_dir() const {
|
||||||
|
float t = static_cast<float>(m_day_tick) / DAY_TIME;
|
||||||
|
|
||||||
|
float azimuth = glm::radians(90.0f - t * 360.0f);
|
||||||
|
|
||||||
|
float altitude =
|
||||||
|
glm::half_pi<float>() * sin((t - 0.25f) * glm::two_pi<float>());
|
||||||
|
|
||||||
|
glm::vec3 dir{cos(altitude) * cos(azimuth), sin(altitude),
|
||||||
|
cos(altitude) * sin(azimuth)};
|
||||||
|
|
||||||
|
return glm::normalize(-dir);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
glm::vec3 World::sunlight_dir() const {
|
||||||
|
float altitude = sin((m_day_tick - 6 * PER_HOUR) /
|
||||||
|
static_cast<float>(DAY_TIME / 2) * std::numbers::pi) *
|
||||||
|
90.0f;
|
||||||
|
|
||||||
|
float t = static_cast<float>(m_day_tick) / DAY_TIME;
|
||||||
|
float azimuth = 90.0f - 360.0f * (t - 0.25f);
|
||||||
|
|
||||||
|
float alt = glm::radians(altitude);
|
||||||
|
float az = glm::radians(azimuth);
|
||||||
|
glm::vec3 dir;
|
||||||
|
dir.x = cos(alt) * sin(az);
|
||||||
|
dir.y = sin(alt);
|
||||||
|
dir.z = cos(alt) * cos(az);
|
||||||
|
|
||||||
|
return glm::normalize(-dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
TickType World::game_tick() const { return m_game_ticks.load(); }
|
||||||
|
TickType World::day_tick() const { return m_day_tick.load(); }
|
||||||
|
void World::day_tick(TickType tick) {
|
||||||
|
tick %= DAY_TIME;
|
||||||
|
m_day_tick = tick;
|
||||||
|
}
|
||||||
|
int World::per_tick_time() const { return m_per_tick_time.load(); }
|
||||||
|
void World::per_tick_time(int ms) { m_per_tick_time = ms; }
|
||||||
|
|
||||||
|
bool World::is_tick_running() const { return m_tick_running.load(); }
|
||||||
|
void World::tick_running(bool run) { m_tick_running = run; }
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
380
src/renderer.cpp
380
src/renderer.cpp
@@ -18,6 +18,7 @@
|
|||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
Renderer::Renderer(const Camera& camera, World& world,
|
Renderer::Renderer(const Camera& camera, World& world,
|
||||||
@@ -42,6 +43,9 @@ Renderer::~Renderer() {
|
|||||||
glDeleteTextures(1, &m_accum_texture);
|
glDeleteTextures(1, &m_accum_texture);
|
||||||
glDeleteTextures(1, &m_reveal_texture);
|
glDeleteTextures(1, &m_reveal_texture);
|
||||||
glDeleteRenderbuffers(1, &m_oit_depth_render_buffer);
|
glDeleteRenderbuffers(1, &m_oit_depth_render_buffer);
|
||||||
|
|
||||||
|
glDeleteFramebuffers(1, &m_depth_map_fbo);
|
||||||
|
glDeleteTextures(1, &m_depth_map_texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::hot_reload() {
|
void Renderer::hot_reload() {
|
||||||
@@ -76,6 +80,10 @@ void Renderer::init() {
|
|||||||
Shader composite_block_shader{"composite",
|
Shader composite_block_shader{"composite",
|
||||||
"shaders/block_composite_v_shader.glsl",
|
"shaders/block_composite_v_shader.glsl",
|
||||||
"shaders/block_composite_f_shader.glsl"};
|
"shaders/block_composite_f_shader.glsl"};
|
||||||
|
Shader depth_shader{"depth_shader", "shaders/depth_shader.glsl",
|
||||||
|
"shaders/depth_fragment_shader.glsl"};
|
||||||
|
Shader billboard{"billboard", "shaders/billboard_v_shader.glsl",
|
||||||
|
"shaders/billboard_f_shader.glsl"};
|
||||||
m_shaders.insert({world_shader.hash(), std::move(world_shader)});
|
m_shaders.insert({world_shader.hash(), std::move(world_shader)});
|
||||||
m_shaders.insert({outline_shader.hash(), std::move(outline_shader)});
|
m_shaders.insert({outline_shader.hash(), std::move(outline_shader)});
|
||||||
m_shaders.insert({sky_shdaer.hash(), std::move(sky_shdaer)});
|
m_shaders.insert({sky_shdaer.hash(), std::move(sky_shdaer)});
|
||||||
@@ -86,6 +94,8 @@ void Renderer::init() {
|
|||||||
m_shaders.insert({accum_shader.hash(), std::move(accum_shader)});
|
m_shaders.insert({accum_shader.hash(), std::move(accum_shader)});
|
||||||
m_shaders.insert(
|
m_shaders.insert(
|
||||||
{composite_block_shader.hash(), std::move(composite_block_shader)});
|
{composite_block_shader.hash(), std::move(composite_block_shader)});
|
||||||
|
m_shaders.insert({depth_shader.hash(), std::move(depth_shader)});
|
||||||
|
m_shaders.insert({billboard.hash(), std::move(billboard)});
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glDepthFunc(GL_LEQUAL);
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
|
||||||
@@ -192,27 +202,56 @@ void Renderer::init_text() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::render() {
|
void Renderer::render() {
|
||||||
|
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
||||||
|
|
||||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
day_night_calculation();
|
||||||
render_sky();
|
render_sky();
|
||||||
render_world();
|
render_world();
|
||||||
render_outline();
|
render_outline();
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0);
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
render_underwater();
|
render_underwater();
|
||||||
|
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||||
render_ui();
|
render_ui();
|
||||||
render_text();
|
render_text();
|
||||||
render_dev_panel();
|
render_dev_panel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::day_night_calculation() {
|
||||||
|
m_parallel_light.sundir = glm::normalize(m_world.sunlight_dir());
|
||||||
|
m_parallel_light.sun_height = (-m_parallel_light.sundir).y;
|
||||||
|
m_parallel_light.lightdir = m_parallel_light.sundir;
|
||||||
|
|
||||||
|
m_parallel_light.day_light =
|
||||||
|
glm::smoothstep(0.15f, 0.3f, m_parallel_light.sun_height);
|
||||||
|
|
||||||
|
m_parallel_light.sun_color = mix(SUNSET_SUNLIGHT_COLOR, NOON_SUNLIGHT_COLOR,
|
||||||
|
m_parallel_light.day_light);
|
||||||
|
|
||||||
|
glm::vec3 ambient_color = mix(SUNSET_AMBIENT_COLOR, NOON_AMBIENT_COLOR,
|
||||||
|
m_parallel_light.day_light);
|
||||||
|
|
||||||
|
m_parallel_light.day_factor =
|
||||||
|
glm::smoothstep(-0.15f, 0.05f, m_parallel_light.sun_height);
|
||||||
|
auto day_factor = m_parallel_light.day_factor;
|
||||||
|
float light_intensity =
|
||||||
|
glm::smoothstep(moon_intensity, sun_intensity, day_factor);
|
||||||
|
m_parallel_light.directional_light_color =
|
||||||
|
glm::mix(MOON_COLOR, m_parallel_light.sun_color, day_factor) *
|
||||||
|
light_intensity;
|
||||||
|
m_parallel_light.finnal_ambient_color =
|
||||||
|
glm::mix(NIGHT_AMBIENT_COLOR, ambient_color, day_factor);
|
||||||
|
|
||||||
|
m_ambient_strength = glm::mix(0.45f, 0.25f, day_factor);
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::render_outline() {
|
void Renderer::render_outline() {
|
||||||
const auto& shader = get_shader("outline");
|
const auto& shader = get_shader("outline");
|
||||||
shader.use();
|
shader.use();
|
||||||
@@ -244,26 +283,114 @@ void Renderer::render_outline() {
|
|||||||
|
|
||||||
void Renderer::render_sky() {
|
void Renderer::render_sky() {
|
||||||
|
|
||||||
const auto& shader = get_shader("sky");
|
glm::vec3 zenith = {0.20f, 0.45f, 0.95f};
|
||||||
|
|
||||||
shader.use();
|
glm::vec3 horizon = {0.55f, 0.75f, 1.00f};
|
||||||
m_mv_loc = shader.loc("mv_matrix");
|
|
||||||
m_proj_loc = shader.loc("proj_matrix");
|
glm::vec3 sunset_zenith = {0.05f, 0.10f, 0.25f};
|
||||||
|
|
||||||
|
glm::vec3 sunset_horizon = {1.0f, 0.35f, 0.10f};
|
||||||
|
|
||||||
|
glm::vec3 night_zenith = {0.018f, 0.023f, 0.048f};
|
||||||
|
glm::vec3 night_horizon = {0.022f, 0.027f, 0.052f};
|
||||||
|
|
||||||
|
constexpr float NIGHT_SHARPNESS = 0.35f;
|
||||||
|
constexpr float SUNSET_SHARPNESS = 0.6f;
|
||||||
|
constexpr float NOON_SHARPNESS = 0.35f;
|
||||||
|
|
||||||
|
constexpr float NIGHT_CLOUD_MIX = 0.3f;
|
||||||
|
constexpr float SUNSET_CLOUD_MIX = 0.4f;
|
||||||
|
constexpr float NOON_CLOUD_MIX = 0.7;
|
||||||
|
|
||||||
|
glm::vec3 day_top = mix(sunset_zenith, zenith, m_parallel_light.day_light);
|
||||||
|
glm::vec3 day_bottom =
|
||||||
|
mix(sunset_horizon, horizon, m_parallel_light.day_light);
|
||||||
|
|
||||||
|
glm::vec3 sky_top = mix(night_zenith, day_top, m_parallel_light.day_factor);
|
||||||
|
glm::vec3 sky_bottom =
|
||||||
|
mix(night_horizon, day_bottom, m_parallel_light.day_factor);
|
||||||
|
|
||||||
|
float day_sharpness =
|
||||||
|
glm::mix(SUNSET_SHARPNESS, NOON_SHARPNESS, m_parallel_light.day_light);
|
||||||
|
|
||||||
|
float horizon_sharpness =
|
||||||
|
glm::mix(NIGHT_SHARPNESS, day_sharpness, m_parallel_light.day_factor);
|
||||||
|
|
||||||
|
float day_cloud_mix =
|
||||||
|
glm::mix(SUNSET_CLOUD_MIX, NOON_CLOUD_MIX, m_parallel_light.day_light);
|
||||||
|
float cloud_white_mix =
|
||||||
|
glm::mix(NIGHT_CLOUD_MIX, day_cloud_mix, m_parallel_light.day_factor);
|
||||||
|
|
||||||
|
m_cloud_time += m_delta_time * m_cloud_speed;
|
||||||
|
|
||||||
|
const auto& sky_shader = get_shader("sky");
|
||||||
|
|
||||||
|
sky_shader.use();
|
||||||
|
m_mv_loc = sky_shader.loc("mv_matrix");
|
||||||
|
m_proj_loc = sky_shader.loc("proj_matrix");
|
||||||
|
|
||||||
m_m_mat = glm::translate(glm::mat4(1.0f), m_camera.get_camera_pos() -
|
m_m_mat = glm::translate(glm::mat4(1.0f), m_camera.get_camera_pos() -
|
||||||
glm::vec3(0.5f, 0.5f, 0.5f));
|
glm::vec3(0.5f, 0.5f, 0.5f));
|
||||||
m_v_mat = m_camera.get_camera_lookat();
|
m_v_mat = m_camera.get_camera_lookat();
|
||||||
m_mv_mat = m_v_mat * m_m_mat;
|
m_mv_mat = m_v_mat * m_m_mat;
|
||||||
|
|
||||||
|
glm::vec3 sun_dir_view = (-m_parallel_light.sundir);
|
||||||
|
|
||||||
glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_mv_mat));
|
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));
|
glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_p_mat));
|
||||||
|
glUniform3fv(sky_shader.loc("skyTop"), 1, glm::value_ptr(sky_top));
|
||||||
|
glUniform3fv(sky_shader.loc("skyBottom"), 1, glm::value_ptr(sky_bottom));
|
||||||
|
glUniform3fv(sky_shader.loc("sunDir"), 1, glm::value_ptr(sun_dir_view));
|
||||||
|
glUniform3fv(sky_shader.loc("sunColor"), 1,
|
||||||
|
glm::value_ptr(m_parallel_light.directional_light_color));
|
||||||
|
glUniform1f(sky_shader.loc("horizonSharpness"), horizon_sharpness);
|
||||||
|
glUniform1f(sky_shader.loc("time"), m_cloud_time);
|
||||||
|
glUniform1f(sky_shader.loc("cloudWhiteMix"), cloud_white_mix);
|
||||||
|
glUniform1f(sky_shader.loc("cloudThresholdLow"), m_cloud_threshold_low);
|
||||||
|
glUniform1f(sky_shader.loc("cloudThresholdHigh"), m_cloud_threshold_high);
|
||||||
glBindVertexArray(m_vao[1]);
|
glBindVertexArray(m_vao[1]);
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
// draw sun and moon
|
||||||
|
const auto& billboard = get_shader("billboard");
|
||||||
|
billboard.use();
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
glBindVertexArray(m_vao[0]);
|
||||||
|
// draw sun
|
||||||
|
glm::vec3 sun_pos = m_camera.get_camera_pos() +
|
||||||
|
normalize(-m_world.sunlight_dir()) * (FAR_PLANE * 0.9f);
|
||||||
|
glm::vec3 sun_view_pos = glm::vec3(m_v_mat * glm::vec4(sun_pos, 1.0f));
|
||||||
|
m_mv_mat = glm::translate(glm::mat4(1.0f), sun_view_pos) *
|
||||||
|
glm::scale(glm::mat4(1.0f), glm::vec3(SUN_SIZE)) *
|
||||||
|
glm::translate(glm::mat4(1.0f), glm::vec3(-0.5f, -0.5f, 0.0f));
|
||||||
|
|
||||||
|
m_mv_loc = billboard.loc("mv_matrix");
|
||||||
|
m_proj_loc = billboard.loc("proj_matrix");
|
||||||
|
|
||||||
|
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));
|
||||||
|
glUniform3fv(billboard.loc("color"), 1, glm::value_ptr(SUN_COLOR));
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
glm::vec3 moon_pos = m_camera.get_camera_pos() +
|
||||||
|
normalize(m_world.sunlight_dir()) * (FAR_PLANE * 0.9f);
|
||||||
|
glm::vec3 moon_view_pos = glm::vec3(m_v_mat * glm::vec4(moon_pos, 1.0f));
|
||||||
|
m_mv_mat = glm::translate(glm::mat4(1.0f), moon_view_pos) *
|
||||||
|
glm::scale(glm::mat4(1.0f), glm::vec3(MOON_SIZE)) *
|
||||||
|
glm::translate(glm::mat4(1.0f), glm::vec3(-0.5f, -0.5f, 0.0f));
|
||||||
|
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));
|
||||||
|
glUniform3fv(billboard.loc("color"), 1, glm::value_ptr(MOON_COLOR));
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::render_text() {
|
void Renderer::render_text() {
|
||||||
@@ -343,7 +470,8 @@ void Renderer::update_fov(float fov) {
|
|||||||
|
|
||||||
void Renderer::update_proj_matrix(float aspect, float width, float height) {
|
void Renderer::update_proj_matrix(float aspect, float width, float height) {
|
||||||
m_aspect = aspect;
|
m_aspect = aspect;
|
||||||
m_p_mat = glm::perspective(glm::radians(m_fov), aspect, 0.1f, 1000.0f);
|
m_p_mat =
|
||||||
|
glm::perspective(glm::radians(m_fov), aspect, NEAR_PLANE, FAR_PLANE);
|
||||||
m_ui_proj = glm::ortho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
|
m_ui_proj = glm::ortho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
|
||||||
// scale and then translate
|
// scale and then translate
|
||||||
m_ui_m_matrix =
|
m_ui_m_matrix =
|
||||||
@@ -423,11 +551,150 @@ void Renderer::updata_framebuffer(int width, int height) {
|
|||||||
}
|
}
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
// depth map fbo
|
||||||
|
if (m_depth_map_fbo == 0) {
|
||||||
|
glGenFramebuffers(1, &m_depth_map_fbo);
|
||||||
|
}
|
||||||
|
glDeleteTextures(1, &m_depth_map_texture);
|
||||||
|
glGenTextures(1, &m_depth_map_texture);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_depth_map_texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, DEPTH_MAP_SIZE,
|
||||||
|
DEPTH_MAP_SIZE, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||||
|
float border_color[] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||||
|
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
|
||||||
|
// Manually compare shadows
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||||
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
|
||||||
|
// GL_COMPARE_REF_TO_TEXTURE);
|
||||||
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, m_depth_map_fbo);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
|
||||||
|
m_depth_map_texture, 0);
|
||||||
|
glDrawBuffer(GL_NONE);
|
||||||
|
glReadBuffer(GL_NONE);
|
||||||
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
Logger::error("FBO incomplete after resize!");
|
||||||
|
} else {
|
||||||
|
Logger::info("Frame Buffer Complete!");
|
||||||
|
}
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
m_width = width;
|
m_width = width;
|
||||||
m_height = height;
|
m_height = height;
|
||||||
}
|
}
|
||||||
|
#pragma region render_world
|
||||||
void Renderer::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;
|
||||||
|
|
||||||
|
const auto& lightdir = m_parallel_light.lightdir;
|
||||||
|
|
||||||
|
if (m_shader_on) {
|
||||||
|
const auto& depth_shader = get_shader("depth_shader");
|
||||||
|
depth_shader.use();
|
||||||
|
|
||||||
|
glm::vec3 cam_pos = m_camera.get_camera_pos();
|
||||||
|
glm::vec3 cam_fwd = m_camera.get_camera_front();
|
||||||
|
float half_extent = 128.0f;
|
||||||
|
|
||||||
|
glm::vec3 center = cam_pos + cam_fwd * (half_extent * 0.5f);
|
||||||
|
|
||||||
|
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_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;
|
||||||
|
ls_center.y =
|
||||||
|
std::round(ls_center.y * texels_per_unit) / texels_per_unit;
|
||||||
|
glm::vec3 snapped_center =
|
||||||
|
glm::vec3(glm::inverse(light_basis) * glm::vec4(ls_center, 1.0f));
|
||||||
|
|
||||||
|
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_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,
|
||||||
|
near_plane, far_plane);
|
||||||
|
|
||||||
|
light_space_matrix = light_projection * light_view;
|
||||||
|
glUniformMatrix4fv(depth_shader.loc("lightSpaceMatrix"), 1, GL_FALSE,
|
||||||
|
glm::value_ptr(light_space_matrix));
|
||||||
|
glUniform1i(depth_shader.loc("is_discard_tranparent"),
|
||||||
|
m_discard_tranparent);
|
||||||
|
glViewport(0, 0, DEPTH_MAP_SIZE, DEPTH_MAP_SIZE);
|
||||||
|
if (m_light_cull_face == 0) {
|
||||||
|
glCullFace(GL_FRONT);
|
||||||
|
} else if (m_light_cull_face == 1) {
|
||||||
|
glCullFace(GL_BACK);
|
||||||
|
} else {
|
||||||
|
Logger::warn("Light Cull Face {} Over The Max Selection",
|
||||||
|
m_light_cull_face);
|
||||||
|
glCullFace(GL_BACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, m_depth_map_fbo);
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
for (const auto& snapshot : m_render_snapshots) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY,
|
||||||
|
m_texture_manager.get_texture_array());
|
||||||
|
glBindVertexArray(snapshot.normal_vao);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, snapshot.normal_vertices_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// cross_plane and discard
|
||||||
|
|
||||||
|
for (const auto& snapshot : m_render_snapshots) {
|
||||||
|
|
||||||
|
glm::vec2 camera_pos_xz{camera_pos.x, camera_pos.z};
|
||||||
|
if (snapshot.cross_vertices_count != 0) {
|
||||||
|
glm::vec2 center_xz{snapshot.center.x, snapshot.center.z};
|
||||||
|
float dist2d = glm::distance(camera_pos_xz, center_xz);
|
||||||
|
if (dist2d <= CROSS_PLANE_DISTANCE * 16) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY,
|
||||||
|
m_texture_manager.get_texture_array());
|
||||||
|
glBindVertexArray(snapshot.cross_vao);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0,
|
||||||
|
snapshot.cross_vertices_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (snapshot.normal_discard_vertices_count != 0) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY,
|
||||||
|
m_texture_manager.get_texture_array());
|
||||||
|
glBindVertexArray(snapshot.normal_discard_vao);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0,
|
||||||
|
snapshot.normal_discard_vertices_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
||||||
|
|
||||||
|
glCullFace(GL_BACK);
|
||||||
|
glViewport(0, 0, m_width, m_height);
|
||||||
const auto& normal_block_shader = get_shader("normal_block");
|
const auto& normal_block_shader = get_shader("normal_block");
|
||||||
normal_block_shader.use();
|
normal_block_shader.use();
|
||||||
|
|
||||||
@@ -435,17 +702,43 @@ void Renderer::render_world() {
|
|||||||
m_proj_loc = normal_block_shader.loc("proj_matrix");
|
m_proj_loc = normal_block_shader.loc("proj_matrix");
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_depth_map_texture);
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
|
||||||
m_m_mat = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f));
|
m_m_mat = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f));
|
||||||
m_v_mat = m_camera.get_camera_lookat();
|
m_v_mat = m_camera.get_camera_lookat();
|
||||||
m_mv_mat = m_v_mat * m_m_mat;
|
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) * lightdir);
|
||||||
|
|
||||||
glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_mv_mat));
|
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));
|
glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_p_mat));
|
||||||
|
glUniformMatrix4fv(normal_block_shader.loc("norm_matrix"), 1, GL_FALSE,
|
||||||
|
glm::value_ptr(m_norm_mat));
|
||||||
|
glUniformMatrix4fv(normal_block_shader.loc("lightSpaceMatrix"), 1, GL_FALSE,
|
||||||
|
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(m_parallel_light.directional_light_color));
|
||||||
|
glUniform3fv(normal_block_shader.loc("ambientColor"), 1,
|
||||||
|
glm::value_ptr(m_parallel_light.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;
|
m_mvp_mat = m_p_mat * m_mv_mat;
|
||||||
|
|
||||||
auto& camera_pos = m_camera.get_camera_pos();
|
|
||||||
auto& m_planes = m_world.planes();
|
auto& m_planes = m_world.planes();
|
||||||
auto& m_render_snapshots = m_world.render_snapshots();
|
|
||||||
|
|
||||||
Math::extract_frustum_planes(m_mvp_mat, m_planes);
|
Math::extract_frustum_planes(m_mvp_mat, m_planes);
|
||||||
|
|
||||||
@@ -526,6 +819,7 @@ void Renderer::render_world() {
|
|||||||
glBlendFunci(0, GL_ONE, GL_ONE);
|
glBlendFunci(0, GL_ONE, GL_ONE);
|
||||||
|
|
||||||
glBlendFunci(1, GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
|
glBlendFunci(1, GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
for (const auto& snapshot : m_render_snapshots) {
|
for (const auto& snapshot : m_render_snapshots) {
|
||||||
if (!Math::is_aabb_in_frustum(snapshot.center, snapshot.half_extents,
|
if (!Math::is_aabb_in_frustum(snapshot.center, snapshot.half_extents,
|
||||||
m_planes)) {
|
m_planes)) {
|
||||||
@@ -564,11 +858,71 @@ void Renderer::render_world() {
|
|||||||
DebugCollector::get().report(
|
DebugCollector::get().report(
|
||||||
"rendered_chunk", "Rendered Chunk: " + std::to_string(rendered_sum));
|
"rendered_chunk", "Rendered Chunk: " + std::to_string(rendered_sum));
|
||||||
}
|
}
|
||||||
|
#pragma endregion
|
||||||
void Renderer::render_dev_panel() {
|
void Renderer::render_dev_panel() {
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
m_dev_panel.render();
|
m_dev_panel.render();
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 Renderer::quantize_sun_direction(const glm::vec3& lightdir,
|
||||||
|
float angle_step_deg) const {
|
||||||
|
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);
|
||||||
|
|
||||||
|
float quantized_elevation = std::round(elevation / step) * step;
|
||||||
|
float quantized_azimuth = std::round(azimuth / step) * step;
|
||||||
|
|
||||||
|
glm::vec3 quantized_dir;
|
||||||
|
quantized_dir.x =
|
||||||
|
std::cos(quantized_elevation) * std::cos(quantized_azimuth);
|
||||||
|
quantized_dir.z =
|
||||||
|
std::cos(quantized_elevation) * std::sin(quantized_azimuth);
|
||||||
|
quantized_dir.y = std::sin(quantized_elevation);
|
||||||
|
|
||||||
|
return glm::normalize(quantized_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3
|
||||||
|
Renderer::get_smoothed_shadow_lightdir(const glm::vec3& raw_shadow_lightdir,
|
||||||
|
float dt) {
|
||||||
|
if (!m_blend_initialized) {
|
||||||
|
|
||||||
|
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_lightdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw_shadow_lightdir != m_blend_to_lightdir) {
|
||||||
|
glm::vec3 current_displayed = glm::normalize(
|
||||||
|
Math::slerp(m_blend_from_lightdir, m_blend_to_lightdir, m_blend_t));
|
||||||
|
|
||||||
|
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_lightdir, m_blend_to_lightdir, m_blend_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
float& Renderer::ambient_strength() { return m_ambient_strength; }
|
||||||
|
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; }
|
||||||
|
float& Renderer::cloud_speed() { return m_cloud_speed; }
|
||||||
|
float& Renderer::cloud_threshold_low() { return m_cloud_threshold_low; }
|
||||||
|
float& Renderer::cloud_threshold_high() { return m_cloud_threshold_high; }
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -164,6 +164,8 @@ void TextureManager::init_block() {
|
|||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,
|
||||||
GL_LINEAR_MIPMAP_LINEAR);
|
GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
||||||
if (m_aniso >= 1) {
|
if (m_aniso >= 1) {
|
||||||
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY,
|
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY,
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#include "Cubed/tools/math_tools.hpp"
|
#include "Cubed/tools/math_tools.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
namespace Math {
|
namespace Math {
|
||||||
@@ -65,6 +67,39 @@ float deterministic_random(int x, int z, uint64_t seed) {
|
|||||||
h = h * 6364136223846793005ULL + (uint64_t)z;
|
h = h * 6364136223846793005ULL + (uint64_t)z;
|
||||||
return (float)(h >> 40) / (float)(1 << 24);
|
return (float)(h >> 40) / (float)(1 << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 slerp(const glm::vec3& from, const glm::vec3& to, float t) {
|
||||||
|
|
||||||
|
float cos_theta = glm::clamp(glm::dot(from, to), -1.0f, 1.0f);
|
||||||
|
|
||||||
|
if (cos_theta > 0.9995f) {
|
||||||
|
return glm::normalize(glm::mix(from, to, t));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cos_theta < -0.9995f) {
|
||||||
|
|
||||||
|
glm::vec3 axis = (std::fabs(from.x) < 0.9f)
|
||||||
|
? glm::vec3(1.0f, 0.0f, 0.0f)
|
||||||
|
: glm::vec3(0.0f, 1.0f, 0.0f);
|
||||||
|
glm::vec3 ortho = glm::normalize(glm::cross(from, axis));
|
||||||
|
|
||||||
|
float angle = glm::pi<float>() * t;
|
||||||
|
|
||||||
|
glm::vec3 rotated =
|
||||||
|
from * std::cos(angle) + glm::cross(ortho, from) * std::sin(angle);
|
||||||
|
|
||||||
|
return glm::normalize(rotated);
|
||||||
|
}
|
||||||
|
|
||||||
|
float theta = std::acos(cos_theta);
|
||||||
|
float sin_theta = std::sin(theta);
|
||||||
|
|
||||||
|
float a = std::sin((1.0f - t) * theta) / sin_theta;
|
||||||
|
float b = std::sin(t * theta) / sin_theta;
|
||||||
|
|
||||||
|
return glm::normalize(a * from + b * to);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Math
|
} // namespace Math
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
Reference in New Issue
Block a user