Merge pull request #535 from MihailRis/update-gfx-pipeline
Advanced graphics mode
This commit is contained in:
commit
976425a968
@ -7,7 +7,7 @@
|
|||||||
"torch_side",
|
"torch_side",
|
||||||
"torch_side"
|
"torch_side"
|
||||||
],
|
],
|
||||||
"emission": [13, 13, 12],
|
"emission": [13, 10, 2],
|
||||||
"model": "aabb",
|
"model": "aabb",
|
||||||
"hitbox": [0.4375, 0.0, 0.4375, 0.125, 0.5, 0.125],
|
"hitbox": [0.4375, 0.0, 0.4375, 0.125, 0.5, 0.125],
|
||||||
"light-passing": true,
|
"light-passing": true,
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
],
|
],
|
||||||
"textures": [
|
"textures": [
|
||||||
"misc/moon",
|
"misc/moon",
|
||||||
|
"misc/moon_flare",
|
||||||
"misc/sun",
|
"misc/sun",
|
||||||
"gui/crosshair"
|
"gui/crosshair"
|
||||||
]
|
]
|
||||||
|
|||||||
@ -42,4 +42,7 @@ function on_open()
|
|||||||
create_setting("graphics.gamma", "Gamma", 0.05, "", "graphics.gamma.tooltip")
|
create_setting("graphics.gamma", "Gamma", 0.05, "", "graphics.gamma.tooltip")
|
||||||
create_checkbox("graphics.backlight", "Backlight", "graphics.backlight.tooltip")
|
create_checkbox("graphics.backlight", "Backlight", "graphics.backlight.tooltip")
|
||||||
create_checkbox("graphics.dense-render", "Dense blocks render", "graphics.dense-render.tooltip")
|
create_checkbox("graphics.dense-render", "Dense blocks render", "graphics.dense-render.tooltip")
|
||||||
|
create_checkbox("graphics.advanced-render", "Advanced render", "graphics.advanced-render.tooltip")
|
||||||
|
create_checkbox("graphics.ssao", "SSAO", "graphics.ssao.tooltip")
|
||||||
|
create_setting("graphics.shadows-quality", "Shadows quality", 1)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -6,10 +6,19 @@
|
|||||||
"lines",
|
"lines",
|
||||||
"entity",
|
"entity",
|
||||||
"background",
|
"background",
|
||||||
"skybox_gen"
|
"skybox_gen",
|
||||||
|
"shadows"
|
||||||
],
|
],
|
||||||
"post-effects": [
|
"post-effects": [
|
||||||
"default"
|
"default",
|
||||||
|
{
|
||||||
|
"name": "ssao",
|
||||||
|
"advanced": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "deferred_lighting",
|
||||||
|
"advanced": true
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"textures": [
|
"textures": [
|
||||||
"gui/menubg",
|
"gui/menubg",
|
||||||
|
|||||||
@ -4,5 +4,8 @@
|
|||||||
"third-person-front",
|
"third-person-front",
|
||||||
"third-person-back",
|
"third-person-back",
|
||||||
"cinematic"
|
"cinematic"
|
||||||
|
],
|
||||||
|
"post-effect-slot": [
|
||||||
|
"default"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,27 @@
|
|||||||
|
local function configure_SSAO()
|
||||||
|
-- Temporary using slot to configure built-in SSAO effect
|
||||||
|
local slot = gfx.posteffects.index("core:default")
|
||||||
|
gfx.posteffects.set_effect(slot, "ssao")
|
||||||
|
|
||||||
|
-- Generating random SSAO samples
|
||||||
|
local buffer = Bytearray(0)
|
||||||
|
for i = 0, 63 do
|
||||||
|
local x = math.random() * 2.0 - 1.0
|
||||||
|
local y = math.random() * 2.0 - 1.0
|
||||||
|
local z = math.random() * 2.0
|
||||||
|
local len = math.sqrt(x * x + y * y + z * z)
|
||||||
|
if len > 0 then
|
||||||
|
x = x / len
|
||||||
|
y = y / len
|
||||||
|
z = z / len
|
||||||
|
end
|
||||||
|
Bytearray.append(buffer, byteutil.pack("fff", x, y, z))
|
||||||
|
end
|
||||||
|
gfx.posteffects.set_array(slot, "u_ssaoSamples", Bytearray_as_string(buffer))
|
||||||
|
-- SSAO effect configured, so 'core:default' slot may be reused now
|
||||||
|
-- for test purposes
|
||||||
|
end
|
||||||
|
|
||||||
function on_hud_open()
|
function on_hud_open()
|
||||||
input.add_callback("player.pick", function ()
|
input.add_callback("player.pick", function ()
|
||||||
if hud.is_paused() or hud.is_inventory_open() then
|
if hud.is_paused() or hud.is_inventory_open() then
|
||||||
@ -55,4 +79,6 @@ function on_hud_open()
|
|||||||
player.set_vel(pid, 0, 1, 0)
|
player.set_vel(pid, 0, 1, 0)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
configure_SSAO()
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
in vec3 v_coord;
|
in vec3 v_coord;
|
||||||
out vec4 f_color;
|
layout (location = 0) out vec4 f_color;
|
||||||
|
layout (location = 1) out vec4 f_position;
|
||||||
|
layout (location = 2) out vec4 f_normal;
|
||||||
|
|
||||||
uniform samplerCube u_cubemap;
|
uniform mat4 u_view;
|
||||||
|
uniform samplerCube u_skybox;
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
vec3 dir = normalize(v_coord);
|
vec3 dir = normalize(v_coord) * 1e6;
|
||||||
f_color = texture(u_cubemap, dir);
|
f_position = u_view * vec4(dir, 1.0);
|
||||||
|
f_normal = vec4(0.0, 0.0, 1.0, 1.0);
|
||||||
|
f_color = texture(u_skybox, dir);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ uniform float u_ar;
|
|||||||
uniform float u_zoom;
|
uniform float u_zoom;
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
v_coord = (vec4(v_position*vec2(u_ar, 1.0f)*u_zoom, -1.0, 1.0) * u_view).xyz;
|
v_coord = (vec4(v_position * vec2(u_ar, 1.0f) * u_zoom, -1.0, 1.0) * u_view).xyz;
|
||||||
gl_Position = vec4(v_position, 0.0, 1.0);
|
gl_Position = vec4(v_position, 1.0 - 1e-6, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,22 @@ in vec2 v_uv;
|
|||||||
out vec4 f_color;
|
out vec4 f_color;
|
||||||
|
|
||||||
uniform sampler2D u_screen;
|
uniform sampler2D u_screen;
|
||||||
|
uniform sampler2D u_position;
|
||||||
|
uniform sampler2D u_normal;
|
||||||
|
uniform sampler2D u_emission;
|
||||||
|
uniform sampler2D u_noise;
|
||||||
|
uniform sampler2D u_ssao;
|
||||||
|
uniform samplerCube u_skybox;
|
||||||
|
|
||||||
uniform ivec2 u_screenSize;
|
uniform ivec2 u_screenSize;
|
||||||
uniform float u_intensity;
|
uniform float u_intensity;
|
||||||
|
uniform float u_timer;
|
||||||
|
uniform bool u_enableShadows;
|
||||||
|
uniform mat4 u_projection;
|
||||||
|
uniform mat4 u_view;
|
||||||
|
uniform mat4 u_inverseView;
|
||||||
|
uniform vec3 u_sunDir;
|
||||||
|
uniform vec3 u_cameraPos;
|
||||||
|
|
||||||
#include <__effect__>
|
#include <__effect__>
|
||||||
|
|
||||||
|
|||||||
35
res/shaders/effects/deferred_lighting.glsl
Normal file
35
res/shaders/effects/deferred_lighting.glsl
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include <shadows>
|
||||||
|
#include <fog>
|
||||||
|
|
||||||
|
vec4 effect() {
|
||||||
|
vec4 pos = texture(u_position, v_uv);
|
||||||
|
float light = 1.0;
|
||||||
|
|
||||||
|
#ifdef ENABLE_SSAO
|
||||||
|
light = 0.0;
|
||||||
|
float z = pos.z;
|
||||||
|
for (int y = -2; y <= 2; y++) {
|
||||||
|
for (int x = -2; x <= 2; x++) {
|
||||||
|
vec2 offset = vec2(x, y) / u_screenSize;
|
||||||
|
light += texture(u_ssao, v_uv + offset * 2.0).r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
light /= 24.0;
|
||||||
|
#endif // ENABLE_SSAO
|
||||||
|
|
||||||
|
vec4 modelpos = u_inverseView * pos;
|
||||||
|
vec3 normal = transpose(mat3(u_view)) * texture(u_normal, v_uv).xyz;
|
||||||
|
vec3 dir = modelpos.xyz - u_cameraPos;
|
||||||
|
|
||||||
|
float emission = texture(u_emission, v_uv).r;
|
||||||
|
|
||||||
|
#ifdef ENABLE_SHADOWS
|
||||||
|
light *= calc_shadow(modelpos, normal, length(pos));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
light = max(light, emission);
|
||||||
|
|
||||||
|
vec3 fogColor = texture(u_skybox, dir).rgb;
|
||||||
|
float fog = calc_fog(length(u_view * vec4((modelpos.xyz - u_cameraPos) * FOG_POS_SCALE, 0.0)) / 256.0);
|
||||||
|
return vec4(mix(texture(u_screen, v_uv).rgb * mix(1.0, light, 1.0), fogColor, fog), 1.0);
|
||||||
|
}
|
||||||
37
res/shaders/effects/ssao.glsl
Normal file
37
res/shaders/effects/ssao.glsl
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#param vec3 u_ssaoSamples[64]
|
||||||
|
#param int u_kernelSize = 16
|
||||||
|
#param float u_radius = 0.4
|
||||||
|
#param float u_bias = 0.006
|
||||||
|
|
||||||
|
vec4 effect() {
|
||||||
|
vec2 noiseScale = u_screenSize / 4.0;
|
||||||
|
|
||||||
|
vec3 position = texture(u_position, v_uv).xyz;
|
||||||
|
vec3 normal = texture(u_normal, v_uv).xyz;
|
||||||
|
vec3 randomVec = normalize(texture(u_noise, v_uv * noiseScale).xyz);
|
||||||
|
|
||||||
|
vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
|
||||||
|
vec3 bitangent = cross(normal, tangent);
|
||||||
|
mat3 tbn = mat3(tangent, bitangent, normal);
|
||||||
|
|
||||||
|
float occlusion = 0.0;
|
||||||
|
for (int i = 0; i < u_kernelSize; i++) {
|
||||||
|
vec3 samplePos = tbn * u_ssaoSamples[i];
|
||||||
|
samplePos = position + samplePos * u_radius;
|
||||||
|
|
||||||
|
vec4 offset = vec4(samplePos, 1.0);
|
||||||
|
offset = u_projection * offset;
|
||||||
|
offset.xyz /= offset.w;
|
||||||
|
offset.xyz = offset.xyz * 0.5 + 0.5;
|
||||||
|
|
||||||
|
float sampleDepth = texture(u_position, offset.xy).z;
|
||||||
|
float rangeCheck = smoothstep(0.0, 1.0, u_radius / abs(position.z - sampleDepth));
|
||||||
|
occlusion += (sampleDepth >= samplePos.z + u_bias ? 1.0 : 0.0) * rangeCheck;
|
||||||
|
}
|
||||||
|
occlusion = min(1.0, 1.05 - (occlusion / u_kernelSize));
|
||||||
|
occlusion = max(occlusion, texture(u_emission, v_uv).r);
|
||||||
|
|
||||||
|
float z = -position.z * 0.01;
|
||||||
|
z = max(0.0, 1.0 - z);
|
||||||
|
return vec4(mix(1.0, occlusion, z), 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
@ -1,23 +1,45 @@
|
|||||||
in vec4 a_color;
|
layout (location = 0) out vec4 f_color;
|
||||||
|
layout (location = 1) out vec4 f_position;
|
||||||
|
layout (location = 2) out vec4 f_normal;
|
||||||
|
layout (location = 3) out vec4 f_emission;
|
||||||
|
|
||||||
|
in float a_distance;
|
||||||
|
in float a_fog;
|
||||||
in vec2 a_texCoord;
|
in vec2 a_texCoord;
|
||||||
in vec3 a_dir;
|
in vec3 a_dir;
|
||||||
in float a_fog;
|
in vec3 a_normal;
|
||||||
out vec4 f_color;
|
in vec3 a_position;
|
||||||
|
in vec3 a_realnormal;
|
||||||
|
in vec4 a_color;
|
||||||
|
in vec4 a_modelpos;
|
||||||
|
in float a_emission;
|
||||||
|
|
||||||
uniform sampler2D u_texture0;
|
uniform sampler2D u_texture0;
|
||||||
uniform samplerCube u_cubemap;
|
uniform samplerCube u_skybox;
|
||||||
uniform vec3 u_fogColor;
|
uniform vec3 u_fogColor;
|
||||||
uniform float u_fogFactor;
|
uniform float u_fogFactor;
|
||||||
uniform float u_fogCurve;
|
uniform float u_fogCurve;
|
||||||
uniform bool u_alphaClip;
|
uniform bool u_alphaClip;
|
||||||
|
uniform vec3 u_sunDir;
|
||||||
|
|
||||||
|
#include <shadows>
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec3 fogColor = texture(u_cubemap, a_dir).rgb;
|
vec4 texColor = texture(u_texture0, a_texCoord);
|
||||||
vec4 tex_color = texture(u_texture0, a_texCoord);
|
float alpha = a_color.a * texColor.a;
|
||||||
float alpha = a_color.a * tex_color.a;
|
|
||||||
// anyway it's any alpha-test alternative required
|
// anyway it's any alpha-test alternative required
|
||||||
if (alpha < (u_alphaClip ? 0.5f : 0.15f))
|
if (alpha < (u_alphaClip ? 0.5f : 0.15f)) {
|
||||||
discard;
|
discard;
|
||||||
f_color = mix(a_color * tex_color, vec4(fogColor,1.0), a_fog);
|
}
|
||||||
|
f_color = a_color * texColor;
|
||||||
|
|
||||||
|
#ifndef ADVANCED_RENDER
|
||||||
|
vec3 fogColor = texture(u_skybox, a_dir).rgb;
|
||||||
|
f_color = mix(f_color, vec4(fogColor, 1.0), a_fog);
|
||||||
|
#endif
|
||||||
|
|
||||||
f_color.a = alpha;
|
f_color.a = alpha;
|
||||||
|
f_position = vec4(a_position, 1.0);
|
||||||
|
f_normal = vec4(a_normal, 1.0);
|
||||||
|
f_emission = vec4(vec3(a_emission), 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,11 +4,18 @@ layout (location = 0) in vec3 v_position;
|
|||||||
layout (location = 1) in vec2 v_texCoord;
|
layout (location = 1) in vec2 v_texCoord;
|
||||||
layout (location = 2) in vec3 v_color;
|
layout (location = 2) in vec3 v_color;
|
||||||
layout (location = 3) in vec4 v_light;
|
layout (location = 3) in vec4 v_light;
|
||||||
|
layout (location = 4) in vec4 v_normal;
|
||||||
|
|
||||||
out vec4 a_color;
|
out float a_distance;
|
||||||
out vec2 a_texCoord;
|
|
||||||
out float a_fog;
|
out float a_fog;
|
||||||
|
out vec2 a_texCoord;
|
||||||
out vec3 a_dir;
|
out vec3 a_dir;
|
||||||
|
out vec3 a_normal;
|
||||||
|
out vec3 a_position;
|
||||||
|
out vec3 a_realnormal;
|
||||||
|
out vec4 a_color;
|
||||||
|
out vec4 a_modelpos;
|
||||||
|
out float a_emission;
|
||||||
|
|
||||||
uniform mat4 u_model;
|
uniform mat4 u_model;
|
||||||
uniform mat4 u_proj;
|
uniform mat4 u_proj;
|
||||||
@ -16,36 +23,40 @@ uniform mat4 u_view;
|
|||||||
uniform vec3 u_cameraPos;
|
uniform vec3 u_cameraPos;
|
||||||
uniform float u_gamma;
|
uniform float u_gamma;
|
||||||
uniform float u_opacity;
|
uniform float u_opacity;
|
||||||
uniform float u_fogFactor;
|
uniform float u_timer;
|
||||||
uniform float u_fogCurve;
|
uniform samplerCube u_skybox;
|
||||||
uniform float u_weatherFogOpacity;
|
|
||||||
uniform float u_weatherFogDencity;
|
|
||||||
uniform float u_weatherFogCurve;
|
|
||||||
uniform samplerCube u_cubemap;
|
|
||||||
|
|
||||||
uniform vec3 u_torchlightColor;
|
uniform vec3 u_torchlightColor;
|
||||||
uniform float u_torchlightDistance;
|
uniform float u_torchlightDistance;
|
||||||
|
|
||||||
|
#include <lighting>
|
||||||
|
#include <fog>
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 modelpos = u_model * vec4(v_position, 1.0);
|
a_modelpos = u_model * vec4(v_position, 1.0);
|
||||||
vec3 pos3d = modelpos.xyz - u_cameraPos;
|
vec3 pos3d = a_modelpos.xyz - u_cameraPos;
|
||||||
modelpos.xyz = apply_planet_curvature(modelpos.xyz, pos3d);
|
a_modelpos.xyz = apply_planet_curvature(a_modelpos.xyz, pos3d);
|
||||||
|
|
||||||
|
a_realnormal = v_normal.xyz * 2.0 - 1.0;
|
||||||
|
a_normal = calc_screen_normal(a_realnormal);
|
||||||
|
|
||||||
vec3 light = v_light.rgb;
|
vec3 light = v_light.rgb;
|
||||||
float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) /
|
float torchlight = calc_torch_light(a_realnormal, a_modelpos.xyz);
|
||||||
u_torchlightDistance);
|
|
||||||
light += torchlight * u_torchlightColor;
|
light += torchlight * u_torchlightColor;
|
||||||
a_color = vec4(pow(light, vec3(u_gamma)),1.0f);
|
a_color = vec4(pow(light, vec3(u_gamma)), 1.0f);
|
||||||
a_texCoord = v_texCoord;
|
a_texCoord = v_texCoord;
|
||||||
|
|
||||||
a_dir = modelpos.xyz - u_cameraPos;
|
a_dir = a_modelpos.xyz - u_cameraPos;
|
||||||
vec3 skyLightColor = pick_sky_color(u_cubemap);
|
vec3 skyLightColor = pick_sky_color(u_skybox);
|
||||||
a_color.rgb = max(a_color.rgb, skyLightColor.rgb*v_light.a) * v_color;
|
a_color.rgb = max(a_color.rgb, skyLightColor.rgb * v_light.a) * v_color;
|
||||||
a_color.a = u_opacity;
|
a_color.a = u_opacity;
|
||||||
|
|
||||||
float dist = length(u_view * u_model * vec4(pos3d * FOG_POS_SCALE, 0.0));
|
mat4 viewmodel = u_view * u_model;
|
||||||
float depth = (dist / 256.0);
|
a_distance = length(viewmodel * vec4(pos3d, 0.0));
|
||||||
a_fog = min(1.0, max(pow(depth * u_fogFactor, u_fogCurve),
|
a_fog = calc_fog(length(viewmodel * vec4(pos3d * FOG_POS_SCALE, 0.0)) / 256.0);
|
||||||
min(pow(depth * u_weatherFogDencity, u_weatherFogCurve), u_weatherFogOpacity)));
|
a_emission = v_normal.w;
|
||||||
gl_Position = u_proj * u_view * modelpos;
|
|
||||||
|
vec4 viewmodelpos = u_view * a_modelpos;
|
||||||
|
a_position = viewmodelpos.xyz;
|
||||||
|
gl_Position = u_proj * viewmodelpos;
|
||||||
}
|
}
|
||||||
|
|||||||
19
res/shaders/lib/fog.glsl
Normal file
19
res/shaders/lib/fog.glsl
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef FOG_GLSL_
|
||||||
|
#define FOG_GLSL_
|
||||||
|
|
||||||
|
uniform float u_fogFactor;
|
||||||
|
uniform float u_fogCurve;
|
||||||
|
uniform float u_weatherFogOpacity;
|
||||||
|
uniform float u_weatherFogDencity;
|
||||||
|
uniform float u_weatherFogCurve;
|
||||||
|
|
||||||
|
float calc_fog(float depth) {
|
||||||
|
return min(
|
||||||
|
1.0,
|
||||||
|
max(pow(depth * u_fogFactor, u_fogCurve),
|
||||||
|
min(pow(depth * u_weatherFogDencity, u_weatherFogCurve),
|
||||||
|
u_weatherFogOpacity))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FOG_GLSL_
|
||||||
13
res/shaders/lib/lighting.glsl
Normal file
13
res/shaders/lib/lighting.glsl
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef LIGHTING_GLSL_
|
||||||
|
#define LIGHTING_GLSL_
|
||||||
|
|
||||||
|
float calc_torch_light(vec3 normal, vec3 modelpos) {
|
||||||
|
return max(0.0, 1.0 - distance(u_cameraPos, modelpos) / u_torchlightDistance)
|
||||||
|
* max(0.0, -dot(normal, normalize(modelpos - u_cameraPos)));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 calc_screen_normal(vec3 normal) {
|
||||||
|
return transpose(inverse(mat3(u_view * u_model))) * normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // LIGHTING_GLSL_
|
||||||
47
res/shaders/lib/shadows.glsl
Normal file
47
res/shaders/lib/shadows.glsl
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef SHADOWS_GLSL_
|
||||||
|
#define SHADOWS_GLSL_
|
||||||
|
|
||||||
|
#include <constants>
|
||||||
|
|
||||||
|
uniform sampler2DShadow u_shadows[2];
|
||||||
|
uniform mat4 u_shadowsMatrix[2];
|
||||||
|
uniform float u_dayTime;
|
||||||
|
uniform int u_shadowsRes;
|
||||||
|
uniform float u_shadowsOpacity;
|
||||||
|
uniform float u_shadowsSoftness;
|
||||||
|
|
||||||
|
float calc_shadow(vec4 modelPos, vec3 realnormal, float distance) {
|
||||||
|
#ifdef ENABLE_SHADOWS
|
||||||
|
float step = 1.0 / float(u_shadowsRes);
|
||||||
|
float s = pow(abs(cos(u_dayTime * PI2)), 0.25) * u_shadowsOpacity;
|
||||||
|
vec3 normalOffset = realnormal * (distance > 64.0 ? 0.2 : 0.04);
|
||||||
|
int shadowIdx = distance > 80.0 ? 1 : 0;
|
||||||
|
|
||||||
|
vec4 mpos = u_shadowsMatrix[shadowIdx] * vec4(modelPos.xyz + normalOffset, 1.0);
|
||||||
|
vec3 projCoords = mpos.xyz / mpos.w;
|
||||||
|
projCoords = projCoords * 0.5 + 0.5;
|
||||||
|
projCoords.z -= 0.00001 / u_shadowsRes;
|
||||||
|
if (shadowIdx > 0) {
|
||||||
|
projCoords.z -= 0.001;
|
||||||
|
}
|
||||||
|
|
||||||
|
float shadow = 0.0;
|
||||||
|
if (dot(realnormal, u_sunDir) < 0.0) {
|
||||||
|
// 3x3 kernel
|
||||||
|
for (int y = -1; y <= 1; y++) {
|
||||||
|
for (int x = -1; x <= 1; x++) {
|
||||||
|
vec3 offset = vec3(x, y, -(abs(x) + abs(y)) * 0.8) * step * 1.0 * u_shadowsSoftness;
|
||||||
|
shadow += texture(u_shadows[shadowIdx], projCoords + offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shadow /= 9.0;
|
||||||
|
} else {
|
||||||
|
shadow = 0.5;
|
||||||
|
}
|
||||||
|
return 0.5 * (1.0 + s * shadow);
|
||||||
|
#else
|
||||||
|
return 1.0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SHADOWS_GLSL_
|
||||||
@ -1,20 +1,34 @@
|
|||||||
in vec4 a_color;
|
layout (location = 0) out vec4 f_color;
|
||||||
in vec2 a_texCoord;
|
layout (location = 1) out vec4 f_position;
|
||||||
|
layout (location = 2) out vec4 f_normal;
|
||||||
|
layout (location = 3) out vec4 f_emission;
|
||||||
|
|
||||||
|
in float a_distance;
|
||||||
in float a_fog;
|
in float a_fog;
|
||||||
|
in vec2 a_texCoord;
|
||||||
in vec3 a_dir;
|
in vec3 a_dir;
|
||||||
out vec4 f_color;
|
in vec3 a_normal;
|
||||||
|
in vec3 a_position;
|
||||||
|
in vec3 a_realnormal;
|
||||||
|
in vec3 a_skyLight;
|
||||||
|
in vec4 a_modelpos;
|
||||||
|
in vec4 a_torchLight;
|
||||||
|
in float a_emission;
|
||||||
|
|
||||||
uniform sampler2D u_texture0;
|
uniform sampler2D u_texture0;
|
||||||
uniform samplerCube u_cubemap;
|
uniform samplerCube u_skybox;
|
||||||
|
uniform vec3 u_sunDir;
|
||||||
|
|
||||||
|
// flags
|
||||||
uniform bool u_alphaClip;
|
uniform bool u_alphaClip;
|
||||||
uniform bool u_debugLights;
|
uniform bool u_debugLights;
|
||||||
|
uniform bool u_debugNormals;
|
||||||
|
|
||||||
|
#include <shadows>
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec3 fogColor = texture(u_cubemap, a_dir).rgb;
|
vec4 texColor = texture(u_texture0, a_texCoord);
|
||||||
vec4 tex_color = texture(u_texture0, a_texCoord);
|
float alpha = texColor.a;
|
||||||
if (u_debugLights)
|
|
||||||
tex_color.rgb = vec3(1.0);
|
|
||||||
float alpha = a_color.a * tex_color.a;
|
|
||||||
if (u_alphaClip) {
|
if (u_alphaClip) {
|
||||||
if (alpha < 0.2f)
|
if (alpha < 0.2f)
|
||||||
discard;
|
discard;
|
||||||
@ -23,6 +37,20 @@ void main() {
|
|||||||
if (alpha < 0.002f)
|
if (alpha < 0.002f)
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
f_color = mix(a_color * tex_color, vec4(fogColor,1.0), a_fog);
|
if (u_debugLights)
|
||||||
|
texColor.rgb = u_debugNormals ? (a_normal * 0.5 + 0.5) : vec3(1.0);
|
||||||
|
else if (u_debugNormals) {
|
||||||
|
texColor.rgb *= a_normal * 0.5 + 0.5;
|
||||||
|
}
|
||||||
|
f_color = texColor;
|
||||||
|
f_color.rgb *= min(vec3(1.0), a_torchLight.rgb + a_skyLight);
|
||||||
|
|
||||||
|
#ifndef ADVANCED_RENDER
|
||||||
|
vec3 fogColor = texture(u_skybox, a_dir).rgb;
|
||||||
|
f_color = mix(f_color, vec4(fogColor, 1.0), a_fog);
|
||||||
|
#endif
|
||||||
f_color.a = alpha;
|
f_color.a = alpha;
|
||||||
|
f_position = vec4(a_position, 1.0);
|
||||||
|
f_normal = vec4(a_normal, 1.0);
|
||||||
|
f_emission = vec4(vec3(a_emission), 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,48 +3,58 @@
|
|||||||
layout (location = 0) in vec3 v_position;
|
layout (location = 0) in vec3 v_position;
|
||||||
layout (location = 1) in vec2 v_texCoord;
|
layout (location = 1) in vec2 v_texCoord;
|
||||||
layout (location = 2) in vec4 v_light;
|
layout (location = 2) in vec4 v_light;
|
||||||
|
layout (location = 3) in vec4 v_normal;
|
||||||
|
|
||||||
out vec4 a_color;
|
|
||||||
out vec2 a_texCoord;
|
|
||||||
out float a_distance;
|
out float a_distance;
|
||||||
out float a_fog;
|
out float a_fog;
|
||||||
|
out vec2 a_texCoord;
|
||||||
out vec3 a_dir;
|
out vec3 a_dir;
|
||||||
|
out vec3 a_normal;
|
||||||
|
out vec3 a_position;
|
||||||
|
out vec3 a_realnormal;
|
||||||
|
out vec4 a_torchLight;
|
||||||
|
out vec3 a_skyLight;
|
||||||
|
out vec4 a_modelpos;
|
||||||
|
out float a_emission;
|
||||||
|
|
||||||
uniform mat4 u_model;
|
uniform mat4 u_model;
|
||||||
uniform mat4 u_proj;
|
uniform mat4 u_proj;
|
||||||
uniform mat4 u_view;
|
uniform mat4 u_view;
|
||||||
uniform vec3 u_cameraPos;
|
uniform vec3 u_cameraPos;
|
||||||
uniform float u_gamma;
|
uniform float u_gamma;
|
||||||
uniform float u_fogFactor;
|
|
||||||
uniform float u_fogCurve;
|
|
||||||
uniform float u_weatherFogOpacity;
|
|
||||||
uniform float u_weatherFogDencity;
|
|
||||||
uniform float u_weatherFogCurve;
|
|
||||||
uniform float u_timer;
|
uniform float u_timer;
|
||||||
uniform samplerCube u_cubemap;
|
uniform samplerCube u_skybox;
|
||||||
|
|
||||||
uniform vec3 u_torchlightColor;
|
uniform vec3 u_torchlightColor;
|
||||||
uniform float u_torchlightDistance;
|
uniform float u_torchlightDistance;
|
||||||
|
|
||||||
|
#include <lighting>
|
||||||
|
#include <fog>
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 modelpos = u_model * vec4(v_position, 1.0f);
|
a_modelpos = u_model * vec4(v_position, 1.0f);
|
||||||
vec3 pos3d = modelpos.xyz-u_cameraPos;
|
vec3 pos3d = a_modelpos.xyz - u_cameraPos;
|
||||||
modelpos.xyz = apply_planet_curvature(modelpos.xyz, pos3d);
|
a_modelpos.xyz = apply_planet_curvature(a_modelpos.xyz, pos3d);
|
||||||
|
|
||||||
|
a_realnormal = v_normal.xyz * 2.0 - 1.0;
|
||||||
|
a_normal = calc_screen_normal(a_realnormal);
|
||||||
|
|
||||||
vec3 light = v_light.rgb;
|
vec3 light = v_light.rgb;
|
||||||
float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) /
|
float torchlight = calc_torch_light(a_realnormal, a_modelpos.xyz);
|
||||||
u_torchlightDistance);
|
a_torchLight = vec4(pow(light + torchlight * u_torchlightColor, vec3(u_gamma)), 1.0f);
|
||||||
light += torchlight * u_torchlightColor;
|
|
||||||
a_color = vec4(pow(light, vec3(u_gamma)),1.0f);
|
|
||||||
a_texCoord = v_texCoord;
|
a_texCoord = v_texCoord;
|
||||||
|
|
||||||
a_dir = modelpos.xyz - u_cameraPos;
|
a_dir = a_modelpos.xyz - u_cameraPos;
|
||||||
vec3 skyLightColor = pick_sky_color(u_cubemap);
|
vec3 skyLightColor = pick_sky_color(u_skybox);
|
||||||
a_color.rgb = max(a_color.rgb, skyLightColor.rgb*v_light.a);
|
a_skyLight = skyLightColor.rgb*v_light.a;
|
||||||
|
|
||||||
a_distance = length(u_view * u_model * vec4(pos3d * FOG_POS_SCALE, 0.0));
|
mat4 viewmodel = u_view * u_model;
|
||||||
float depth = (a_distance / 256.0);
|
a_distance = length(viewmodel * vec4(pos3d, 0.0));
|
||||||
a_fog = min(1.0, max(pow(depth * u_fogFactor, u_fogCurve),
|
a_fog = calc_fog(length(viewmodel * vec4(pos3d * FOG_POS_SCALE, 0.0)) / 256.0);
|
||||||
min(pow(depth * u_weatherFogDencity, u_weatherFogCurve), u_weatherFogOpacity)));
|
a_emission = v_normal.w;
|
||||||
gl_Position = u_proj * u_view * modelpos;
|
|
||||||
|
vec4 viewmodelpos = u_view * a_modelpos;
|
||||||
|
a_position = viewmodelpos.xyz;
|
||||||
|
gl_Position = u_proj * viewmodelpos;
|
||||||
}
|
}
|
||||||
|
|||||||
11
res/shaders/shadows.glslf
Normal file
11
res/shaders/shadows.glslf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
in vec2 a_texCoord;
|
||||||
|
|
||||||
|
uniform sampler2D u_texture0;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 tex_color = texture(u_texture0, a_texCoord);
|
||||||
|
if (tex_color.a < 0.5) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
// depth will be written anyway
|
||||||
|
}
|
||||||
17
res/shaders/shadows.glslv
Normal file
17
res/shaders/shadows.glslv
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include <commons>
|
||||||
|
|
||||||
|
layout (location = 0) in vec3 v_position;
|
||||||
|
layout (location = 1) in vec2 v_texCoord;
|
||||||
|
layout (location = 2) in vec4 v_light;
|
||||||
|
layout (location = 3) in vec4 v_normal;
|
||||||
|
|
||||||
|
out vec2 a_texCoord;
|
||||||
|
|
||||||
|
uniform mat4 u_model;
|
||||||
|
uniform mat4 u_proj;
|
||||||
|
uniform mat4 u_view;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
a_texCoord = v_texCoord;
|
||||||
|
gl_Position = u_proj * u_view * u_model * vec4(v_position, 1.0f);
|
||||||
|
}
|
||||||
@ -268,7 +268,7 @@ void main() {
|
|||||||
camera_vector, // the camera vector (ray direction of this pixel)
|
camera_vector, // the camera vector (ray direction of this pixel)
|
||||||
1e12f, // max dist, essentially the scene depth
|
1e12f, // max dist, essentially the scene depth
|
||||||
vec3(0.0f), // scene color, the color of the current pixel being rendered
|
vec3(0.0f), // scene color, the color of the current pixel being rendered
|
||||||
u_lightDir, // light direction
|
vec3(u_lightDir.x, pow(u_lightDir.y, 3.0), u_lightDir.z), // light direction
|
||||||
vec3(40.0*fog), // light intensity, 40 looks nice
|
vec3(40.0*fog), // light intensity, 40 looks nice
|
||||||
PLANET_POS, // position of the planet
|
PLANET_POS, // position of the planet
|
||||||
PLANET_RADIUS, // radius of the planet in meters
|
PLANET_RADIUS, // radius of the planet in meters
|
||||||
|
|||||||
@ -98,6 +98,8 @@ settings.V-Sync=Вертикальная Синхронизация
|
|||||||
settings.Key=Кнопка
|
settings.Key=Кнопка
|
||||||
settings.Controls Search Mode=Поиск по привязанной кнопки управления
|
settings.Controls Search Mode=Поиск по привязанной кнопки управления
|
||||||
settings.Limit Background FPS=Ограничить фоновую частоту кадров
|
settings.Limit Background FPS=Ограничить фоновую частоту кадров
|
||||||
|
settings.Advanced render=Продвинутый рендер
|
||||||
|
settings.Shadows quality=Качество теней
|
||||||
|
|
||||||
# Управление
|
# Управление
|
||||||
chunks.reload=Перезагрузить Чанки
|
chunks.reload=Перезагрузить Чанки
|
||||||
|
|||||||
BIN
res/textures/misc/moon_flare.png
Normal file
BIN
res/textures/misc/moon_flare.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@ -147,14 +147,12 @@ void AssetsLoader::processPreload(
|
|||||||
add(tag, path, name);
|
add(tag, path, name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
std::shared_ptr<AssetCfg> config = nullptr;
|
||||||
map.at("path").get(path);
|
map.at("path").get(path);
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case AssetType::SOUND: {
|
case AssetType::SOUND: {
|
||||||
bool keepPCM = false;
|
bool keepPCM = false;
|
||||||
add(tag,
|
config = std::make_shared<SoundCfg>(map.at("keep-pcm").get(keepPCM));
|
||||||
path,
|
|
||||||
name,
|
|
||||||
std::make_shared<SoundCfg>(map.at("keep-pcm").get(keepPCM)));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AssetType::ATLAS: {
|
case AssetType::ATLAS: {
|
||||||
@ -164,13 +162,19 @@ void AssetsLoader::processPreload(
|
|||||||
if (typeName == "separate") {
|
if (typeName == "separate") {
|
||||||
type = AtlasType::SEPARATE;
|
type = AtlasType::SEPARATE;
|
||||||
}
|
}
|
||||||
add(tag, path, name, std::make_shared<AtlasCfg>(type));
|
config = std::make_shared<AtlasCfg>(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AssetType::POST_EFFECT: {
|
||||||
|
bool advanced = false;
|
||||||
|
map.at("advanced").get(advanced);
|
||||||
|
config = std::make_shared<PostEffectCfg>(advanced);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
add(tag, path, name);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
add(tag, path, name, std::move(config));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsLoader::processPreloadList(AssetType tag, const dv::value& list) {
|
void AssetsLoader::processPreloadList(AssetType tag, const dv::value& list) {
|
||||||
|
|||||||
@ -40,8 +40,7 @@ struct LayoutCfg : AssetCfg {
|
|||||||
struct SoundCfg : AssetCfg {
|
struct SoundCfg : AssetCfg {
|
||||||
bool keepPCM;
|
bool keepPCM;
|
||||||
|
|
||||||
SoundCfg(bool keepPCM) : keepPCM(keepPCM) {
|
SoundCfg(bool keepPCM) : keepPCM(keepPCM) {}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class AtlasType {
|
enum class AtlasType {
|
||||||
@ -51,8 +50,13 @@ enum class AtlasType {
|
|||||||
struct AtlasCfg : AssetCfg {
|
struct AtlasCfg : AssetCfg {
|
||||||
AtlasType type;
|
AtlasType type;
|
||||||
|
|
||||||
AtlasCfg(AtlasType type) : type(type) {
|
AtlasCfg(AtlasType type) : type(type) {}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
struct PostEffectCfg : AssetCfg {
|
||||||
|
bool advanced;
|
||||||
|
|
||||||
|
PostEffectCfg(bool advanced) : advanced(advanced) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
using aloader_func = std::function<
|
using aloader_func = std::function<
|
||||||
|
|||||||
@ -76,6 +76,14 @@ static auto process_program(const ResPaths& paths, const std::string& filename)
|
|||||||
return std::make_pair(vertex, fragment);
|
return std::make_pair(vertex, fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static auto read_program(const ResPaths& paths, const std::string& filename) {
|
||||||
|
io::path vertexFile = paths.find(filename + ".glslv");
|
||||||
|
io::path fragmentFile = paths.find(filename + ".glslf");
|
||||||
|
return std::make_pair(
|
||||||
|
io::read_string(vertexFile), io::read_string(fragmentFile)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
assetload::postfunc assetload::shader(
|
assetload::postfunc assetload::shader(
|
||||||
AssetsLoader*,
|
AssetsLoader*,
|
||||||
const ResPaths& paths,
|
const ResPaths& paths,
|
||||||
@ -83,21 +91,18 @@ assetload::postfunc assetload::shader(
|
|||||||
const std::string& name,
|
const std::string& name,
|
||||||
const std::shared_ptr<AssetCfg>&
|
const std::shared_ptr<AssetCfg>&
|
||||||
) {
|
) {
|
||||||
auto [vertex, fragment] = process_program(paths, filename);
|
auto result = read_program(paths, filename);
|
||||||
|
auto vertex = result.first;
|
||||||
|
auto fragment = result.second;
|
||||||
|
|
||||||
io::path vertexFile = paths.find(filename + ".glslv");
|
io::path vertexFile = paths.find(filename + ".glslv");
|
||||||
io::path fragmentFile = paths.find(filename + ".glslf");
|
io::path fragmentFile = paths.find(filename + ".glslf");
|
||||||
|
|
||||||
std::string vertexSource = std::move(vertex.code);
|
|
||||||
std::string fragmentSource = std::move(fragment.code);
|
|
||||||
|
|
||||||
return [=](auto assets) {
|
return [=](auto assets) {
|
||||||
assets->store(
|
assets->store(
|
||||||
Shader::create(
|
Shader::create(
|
||||||
vertexFile.string(),
|
{vertexFile.string(), vertex},
|
||||||
fragmentFile.string(),
|
{fragmentFile.string(), fragment}
|
||||||
vertexSource,
|
|
||||||
fragmentSource
|
|
||||||
),
|
),
|
||||||
name
|
name
|
||||||
);
|
);
|
||||||
@ -127,13 +132,16 @@ assetload::postfunc assetload::posteffect(
|
|||||||
|
|
||||||
return [=](auto assets) {
|
return [=](auto assets) {
|
||||||
auto program = Shader::create(
|
auto program = Shader::create(
|
||||||
effectFile.string(),
|
{effectFile.string(), vertexSource},
|
||||||
effectFile.string(),
|
{effectFile.string(), fragmentSource}
|
||||||
vertexSource,
|
|
||||||
fragmentSource
|
|
||||||
);
|
);
|
||||||
|
bool advanced = false;
|
||||||
|
if (settings) {
|
||||||
|
advanced = dynamic_cast<const PostEffectCfg*>(settings.get())->advanced;
|
||||||
|
}
|
||||||
assets->store(
|
assets->store(
|
||||||
std::make_shared<PostEffect>(std::move(program), params), name
|
std::make_shared<PostEffect>(advanced, std::move(program), params),
|
||||||
|
name
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,6 +76,14 @@ void GLSLExtension::undefine(const std::string& name) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLSLExtension::setDefined(const std::string& name, bool defined) {
|
||||||
|
if (defined) {
|
||||||
|
define(name, "TRUE");
|
||||||
|
} else {
|
||||||
|
undefine(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline std::runtime_error parsing_error(
|
inline std::runtime_error parsing_error(
|
||||||
const io::path& file, uint linenum, const std::string& message
|
const io::path& file, uint linenum, const std::string& message
|
||||||
) {
|
) {
|
||||||
@ -98,6 +106,8 @@ inline void source_line(std::stringstream& ss, uint linenum) {
|
|||||||
|
|
||||||
static Value default_value_for(Type type) {
|
static Value default_value_for(Type type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case Type::INT:
|
||||||
|
return 0;
|
||||||
case Type::FLOAT:
|
case Type::FLOAT:
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
case Type::VEC2:
|
case Type::VEC2:
|
||||||
@ -156,7 +166,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool processVersionDirective() {
|
bool processVersionDirective() {
|
||||||
parsing_warning(filename, line, "removed #version directive");
|
|
||||||
source_line(ss, line);
|
source_line(ss, line);
|
||||||
skipLine();
|
skipLine();
|
||||||
return false;
|
return false;
|
||||||
@ -183,6 +192,8 @@ public:
|
|||||||
|
|
||||||
Value parseDefaultValue(Type type, const std::string& name) {
|
Value parseDefaultValue(Type type, const std::string& name) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case Type::INT:
|
||||||
|
return static_cast<int>(parseNumber(1).asInteger());
|
||||||
case Type::FLOAT:
|
case Type::FLOAT:
|
||||||
return static_cast<float>(parseNumber(1).asNumber());
|
return static_cast<float>(parseNumber(1).asNumber());
|
||||||
case Type::VEC2:
|
case Type::VEC2:
|
||||||
@ -212,8 +223,22 @@ public:
|
|||||||
if (params.find(paramName) != params.end()) {
|
if (params.find(paramName) != params.end()) {
|
||||||
throw error("duplicating param " + util::quote(paramName));
|
throw error("duplicating param " + util::quote(paramName));
|
||||||
}
|
}
|
||||||
|
|
||||||
skipWhitespace(false);
|
skipWhitespace(false);
|
||||||
ss << "uniform " << typeName << " " << paramName << ";\n";
|
int start = pos;
|
||||||
|
|
||||||
|
ss << "uniform " << typeName << " " << paramName;
|
||||||
|
|
||||||
|
bool array = false;
|
||||||
|
if (peekNoJump() == '[') {
|
||||||
|
skip(1);
|
||||||
|
array = true;
|
||||||
|
readUntil(']');
|
||||||
|
skip(1);
|
||||||
|
ss << source.substr(start, pos - start + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ss << ";\n";
|
||||||
|
|
||||||
auto defValue = default_value_for(type);
|
auto defValue = default_value_for(type);
|
||||||
// Parse default value
|
// Parse default value
|
||||||
@ -225,7 +250,7 @@ public:
|
|||||||
|
|
||||||
skipLine();
|
skipLine();
|
||||||
|
|
||||||
params[paramName] = PostEffect::Param(type, std::move(defValue));
|
params[paramName] = PostEffect::Param(type, std::move(defValue), array);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,7 @@ public:
|
|||||||
|
|
||||||
void define(const std::string& name, std::string value);
|
void define(const std::string& name, std::string value);
|
||||||
void undefine(const std::string& name);
|
void undefine(const std::string& name);
|
||||||
|
void setDefined(const std::string& name, bool defined);
|
||||||
void addHeader(const std::string& name, ProcessingResult header);
|
void addHeader(const std::string& name, ProcessingResult header);
|
||||||
|
|
||||||
const ProcessingResult& getHeader(const std::string& name) const;
|
const ProcessingResult& getHeader(const std::string& name) const;
|
||||||
|
|||||||
@ -178,6 +178,8 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
|
|||||||
uicamera = std::make_unique<Camera>(glm::vec3(), 1);
|
uicamera = std::make_unique<Camera>(glm::vec3(), 1);
|
||||||
uicamera->perspective = false;
|
uicamera->perspective = false;
|
||||||
uicamera->flipped = true;
|
uicamera->flipped = true;
|
||||||
|
uicamera->near = -1.0f;
|
||||||
|
uicamera->far = 1.0f;
|
||||||
|
|
||||||
debugPanel = create_debug_panel(
|
debugPanel = create_debug_panel(
|
||||||
engine, frontend.getLevel(), player, allowDebugCheats
|
engine, frontend.getLevel(), player, allowDebugCheats
|
||||||
|
|||||||
@ -22,6 +22,8 @@ MenuScreen::MenuScreen(Engine& engine) : Screen(engine) {
|
|||||||
uicamera =
|
uicamera =
|
||||||
std::make_unique<Camera>(glm::vec3(), engine.getWindow().getSize().y);
|
std::make_unique<Camera>(glm::vec3(), engine.getWindow().getSize().y);
|
||||||
uicamera->perspective = false;
|
uicamera->perspective = false;
|
||||||
|
uicamera->near = -1.0f;
|
||||||
|
uicamera->far = 1.0f;
|
||||||
uicamera->flipped = true;
|
uicamera->flipped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -60,17 +60,17 @@ void Batch2D::vertex(
|
|||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch2D::texture(const Texture* new_texture){
|
void Batch2D::texture(const Texture* newTexture){
|
||||||
if (currentTexture == new_texture) {
|
if (currentTexture == newTexture) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
flush();
|
flush();
|
||||||
currentTexture = new_texture;
|
currentTexture = newTexture;
|
||||||
if (new_texture == nullptr) {
|
if (newTexture == nullptr) {
|
||||||
blank->bind();
|
blank->bind();
|
||||||
region = blank->getUVRegion();
|
region = blank->getUVRegion();
|
||||||
} else {
|
} else {
|
||||||
new_texture->bind();
|
newTexture->bind();
|
||||||
region = currentTexture->getUVRegion();
|
region = currentTexture->getUVRegion();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,8 +13,6 @@ namespace {
|
|||||||
|
|
||||||
Batch3D::Batch3D(size_t capacity)
|
Batch3D::Batch3D(size_t capacity)
|
||||||
: capacity(capacity) {
|
: capacity(capacity) {
|
||||||
|
|
||||||
|
|
||||||
buffer = std::make_unique<Batch3DVertex[]>(capacity);
|
buffer = std::make_unique<Batch3DVertex[]>(capacity);
|
||||||
mesh = std::make_unique<Mesh<Batch3DVertex>>(buffer.get(), 0);
|
mesh = std::make_unique<Mesh<Batch3DVertex>>(buffer.get(), 0);
|
||||||
index = 0;
|
index = 0;
|
||||||
|
|||||||
@ -100,7 +100,7 @@ void DrawContext::setViewport(const glm::uvec2& viewport) {
|
|||||||
glViewport(0, 0, viewport.x, viewport.y);
|
glViewport(0, 0, viewport.x, viewport.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawContext::setFramebuffer(Framebuffer* fbo) {
|
void DrawContext::setFramebuffer(Bindable* fbo) {
|
||||||
if (this->fbo == fbo)
|
if (this->fbo == fbo)
|
||||||
return;
|
return;
|
||||||
this->fbo = fbo;
|
this->fbo = fbo;
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class DrawContext {
|
|||||||
glm::uvec2 viewport;
|
glm::uvec2 viewport;
|
||||||
Batch2D* g2d;
|
Batch2D* g2d;
|
||||||
Flushable* flushable = nullptr;
|
Flushable* flushable = nullptr;
|
||||||
Framebuffer* fbo = nullptr;
|
Bindable* fbo = nullptr;
|
||||||
bool depthMask = true;
|
bool depthMask = true;
|
||||||
bool depthTest = false;
|
bool depthTest = false;
|
||||||
bool cullFace = false;
|
bool cullFace = false;
|
||||||
@ -37,7 +37,7 @@ public:
|
|||||||
[[nodiscard]] DrawContext sub(Flushable* flushable=nullptr) const;
|
[[nodiscard]] DrawContext sub(Flushable* flushable=nullptr) const;
|
||||||
|
|
||||||
void setViewport(const glm::uvec2& viewport);
|
void setViewport(const glm::uvec2& viewport);
|
||||||
void setFramebuffer(Framebuffer* fbo);
|
void setFramebuffer(Bindable* fbo);
|
||||||
void setDepthMask(bool flag);
|
void setDepthMask(bool flag);
|
||||||
void setDepthTest(bool flag);
|
void setDepthTest(bool flag);
|
||||||
void setCullFace(bool flag);
|
void setCullFace(bool flag);
|
||||||
|
|||||||
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include "Texture.hpp"
|
#include "Texture.hpp"
|
||||||
|
#include "debug/Logger.hpp"
|
||||||
|
|
||||||
|
static debug::Logger logger("gl-framebuffer");
|
||||||
|
|
||||||
Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture)
|
Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture)
|
||||||
: fbo(fbo), depth(depth), texture(std::move(texture))
|
: fbo(fbo), depth(depth), texture(std::move(texture))
|
||||||
@ -44,6 +47,11 @@ Framebuffer::Framebuffer(uint width, uint height, bool alpha)
|
|||||||
glBindRenderbuffer(GL_RENDERBUFFER, depth);
|
glBindRenderbuffer(GL_RENDERBUFFER, depth);
|
||||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
|
||||||
|
|
||||||
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
logger.error() << "framebuffer is not complete!";
|
||||||
|
}
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,11 +75,12 @@ void Framebuffer::resize(uint width, uint height) {
|
|||||||
this->width = width;
|
this->width = width;
|
||||||
this->height = height;
|
this->height = height;
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, depth);
|
glBindRenderbuffer(GL_RENDERBUFFER, depth);
|
||||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
|
||||||
texture = create_texture(width, height, format);
|
texture = create_texture(width, height, format);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
@ -87,3 +96,7 @@ uint Framebuffer::getWidth() const {
|
|||||||
uint Framebuffer::getHeight() const {
|
uint Framebuffer::getHeight() const {
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint Framebuffer::getFBO() const {
|
||||||
|
return fbo;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "typedefs.hpp"
|
#include "typedefs.hpp"
|
||||||
|
#include "commons.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
class Framebuffer {
|
class Framebuffer : public Bindable {
|
||||||
uint fbo;
|
uint fbo;
|
||||||
uint depth;
|
uint depth;
|
||||||
uint width;
|
uint width;
|
||||||
@ -19,10 +20,10 @@ public:
|
|||||||
~Framebuffer();
|
~Framebuffer();
|
||||||
|
|
||||||
/// @brief Use framebuffer
|
/// @brief Use framebuffer
|
||||||
void bind();
|
void bind() override;
|
||||||
|
|
||||||
/// @brief Stop using framebuffer
|
/// @brief Stop using framebuffer
|
||||||
void unbind();
|
void unbind() override;
|
||||||
|
|
||||||
/// @brief Update framebuffer texture size
|
/// @brief Update framebuffer texture size
|
||||||
/// @param width new width
|
/// @param width new width
|
||||||
@ -36,4 +37,6 @@ public:
|
|||||||
uint getWidth() const;
|
uint getWidth() const;
|
||||||
/// @brief Get framebuffer height
|
/// @brief Get framebuffer height
|
||||||
uint getHeight() const;
|
uint getHeight() const;
|
||||||
|
|
||||||
|
uint getFBO() const;
|
||||||
};
|
};
|
||||||
|
|||||||
273
src/graphics/core/GBuffer.cpp
Normal file
273
src/graphics/core/GBuffer.cpp
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
#include "GBuffer.hpp"
|
||||||
|
|
||||||
|
#include <GL/glew.h>
|
||||||
|
|
||||||
|
#include "debug/Logger.hpp"
|
||||||
|
|
||||||
|
using namespace advanced_pipeline;
|
||||||
|
|
||||||
|
static debug::Logger logger("gl-gbuffer");
|
||||||
|
|
||||||
|
// TODO: REFACTOR
|
||||||
|
|
||||||
|
void GBuffer::createColorBuffer() {
|
||||||
|
if (colorBuffer == 0)
|
||||||
|
glGenTextures(1, &colorBuffer);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, colorBuffer);
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_RGB,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
0,
|
||||||
|
GL_RGB,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glFramebufferTexture2D(
|
||||||
|
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBuffer::createPositionsBuffer() {
|
||||||
|
if (positionsBuffer == 0)
|
||||||
|
glGenTextures(1, &positionsBuffer);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, positionsBuffer);
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_RGBA16F,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
0,
|
||||||
|
GL_RGBA,
|
||||||
|
GL_FLOAT,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glFramebufferTexture2D(
|
||||||
|
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, positionsBuffer, 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBuffer::createNormalsBuffer() {
|
||||||
|
if (normalsBuffer == 0)
|
||||||
|
glGenTextures(1, &normalsBuffer);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, normalsBuffer);
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_RGBA16F,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
0,
|
||||||
|
GL_RGB,
|
||||||
|
GL_FLOAT,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glFramebufferTexture2D(
|
||||||
|
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, normalsBuffer, 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBuffer::createEmissionBuffer() {
|
||||||
|
if (emissionBuffer == 0)
|
||||||
|
glGenTextures(1, &emissionBuffer);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, emissionBuffer);
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_R8,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
0,
|
||||||
|
GL_RED,
|
||||||
|
GL_FLOAT,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glFramebufferTexture2D(
|
||||||
|
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, emissionBuffer, 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBuffer::createDepthBuffer() {
|
||||||
|
if (depthBuffer == 0)
|
||||||
|
glGenRenderbuffers(1, &depthBuffer);
|
||||||
|
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
|
||||||
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
||||||
|
glFramebufferRenderbuffer(
|
||||||
|
GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBuffer::createSSAOBuffer() {
|
||||||
|
if (ssaoBuffer == 0)
|
||||||
|
glGenTextures(1, &ssaoBuffer);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, ssaoBuffer);
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_R16F,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
0,
|
||||||
|
GL_RED,
|
||||||
|
GL_FLOAT,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
GBuffer::GBuffer(uint width, uint height) : width(width), height(height) {
|
||||||
|
glGenFramebuffers(1, &fbo);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
|
||||||
|
createColorBuffer();
|
||||||
|
createPositionsBuffer();
|
||||||
|
createNormalsBuffer();
|
||||||
|
createEmissionBuffer();
|
||||||
|
|
||||||
|
GLenum attachments[4] = {
|
||||||
|
GL_COLOR_ATTACHMENT0,
|
||||||
|
GL_COLOR_ATTACHMENT1,
|
||||||
|
GL_COLOR_ATTACHMENT2,
|
||||||
|
GL_COLOR_ATTACHMENT3,
|
||||||
|
};
|
||||||
|
glDrawBuffers(4, attachments);
|
||||||
|
|
||||||
|
createDepthBuffer();
|
||||||
|
|
||||||
|
int status;
|
||||||
|
if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
logger.error() << "gbuffer is not complete! (" << status << ")";
|
||||||
|
}
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
glGenFramebuffers(1, &ssaoFbo);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, ssaoFbo);
|
||||||
|
createSSAOBuffer();
|
||||||
|
glFramebufferTexture2D(
|
||||||
|
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ssaoBuffer, 0
|
||||||
|
);
|
||||||
|
GLenum ssaoAttachments[1] = {GL_COLOR_ATTACHMENT0};
|
||||||
|
glDrawBuffers(1, ssaoAttachments);
|
||||||
|
|
||||||
|
|
||||||
|
if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
logger.error() << "SSAO framebuffer is not complete! (" << status << ")";
|
||||||
|
}
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
GBuffer::~GBuffer() {
|
||||||
|
glDeleteTextures(1, &colorBuffer);
|
||||||
|
glDeleteTextures(1, &positionsBuffer);
|
||||||
|
glDeleteTextures(1, &normalsBuffer);
|
||||||
|
glDeleteTextures(1, &emissionBuffer);
|
||||||
|
glDeleteTextures(1, &ssaoBuffer);
|
||||||
|
glDeleteRenderbuffers(1, &depthBuffer);
|
||||||
|
glDeleteFramebuffers(1, &fbo);
|
||||||
|
glDeleteFramebuffers(1, &ssaoFbo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBuffer::bind() {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBuffer::bindSSAO() const {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, ssaoFbo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBuffer::unbind() {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBuffer::bindBuffers() const {
|
||||||
|
glActiveTexture(GL_TEXTURE0 + TARGET_EMISSION);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, emissionBuffer);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0 + TARGET_NORMALS);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, normalsBuffer);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0 + TARGET_POSITIONS);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, positionsBuffer);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0 + TARGET_COLOR);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, colorBuffer);
|
||||||
|
|
||||||
|
if (TARGET_COLOR != 0)
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBuffer::bindSSAOBuffer() const {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, ssaoBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBuffer::bindDepthBuffer(int drawFbo) {
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFbo);
|
||||||
|
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
|
||||||
|
GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBuffer::resize(uint width, uint height) {
|
||||||
|
if (this->width == width && this->height == height) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->width = width;
|
||||||
|
this->height = height;
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
|
||||||
|
createDepthBuffer();
|
||||||
|
createColorBuffer();
|
||||||
|
createPositionsBuffer();
|
||||||
|
createNormalsBuffer();
|
||||||
|
createEmissionBuffer();
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, ssaoFbo);
|
||||||
|
createSSAOBuffer();
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ImageData> GBuffer::toImage() const {
|
||||||
|
auto data = std::make_unique<ubyte[]>(width * height * 3);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, colorBuffer);
|
||||||
|
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, data.get());
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
return std::make_unique<ImageData>(
|
||||||
|
ImageFormat::rgb888, width, height, std::move(data)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint GBuffer::getWidth() const {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint GBuffer::getHeight() const {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
46
src/graphics/core/GBuffer.hpp
Normal file
46
src/graphics/core/GBuffer.hpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "typedefs.hpp"
|
||||||
|
#include "commons.hpp"
|
||||||
|
#include "ImageData.hpp"
|
||||||
|
|
||||||
|
class GBuffer : public Bindable {
|
||||||
|
public:
|
||||||
|
GBuffer(uint width, uint height);
|
||||||
|
~GBuffer() override;
|
||||||
|
|
||||||
|
void bind() override;
|
||||||
|
void bindSSAO() const;
|
||||||
|
void unbind() override;
|
||||||
|
|
||||||
|
void bindBuffers() const;
|
||||||
|
void bindSSAOBuffer() const;
|
||||||
|
|
||||||
|
void bindDepthBuffer(int drawFbo);
|
||||||
|
|
||||||
|
void resize(uint width, uint height);
|
||||||
|
|
||||||
|
uint getWidth() const;
|
||||||
|
uint getHeight() const;
|
||||||
|
|
||||||
|
std::unique_ptr<ImageData> toImage() const;
|
||||||
|
private:
|
||||||
|
uint width;
|
||||||
|
uint height;
|
||||||
|
|
||||||
|
uint fbo;
|
||||||
|
uint colorBuffer = 0;
|
||||||
|
uint positionsBuffer = 0;
|
||||||
|
uint normalsBuffer = 0;
|
||||||
|
uint emissionBuffer = 0;
|
||||||
|
uint depthBuffer = 0;
|
||||||
|
uint ssaoFbo = 0;
|
||||||
|
uint ssaoBuffer = 0;
|
||||||
|
|
||||||
|
void createColorBuffer();
|
||||||
|
void createPositionsBuffer();
|
||||||
|
void createNormalsBuffer();
|
||||||
|
void createEmissionBuffer();
|
||||||
|
void createDepthBuffer();
|
||||||
|
void createSSAOBuffer();
|
||||||
|
};
|
||||||
@ -2,18 +2,81 @@
|
|||||||
|
|
||||||
#include "Shader.hpp"
|
#include "Shader.hpp"
|
||||||
#include "data/dv_util.hpp"
|
#include "data/dv_util.hpp"
|
||||||
|
#include "debug/Logger.hpp"
|
||||||
|
|
||||||
|
static debug::Logger logger("post-effect");
|
||||||
|
|
||||||
PostEffect::Param::Param() : type(Type::FLOAT) {}
|
PostEffect::Param::Param() : type(Type::FLOAT) {}
|
||||||
|
|
||||||
PostEffect::Param::Param(Type type, Value defValue)
|
PostEffect::Param::Param(Type type, Value defValue, bool array)
|
||||||
: type(type), defValue(defValue), value(defValue) {
|
: type(type), defValue(defValue), value(defValue), array(array) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PostEffect::PostEffect(
|
PostEffect::PostEffect(
|
||||||
|
bool advanced,
|
||||||
std::shared_ptr<Shader> shader,
|
std::shared_ptr<Shader> shader,
|
||||||
std::unordered_map<std::string, Param> params
|
std::unordered_map<std::string, Param> params
|
||||||
)
|
)
|
||||||
: shader(std::move(shader)), params(std::move(params)) {
|
: advanced(advanced), shader(std::move(shader)), params(std::move(params)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apply_uniform_value(
|
||||||
|
const PostEffect::Param& param,
|
||||||
|
Shader& shader,
|
||||||
|
const std::string& name
|
||||||
|
) {
|
||||||
|
using Type = PostEffect::Param::Type;
|
||||||
|
switch (param.type) {
|
||||||
|
case Type::INT:
|
||||||
|
shader.uniform1i(name, std::get<int>(param.value));
|
||||||
|
break;
|
||||||
|
case Type::FLOAT:
|
||||||
|
shader.uniform1f(name, std::get<float>(param.value));
|
||||||
|
break;
|
||||||
|
case Type::VEC2:
|
||||||
|
shader.uniform2f(name, std::get<glm::vec2>(param.value));
|
||||||
|
break;
|
||||||
|
case Type::VEC3:
|
||||||
|
shader.uniform3f(name, std::get<glm::vec3>(param.value));
|
||||||
|
break;
|
||||||
|
case Type::VEC4:
|
||||||
|
shader.uniform4f(name, std::get<glm::vec4>(param.value));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apply_uniform_array(
|
||||||
|
const PostEffect::Param& param,
|
||||||
|
Shader& shader,
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<ubyte>& values
|
||||||
|
) {
|
||||||
|
size_t size = values.size();
|
||||||
|
auto ibuffer = reinterpret_cast<const int*>(values.data());
|
||||||
|
auto fbuffer = reinterpret_cast<const float*>(values.data());
|
||||||
|
|
||||||
|
using Type = PostEffect::Param::Type;
|
||||||
|
switch (param.type) {
|
||||||
|
case Type::INT:
|
||||||
|
shader.uniform1v(name, size / sizeof(int), ibuffer);
|
||||||
|
break;
|
||||||
|
case Type::FLOAT:
|
||||||
|
shader.uniform1v(name, size / sizeof(float), fbuffer);
|
||||||
|
break;
|
||||||
|
case Type::VEC2:
|
||||||
|
shader.uniform2v(name, size / sizeof(glm::vec2), fbuffer);
|
||||||
|
break;
|
||||||
|
case Type::VEC3:
|
||||||
|
shader.uniform3v(name, size / sizeof(glm::vec3), fbuffer);
|
||||||
|
break;
|
||||||
|
case Type::VEC4:
|
||||||
|
shader.uniform4v(name, size / sizeof(glm::vec4), fbuffer);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader& PostEffect::use() {
|
Shader& PostEffect::use() {
|
||||||
@ -23,27 +86,24 @@ Shader& PostEffect::use() {
|
|||||||
if (!param.dirty) {
|
if (!param.dirty) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (param.type) {
|
if (param.array) {
|
||||||
case Param::Type::FLOAT:
|
const auto& found = arrayValues.find(name);
|
||||||
shader->uniform1f(name, std::get<float>(param.value));
|
if (found == arrayValues.end()) {
|
||||||
break;
|
continue;
|
||||||
case Param::Type::VEC2:
|
}
|
||||||
shader->uniform2f(name, std::get<glm::vec2>(param.value));
|
apply_uniform_array(param, *shader, name, found->second);
|
||||||
break;
|
} else {
|
||||||
case Param::Type::VEC3:
|
apply_uniform_value(param, *shader, name);
|
||||||
shader->uniform3f(name, std::get<glm::vec3>(param.value));
|
|
||||||
break;
|
|
||||||
case Param::Type::VEC4:
|
|
||||||
shader->uniform4f(name, std::get<glm::vec4>(param.value));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
}
|
||||||
param.dirty = false;
|
param.dirty = false;
|
||||||
}
|
}
|
||||||
return *shader;
|
return *shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shader& PostEffect::getShader() {
|
||||||
|
return *shader;
|
||||||
|
}
|
||||||
|
|
||||||
float PostEffect::getIntensity() const {
|
float PostEffect::getIntensity() const {
|
||||||
return intensity;
|
return intensity;
|
||||||
}
|
}
|
||||||
@ -66,6 +126,9 @@ void PostEffect::setParam(const std::string& name, const dv::value& value) {
|
|||||||
}
|
}
|
||||||
auto& param = found->second;
|
auto& param = found->second;
|
||||||
switch (param.type) {
|
switch (param.type) {
|
||||||
|
case Param::Type::INT:
|
||||||
|
param.value = static_cast<int>(value.asInteger());
|
||||||
|
break;
|
||||||
case Param::Type::FLOAT:
|
case Param::Type::FLOAT:
|
||||||
param.value = static_cast<float>(value.asNumber());
|
param.value = static_cast<float>(value.asNumber());
|
||||||
break;
|
break;
|
||||||
@ -81,3 +144,20 @@ void PostEffect::setParam(const std::string& name, const dv::value& value) {
|
|||||||
}
|
}
|
||||||
param.dirty = true;
|
param.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PostEffect::setArray(const std::string& name, std::vector<ubyte>&& values) {
|
||||||
|
const auto& found = params.find(name);
|
||||||
|
if (found == params.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto& param = found->second;
|
||||||
|
if (!param.array) {
|
||||||
|
logger.warning() << "set_array is used on non-array effect parameter";
|
||||||
|
if (!values.empty()) {
|
||||||
|
setParam(name, values[0]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
param.dirty = true;
|
||||||
|
arrayValues[name] = std::move(values);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include "typedefs.hpp"
|
||||||
#include "data/dv_fwd.hpp"
|
#include "data/dv_fwd.hpp"
|
||||||
#include "util/EnumMetadata.hpp"
|
#include "util/EnumMetadata.hpp"
|
||||||
|
|
||||||
@ -14,27 +16,30 @@ class Shader;
|
|||||||
class PostEffect {
|
class PostEffect {
|
||||||
public:
|
public:
|
||||||
struct Param {
|
struct Param {
|
||||||
enum class Type { FLOAT, VEC2, VEC3, VEC4 };
|
enum class Type { INT, FLOAT, VEC2, VEC3, VEC4 };
|
||||||
|
|
||||||
VC_ENUM_METADATA(Type)
|
VC_ENUM_METADATA(Type)
|
||||||
|
{"int", Type::INT},
|
||||||
{"float", Type::FLOAT},
|
{"float", Type::FLOAT},
|
||||||
{"vec2", Type::VEC2},
|
{"vec2", Type::VEC2},
|
||||||
{"vec3", Type::VEC3},
|
{"vec3", Type::VEC3},
|
||||||
{"vec4", Type::VEC4},
|
{"vec4", Type::VEC4},
|
||||||
VC_ENUM_END
|
VC_ENUM_END
|
||||||
|
|
||||||
using Value = std::variant<float, glm::vec2, glm::vec3, glm::vec4>;
|
using Value = std::variant<int, float, glm::vec2, glm::vec3, glm::vec4>;
|
||||||
|
|
||||||
Type type;
|
Type type;
|
||||||
Value defValue;
|
Value defValue;
|
||||||
Value value;
|
Value value;
|
||||||
|
bool array = false;
|
||||||
bool dirty = true;
|
bool dirty = true;
|
||||||
|
|
||||||
Param();
|
Param();
|
||||||
Param(Type type, Value defValue);
|
Param(Type type, Value defValue, bool array);
|
||||||
};
|
};
|
||||||
|
|
||||||
PostEffect(
|
PostEffect(
|
||||||
|
bool advanced,
|
||||||
std::shared_ptr<Shader> shader,
|
std::shared_ptr<Shader> shader,
|
||||||
std::unordered_map<std::string, Param> params
|
std::unordered_map<std::string, Param> params
|
||||||
);
|
);
|
||||||
@ -43,16 +48,26 @@ public:
|
|||||||
|
|
||||||
Shader& use();
|
Shader& use();
|
||||||
|
|
||||||
|
Shader& getShader();
|
||||||
|
|
||||||
float getIntensity() const;
|
float getIntensity() const;
|
||||||
void setIntensity(float value);
|
void setIntensity(float value);
|
||||||
|
|
||||||
void setParam(const std::string& name, const dv::value& value);
|
void setParam(const std::string& name, const dv::value& value);
|
||||||
|
|
||||||
|
void setArray(const std::string& name, std::vector<ubyte>&& values);
|
||||||
|
|
||||||
|
bool isAdvanced() const {
|
||||||
|
return advanced;
|
||||||
|
}
|
||||||
|
|
||||||
bool isActive() {
|
bool isActive() {
|
||||||
return intensity > 1e-4f;
|
return intensity > 1e-4f;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
bool advanced = false;
|
||||||
std::shared_ptr<Shader> shader;
|
std::shared_ptr<Shader> shader;
|
||||||
std::unordered_map<std::string, Param> params;
|
std::unordered_map<std::string, Param> params;
|
||||||
|
std::unordered_map<std::string, std::vector<ubyte>> arrayValues;
|
||||||
float intensity = 0.0f;
|
float intensity = 0.0f;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,18 +1,25 @@
|
|||||||
#include "PostProcessing.hpp"
|
#include "PostProcessing.hpp"
|
||||||
#include "Mesh.hpp"
|
#include "Mesh.hpp"
|
||||||
#include "Shader.hpp"
|
#include "Shader.hpp"
|
||||||
|
#include "GBuffer.hpp"
|
||||||
#include "Texture.hpp"
|
#include "Texture.hpp"
|
||||||
#include "Framebuffer.hpp"
|
#include "Framebuffer.hpp"
|
||||||
#include "DrawContext.hpp"
|
#include "DrawContext.hpp"
|
||||||
#include "PostEffect.hpp"
|
#include "PostEffect.hpp"
|
||||||
#include "assets/Assets.hpp"
|
#include "assets/Assets.hpp"
|
||||||
|
#include "window/Camera.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
// TODO: REFACTOR WHOLE RENDER ENGINE
|
||||||
|
|
||||||
|
using namespace advanced_pipeline;
|
||||||
|
|
||||||
PostProcessing::PostProcessing(size_t effectSlotsCount)
|
PostProcessing::PostProcessing(size_t effectSlotsCount)
|
||||||
: effectSlots(effectSlotsCount) {
|
: effectSlots(effectSlotsCount) {
|
||||||
// Fullscreen quad mesh bulding
|
// Fullscreen quad mesh bulding
|
||||||
PostProcessingVertex meshData[]{
|
PostProcessingVertex meshData[] {
|
||||||
{{-1.0f, -1.0f}},
|
{{-1.0f, -1.0f}},
|
||||||
{{-1.0f, 1.0f}},
|
{{-1.0f, 1.0f}},
|
||||||
{{1.0f, 1.0f}},
|
{{1.0f, 1.0f}},
|
||||||
@ -22,37 +29,172 @@ PostProcessing::PostProcessing(size_t effectSlotsCount)
|
|||||||
};
|
};
|
||||||
|
|
||||||
quadMesh = std::make_unique<Mesh<PostProcessingVertex>>(meshData, 6);
|
quadMesh = std::make_unique<Mesh<PostProcessingVertex>>(meshData, 6);
|
||||||
|
|
||||||
|
std::vector<glm::vec3> ssaoNoise;
|
||||||
|
for (unsigned int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
glm::vec3 noise(
|
||||||
|
(rand() / static_cast<float>(RAND_MAX)) * 2.0 - 1.0,
|
||||||
|
(rand() / static_cast<float>(RAND_MAX)) * 2.0 - 1.0,
|
||||||
|
0.0f);
|
||||||
|
ssaoNoise.push_back(noise);
|
||||||
|
}
|
||||||
|
glGenTextures(1, &noiseTexture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, noiseTexture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, 4, 4, 0, GL_RGB, GL_FLOAT, ssaoNoise.data());
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
PostProcessing::~PostProcessing() = default;
|
PostProcessing::~PostProcessing() = default;
|
||||||
|
|
||||||
void PostProcessing::use(DrawContext& context) {
|
void PostProcessing::use(DrawContext& context, bool gbufferPipeline) {
|
||||||
const auto& vp = context.getViewport();
|
const auto& vp = context.getViewport();
|
||||||
if (fbo) {
|
|
||||||
fbo->resize(vp.x, vp.y);
|
if (gbufferPipeline) {
|
||||||
fboSecond->resize(vp.x, vp.y);
|
if (gbuffer == nullptr) {
|
||||||
|
gbuffer = std::make_unique<GBuffer>(vp.x, vp.y);
|
||||||
} else {
|
} else {
|
||||||
fbo = std::make_unique<Framebuffer>(vp.x, vp.y);
|
gbuffer->resize(vp.x, vp.y);
|
||||||
fboSecond = std::make_unique<Framebuffer>(vp.x, vp.y);
|
|
||||||
}
|
}
|
||||||
|
context.setFramebuffer(gbuffer.get());
|
||||||
|
} else {
|
||||||
|
gbuffer.reset();
|
||||||
|
refreshFbos(vp.x, vp.y);
|
||||||
context.setFramebuffer(fbo.get());
|
context.setFramebuffer(fbo.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessing::refreshFbos(uint width, uint height) {
|
||||||
|
if (fbo) {
|
||||||
|
fbo->resize(width, height);
|
||||||
|
fboSecond->resize(width, height);
|
||||||
|
} else {
|
||||||
|
fbo = std::make_unique<Framebuffer>(width, height);
|
||||||
|
fboSecond = std::make_unique<Framebuffer>(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessing::bindDepthBuffer() {
|
||||||
|
if (gbuffer) {
|
||||||
|
gbuffer->bindDepthBuffer(fbo->getFBO());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessing::configureEffect(
|
||||||
|
const DrawContext& context,
|
||||||
|
PostEffect& effect,
|
||||||
|
Shader& shader,
|
||||||
|
float timer,
|
||||||
|
const Camera& camera
|
||||||
|
) {
|
||||||
|
const auto& viewport = context.getViewport();
|
||||||
|
shader.uniform1i("u_screen", TARGET_COLOR);
|
||||||
|
shader.uniform1i("u_skybox", TARGET_SKYBOX);
|
||||||
|
if (gbuffer) {
|
||||||
|
shader.uniform1i("u_position", TARGET_POSITIONS);
|
||||||
|
shader.uniform1i("u_normal", TARGET_NORMALS);
|
||||||
|
shader.uniform1i("u_emission", TARGET_EMISSION);
|
||||||
|
}
|
||||||
|
shader.uniform1i("u_noise", TARGET_SSAO); // used in SSAO pass
|
||||||
|
shader.uniform1i("u_ssao", TARGET_SSAO);
|
||||||
|
shader.uniform2i("u_screenSize", viewport);
|
||||||
|
shader.uniform3f("u_cameraPos", camera.position);
|
||||||
|
shader.uniform1f("u_timer", timer);
|
||||||
|
shader.uniformMatrix("u_projection", camera.getProjection());
|
||||||
|
shader.uniformMatrix("u_view", camera.getView());
|
||||||
|
shader.uniformMatrix("u_inverseView", glm::inverse(camera.getView()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessing::renderDeferredShading(
|
||||||
|
const DrawContext& context,
|
||||||
|
const Assets& assets,
|
||||||
|
float timer,
|
||||||
|
const Camera& camera
|
||||||
|
) {
|
||||||
|
if (gbuffer == nullptr) {
|
||||||
|
throw std::runtime_error("gbuffer is not initialized");
|
||||||
|
}
|
||||||
|
// Generating ssao
|
||||||
|
gbuffer->bindBuffers();
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0 + TARGET_SSAO);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, noiseTexture);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
auto& ssaoEffect = assets.require<PostEffect>("ssao");
|
||||||
|
auto& shader = ssaoEffect.use();
|
||||||
|
configureEffect(
|
||||||
|
context,
|
||||||
|
ssaoEffect,
|
||||||
|
shader,
|
||||||
|
timer,
|
||||||
|
camera
|
||||||
|
);
|
||||||
|
gbuffer->bindSSAO();
|
||||||
|
quadMesh->draw();
|
||||||
|
gbuffer->unbind();
|
||||||
|
|
||||||
|
{
|
||||||
|
auto viewport = context.getViewport();
|
||||||
|
refreshFbos(viewport.x, viewport.y);
|
||||||
|
|
||||||
|
auto ctx = context.sub();
|
||||||
|
ctx.setFramebuffer(fbo.get());
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0 + TARGET_SSAO);
|
||||||
|
gbuffer->bindSSAOBuffer();
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
gbuffer->bindBuffers();
|
||||||
|
|
||||||
|
auto& effect = assets.require<PostEffect>("deferred_lighting");
|
||||||
|
auto& shader = effect.use();
|
||||||
|
configureEffect(
|
||||||
|
context,
|
||||||
|
effect,
|
||||||
|
shader,
|
||||||
|
timer,
|
||||||
|
camera
|
||||||
|
);
|
||||||
|
quadMesh->draw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostProcessing::render(
|
void PostProcessing::render(
|
||||||
const DrawContext& context, const Assets& assets, float timer
|
const DrawContext& context,
|
||||||
|
const Assets& assets,
|
||||||
|
float timer,
|
||||||
|
const Camera& camera
|
||||||
) {
|
) {
|
||||||
if (fbo == nullptr) {
|
if (fbo == nullptr) {
|
||||||
throw std::runtime_error("'use(...)' was never called");
|
throw std::runtime_error("'use(...)' was never called");
|
||||||
}
|
}
|
||||||
int totalPasses = 0;
|
int totalPasses = 0;
|
||||||
for (const auto& effect : effectSlots) {
|
for (const auto& effect : effectSlots) {
|
||||||
totalPasses += (effect != nullptr && effect->isActive());
|
totalPasses +=
|
||||||
|
(effect != nullptr && effect->isActive() &&
|
||||||
|
!(effect->isAdvanced() && gbuffer == nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalPasses == 0) {
|
const auto& vp = context.getViewport();
|
||||||
auto& effect = assets.require<PostEffect>("default");
|
refreshFbos(vp.x, vp.y);
|
||||||
effect.use();
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
fbo->getTexture()->bind();
|
fbo->getTexture()->bind();
|
||||||
|
|
||||||
|
if (totalPasses == 0) {
|
||||||
|
// replace 'default' blit shader with glBlitFramebuffer?
|
||||||
|
auto& effect = assets.require<PostEffect>("default");
|
||||||
|
auto& shader = effect.use();
|
||||||
|
configureEffect(
|
||||||
|
context, effect, shader, timer, camera
|
||||||
|
);
|
||||||
quadMesh->draw();
|
quadMesh->draw();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -62,17 +204,26 @@ void PostProcessing::render(
|
|||||||
if (effect == nullptr || !effect->isActive()) {
|
if (effect == nullptr || !effect->isActive()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (effect->isAdvanced() && gbuffer == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
auto& shader = effect->use();
|
auto& shader = effect->use();
|
||||||
|
configureEffect(
|
||||||
|
context,
|
||||||
|
*effect,
|
||||||
|
shader,
|
||||||
|
timer,
|
||||||
|
camera
|
||||||
|
);
|
||||||
|
|
||||||
const auto& viewport = context.getViewport();
|
if (currentPass > 1) {
|
||||||
shader.uniform1i("u_screen", 0);
|
|
||||||
shader.uniform2i("u_screenSize", viewport);
|
|
||||||
shader.uniform1f("u_timer", timer);
|
|
||||||
|
|
||||||
fbo->getTexture()->bind();
|
fbo->getTexture()->bind();
|
||||||
|
}
|
||||||
|
|
||||||
if (currentPass < totalPasses) {
|
if (currentPass < totalPasses) {
|
||||||
fboSecond->bind();
|
fboSecond->bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
quadMesh->draw();
|
quadMesh->draw();
|
||||||
if (currentPass < totalPasses) {
|
if (currentPass < totalPasses) {
|
||||||
fboSecond->unbind();
|
fboSecond->unbind();
|
||||||
|
|||||||
@ -11,6 +11,9 @@ class Framebuffer;
|
|||||||
class DrawContext;
|
class DrawContext;
|
||||||
class ImageData;
|
class ImageData;
|
||||||
class PostEffect;
|
class PostEffect;
|
||||||
|
class Camera;
|
||||||
|
class GBuffer;
|
||||||
|
class Shader;
|
||||||
|
|
||||||
struct PostProcessingVertex {
|
struct PostProcessingVertex {
|
||||||
glm::vec2 position;
|
glm::vec2 position;
|
||||||
@ -24,25 +27,31 @@ struct PostProcessingVertex {
|
|||||||
/// @attention Current implementation does not support multiple render passes
|
/// @attention Current implementation does not support multiple render passes
|
||||||
/// for multiple effects. Will be implemented in v0.21
|
/// for multiple effects. Will be implemented in v0.21
|
||||||
class PostProcessing {
|
class PostProcessing {
|
||||||
/// @brief Main framebuffer (lasy field)
|
|
||||||
std::unique_ptr<Framebuffer> fbo;
|
|
||||||
std::unique_ptr<Framebuffer> fboSecond;
|
|
||||||
/// @brief Fullscreen quad mesh as the post-processing canvas
|
|
||||||
std::unique_ptr<Mesh<PostProcessingVertex>> quadMesh;
|
|
||||||
std::vector<std::shared_ptr<PostEffect>> effectSlots;
|
|
||||||
public:
|
public:
|
||||||
PostProcessing(size_t effectSlotsCount);
|
PostProcessing(size_t effectSlotsCount);
|
||||||
~PostProcessing();
|
~PostProcessing();
|
||||||
|
|
||||||
/// @brief Prepare and bind framebuffer
|
/// @brief Prepare and bind framebuffer
|
||||||
/// @param context graphics context will be modified
|
/// @param context graphics context will be modified
|
||||||
void use(DrawContext& context);
|
void use(DrawContext& context, bool gbufferPipeline);
|
||||||
|
|
||||||
|
void renderDeferredShading(
|
||||||
|
const DrawContext& context,
|
||||||
|
const Assets& assets,
|
||||||
|
float timer,
|
||||||
|
const Camera& camera
|
||||||
|
);
|
||||||
|
|
||||||
/// @brief Render fullscreen quad using the passed shader
|
/// @brief Render fullscreen quad using the passed shader
|
||||||
/// with framebuffer texture bound
|
/// with framebuffer texture bound
|
||||||
/// @param context graphics context
|
/// @param context graphics context
|
||||||
/// @throws std::runtime_error if use(...) wasn't called before
|
/// @throws std::runtime_error if use(...) wasn't called before
|
||||||
void render(const DrawContext& context, const Assets& assets, float timer);
|
void render(
|
||||||
|
const DrawContext& context,
|
||||||
|
const Assets& assets,
|
||||||
|
float timer,
|
||||||
|
const Camera& camera
|
||||||
|
);
|
||||||
|
|
||||||
void setEffect(size_t slot, std::shared_ptr<PostEffect> effect);
|
void setEffect(size_t slot, std::shared_ptr<PostEffect> effect);
|
||||||
|
|
||||||
@ -52,4 +61,24 @@ public:
|
|||||||
std::unique_ptr<ImageData> toImage();
|
std::unique_ptr<ImageData> toImage();
|
||||||
|
|
||||||
Framebuffer* getFramebuffer() const;
|
Framebuffer* getFramebuffer() const;
|
||||||
|
void bindDepthBuffer();
|
||||||
|
private:
|
||||||
|
void configureEffect(
|
||||||
|
const DrawContext& context,
|
||||||
|
PostEffect& effect,
|
||||||
|
Shader& shader,
|
||||||
|
float timer,
|
||||||
|
const Camera& camera
|
||||||
|
);
|
||||||
|
|
||||||
|
void refreshFbos(uint width, uint height);
|
||||||
|
|
||||||
|
/// @brief Main framebuffer (lasy field)
|
||||||
|
std::unique_ptr<Framebuffer> fbo;
|
||||||
|
std::unique_ptr<Framebuffer> fboSecond;
|
||||||
|
/// @brief Fullscreen quad mesh as the post-processing canvas
|
||||||
|
std::unique_ptr<Mesh<PostProcessingVertex>> quadMesh;
|
||||||
|
std::vector<std::shared_ptr<PostEffect>> effectSlots;
|
||||||
|
std::unique_ptr<GBuffer> gbuffer;
|
||||||
|
uint noiseTexture;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,20 +12,25 @@
|
|||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
#include "coders/GLSLExtension.hpp"
|
#include "coders/GLSLExtension.hpp"
|
||||||
|
#include "debug/Logger.hpp"
|
||||||
|
|
||||||
|
static debug::Logger logger("gl-shader");
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
GLSLExtension* Shader::preprocessor = new GLSLExtension();
|
GLSLExtension* Shader::preprocessor = new GLSLExtension();
|
||||||
Shader* Shader::used = nullptr;
|
Shader* Shader::used = nullptr;
|
||||||
|
|
||||||
Shader::Shader(uint id) : id(id){
|
Shader::Shader(uint id, Source&& vertexSource, Source&& fragmentSource)
|
||||||
}
|
: id(id),
|
||||||
|
vertexSource(std::move(vertexSource)),
|
||||||
|
fragmentSource(std::move(fragmentSource)) {}
|
||||||
|
|
||||||
Shader::~Shader(){
|
Shader::~Shader() {
|
||||||
glDeleteProgram(id);
|
glDeleteProgram(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::use(){
|
void Shader::use() {
|
||||||
used = this;
|
used = this;
|
||||||
glUseProgram(id);
|
glUseProgram(id);
|
||||||
}
|
}
|
||||||
@ -40,8 +45,16 @@ uint Shader::getUniformLocation(const std::string& name) {
|
|||||||
return found->second;
|
return found->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::uniformMatrix(const std::string& name, const glm::mat4& matrix){
|
void Shader::uniformMatrix(const std::string& name, const glm::mat4& matrix) {
|
||||||
glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, glm::value_ptr(matrix));
|
glUniformMatrix4fv(
|
||||||
|
getUniformLocation(name), 1, GL_FALSE, glm::value_ptr(matrix)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::uniformMatrix(const std::string& name, const glm::mat3& matrix) {
|
||||||
|
glUniformMatrix3fv(
|
||||||
|
getUniformLocation(name), 1, GL_FALSE, glm::value_ptr(matrix)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::uniform1i(const std::string& name, int x){
|
void Shader::uniform1i(const std::string& name, int x){
|
||||||
@ -76,8 +89,27 @@ void Shader::uniform4f(const std::string& name, const glm::vec4& xyzw) {
|
|||||||
glUniform4f(getUniformLocation(name), xyzw.x, xyzw.y, xyzw.z, xyzw.w);
|
glUniform4f(getUniformLocation(name), xyzw.x, xyzw.y, xyzw.z, xyzw.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Shader::uniform1v(const std::string& name, int length, const int* v) {
|
||||||
|
glUniform1iv(getUniformLocation(name), length, v);
|
||||||
|
}
|
||||||
|
|
||||||
inline auto shader_deleter = [](GLuint* shader) {
|
void Shader::uniform1v(const std::string& name, int length, const float* v) {
|
||||||
|
glUniform1fv(getUniformLocation(name), length, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::uniform2v(const std::string& name, int length, const float* v) {
|
||||||
|
glUniform2fv(getUniformLocation(name), length, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::uniform3v(const std::string& name, int length, const float* v) {
|
||||||
|
glUniform3fv(getUniformLocation(name), length, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::uniform4v(const std::string& name, int length, const float* v) {
|
||||||
|
glUniform4fv(getUniformLocation(name), length, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline auto shader_deleter = [](GLuint* shader) {
|
||||||
glDeleteShader(*shader);
|
glDeleteShader(*shader);
|
||||||
delete shader;
|
delete shader;
|
||||||
};
|
};
|
||||||
@ -93,45 +125,73 @@ glshader compile_shader(GLenum type, const GLchar* source, const std::string& fi
|
|||||||
glShaderSource(shader, 1, &source, nullptr);
|
glShaderSource(shader, 1, &source, nullptr);
|
||||||
glCompileShader(shader);
|
glCompileShader(shader);
|
||||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||||
if (!success){
|
if (!success) {
|
||||||
GLchar infoLog[GL_LOG_LEN];
|
GLchar infoLog[GL_LOG_LEN];
|
||||||
glGetShaderInfoLog(shader, GL_LOG_LEN, nullptr, infoLog);
|
glGetShaderInfoLog(shader, GL_LOG_LEN, nullptr, infoLog);
|
||||||
glDeleteShader(shader);
|
glDeleteShader(shader);
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"vertex shader compilation failed ("+file+"):\n"+std::string(infoLog)
|
"vertex shader compilation failed (" + file + "):\n" +
|
||||||
|
std::string(infoLog)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return glshader(new GLuint(shader), shader_deleter); //-V508
|
return glshader(new GLuint(shader), shader_deleter); //-V508
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Shader> Shader::create(
|
static GLuint compile_program(
|
||||||
const std::string& vertexFile,
|
const Shader::Source& vertexSource, const Shader::Source& fragmentSource
|
||||||
const std::string& fragmentFile,
|
|
||||||
const std::string& vertexCode,
|
|
||||||
const std::string& fragmentCode
|
|
||||||
) {
|
) {
|
||||||
|
auto& preprocessor = *Shader::preprocessor;
|
||||||
|
|
||||||
|
auto vertexCode = std::move(
|
||||||
|
preprocessor.process(vertexSource.file, vertexSource.code).code
|
||||||
|
);
|
||||||
|
auto fragmentCode = std::move(
|
||||||
|
preprocessor.process(fragmentSource.file, fragmentSource.code).code
|
||||||
|
);
|
||||||
|
|
||||||
const GLchar* vCode = vertexCode.c_str();
|
const GLchar* vCode = vertexCode.c_str();
|
||||||
const GLchar* fCode = fragmentCode.c_str();
|
const GLchar* fCode = fragmentCode.c_str();
|
||||||
|
|
||||||
glshader vertex = compile_shader(GL_VERTEX_SHADER, vCode, vertexFile);
|
glshader vertex =
|
||||||
glshader fragment = compile_shader(GL_FRAGMENT_SHADER, fCode, fragmentFile);
|
compile_shader(GL_VERTEX_SHADER, vCode, vertexSource.file);
|
||||||
|
glshader fragment =
|
||||||
|
compile_shader(GL_FRAGMENT_SHADER, fCode, fragmentSource.file);
|
||||||
|
|
||||||
// Shader Program
|
// Shader Program
|
||||||
GLint success;
|
GLint success;
|
||||||
GLuint id = glCreateProgram();
|
GLuint program = glCreateProgram();
|
||||||
glAttachShader(id, *vertex);
|
glAttachShader(program, *vertex);
|
||||||
glAttachShader(id, *fragment);
|
glAttachShader(program, *fragment);
|
||||||
glLinkProgram(id);
|
glLinkProgram(program);
|
||||||
|
|
||||||
glGetProgramiv(id, GL_LINK_STATUS, &success);
|
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
||||||
if (!success){
|
|
||||||
|
if (!success) {
|
||||||
GLchar infoLog[GL_LOG_LEN];
|
GLchar infoLog[GL_LOG_LEN];
|
||||||
glGetProgramInfoLog(id, GL_LOG_LEN, nullptr, infoLog);
|
glGetProgramInfoLog(program, GL_LOG_LEN, nullptr, infoLog);
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"shader program linking failed:\n"+std::string(infoLog)
|
"shader program linking failed:\n" + std::string(infoLog)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return std::make_unique<Shader>(id);
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::recompile() {
|
||||||
|
GLuint newProgram = compile_program(vertexSource, fragmentSource);
|
||||||
|
glDeleteProgram(id);
|
||||||
|
id = newProgram;
|
||||||
|
uniformLocations.clear();
|
||||||
|
logger.info() << "shader " << id << " has been recompiled";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Shader> Shader::create(
|
||||||
|
Source&& vertexSource, Source&& fragmentSource
|
||||||
|
) {
|
||||||
|
return std::make_unique<Shader>(
|
||||||
|
compile_program(vertexSource, fragmentSource),
|
||||||
|
std::move(vertexSource),
|
||||||
|
std::move(fragmentSource)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader& Shader::getUsed() {
|
Shader& Shader::getUsed() {
|
||||||
|
|||||||
@ -10,19 +10,30 @@
|
|||||||
class GLSLExtension;
|
class GLSLExtension;
|
||||||
|
|
||||||
class Shader {
|
class Shader {
|
||||||
|
public:
|
||||||
|
struct Source {
|
||||||
|
std::string file;
|
||||||
|
std::string code;
|
||||||
|
};
|
||||||
|
private:
|
||||||
static Shader* used;
|
static Shader* used;
|
||||||
uint id;
|
uint id;
|
||||||
std::unordered_map<std::string, uint> uniformLocations;
|
std::unordered_map<std::string, uint> uniformLocations;
|
||||||
|
|
||||||
|
// source code used for re-compiling shaders after updating defines
|
||||||
|
Source vertexSource;
|
||||||
|
Source fragmentSource;
|
||||||
|
|
||||||
uint getUniformLocation(const std::string& name);
|
uint getUniformLocation(const std::string& name);
|
||||||
public:
|
public:
|
||||||
static GLSLExtension* preprocessor;
|
static GLSLExtension* preprocessor;
|
||||||
|
|
||||||
Shader(uint id);
|
Shader(uint id, Source&& vertexSource, Source&& fragmentSource);
|
||||||
~Shader();
|
~Shader();
|
||||||
|
|
||||||
void use();
|
void use();
|
||||||
void uniformMatrix(const std::string&, const glm::mat4& matrix);
|
void uniformMatrix(const std::string&, const glm::mat4& matrix);
|
||||||
|
void uniformMatrix(const std::string&, const glm::mat3& matrix);
|
||||||
void uniform1i(const std::string& name, int x);
|
void uniform1i(const std::string& name, int x);
|
||||||
void uniform1f(const std::string& name, float x);
|
void uniform1f(const std::string& name, float x);
|
||||||
void uniform2f(const std::string& name, float x, float y);
|
void uniform2f(const std::string& name, float x, float y);
|
||||||
@ -32,17 +43,19 @@ public:
|
|||||||
void uniform3f(const std::string& name, const glm::vec3& xyz);
|
void uniform3f(const std::string& name, const glm::vec3& xyz);
|
||||||
void uniform4f(const std::string& name, const glm::vec4& xyzw);
|
void uniform4f(const std::string& name, const glm::vec4& xyzw);
|
||||||
|
|
||||||
|
void uniform1v(const std::string& name, int length, const int* v);
|
||||||
|
void uniform1v(const std::string& name, int length, const float* v);
|
||||||
|
void uniform2v(const std::string& name, int length, const float* v);
|
||||||
|
void uniform3v(const std::string& name, int length, const float* v);
|
||||||
|
void uniform4v(const std::string& name, int length, const float* v);
|
||||||
|
|
||||||
|
/// @brief Re-preprocess source code and re-compile shader program
|
||||||
|
void recompile();
|
||||||
|
|
||||||
/// @brief Create shader program using vertex and fragment shaders source.
|
/// @brief Create shader program using vertex and fragment shaders source.
|
||||||
/// @param vertexFile vertex shader file name
|
|
||||||
/// @param fragmentFile fragment shader file name
|
|
||||||
/// @param vertexSource vertex shader source code
|
|
||||||
/// @param fragmentSource fragment shader source code
|
|
||||||
/// @return linked shader program containing vertex and fragment shaders
|
/// @return linked shader program containing vertex and fragment shaders
|
||||||
static std::unique_ptr<Shader> create(
|
static std::unique_ptr<Shader> create(
|
||||||
const std::string& vertexFile,
|
Source&& vertexSource, Source&& fragmentSource
|
||||||
const std::string& fragmentFile,
|
|
||||||
const std::string& vertexSource,
|
|
||||||
const std::string& fragmentSource
|
|
||||||
);
|
);
|
||||||
|
|
||||||
static Shader& getUsed();
|
static Shader& getUsed();
|
||||||
|
|||||||
47
src/graphics/core/ShadowMap.cpp
Normal file
47
src/graphics/core/ShadowMap.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "ShadowMap.hpp"
|
||||||
|
|
||||||
|
#include <GL/glew.h>
|
||||||
|
|
||||||
|
ShadowMap::ShadowMap(int resolution) : resolution(resolution) {
|
||||||
|
glGenTextures(1, &depthMap);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, depthMap);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
|
||||||
|
resolution, resolution, 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);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
|
||||||
|
float border[4] {1.0f, 1.0f, 1.0f, 1.0f};
|
||||||
|
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_BORDER_COLOR, border);
|
||||||
|
|
||||||
|
glGenFramebuffers(1, &fbo);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0);
|
||||||
|
glDrawBuffer(GL_NONE);
|
||||||
|
glReadBuffer(GL_NONE);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShadowMap::~ShadowMap() {
|
||||||
|
glDeleteFramebuffers(1, &fbo);
|
||||||
|
glDeleteTextures(1, &depthMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowMap::bind() {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowMap::unbind() {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint ShadowMap::getDepthMap() const {
|
||||||
|
return depthMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ShadowMap::getResolution() const {
|
||||||
|
return resolution;
|
||||||
|
}
|
||||||
18
src/graphics/core/ShadowMap.hpp
Normal file
18
src/graphics/core/ShadowMap.hpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "typedefs.hpp"
|
||||||
|
|
||||||
|
class ShadowMap {
|
||||||
|
public:
|
||||||
|
ShadowMap(int resolution);
|
||||||
|
~ShadowMap();
|
||||||
|
|
||||||
|
void bind();
|
||||||
|
void unbind();
|
||||||
|
uint getDepthMap() const;
|
||||||
|
int getResolution() const;
|
||||||
|
private:
|
||||||
|
uint fbo;
|
||||||
|
uint depthMap;
|
||||||
|
int resolution;
|
||||||
|
};
|
||||||
@ -50,6 +50,17 @@ enum class CursorShape {
|
|||||||
LAST=NOT_ALLOWED
|
LAST=NOT_ALLOWED
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace advanced_pipeline {
|
||||||
|
inline constexpr int TARGET_COLOR = 0;
|
||||||
|
inline constexpr int TARGET_SKYBOX = 1;
|
||||||
|
inline constexpr int TARGET_POSITIONS = 2;
|
||||||
|
inline constexpr int TARGET_NORMALS = 3;
|
||||||
|
inline constexpr int TARGET_EMISSION = 4;
|
||||||
|
inline constexpr int TARGET_SSAO = 5;
|
||||||
|
inline constexpr int TARGET_SHADOWS0 = 6;
|
||||||
|
inline constexpr int TARGET_SHADOWS1 = 7;
|
||||||
|
}
|
||||||
|
|
||||||
VC_ENUM_METADATA(CursorShape)
|
VC_ENUM_METADATA(CursorShape)
|
||||||
{"arrow", CursorShape::ARROW},
|
{"arrow", CursorShape::ARROW},
|
||||||
{"text", CursorShape::TEXT},
|
{"text", CursorShape::TEXT},
|
||||||
@ -69,3 +80,11 @@ public:
|
|||||||
|
|
||||||
virtual void flush() = 0;
|
virtual void flush() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Bindable {
|
||||||
|
public:
|
||||||
|
virtual ~Bindable() = default;
|
||||||
|
|
||||||
|
virtual void bind() = 0;
|
||||||
|
virtual void unbind() = 0;
|
||||||
|
};
|
||||||
|
|||||||
@ -39,17 +39,27 @@ BlocksRenderer::~BlocksRenderer() {
|
|||||||
|
|
||||||
/// Basic vertex add method
|
/// Basic vertex add method
|
||||||
void BlocksRenderer::vertex(
|
void BlocksRenderer::vertex(
|
||||||
const glm::vec3& coord, float u, float v, const glm::vec4& light
|
const glm::vec3& coord,
|
||||||
|
float u,
|
||||||
|
float v,
|
||||||
|
const glm::vec4& light,
|
||||||
|
const glm::vec3& normal,
|
||||||
|
float emission
|
||||||
) {
|
) {
|
||||||
|
|
||||||
vertexBuffer[vertexCount].position = coord;
|
vertexBuffer[vertexCount].position = coord;
|
||||||
|
|
||||||
vertexBuffer[vertexCount].uv = {u,v};
|
vertexBuffer[vertexCount].uv = {u,v};
|
||||||
|
|
||||||
|
vertexBuffer[vertexCount].normal[0] = static_cast<uint8_t>(normal.r * 127 + 128);
|
||||||
|
vertexBuffer[vertexCount].normal[1] = static_cast<uint8_t>(normal.g * 127 + 128);
|
||||||
|
vertexBuffer[vertexCount].normal[2] = static_cast<uint8_t>(normal.b * 127 + 128);
|
||||||
|
vertexBuffer[vertexCount].normal[3] = static_cast<uint8_t>(emission * 255);
|
||||||
|
|
||||||
vertexBuffer[vertexCount].color[0] = static_cast<uint8_t>(light.r * 255);
|
vertexBuffer[vertexCount].color[0] = static_cast<uint8_t>(light.r * 255);
|
||||||
vertexBuffer[vertexCount].color[1] = static_cast<uint8_t>(light.g * 255);
|
vertexBuffer[vertexCount].color[1] = static_cast<uint8_t>(light.g * 255);
|
||||||
vertexBuffer[vertexCount].color[2] = static_cast<uint8_t>(light.b * 255);
|
vertexBuffer[vertexCount].color[2] = static_cast<uint8_t>(light.b * 255);
|
||||||
vertexBuffer[vertexCount].color[3] = static_cast<uint8_t>(light.a * 255);
|
vertexBuffer[vertexCount].color[3] = static_cast<uint8_t>(light.a * 255);
|
||||||
|
|
||||||
vertexCount++;
|
vertexCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,10 +92,10 @@ void BlocksRenderer::face(
|
|||||||
auto Y = axisY * h;
|
auto Y = axisY * h;
|
||||||
auto Z = axisZ * d;
|
auto Z = axisZ * d;
|
||||||
float s = 0.5f;
|
float s = 0.5f;
|
||||||
vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, lights[0] * tint);
|
vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, lights[0] * tint, axisZ, 0);
|
||||||
vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, lights[1] * tint);
|
vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, lights[1] * tint, axisZ, 0);
|
||||||
vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, lights[2] * tint);
|
vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, lights[2] * tint, axisZ, 0);
|
||||||
vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, lights[3] * tint);
|
vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, lights[3] * tint, axisZ, 0);
|
||||||
index(0, 1, 3, 1, 2, 3);
|
index(0, 1, 3, 1, 2, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +113,7 @@ void BlocksRenderer::vertexAO(
|
|||||||
axisX,
|
axisX,
|
||||||
axisY
|
axisY
|
||||||
);
|
);
|
||||||
vertex(coord, u, v, light * tint);
|
vertex(coord, u, v, light * tint, axisZ, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlocksRenderer::faceAO(
|
void BlocksRenderer::faceAO(
|
||||||
@ -134,11 +144,12 @@ void BlocksRenderer::faceAO(
|
|||||||
vertexAO(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, axisX, axisY, axisZ);
|
vertexAO(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, axisX, axisY, axisZ);
|
||||||
vertexAO(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, axisX, axisY, axisZ);
|
vertexAO(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, axisX, axisY, axisZ);
|
||||||
} else {
|
} else {
|
||||||
|
auto axisZ = glm::normalize(Z);
|
||||||
glm::vec4 tint(1.0f);
|
glm::vec4 tint(1.0f);
|
||||||
vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint);
|
vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint, axisZ, 1);
|
||||||
vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint);
|
vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint, axisZ, 1);
|
||||||
vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint);
|
vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, axisZ, 1);
|
||||||
vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint);
|
vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, axisZ, 1);
|
||||||
}
|
}
|
||||||
index(0, 1, 2, 0, 2, 3);
|
index(0, 1, 2, 0, 2, 3);
|
||||||
}
|
}
|
||||||
@ -163,10 +174,10 @@ void BlocksRenderer::face(
|
|||||||
d = (1.0f - DIRECTIONAL_LIGHT_FACTOR) + d * DIRECTIONAL_LIGHT_FACTOR;
|
d = (1.0f - DIRECTIONAL_LIGHT_FACTOR) + d * DIRECTIONAL_LIGHT_FACTOR;
|
||||||
tint *= d;
|
tint *= d;
|
||||||
}
|
}
|
||||||
vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint);
|
vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint, Z, lights ? 0 : 1);
|
||||||
vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint);
|
vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint, Z, lights ? 0 : 1);
|
||||||
vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint);
|
vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, Z, lights ? 0 : 1);
|
||||||
vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint);
|
vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, Z, lights ? 0 : 1);
|
||||||
index(0, 1, 2, 0, 2, 3);
|
index(0, 1, 2, 0, 2, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,14 +209,16 @@ void BlocksRenderer::blockXSprite(
|
|||||||
const float w = size.x / 1.41f;
|
const float w = size.x / 1.41f;
|
||||||
const glm::vec4 tint (0.8f);
|
const glm::vec4 tint (0.8f);
|
||||||
|
|
||||||
face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, 1}, {0, 1, 0}, glm::vec3(),
|
glm::vec3 n(0.0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
|
face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, 1}, {0, 1, 0}, n,
|
||||||
texface1, lights2, tint);
|
texface1, lights2, tint);
|
||||||
face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, 1}, {0, 1, 0}, glm::vec3(),
|
face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, 1}, {0, 1, 0}, n,
|
||||||
texface1, lights1, tint);
|
texface1, lights1, tint);
|
||||||
|
|
||||||
face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, -1}, {0, 1, 0}, glm::vec3(),
|
face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, -1}, {0, 1, 0}, n,
|
||||||
texface2, lights2, tint);
|
texface2, lights2, tint);
|
||||||
face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, -1}, {0, 1, 0}, glm::vec3(),
|
face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, -1}, {0, 1, 0}, n,
|
||||||
texface2, lights1, tint);
|
texface2, lights1, tint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,7 +350,9 @@ void BlocksRenderer::blockCustomModel(
|
|||||||
coord + vcoord.x * X + vcoord.y * Y + vcoord.z * Z,
|
coord + vcoord.x * X + vcoord.y * Y + vcoord.z * Z,
|
||||||
vertex.uv.x,
|
vertex.uv.x,
|
||||||
vertex.uv.y,
|
vertex.uv.y,
|
||||||
glm::vec4(d, d, d, d) * aoColor
|
glm::vec4(d, d, d, d) * aoColor,
|
||||||
|
n,
|
||||||
|
0.0f
|
||||||
);
|
);
|
||||||
indexBuffer[indexCount++] = vertexOffset++;
|
indexBuffer[indexCount++] = vertexOffset++;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,7 +44,14 @@ class BlocksRenderer {
|
|||||||
|
|
||||||
SortingMeshData sortingMesh;
|
SortingMeshData sortingMesh;
|
||||||
|
|
||||||
void vertex(const glm::vec3& coord, float u, float v, const glm::vec4& light);
|
void vertex(
|
||||||
|
const glm::vec3& coord,
|
||||||
|
float u,
|
||||||
|
float v,
|
||||||
|
const glm::vec4& light,
|
||||||
|
const glm::vec3& normal,
|
||||||
|
float emission
|
||||||
|
);
|
||||||
void index(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f);
|
void index(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f);
|
||||||
|
|
||||||
void vertexAO(
|
void vertexAO(
|
||||||
|
|||||||
@ -143,7 +143,7 @@ void ChunksRenderer::update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Mesh<ChunkVertex>* ChunksRenderer::retrieveChunk(
|
const Mesh<ChunkVertex>* ChunksRenderer::retrieveChunk(
|
||||||
size_t index, const Camera& camera, Shader& shader, bool culling
|
size_t index, const Camera& camera, bool culling
|
||||||
) {
|
) {
|
||||||
auto chunk = chunks.getChunks()[index];
|
auto chunk = chunks.getChunks()[index];
|
||||||
if (chunk == nullptr) {
|
if (chunk == nullptr) {
|
||||||
@ -182,13 +182,39 @@ const Mesh<ChunkVertex>* ChunksRenderer::retrieveChunk(
|
|||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChunksRenderer::drawChunksShadowsPass(
|
||||||
|
const Camera& camera, Shader& shader
|
||||||
|
) {
|
||||||
|
const auto& atlas = assets.require<Atlas>("blocks");
|
||||||
|
|
||||||
|
atlas.getTexture()->bind();
|
||||||
|
|
||||||
|
for (const auto& chunk : chunks.getChunks()) {
|
||||||
|
if (chunk == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto& found = meshes.find({chunk->x, chunk->z});
|
||||||
|
if (found == meshes.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto mesh = found->second.mesh.get();
|
||||||
|
if (mesh) {
|
||||||
|
glm::vec3 coord(
|
||||||
|
chunk->x * CHUNK_W + 0.5f, 0.5f, chunk->z * CHUNK_D + 0.5f
|
||||||
|
);
|
||||||
|
glm::mat4 model = glm::translate(glm::mat4(1.0f), coord);
|
||||||
|
shader.uniformMatrix("u_model", model);
|
||||||
|
mesh->draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ChunksRenderer::drawChunks(
|
void ChunksRenderer::drawChunks(
|
||||||
const Camera& camera, Shader& shader
|
const Camera& camera, Shader& shader
|
||||||
) {
|
) {
|
||||||
const auto& atlas = assets.require<Atlas>("blocks");
|
const auto& atlas = assets.require<Atlas>("blocks");
|
||||||
|
|
||||||
atlas.getTexture()->bind();
|
atlas.getTexture()->bind();
|
||||||
update();
|
|
||||||
|
|
||||||
// [warning] this whole method is not thread-safe for chunks
|
// [warning] this whole method is not thread-safe for chunks
|
||||||
|
|
||||||
@ -219,7 +245,7 @@ void ChunksRenderer::drawChunks(
|
|||||||
// TODO: minimize draw calls number
|
// TODO: minimize draw calls number
|
||||||
for (int i = indices.size()-1; i >= 0; i--) {
|
for (int i = indices.size()-1; i >= 0; i--) {
|
||||||
auto& chunk = chunks.getChunks()[indices[i].index];
|
auto& chunk = chunks.getChunks()[indices[i].index];
|
||||||
auto mesh = retrieveChunk(indices[i].index, camera, shader, culling);
|
auto mesh = retrieveChunk(indices[i].index, camera, culling);
|
||||||
|
|
||||||
if (mesh) {
|
if (mesh) {
|
||||||
glm::vec3 coord(
|
glm::vec3 coord(
|
||||||
|
|||||||
@ -50,7 +50,7 @@ class ChunksRenderer {
|
|||||||
std::vector<ChunksSortEntry> indices;
|
std::vector<ChunksSortEntry> indices;
|
||||||
util::ThreadPool<std::shared_ptr<Chunk>, RendererResult> threadPool;
|
util::ThreadPool<std::shared_ptr<Chunk>, RendererResult> threadPool;
|
||||||
const Mesh<ChunkVertex>* retrieveChunk(
|
const Mesh<ChunkVertex>* retrieveChunk(
|
||||||
size_t index, const Camera& camera, Shader& shader, bool culling
|
size_t index, const Camera& camera, bool culling
|
||||||
);
|
);
|
||||||
public:
|
public:
|
||||||
ChunksRenderer(
|
ChunksRenderer(
|
||||||
@ -72,6 +72,9 @@ public:
|
|||||||
const Mesh<ChunkVertex>* getOrRender(
|
const Mesh<ChunkVertex>* getOrRender(
|
||||||
const std::shared_ptr<Chunk>& chunk, bool important
|
const std::shared_ptr<Chunk>& chunk, bool important
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void drawChunksShadowsPass(const Camera& camera, Shader& shader);
|
||||||
|
|
||||||
void drawChunks(const Camera& camera, Shader& shader);
|
void drawChunks(const Camera& camera, Shader& shader);
|
||||||
|
|
||||||
void drawSortedMeshes(const Camera& camera, Shader& shader);
|
void drawSortedMeshes(const Camera& camera, Shader& shader);
|
||||||
|
|||||||
@ -95,37 +95,37 @@ void MainBatch::cube(
|
|||||||
|
|
||||||
quad(
|
quad(
|
||||||
coord + Z * size.z * 0.5f,
|
coord + Z * size.z * 0.5f,
|
||||||
X, Y, glm::vec2(size.x, size.y),
|
X, Y, Z, glm::vec2(size.x, size.y),
|
||||||
(shading ? do_tint(0.8) * tint : tint),
|
(shading ? do_tint(0.8) * tint : tint),
|
||||||
glm::vec3(1.0f), texfaces[5]
|
glm::vec3(1.0f), texfaces[5]
|
||||||
);
|
);
|
||||||
quad(
|
quad(
|
||||||
coord - Z * size.z * 0.5f,
|
coord - Z * size.z * 0.5f,
|
||||||
-X, Y, glm::vec2(size.x, size.y),
|
-X, Y, -Z, glm::vec2(size.x, size.y),
|
||||||
(shading ? do_tint(0.9f) * tint : tint),
|
(shading ? do_tint(0.9f) * tint : tint),
|
||||||
glm::vec3(1.0f), texfaces[4]
|
glm::vec3(1.0f), texfaces[4]
|
||||||
);
|
);
|
||||||
quad(
|
quad(
|
||||||
coord + Y * size.y * 0.5f,
|
coord + Y * size.y * 0.5f,
|
||||||
-X, Z, glm::vec2(size.x, size.z),
|
-X, Z, Y, glm::vec2(size.x, size.z),
|
||||||
(shading ? do_tint(1.0f) * tint : tint),
|
(shading ? do_tint(1.0f) * tint : tint),
|
||||||
glm::vec3(1.0f), texfaces[3]
|
glm::vec3(1.0f), texfaces[3]
|
||||||
);
|
);
|
||||||
quad(
|
quad(
|
||||||
coord - Y * size.y * 0.5f,
|
coord - Y * size.y * 0.5f,
|
||||||
X, Z, glm::vec2(size.x, size.z),
|
X, Z, -Y, glm::vec2(size.x, size.z),
|
||||||
(shading ? do_tint(0.7f) * tint : tint),
|
(shading ? do_tint(0.7f) * tint : tint),
|
||||||
glm::vec3(1.0f), texfaces[2]
|
glm::vec3(1.0f), texfaces[2]
|
||||||
);
|
);
|
||||||
quad(
|
quad(
|
||||||
coord + X * size.x * 0.5f,
|
coord + X * size.x * 0.5f,
|
||||||
-Z, Y, glm::vec2(size.z, size.y),
|
-Z, Y, X, glm::vec2(size.z, size.y),
|
||||||
(shading ? do_tint(0.8f) * tint : tint),
|
(shading ? do_tint(0.8f) * tint : tint),
|
||||||
glm::vec3(1.0f), texfaces[1]
|
glm::vec3(1.0f), texfaces[1]
|
||||||
);
|
);
|
||||||
quad(
|
quad(
|
||||||
coord - X * size.x * 0.5f,
|
coord - X * size.x * 0.5f,
|
||||||
Z, Y, glm::vec2(size.z, size.y),
|
Z, Y, -X, glm::vec2(size.z, size.y),
|
||||||
(shading ? do_tint(0.9f) * tint : tint),
|
(shading ? do_tint(0.9f) * tint : tint),
|
||||||
glm::vec3(1.0f), texfaces[1]
|
glm::vec3(1.0f), texfaces[1]
|
||||||
);
|
);
|
||||||
|
|||||||
@ -18,13 +18,15 @@ struct MainBatchVertex {
|
|||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
glm::vec2 uv;
|
glm::vec2 uv;
|
||||||
glm::vec3 tint;
|
glm::vec3 tint;
|
||||||
std::array<uint8_t,4> color;
|
std::array<uint8_t, 4> color;
|
||||||
|
std::array<uint8_t, 4> normal;
|
||||||
|
|
||||||
static constexpr VertexAttribute ATTRIBUTES[] = {
|
static constexpr VertexAttribute ATTRIBUTES[] = {
|
||||||
{VertexAttribute::Type::FLOAT, false, 3},
|
{VertexAttribute::Type::FLOAT, false, 3},
|
||||||
{VertexAttribute::Type::FLOAT, false, 2},
|
{VertexAttribute::Type::FLOAT, false, 2},
|
||||||
{VertexAttribute::Type::FLOAT, false, 3},
|
{VertexAttribute::Type::FLOAT, false, 3},
|
||||||
{VertexAttribute::Type::UNSIGNED_BYTE, true, 4},
|
{VertexAttribute::Type::UNSIGNED_BYTE, true, 4},
|
||||||
|
{VertexAttribute::Type::UNSIGNED_BYTE, true, 4},
|
||||||
{{}, 0}};
|
{{}, 0}};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -61,7 +63,9 @@ public:
|
|||||||
const glm::vec3& pos,
|
const glm::vec3& pos,
|
||||||
const glm::vec2& uv,
|
const glm::vec2& uv,
|
||||||
const glm::vec4& light,
|
const glm::vec4& light,
|
||||||
const glm::vec3& tint
|
const glm::vec3& tint,
|
||||||
|
const glm::vec3& normal,
|
||||||
|
float emission
|
||||||
) {
|
) {
|
||||||
MainBatchVertex* buffer = this->buffer.get();
|
MainBatchVertex* buffer = this->buffer.get();
|
||||||
buffer[index].position = pos;
|
buffer[index].position = pos;
|
||||||
@ -72,6 +76,11 @@ public:
|
|||||||
buffer[index].color[1] = static_cast<uint8_t>(light.g * 255);
|
buffer[index].color[1] = static_cast<uint8_t>(light.g * 255);
|
||||||
buffer[index].color[2] = static_cast<uint8_t>(light.b * 255);
|
buffer[index].color[2] = static_cast<uint8_t>(light.b * 255);
|
||||||
buffer[index].color[3] = static_cast<uint8_t>(light.a * 255);
|
buffer[index].color[3] = static_cast<uint8_t>(light.a * 255);
|
||||||
|
|
||||||
|
buffer[index].normal[0] = static_cast<uint8_t>(normal.x * 128 + 127);
|
||||||
|
buffer[index].normal[1] = static_cast<uint8_t>(normal.y * 128 + 127);
|
||||||
|
buffer[index].normal[2] = static_cast<uint8_t>(normal.z * 128 + 127);
|
||||||
|
buffer[index].normal[3] = static_cast<uint8_t>(emission * 255);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,48 +88,62 @@ public:
|
|||||||
const glm::vec3& pos,
|
const glm::vec3& pos,
|
||||||
const glm::vec3& right,
|
const glm::vec3& right,
|
||||||
const glm::vec3& up,
|
const glm::vec3& up,
|
||||||
|
const glm::vec3& normal,
|
||||||
const glm::vec2& size,
|
const glm::vec2& size,
|
||||||
const glm::vec4& light,
|
const glm::vec4& light,
|
||||||
const glm::vec3& tint,
|
const glm::vec3& tint,
|
||||||
const UVRegion& subregion
|
const UVRegion& subregion,
|
||||||
|
float emission = 0.0f
|
||||||
) {
|
) {
|
||||||
prepare(6);
|
prepare(6);
|
||||||
vertex(
|
vertex(
|
||||||
pos - right * size.x * 0.5f - up * size.y * 0.5f,
|
pos - right * size.x * 0.5f - up * size.y * 0.5f,
|
||||||
{subregion.u1, subregion.v1},
|
{subregion.u1, subregion.v1},
|
||||||
light,
|
light,
|
||||||
tint
|
tint,
|
||||||
|
normal,
|
||||||
|
emission
|
||||||
);
|
);
|
||||||
vertex(
|
vertex(
|
||||||
pos + right * size.x * 0.5f - up * size.y * 0.5f,
|
pos + right * size.x * 0.5f - up * size.y * 0.5f,
|
||||||
{subregion.u2, subregion.v1},
|
{subregion.u2, subregion.v1},
|
||||||
light,
|
light,
|
||||||
tint
|
tint,
|
||||||
|
normal,
|
||||||
|
emission
|
||||||
);
|
);
|
||||||
vertex(
|
vertex(
|
||||||
pos + right * size.x * 0.5f + up * size.y * 0.5f,
|
pos + right * size.x * 0.5f + up * size.y * 0.5f,
|
||||||
{subregion.u2, subregion.v2},
|
{subregion.u2, subregion.v2},
|
||||||
light,
|
light,
|
||||||
tint
|
tint,
|
||||||
|
normal,
|
||||||
|
emission
|
||||||
);
|
);
|
||||||
|
|
||||||
vertex(
|
vertex(
|
||||||
pos - right * size.x * 0.5f - up * size.y * 0.5f,
|
pos - right * size.x * 0.5f - up * size.y * 0.5f,
|
||||||
{subregion.u1, subregion.v1},
|
{subregion.u1, subregion.v1},
|
||||||
light,
|
light,
|
||||||
tint
|
tint,
|
||||||
|
normal,
|
||||||
|
emission
|
||||||
);
|
);
|
||||||
vertex(
|
vertex(
|
||||||
pos + right * size.x * 0.5f + up * size.y * 0.5f,
|
pos + right * size.x * 0.5f + up * size.y * 0.5f,
|
||||||
{subregion.u2, subregion.v2},
|
{subregion.u2, subregion.v2},
|
||||||
light,
|
light,
|
||||||
tint
|
tint,
|
||||||
|
normal,
|
||||||
|
emission
|
||||||
);
|
);
|
||||||
vertex(
|
vertex(
|
||||||
pos - right * size.x * 0.5f + up * size.y * 0.5f,
|
pos - right * size.x * 0.5f + up * size.y * 0.5f,
|
||||||
{subregion.u1, subregion.v2},
|
{subregion.u1, subregion.v2},
|
||||||
light,
|
light,
|
||||||
tint
|
tint,
|
||||||
|
normal,
|
||||||
|
emission
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -57,12 +57,14 @@ ModelBatch::ModelBatch(
|
|||||||
|
|
||||||
ModelBatch::~ModelBatch() = default;
|
ModelBatch::~ModelBatch() = default;
|
||||||
|
|
||||||
void ModelBatch::draw(const model::Mesh& mesh, const glm::mat4& matrix,
|
void ModelBatch::draw(
|
||||||
const glm::mat3& rotation, glm::vec3 tint,
|
const model::Mesh& mesh,
|
||||||
|
const glm::mat4& matrix,
|
||||||
|
const glm::mat3& rotation,
|
||||||
|
glm::vec3 tint,
|
||||||
const texture_names_map* varTextures,
|
const texture_names_map* varTextures,
|
||||||
bool backlight) {
|
bool backlight
|
||||||
|
) {
|
||||||
|
|
||||||
setTexture(mesh.texture, varTextures);
|
setTexture(mesh.texture, varTextures);
|
||||||
size_t vcount = mesh.vertices.size();
|
size_t vcount = mesh.vertices.size();
|
||||||
const auto& vertexData = mesh.vertices.data();
|
const auto& vertexData = mesh.vertices.data();
|
||||||
@ -78,12 +80,19 @@ void ModelBatch::draw(const model::Mesh& mesh, const glm::mat4& matrix,
|
|||||||
for (size_t j = 0; j < 3; j++) {
|
for (size_t j = 0; j < 3; j++) {
|
||||||
const auto vert = vertexData[i * 3 + j];
|
const auto vert = vertexData[i * 3 + j];
|
||||||
float d = 1.0f;
|
float d = 1.0f;
|
||||||
if (mesh.lighting) {
|
|
||||||
auto norm = rotation * vert.normal;
|
auto norm = rotation * vert.normal;
|
||||||
|
if (mesh.lighting) {
|
||||||
d = glm::dot(norm, SUN_VECTOR);
|
d = glm::dot(norm, SUN_VECTOR);
|
||||||
d = 0.8f + d * 0.2f;
|
d = 0.8f + d * 0.2f;
|
||||||
}
|
}
|
||||||
batch->vertex(matrix * glm::vec4(vert.coord, 1.0f), vert.uv, lights*d, tint);
|
batch->vertex(
|
||||||
|
matrix * glm::vec4(vert.coord, 1.0f),
|
||||||
|
vert.uv,
|
||||||
|
lights * d,
|
||||||
|
tint,
|
||||||
|
norm,
|
||||||
|
mesh.lighting ? 0.0f : 1.0f
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -117,7 +117,6 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) {
|
|||||||
light *= 0.9f + (particle.random % 100) * 0.001f;
|
light *= 0.9f + (particle.random % 100) * 0.001f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
glm::vec3 localRight = right;
|
glm::vec3 localRight = right;
|
||||||
glm::vec3 localUp = preset.globalUpVector ? glm::vec3(0, 1, 0) : up;
|
glm::vec3 localUp = preset.globalUpVector ? glm::vec3(0, 1, 0) : up;
|
||||||
float angle = particle.angle;
|
float angle = particle.angle;
|
||||||
@ -134,10 +133,12 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) {
|
|||||||
particle.position,
|
particle.position,
|
||||||
localRight,
|
localRight,
|
||||||
localUp,
|
localUp,
|
||||||
|
-camera.front,
|
||||||
preset.size * scale,
|
preset.size * scale,
|
||||||
light,
|
light,
|
||||||
glm::vec3(1.0f),
|
glm::vec3(1.0f),
|
||||||
particle.region
|
particle.region,
|
||||||
|
preset.lighting ? 0.0f : 1.0f
|
||||||
);
|
);
|
||||||
if (particle.lifetime <= 0.0f) {
|
if (particle.lifetime <= 0.0f) {
|
||||||
iter = vec.erase(iter);
|
iter = vec.erase(iter);
|
||||||
|
|||||||
@ -146,6 +146,7 @@ void PrecipitationRenderer::render(
|
|||||||
pos,
|
pos,
|
||||||
face.right,
|
face.right,
|
||||||
{0, 1, 0},
|
{0, 1, 0},
|
||||||
|
glm::cross(glm::vec3(0, 1, 0), face.right),
|
||||||
FACE_SIZE,
|
FACE_SIZE,
|
||||||
light_at(chunks, pos.x, y, pos.z),
|
light_at(chunks, pos.x, y, pos.z),
|
||||||
glm::vec3(1.0f),
|
glm::vec3(1.0f),
|
||||||
|
|||||||
@ -15,11 +15,10 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#include <glm/gtc/constants.hpp>
|
#include <glm/gtc/constants.hpp>
|
||||||
|
|
||||||
#ifndef M_PI
|
using namespace advanced_pipeline;
|
||||||
#define M_PI 3.141592
|
|
||||||
#endif // M_PI
|
|
||||||
|
|
||||||
const int STARS_COUNT = 3000;
|
const int STARS_COUNT = 3000;
|
||||||
const int STARS_SEED = 632;
|
const int STARS_SEED = 632;
|
||||||
@ -46,18 +45,28 @@ Skybox::Skybox(uint size, Shader& shader)
|
|||||||
|
|
||||||
mesh = std::make_unique<Mesh<SkyboxVertex>>(vertices, 6);
|
mesh = std::make_unique<Mesh<SkyboxVertex>>(vertices, 6);
|
||||||
|
|
||||||
sprites.push_back(skysprite {
|
sprites.push_back(SkySprite {
|
||||||
"misc/moon",
|
"misc/moon",
|
||||||
glm::pi<float>()*0.5f,
|
glm::pi<float>() * 0.5f,
|
||||||
4.0f,
|
4.0f,
|
||||||
false
|
false,
|
||||||
|
glm::pi<float>() * 0.25f,
|
||||||
});
|
});
|
||||||
|
|
||||||
sprites.push_back(skysprite {
|
sprites.push_back(SkySprite {
|
||||||
|
"misc/moon_flare",
|
||||||
|
glm::pi<float>() * 0.5f,
|
||||||
|
0.5f,
|
||||||
|
false,
|
||||||
|
glm::pi<float>() * 0.25f,
|
||||||
|
});
|
||||||
|
|
||||||
|
sprites.push_back(SkySprite {
|
||||||
"misc/sun",
|
"misc/sun",
|
||||||
glm::pi<float>()*1.5f,
|
glm::pi<float>() * 1.5f,
|
||||||
4.0f,
|
4.0f,
|
||||||
true
|
true,
|
||||||
|
glm::pi<float>() * 0.25f,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,9 +78,11 @@ void Skybox::drawBackground(
|
|||||||
auto backShader = assets.get<Shader>("background");
|
auto backShader = assets.get<Shader>("background");
|
||||||
backShader->use();
|
backShader->use();
|
||||||
backShader->uniformMatrix("u_view", camera.getView(false));
|
backShader->uniformMatrix("u_view", camera.getView(false));
|
||||||
backShader->uniform1f("u_zoom", camera.zoom*camera.getFov()/(M_PI*0.5f));
|
backShader->uniform1f(
|
||||||
|
"u_zoom", camera.zoom * camera.getFov() / glm::half_pi<float>()
|
||||||
|
);
|
||||||
backShader->uniform1f("u_ar", float(width)/float(height));
|
backShader->uniform1f("u_ar", float(width)/float(height));
|
||||||
backShader->uniform1i("u_cubemap", 1);
|
backShader->uniform1i("u_skybox", 1);
|
||||||
bind();
|
bind();
|
||||||
mesh->draw();
|
mesh->draw();
|
||||||
unbind();
|
unbind();
|
||||||
@ -80,20 +91,29 @@ void Skybox::drawBackground(
|
|||||||
void Skybox::drawStars(float angle, float opacity) {
|
void Skybox::drawStars(float angle, float opacity) {
|
||||||
batch3d->texture(nullptr);
|
batch3d->texture(nullptr);
|
||||||
random.setSeed(STARS_SEED);
|
random.setSeed(STARS_SEED);
|
||||||
|
|
||||||
|
glm::mat4 rotation = glm::rotate(
|
||||||
|
glm::mat4(1.0f),
|
||||||
|
-angle + glm::pi<float>() * 0.5f,
|
||||||
|
glm::vec3(0, 0, -1)
|
||||||
|
);
|
||||||
|
rotation = glm::rotate(rotation, sunAltitude, glm::vec3(1, 0, 0));
|
||||||
|
|
||||||
|
float depth = 1e3;
|
||||||
for (int i = 0; i < STARS_COUNT; i++) {
|
for (int i = 0; i < STARS_COUNT; i++) {
|
||||||
float rx = (random.randFloat()) - 0.5f;
|
float rx = (random.randFloat()) - 0.5f;
|
||||||
float ry = (random.randFloat()) - 0.5f;
|
float ry = (random.randFloat()) - 0.5f;
|
||||||
float z = (random.randFloat()) - 0.5f;
|
float rz = (random.randFloat()) - 0.5f;
|
||||||
float x = rx * std::sin(angle) + ry * -std::cos(angle);
|
|
||||||
float y = rx * std::cos(angle) + ry * std::sin(angle);
|
glm::vec3 pos = glm::vec4(rx, ry, rz, 1) * rotation;
|
||||||
|
|
||||||
float sopacity = random.randFloat();
|
float sopacity = random.randFloat();
|
||||||
if (y < 0.0f)
|
if (pos.y < 0.0f)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sopacity *= (0.2f+std::sqrt(std::cos(angle))*0.5f) - 0.05f;
|
sopacity *= (0.2f + std::sqrt(std::cos(angle)) * 0.5f) - 0.05f;
|
||||||
glm::vec4 tint (1,1,1, sopacity * opacity);
|
glm::vec4 tint (1,1,1, sopacity * opacity);
|
||||||
batch3d->point(glm::vec3(x, y, z), tint);
|
batch3d->point(pos * depth, tint);
|
||||||
}
|
}
|
||||||
batch3d->flushPoints();
|
batch3d->flushPoints();
|
||||||
}
|
}
|
||||||
@ -107,6 +127,8 @@ void Skybox::draw(
|
|||||||
{
|
{
|
||||||
const glm::uvec2& viewport = pctx.getViewport();
|
const glm::uvec2& viewport = pctx.getViewport();
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
drawBackground(camera, assets, viewport.x, viewport.y);
|
drawBackground(camera, assets, viewport.x, viewport.y);
|
||||||
|
|
||||||
DrawContext ctx = pctx.sub();
|
DrawContext ctx = pctx.sub();
|
||||||
@ -119,24 +141,32 @@ void Skybox::draw(
|
|||||||
batch3d->begin();
|
batch3d->begin();
|
||||||
|
|
||||||
float angle = daytime * glm::pi<float>() * 2.0f;
|
float angle = daytime * glm::pi<float>() * 2.0f;
|
||||||
float opacity = glm::pow(1.0f-fog, 7.0f);
|
float opacity = glm::pow(1.0f - fog, 7.0f);
|
||||||
|
|
||||||
|
float depthScale = 1e3;
|
||||||
for (auto& sprite : sprites) {
|
for (auto& sprite : sprites) {
|
||||||
batch3d->texture(assets.get<Texture>(sprite.texture));
|
batch3d->texture(assets.get<Texture>(sprite.texture));
|
||||||
|
|
||||||
float sangle = daytime * glm::pi<float>()*2.0 + sprite.phase;
|
float sangle = daytime * glm::pi<float>() * 2.0 + sprite.phase;
|
||||||
float distance = sprite.distance;
|
float distance = sprite.distance * depthScale;
|
||||||
|
|
||||||
glm::vec3 pos(-std::cos(sangle)*distance, std::sin(sangle)*distance, 0);
|
glm::mat4 rotation = glm::rotate(
|
||||||
glm::vec3 up(-std::sin(-sangle), std::cos(-sangle), 0.0f);
|
glm::mat4(1.0f),
|
||||||
|
-sangle + glm::pi<float>() * 0.5f,
|
||||||
|
glm::vec3(0, 0, -1)
|
||||||
|
);
|
||||||
|
rotation = glm::rotate(rotation, sprite.altitude, glm::vec3(1, 0, 0));
|
||||||
|
glm::vec3 pos = glm::vec4(0, distance, 0, 1) * rotation;
|
||||||
|
glm::vec3 up = glm::vec4(depthScale, 0, 0, 1) * rotation;
|
||||||
|
glm::vec3 right = glm::vec4(0, 0, depthScale, 1) * rotation;
|
||||||
glm::vec4 tint (1,1,1, opacity);
|
glm::vec4 tint (1,1,1, opacity);
|
||||||
if (!sprite.emissive) {
|
if (!sprite.emissive) {
|
||||||
tint *= 0.6f+std::cos(angle)*0.4;
|
tint *= 0.6f + std::cos(angle)*0.4;
|
||||||
}
|
}
|
||||||
batch3d->sprite(pos, glm::vec3(0, 0, 1),
|
batch3d->sprite(pos, right,
|
||||||
up, 1, 1, UVRegion(), tint);
|
up, 1, 1, UVRegion(), tint);
|
||||||
}
|
}
|
||||||
|
batch3d->flush();
|
||||||
drawStars(angle, opacity);
|
drawStars(angle, opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,12 +183,22 @@ void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality)
|
|||||||
assert(cubemap != nullptr);
|
assert(cubemap != nullptr);
|
||||||
|
|
||||||
ready = true;
|
ready = true;
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE0 + TARGET_SKYBOX);
|
||||||
cubemap->bind();
|
cubemap->bind();
|
||||||
shader.use();
|
shader.use();
|
||||||
t *= glm::pi<float>()*2.0f;
|
t *= glm::two_pi<float>();
|
||||||
|
|
||||||
lightDir = glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f));
|
lightDir = glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f));
|
||||||
|
|
||||||
|
float sunAngle = glm::radians((t / glm::two_pi<float>() - 0.25f) * 360.0f);
|
||||||
|
float x = -glm::cos(sunAngle + glm::pi<float>() * 0.5f) * glm::radians(sunAltitude);
|
||||||
|
float y = sunAngle - glm::pi<float>() * 0.5f;
|
||||||
|
float z = glm::radians(0.0f);
|
||||||
|
rotation = glm::rotate(glm::mat4(1.0f), y, glm::vec3(0, 1, 0));
|
||||||
|
rotation = glm::rotate(rotation, x, glm::vec3(1, 0, 0));
|
||||||
|
rotation = glm::rotate(rotation, z, glm::vec3(0, 0, 1));
|
||||||
|
lightDir = glm::vec3(rotation * glm::vec4(0, 0, -1, 1));
|
||||||
|
|
||||||
shader.uniform1i("u_quality", quality);
|
shader.uniform1i("u_quality", quality);
|
||||||
shader.uniform1f("u_mie", mie);
|
shader.uniform1f("u_mie", mie);
|
||||||
shader.uniform1f("u_fog", mie - 1.0f);
|
shader.uniform1f("u_fog", mie - 1.0f);
|
||||||
@ -223,13 +263,13 @@ void Skybox::refreshFace(uint face, Cubemap* cubemap) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Skybox::bind() const {
|
void Skybox::bind() const {
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE0 + TARGET_SKYBOX);
|
||||||
fbo->getTexture()->bind();
|
fbo->getTexture()->bind();
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Skybox::unbind() const {
|
void Skybox::unbind() const {
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE0 + TARGET_SKYBOX);
|
||||||
fbo->getTexture()->unbind();
|
fbo->getTexture()->unbind();
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,11 +25,12 @@ struct SkyboxVertex {
|
|||||||
{{}, 0}};
|
{{}, 0}};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct skysprite {
|
struct SkySprite {
|
||||||
std::string texture;
|
std::string texture;
|
||||||
float phase;
|
float phase;
|
||||||
float distance;
|
float distance;
|
||||||
bool emissive;
|
bool emissive;
|
||||||
|
float altitude;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Skybox {
|
class Skybox {
|
||||||
@ -42,11 +43,13 @@ class Skybox {
|
|||||||
|
|
||||||
std::unique_ptr<Mesh<SkyboxVertex>> mesh;
|
std::unique_ptr<Mesh<SkyboxVertex>> mesh;
|
||||||
std::unique_ptr<Batch3D> batch3d;
|
std::unique_ptr<Batch3D> batch3d;
|
||||||
std::vector<skysprite> sprites;
|
std::vector<SkySprite> sprites;
|
||||||
int frameid = 0;
|
int frameid = 0;
|
||||||
|
|
||||||
float prevMie = -1.0f;
|
float prevMie = -1.0f;
|
||||||
float prevT = -1.0f;
|
float prevT = -1.0f;
|
||||||
|
float sunAltitude = 45.0f;
|
||||||
|
glm::mat4 rotation;
|
||||||
|
|
||||||
void drawStars(float angle, float opacity);
|
void drawStars(float angle, float opacity);
|
||||||
void drawBackground(
|
void drawBackground(
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include "assets/assets_util.hpp"
|
#include "assets/assets_util.hpp"
|
||||||
#include "content/Content.hpp"
|
#include "content/Content.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
|
#include "coders/GLSLExtension.hpp"
|
||||||
#include "frontend/LevelFrontend.hpp"
|
#include "frontend/LevelFrontend.hpp"
|
||||||
#include "frontend/ContentGfxCache.hpp"
|
#include "frontend/ContentGfxCache.hpp"
|
||||||
#include "items/Inventory.hpp"
|
#include "items/Inventory.hpp"
|
||||||
@ -26,7 +27,6 @@
|
|||||||
#include "voxels/Block.hpp"
|
#include "voxels/Block.hpp"
|
||||||
#include "voxels/Chunk.hpp"
|
#include "voxels/Chunk.hpp"
|
||||||
#include "voxels/Chunks.hpp"
|
#include "voxels/Chunks.hpp"
|
||||||
#include "window/Camera.hpp"
|
|
||||||
#include "window/Window.hpp"
|
#include "window/Window.hpp"
|
||||||
#include "world/Level.hpp"
|
#include "world/Level.hpp"
|
||||||
#include "world/LevelEvents.hpp"
|
#include "world/LevelEvents.hpp"
|
||||||
@ -38,9 +38,12 @@
|
|||||||
#include "graphics/core/LineBatch.hpp"
|
#include "graphics/core/LineBatch.hpp"
|
||||||
#include "graphics/core/Mesh.hpp"
|
#include "graphics/core/Mesh.hpp"
|
||||||
#include "graphics/core/PostProcessing.hpp"
|
#include "graphics/core/PostProcessing.hpp"
|
||||||
|
#include "graphics/core/Framebuffer.hpp"
|
||||||
#include "graphics/core/Shader.hpp"
|
#include "graphics/core/Shader.hpp"
|
||||||
#include "graphics/core/Texture.hpp"
|
#include "graphics/core/Texture.hpp"
|
||||||
#include "graphics/core/Font.hpp"
|
#include "graphics/core/Font.hpp"
|
||||||
|
#include "graphics/core/ShadowMap.hpp"
|
||||||
|
#include "graphics/core/GBuffer.hpp"
|
||||||
#include "BlockWrapsRenderer.hpp"
|
#include "BlockWrapsRenderer.hpp"
|
||||||
#include "ParticlesRenderer.hpp"
|
#include "ParticlesRenderer.hpp"
|
||||||
#include "PrecipitationRenderer.hpp"
|
#include "PrecipitationRenderer.hpp"
|
||||||
@ -52,8 +55,12 @@
|
|||||||
#include "Emitter.hpp"
|
#include "Emitter.hpp"
|
||||||
#include "TextNote.hpp"
|
#include "TextNote.hpp"
|
||||||
|
|
||||||
|
using namespace advanced_pipeline;
|
||||||
|
|
||||||
inline constexpr size_t BATCH3D_CAPACITY = 4096;
|
inline constexpr size_t BATCH3D_CAPACITY = 4096;
|
||||||
inline constexpr size_t MODEL_BATCH_CAPACITY = 20'000;
|
inline constexpr size_t MODEL_BATCH_CAPACITY = 20'000;
|
||||||
|
inline constexpr GLenum TEXTURE_MAIN = GL_TEXTURE0;
|
||||||
|
inline constexpr int MIN_SHADOW_MAP_RES = 512;
|
||||||
|
|
||||||
bool WorldRenderer::showChunkBorders = false;
|
bool WorldRenderer::showChunkBorders = false;
|
||||||
bool WorldRenderer::showEntitiesDebug = false;
|
bool WorldRenderer::showEntitiesDebug = false;
|
||||||
@ -119,13 +126,37 @@ void WorldRenderer::setupWorldShader(
|
|||||||
shader.uniform1f("u_fogFactor", fogFactor);
|
shader.uniform1f("u_fogFactor", fogFactor);
|
||||||
shader.uniform1f("u_fogCurve", settings.graphics.fogCurve.get());
|
shader.uniform1f("u_fogCurve", settings.graphics.fogCurve.get());
|
||||||
shader.uniform1i("u_debugLights", lightsDebug);
|
shader.uniform1i("u_debugLights", lightsDebug);
|
||||||
|
shader.uniform1i("u_debugNormals", false);
|
||||||
shader.uniform1f("u_weatherFogOpacity", weather.fogOpacity());
|
shader.uniform1f("u_weatherFogOpacity", weather.fogOpacity());
|
||||||
shader.uniform1f("u_weatherFogDencity", weather.fogDencity());
|
shader.uniform1f("u_weatherFogDencity", weather.fogDencity());
|
||||||
shader.uniform1f("u_weatherFogCurve", weather.fogCurve());
|
shader.uniform1f("u_weatherFogCurve", weather.fogCurve());
|
||||||
shader.uniform1f("u_dayTime", level.getWorld()->getInfo().daytime);
|
shader.uniform1f("u_dayTime", level.getWorld()->getInfo().daytime);
|
||||||
shader.uniform2f("u_lightDir", skybox->getLightDir());
|
shader.uniform2f("u_lightDir", skybox->getLightDir());
|
||||||
shader.uniform3f("u_cameraPos", camera.position);
|
shader.uniform3f("u_cameraPos", camera.position);
|
||||||
shader.uniform1i("u_cubemap", 1);
|
shader.uniform1i("u_skybox", 1);
|
||||||
|
shader.uniform1i("u_enableShadows", shadows);
|
||||||
|
|
||||||
|
if (shadows) {
|
||||||
|
const auto& worldInfo = level.getWorld()->getInfo();
|
||||||
|
float cloudsIntensity = glm::max(worldInfo.fog, weather.clouds());
|
||||||
|
shader.uniform1i("u_screen", 0);
|
||||||
|
shader.uniformMatrix("u_shadowsMatrix[0]", shadowCamera.getProjView());
|
||||||
|
shader.uniformMatrix("u_shadowsMatrix[1]", wideShadowCamera.getProjView());
|
||||||
|
shader.uniform3f("u_sunDir", shadowCamera.front);
|
||||||
|
shader.uniform1i("u_shadowsRes", shadowMap->getResolution());
|
||||||
|
shader.uniform1f("u_shadowsOpacity", 1.0f - cloudsIntensity); // TODO: make it configurable
|
||||||
|
shader.uniform1f("u_shadowsSoftness", 1.0f + cloudsIntensity * 4); // TODO: make it configurable
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0 + TARGET_SHADOWS0);
|
||||||
|
shader.uniform1i("u_shadows[0]", TARGET_SHADOWS0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, shadowMap->getDepthMap());
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0 + TARGET_SHADOWS1);
|
||||||
|
shader.uniform1i("u_shadows[1]", TARGET_SHADOWS1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, wideShadowMap->getDepthMap());
|
||||||
|
|
||||||
|
glActiveTexture(TEXTURE_MAIN);
|
||||||
|
}
|
||||||
|
|
||||||
auto indices = level.content.getIndices();
|
auto indices = level.content.getIndices();
|
||||||
// Light emission when an emissive item is chosen
|
// Light emission when an emissive item is chosen
|
||||||
@ -195,22 +226,6 @@ void WorldRenderer::renderLevel(
|
|||||||
if (!pause) {
|
if (!pause) {
|
||||||
scripting::on_frontend_render();
|
scripting::on_frontend_render();
|
||||||
}
|
}
|
||||||
|
|
||||||
setupWorldShader(entityShader, camera, settings, fogFactor);
|
|
||||||
|
|
||||||
std::array<const WeatherPreset*, 2> weatherInstances {&weather.a, &weather.b};
|
|
||||||
for (const auto& weather : weatherInstances) {
|
|
||||||
float maxIntensity = weather->fall.maxIntensity;
|
|
||||||
float zero = weather->fall.minOpacity;
|
|
||||||
float one = weather->fall.maxOpacity;
|
|
||||||
float t = (weather->intensity * (one - zero)) * maxIntensity + zero;
|
|
||||||
entityShader.uniform1i("u_alphaClip", weather->fall.opaque);
|
|
||||||
entityShader.uniform1f("u_opacity", weather->fall.opaque ? t * t : t);
|
|
||||||
if (weather->intensity > 1.e-3f && !weather->fall.texture.empty()) {
|
|
||||||
precipitation->render(camera, pause ? 0.0f : delta, *weather);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
skybox->unbind();
|
skybox->unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +247,7 @@ void WorldRenderer::renderBlockSelection() {
|
|||||||
const glm::vec3 center = glm::vec3(pos) + hitbox.center();
|
const glm::vec3 center = glm::vec3(pos) + hitbox.center();
|
||||||
const glm::vec3 size = hitbox.size();
|
const glm::vec3 size = hitbox.size();
|
||||||
lineBatch->box(
|
lineBatch->box(
|
||||||
center, size + glm::vec3(0.01), glm::vec4(0.f, 0.f, 0.f, 0.5f)
|
center, size + glm::vec3(0.01), glm::vec4(0.f, 0.f, 0.f, 1.0f)
|
||||||
);
|
);
|
||||||
if (debug) {
|
if (debug) {
|
||||||
lineBatch->line(
|
lineBatch->line(
|
||||||
@ -324,6 +339,79 @@ void WorldRenderer::renderHands(
|
|||||||
skybox->unbind();
|
skybox->unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldRenderer::generateShadowsMap(
|
||||||
|
const Camera& camera,
|
||||||
|
const DrawContext& pctx,
|
||||||
|
ShadowMap& shadowMap,
|
||||||
|
Camera& shadowCamera,
|
||||||
|
float scale
|
||||||
|
) {
|
||||||
|
auto& shadowsShader = assets.require<Shader>("shadows");
|
||||||
|
|
||||||
|
auto world = level.getWorld();
|
||||||
|
const auto& worldInfo = world->getInfo();
|
||||||
|
|
||||||
|
const auto& settings = engine.getSettings();
|
||||||
|
int resolution = shadowMap.getResolution();
|
||||||
|
int quality = settings.graphics.shadowsQuality.get();
|
||||||
|
float shadowMapScale = 0.32f / (1 << glm::max(0, quality)) * scale;
|
||||||
|
float shadowMapSize = resolution * shadowMapScale;
|
||||||
|
|
||||||
|
glm::vec3 basePos = glm::floor(camera.position / 4.0f) * 4.0f;
|
||||||
|
glm::vec3 prevPos = shadowCamera.position;
|
||||||
|
shadowCamera = Camera(
|
||||||
|
glm::distance2(prevPos, basePos) > 25.0f ? basePos : prevPos,
|
||||||
|
shadowMapSize
|
||||||
|
);
|
||||||
|
shadowCamera.near = 0.1f;
|
||||||
|
shadowCamera.far = 1000.0f;
|
||||||
|
shadowCamera.perspective = false;
|
||||||
|
shadowCamera.setAspectRatio(1.0f);
|
||||||
|
|
||||||
|
float t = worldInfo.daytime - 0.25f;
|
||||||
|
if (t < 0.0f) {
|
||||||
|
t += 1.0f;
|
||||||
|
}
|
||||||
|
t = fmod(t, 0.5f);
|
||||||
|
|
||||||
|
float sunCycleStep = 1.0f / 500.0f;
|
||||||
|
float sunAngle = glm::radians(
|
||||||
|
90.0f -
|
||||||
|
((static_cast<int>(t / sunCycleStep)) * sunCycleStep + 0.25f) * 360.0f
|
||||||
|
);
|
||||||
|
float sunAltitude = glm::pi<float>() * 0.25f;
|
||||||
|
shadowCamera.rotate(
|
||||||
|
-glm::cos(sunAngle + glm::pi<float>() * 0.5f) * sunAltitude,
|
||||||
|
sunAngle - glm::pi<float>() * 0.5f,
|
||||||
|
glm::radians(0.0f)
|
||||||
|
);
|
||||||
|
|
||||||
|
shadowCamera.position -= shadowCamera.front * 500.0f;
|
||||||
|
shadowCamera.position += shadowCamera.up * 0.0f;
|
||||||
|
shadowCamera.position += camera.front * 0.0f;
|
||||||
|
|
||||||
|
auto view = shadowCamera.getView();
|
||||||
|
|
||||||
|
auto currentPos = shadowCamera.position;
|
||||||
|
auto topRight = shadowCamera.right + shadowCamera.up;
|
||||||
|
auto min = view * glm::vec4(currentPos - topRight * shadowMapSize * 0.5f, 1.0f);
|
||||||
|
auto max = view * glm::vec4(currentPos + topRight * shadowMapSize * 0.5f, 1.0f);
|
||||||
|
|
||||||
|
shadowCamera.setProjection(glm::ortho(min.x, max.x, min.y, max.y, 0.1f, 1000.0f));
|
||||||
|
|
||||||
|
{
|
||||||
|
frustumCulling->update(shadowCamera.getProjView());
|
||||||
|
auto sctx = pctx.sub();
|
||||||
|
sctx.setDepthTest(true);
|
||||||
|
sctx.setCullFace(true);
|
||||||
|
sctx.setViewport({resolution, resolution});
|
||||||
|
shadowMap.bind();
|
||||||
|
setupWorldShader(shadowsShader, shadowCamera, settings, 0.0f);
|
||||||
|
chunks->drawChunksShadowsPass(shadowCamera, shadowsShader);
|
||||||
|
shadowMap.unbind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WorldRenderer::draw(
|
void WorldRenderer::draw(
|
||||||
const DrawContext& pctx,
|
const DrawContext& pctx,
|
||||||
Camera& camera,
|
Camera& camera,
|
||||||
@ -332,6 +420,7 @@ void WorldRenderer::draw(
|
|||||||
float uiDelta,
|
float uiDelta,
|
||||||
PostProcessing& postProcessing
|
PostProcessing& postProcessing
|
||||||
) {
|
) {
|
||||||
|
// TODO: REFACTOR WHOLE RENDER ENGINE
|
||||||
float delta = uiDelta * !pause;
|
float delta = uiDelta * !pause;
|
||||||
timer += delta;
|
timer += delta;
|
||||||
weather.update(delta);
|
weather.update(delta);
|
||||||
@ -341,29 +430,75 @@ void WorldRenderer::draw(
|
|||||||
const auto& vp = pctx.getViewport();
|
const auto& vp = pctx.getViewport();
|
||||||
camera.setAspectRatio(vp.x / static_cast<float>(vp.y));
|
camera.setAspectRatio(vp.x / static_cast<float>(vp.y));
|
||||||
|
|
||||||
|
auto& mainShader = assets.require<Shader>("main");
|
||||||
|
auto& entityShader = assets.require<Shader>("entity");
|
||||||
|
auto& deferredShader = assets.require<PostEffect>("deferred_lighting").getShader();
|
||||||
const auto& settings = engine.getSettings();
|
const auto& settings = engine.getSettings();
|
||||||
|
|
||||||
|
gbufferPipeline = settings.graphics.advancedRender.get();
|
||||||
|
int shadowsQuality = settings.graphics.shadowsQuality.get() * gbufferPipeline;
|
||||||
|
int resolution = MIN_SHADOW_MAP_RES << shadowsQuality;
|
||||||
|
if (shadowsQuality > 0 && !shadows) {
|
||||||
|
shadowMap = std::make_unique<ShadowMap>(resolution);
|
||||||
|
wideShadowMap = std::make_unique<ShadowMap>(resolution);
|
||||||
|
shadows = true;
|
||||||
|
} else if (shadowsQuality == 0 && shadows) {
|
||||||
|
shadowMap.reset();
|
||||||
|
wideShadowMap.reset();
|
||||||
|
shadows = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompileTimeShaderSettings currentSettings {
|
||||||
|
gbufferPipeline,
|
||||||
|
shadows,
|
||||||
|
settings.graphics.ssao.get() && gbufferPipeline
|
||||||
|
};
|
||||||
|
if (
|
||||||
|
prevCTShaderSettings.advancedRender != currentSettings.advancedRender ||
|
||||||
|
prevCTShaderSettings.shadows != currentSettings.shadows ||
|
||||||
|
prevCTShaderSettings.ssao != currentSettings.ssao
|
||||||
|
) {
|
||||||
|
Shader::preprocessor->setDefined("ENABLE_SHADOWS", currentSettings.shadows);
|
||||||
|
Shader::preprocessor->setDefined("ENABLE_SSAO", currentSettings.ssao);
|
||||||
|
Shader::preprocessor->setDefined("ADVANCED_RENDER", currentSettings.advancedRender);
|
||||||
|
mainShader.recompile();
|
||||||
|
entityShader.recompile();
|
||||||
|
deferredShader.recompile();
|
||||||
|
prevCTShaderSettings = currentSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shadows && shadowMap->getResolution() != resolution) {
|
||||||
|
shadowMap = std::make_unique<ShadowMap>(resolution);
|
||||||
|
wideShadowMap = std::make_unique<ShadowMap>(resolution);
|
||||||
|
}
|
||||||
|
|
||||||
const auto& worldInfo = world->getInfo();
|
const auto& worldInfo = world->getInfo();
|
||||||
|
|
||||||
float sqrtT = glm::sqrt(weather.t);
|
float clouds = weather.clouds();
|
||||||
float clouds = weather.b.clouds * sqrtT +
|
|
||||||
weather.a.clouds * (1.0f - sqrtT);
|
|
||||||
clouds = glm::max(worldInfo.fog, clouds);
|
clouds = glm::max(worldInfo.fog, clouds);
|
||||||
float mie = 1.0f + glm::max(worldInfo.fog, clouds * 0.5f) * 2.0f;
|
float mie = 1.0f + glm::max(worldInfo.fog, clouds * 0.5f) * 2.0f;
|
||||||
|
|
||||||
skybox->refresh(pctx, worldInfo.daytime, mie, 4);
|
skybox->refresh(pctx, worldInfo.daytime, mie, 4);
|
||||||
|
|
||||||
const auto& assets = *engine.getAssets();
|
chunks->update();
|
||||||
auto& linesShader = assets.require<Shader>("lines");
|
|
||||||
|
|
||||||
|
static int frameid = 0;
|
||||||
|
if (shadows) {
|
||||||
|
if (frameid % 2 == 0) {
|
||||||
|
generateShadowsMap(camera, pctx, *shadowMap, shadowCamera, 1.0f);
|
||||||
|
} else {
|
||||||
|
generateShadowsMap(camera, pctx, *wideShadowMap, wideShadowCamera, 3.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frameid++;
|
||||||
|
|
||||||
|
auto& linesShader = assets.require<Shader>("lines");
|
||||||
/* World render scope with diegetic HUD included */ {
|
/* World render scope with diegetic HUD included */ {
|
||||||
DrawContext wctx = pctx.sub();
|
DrawContext wctx = pctx.sub();
|
||||||
postProcessing.use(wctx);
|
postProcessing.use(wctx, gbufferPipeline);
|
||||||
|
|
||||||
display::clearDepth();
|
display::clearDepth();
|
||||||
|
|
||||||
// Drawing background sky plane
|
|
||||||
skybox->draw(pctx, camera, assets, worldInfo.daytime, clouds);
|
|
||||||
|
|
||||||
/* Actually world render with depth buffer on */ {
|
/* Actually world render with depth buffer on */ {
|
||||||
DrawContext ctx = wctx.sub();
|
DrawContext ctx = wctx.sub();
|
||||||
ctx.setDepthTest(true);
|
ctx.setDepthTest(true);
|
||||||
@ -376,19 +511,59 @@ void WorldRenderer::draw(
|
|||||||
ctx, camera, *lineBatch, linesShader, showChunkBorders
|
ctx, camera, *lineBatch, linesShader, showChunkBorders
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (player.currentCamera == player.fpCamera) {
|
|
||||||
renderHands(camera, delta);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
texts->render(pctx, camera, settings, hudVisible, true);
|
||||||
|
}
|
||||||
|
skybox->bind();
|
||||||
|
float fogFactor =
|
||||||
|
15.0f / static_cast<float>(settings.chunks.loadDistance.get() - 2);
|
||||||
|
if (gbufferPipeline) {
|
||||||
|
deferredShader.use();
|
||||||
|
setupWorldShader(deferredShader, camera, settings, fogFactor);
|
||||||
|
postProcessing.renderDeferredShading(pctx, assets, timer, camera);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
DrawContext ctx = wctx.sub();
|
DrawContext ctx = pctx.sub();
|
||||||
texts->render(ctx, camera, settings, hudVisible, true);
|
ctx.setDepthTest(true);
|
||||||
|
if (gbufferPipeline) {
|
||||||
|
postProcessing.bindDepthBuffer();
|
||||||
|
} else {
|
||||||
|
postProcessing.getFramebuffer()->bind();
|
||||||
|
}
|
||||||
|
// Drawing background sky plane
|
||||||
|
skybox->draw(ctx, camera, assets, worldInfo.daytime, clouds);
|
||||||
|
|
||||||
|
entityShader.use();
|
||||||
|
setupWorldShader(entityShader, camera, settings, fogFactor);
|
||||||
|
|
||||||
|
std::array<const WeatherPreset*, 2> weatherInstances {&weather.a, &weather.b};
|
||||||
|
for (const auto& weather : weatherInstances) {
|
||||||
|
float maxIntensity = weather->fall.maxIntensity;
|
||||||
|
float zero = weather->fall.minOpacity;
|
||||||
|
float one = weather->fall.maxOpacity;
|
||||||
|
float t = (weather->intensity * (one - zero)) * maxIntensity + zero;
|
||||||
|
entityShader.uniform1i("u_alphaClip", weather->fall.opaque);
|
||||||
|
entityShader.uniform1f("u_opacity", weather->fall.opaque ? t * t : t);
|
||||||
|
if (weather->intensity > 1.e-3f && !weather->fall.texture.empty()) {
|
||||||
|
precipitation->render(camera, pause ? 0.0f : delta, *weather);
|
||||||
}
|
}
|
||||||
renderBlockOverlay(wctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
postProcessing.render(pctx, assets, timer);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
postProcessing.render(pctx, assets, timer, camera);
|
||||||
|
|
||||||
|
skybox->unbind();
|
||||||
|
if (player.currentCamera == player.fpCamera) {
|
||||||
|
DrawContext ctx = pctx.sub();
|
||||||
|
ctx.setDepthTest(true);
|
||||||
|
ctx.setCullFace(true);
|
||||||
|
renderHands(camera, delta);
|
||||||
|
}
|
||||||
|
renderBlockOverlay(pctx);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) {
|
void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) {
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "presets/WeatherPreset.hpp"
|
#include "presets/WeatherPreset.hpp"
|
||||||
#include "world/Weather.hpp"
|
#include "world/Weather.hpp"
|
||||||
|
#include "window/Camera.hpp"
|
||||||
|
|
||||||
class Level;
|
class Level;
|
||||||
class Player;
|
class Player;
|
||||||
@ -30,8 +31,16 @@ class PostProcessing;
|
|||||||
class DrawContext;
|
class DrawContext;
|
||||||
class ModelBatch;
|
class ModelBatch;
|
||||||
class Assets;
|
class Assets;
|
||||||
|
class ShadowMap;
|
||||||
|
class GBuffer;
|
||||||
struct EngineSettings;
|
struct EngineSettings;
|
||||||
|
|
||||||
|
struct CompileTimeShaderSettings {
|
||||||
|
bool advancedRender = false;
|
||||||
|
bool shadows = false;
|
||||||
|
bool ssao = false;
|
||||||
|
};
|
||||||
|
|
||||||
class WorldRenderer {
|
class WorldRenderer {
|
||||||
Engine& engine;
|
Engine& engine;
|
||||||
const Level& level;
|
const Level& level;
|
||||||
@ -44,11 +53,19 @@ class WorldRenderer {
|
|||||||
std::unique_ptr<GuidesRenderer> guides;
|
std::unique_ptr<GuidesRenderer> guides;
|
||||||
std::unique_ptr<ChunksRenderer> chunks;
|
std::unique_ptr<ChunksRenderer> chunks;
|
||||||
std::unique_ptr<Skybox> skybox;
|
std::unique_ptr<Skybox> skybox;
|
||||||
|
std::unique_ptr<ShadowMap> shadowMap;
|
||||||
|
std::unique_ptr<ShadowMap> wideShadowMap;
|
||||||
Weather weather {};
|
Weather weather {};
|
||||||
|
Camera shadowCamera;
|
||||||
|
Camera wideShadowCamera;
|
||||||
|
|
||||||
float timer = 0.0f;
|
float timer = 0.0f;
|
||||||
bool debug = false;
|
bool debug = false;
|
||||||
bool lightsDebug = false;
|
bool lightsDebug = false;
|
||||||
|
bool gbufferPipeline = false;
|
||||||
|
bool shadows = false;
|
||||||
|
|
||||||
|
CompileTimeShaderSettings prevCTShaderSettings {};
|
||||||
|
|
||||||
/// @brief Render block selection lines
|
/// @brief Render block selection lines
|
||||||
void renderBlockSelection();
|
void renderBlockSelection();
|
||||||
@ -70,6 +87,14 @@ class WorldRenderer {
|
|||||||
const EngineSettings& settings,
|
const EngineSettings& settings,
|
||||||
float fogFactor
|
float fogFactor
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void generateShadowsMap(
|
||||||
|
const Camera& camera,
|
||||||
|
const DrawContext& pctx,
|
||||||
|
ShadowMap& shadowMap,
|
||||||
|
Camera& shadowCamera,
|
||||||
|
float scale
|
||||||
|
);
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<ParticlesRenderer> particles;
|
std::unique_ptr<ParticlesRenderer> particles;
|
||||||
std::unique_ptr<TextsRenderer> texts;
|
std::unique_ptr<TextsRenderer> texts;
|
||||||
|
|||||||
@ -14,11 +14,13 @@ struct ChunkVertex {
|
|||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
glm::vec2 uv;
|
glm::vec2 uv;
|
||||||
std::array<uint8_t, 4> color;
|
std::array<uint8_t, 4> color;
|
||||||
|
std::array<uint8_t, 4> normal;
|
||||||
|
|
||||||
static constexpr VertexAttribute ATTRIBUTES[] = {
|
static constexpr VertexAttribute ATTRIBUTES[] = {
|
||||||
{VertexAttribute::Type::FLOAT, false, 3},
|
{VertexAttribute::Type::FLOAT, false, 3},
|
||||||
{VertexAttribute::Type::FLOAT, false, 2},
|
{VertexAttribute::Type::FLOAT, false, 2},
|
||||||
{VertexAttribute::Type::UNSIGNED_BYTE, true, 4},
|
{VertexAttribute::Type::UNSIGNED_BYTE, true, 4},
|
||||||
|
{VertexAttribute::Type::UNSIGNED_BYTE, true, 4},
|
||||||
{{}, 0}};
|
{{}, 0}};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -38,6 +38,8 @@ GUI::GUI(Engine& engine)
|
|||||||
std::make_unique<Camera>(glm::vec3(), engine.getWindow().getSize().y);
|
std::make_unique<Camera>(glm::vec3(), engine.getWindow().getSize().y);
|
||||||
uicamera->perspective = false;
|
uicamera->perspective = false;
|
||||||
uicamera->flipped = true;
|
uicamera->flipped = true;
|
||||||
|
uicamera->near = -1.0f;
|
||||||
|
uicamera->far = 1.0f;
|
||||||
|
|
||||||
menu = std::make_shared<Menu>(*this);
|
menu = std::make_shared<Menu>(*this);
|
||||||
menu->setId("menu");
|
menu->setId("menu");
|
||||||
|
|||||||
@ -74,6 +74,9 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
|||||||
builder.add("chunk-max-vertices", &settings.graphics.chunkMaxVertices);
|
builder.add("chunk-max-vertices", &settings.graphics.chunkMaxVertices);
|
||||||
builder.add("chunk-max-vertices-dense", &settings.graphics.chunkMaxVerticesDense);
|
builder.add("chunk-max-vertices-dense", &settings.graphics.chunkMaxVerticesDense);
|
||||||
builder.add("chunk-max-renderers", &settings.graphics.chunkMaxRenderers);
|
builder.add("chunk-max-renderers", &settings.graphics.chunkMaxRenderers);
|
||||||
|
builder.add("advanced-render", &settings.graphics.advancedRender);
|
||||||
|
builder.add("ssao", &settings.graphics.ssao);
|
||||||
|
builder.add("shadows-quality", &settings.graphics.shadowsQuality);
|
||||||
|
|
||||||
builder.section("ui");
|
builder.section("ui");
|
||||||
builder.add("language", &settings.ui.language);
|
builder.add("language", &settings.ui.language);
|
||||||
|
|||||||
@ -17,7 +17,10 @@ static int l_set_effect(lua::State* L) {
|
|||||||
size_t index = static_cast<size_t>(lua::tointeger(L, 1));
|
size_t index = static_cast<size_t>(lua::tointeger(L, 1));
|
||||||
auto name = lua::require_string(L, 2);
|
auto name = lua::require_string(L, 2);
|
||||||
auto& assets = *engine->getAssets();
|
auto& assets = *engine->getAssets();
|
||||||
auto effect = std::make_shared<PostEffect>(assets.require<PostEffect>(name));
|
auto effect = assets.getShared<PostEffect>(name);
|
||||||
|
if (effect == nullptr) {
|
||||||
|
throw std::runtime_error(std::string("post-effect '") + name + "' not found");
|
||||||
|
}
|
||||||
post_processing->setEffect(index, std::move(effect));
|
post_processing->setEffect(index, std::move(effect));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -57,6 +60,22 @@ static int l_set_params(lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_set_array(lua::State* L) {
|
||||||
|
size_t index = static_cast<size_t>(lua::tointeger(L, 1));
|
||||||
|
auto key = lua::require_string(L, 2);
|
||||||
|
auto data = lua::require_lstring(L, 3);
|
||||||
|
auto effect = post_processing->getEffect(index);
|
||||||
|
if (effect == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
std::vector<ubyte> buffer(
|
||||||
|
reinterpret_cast<const ubyte*>(data.data()),
|
||||||
|
reinterpret_cast<const ubyte*>(data.data() + data.size())
|
||||||
|
);
|
||||||
|
effect->setArray(key, std::move(buffer));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const luaL_Reg posteffectslib[] = {
|
const luaL_Reg posteffectslib[] = {
|
||||||
{"index", lua::wrap<l_index>},
|
{"index", lua::wrap<l_index>},
|
||||||
{"set_effect", lua::wrap<l_set_effect>},
|
{"set_effect", lua::wrap<l_set_effect>},
|
||||||
@ -64,5 +83,6 @@ const luaL_Reg posteffectslib[] = {
|
|||||||
{"set_intensity", lua::wrap<l_set_intensity>},
|
{"set_intensity", lua::wrap<l_set_intensity>},
|
||||||
{"is_active", lua::wrap<l_is_active>},
|
{"is_active", lua::wrap<l_is_active>},
|
||||||
{"set_params", lua::wrap<l_set_params>},
|
{"set_params", lua::wrap<l_set_params>},
|
||||||
|
{"set_array", lua::wrap<l_set_array>},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include "libs/api_lua.hpp"
|
#include "libs/api_lua.hpp"
|
||||||
#include "debug/Logger.hpp"
|
#include "debug/Logger.hpp"
|
||||||
@ -149,6 +150,15 @@ int l_debug_print(lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
std::normal_distribution<double> randomFloats(0.0f, 1.0f);
|
||||||
|
std::default_random_engine generator;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_math_normal_random(lua::State* L) {
|
||||||
|
return lua::pushnumber(L, randomFloats(generator));
|
||||||
|
}
|
||||||
|
|
||||||
void initialize_libs_extends(lua::State* L) {
|
void initialize_libs_extends(lua::State* L) {
|
||||||
if (lua::getglobal(L, "debug")) {
|
if (lua::getglobal(L, "debug")) {
|
||||||
lua::pushcfunction(L, lua::wrap<l_debug_error>);
|
lua::pushcfunction(L, lua::wrap<l_debug_error>);
|
||||||
@ -163,6 +173,12 @@ void initialize_libs_extends(lua::State* L) {
|
|||||||
lua::pushcfunction(L, lua::wrap<l_debug_print>);
|
lua::pushcfunction(L, lua::wrap<l_debug_print>);
|
||||||
lua::setfield(L, "print");
|
lua::setfield(L, "print");
|
||||||
|
|
||||||
|
lua::pop(L);
|
||||||
|
}
|
||||||
|
if (lua::getglobal(L, "math")) {
|
||||||
|
lua::pushcfunction(L, lua::wrap<l_math_normal_random>);
|
||||||
|
lua::setfield(L, "normal_random");
|
||||||
|
|
||||||
lua::pop(L);
|
lua::pop(L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,6 +75,12 @@ struct GraphicsSettings {
|
|||||||
IntegerSetting chunkMaxVerticesDense {800'000, 0, 8'000'000};
|
IntegerSetting chunkMaxVerticesDense {800'000, 0, 8'000'000};
|
||||||
/// @brief Limit of chunk renderers count
|
/// @brief Limit of chunk renderers count
|
||||||
IntegerSetting chunkMaxRenderers {6, -4, 32};
|
IntegerSetting chunkMaxRenderers {6, -4, 32};
|
||||||
|
/// @brief Advanced render pipeline
|
||||||
|
FlagSetting advancedRender {true};
|
||||||
|
/// @brief Screen space ambient occlusion
|
||||||
|
FlagSetting ssao {true};
|
||||||
|
/// @brief Shadows quality
|
||||||
|
IntegerSetting shadowsQuality {0, 0, 3};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DebugSettings {
|
struct DebugSettings {
|
||||||
|
|||||||
@ -28,12 +28,15 @@ void Camera::rotate(float x, float y, float z) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 Camera::getProjection() const {
|
glm::mat4 Camera::getProjection() const {
|
||||||
|
if (projset) {
|
||||||
|
return projection;
|
||||||
|
}
|
||||||
if (perspective) {
|
if (perspective) {
|
||||||
return glm::perspective(fov * zoom, ar, near, far);
|
return glm::perspective(fov * zoom, ar, near, far);
|
||||||
} else if (flipped) {
|
} else if (flipped) {
|
||||||
return glm::ortho(0.0f, fov * ar, fov, 0.0f);
|
return glm::ortho(0.0f, fov * ar, fov, 0.0f, near, far);
|
||||||
} else {
|
} else {
|
||||||
return glm::ortho(0.0f, fov * ar, 0.0f, fov);
|
return glm::ortho(0.0f, fov * ar, 0.0f, fov, near, far);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +48,8 @@ glm::mat4 Camera::getView(bool pos) const {
|
|||||||
if (perspective) {
|
if (perspective) {
|
||||||
return glm::lookAt(camera_pos, camera_pos + front, up);
|
return glm::lookAt(camera_pos, camera_pos + front, up);
|
||||||
} else {
|
} else {
|
||||||
return glm::translate(glm::mat4(1.0f), camera_pos);
|
return glm::lookAt(camera_pos, camera_pos + front, up);
|
||||||
|
//return glm::translate(glm::mat4(1.0f), camera_pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +65,11 @@ float Camera::getFov() const {
|
|||||||
return fov;
|
return fov;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Camera::setProjection(const glm::mat4& matrix) {
|
||||||
|
projection = matrix;
|
||||||
|
projset = true;
|
||||||
|
}
|
||||||
|
|
||||||
float Camera::getAspectRatio() const {
|
float Camera::getAspectRatio() const {
|
||||||
return ar;
|
return ar;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,10 @@ public:
|
|||||||
bool perspective = true;
|
bool perspective = true;
|
||||||
bool flipped = false;
|
bool flipped = false;
|
||||||
float near = 0.05f;
|
float near = 0.05f;
|
||||||
float far = 1500.0f;
|
float far = 1e4f;
|
||||||
|
|
||||||
|
bool projset = false;
|
||||||
|
glm::mat4 projection;
|
||||||
|
|
||||||
Camera() {
|
Camera() {
|
||||||
updateVectors();
|
updateVectors();
|
||||||
@ -36,6 +39,8 @@ public:
|
|||||||
void setFov(float fov);
|
void setFov(float fov);
|
||||||
float getFov() const;
|
float getFov() const;
|
||||||
|
|
||||||
|
void setProjection(const glm::mat4& matrix);
|
||||||
|
|
||||||
float getAspectRatio() const;
|
float getAspectRatio() const;
|
||||||
void setAspectRatio(float ar);
|
void setAspectRatio(float ar);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -519,6 +519,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ImageData> takeScreenshot() override {
|
std::unique_ptr<ImageData> takeScreenshot() override {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
auto data = std::make_unique<ubyte[]>(size.x * size.y * 3);
|
auto data = std::make_unique<ubyte[]>(size.x * size.y * 3);
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||||
glReadPixels(0, 0, size.x, size.y, GL_RGB, GL_UNSIGNED_BYTE, data.get());
|
glReadPixels(0, 0, size.x, size.y, GL_RGB, GL_UNSIGNED_BYTE, data.get());
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "presets/WeatherPreset.hpp"
|
#include "presets/WeatherPreset.hpp"
|
||||||
@ -45,6 +46,11 @@ struct Weather : Serializable {
|
|||||||
return b.thunderRate * t + a.thunderRate * (1.0f - t);
|
return b.thunderRate * t + a.thunderRate * (1.0f - t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float clouds() const {
|
||||||
|
float sqrtT = glm::sqrt(t);
|
||||||
|
return b.clouds * sqrtT + a.clouds * (1.0f - sqrtT);
|
||||||
|
}
|
||||||
|
|
||||||
dv::value serialize() const override;
|
dv::value serialize() const override;
|
||||||
void deserialize(const dv::value& src) override;
|
void deserialize(const dv::value& src) override;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user