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"
|
||||
],
|
||||
"emission": [13, 13, 12],
|
||||
"emission": [13, 10, 2],
|
||||
"model": "aabb",
|
||||
"hitbox": [0.4375, 0.0, 0.4375, 0.125, 0.5, 0.125],
|
||||
"light-passing": true,
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
],
|
||||
"textures": [
|
||||
"misc/moon",
|
||||
"misc/moon_flare",
|
||||
"misc/sun",
|
||||
"gui/crosshair"
|
||||
]
|
||||
|
||||
@ -42,4 +42,7 @@ function on_open()
|
||||
create_setting("graphics.gamma", "Gamma", 0.05, "", "graphics.gamma.tooltip")
|
||||
create_checkbox("graphics.backlight", "Backlight", "graphics.backlight.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
|
||||
|
||||
@ -6,10 +6,19 @@
|
||||
"lines",
|
||||
"entity",
|
||||
"background",
|
||||
"skybox_gen"
|
||||
"skybox_gen",
|
||||
"shadows"
|
||||
],
|
||||
"post-effects": [
|
||||
"default"
|
||||
"default",
|
||||
{
|
||||
"name": "ssao",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "deferred_lighting",
|
||||
"advanced": true
|
||||
}
|
||||
],
|
||||
"textures": [
|
||||
"gui/menubg",
|
||||
|
||||
@ -4,5 +4,8 @@
|
||||
"third-person-front",
|
||||
"third-person-back",
|
||||
"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()
|
||||
input.add_callback("player.pick", function ()
|
||||
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)
|
||||
end
|
||||
end)
|
||||
|
||||
configure_SSAO()
|
||||
end
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
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(){
|
||||
vec3 dir = normalize(v_coord);
|
||||
f_color = texture(u_cubemap, dir);
|
||||
vec3 dir = normalize(v_coord) * 1e6;
|
||||
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;
|
||||
|
||||
void main(){
|
||||
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);
|
||||
v_coord = (vec4(v_position * vec2(u_ar, 1.0f) * u_zoom, -1.0, 1.0) * u_view).xyz;
|
||||
gl_Position = vec4(v_position, 1.0 - 1e-6, 1.0);
|
||||
}
|
||||
|
||||
@ -2,8 +2,22 @@ in vec2 v_uv;
|
||||
out vec4 f_color;
|
||||
|
||||
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 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__>
|
||||
|
||||
|
||||
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 vec3 a_dir;
|
||||
in float a_fog;
|
||||
out vec4 f_color;
|
||||
in vec3 a_normal;
|
||||
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 samplerCube u_cubemap;
|
||||
uniform samplerCube u_skybox;
|
||||
uniform vec3 u_fogColor;
|
||||
uniform float u_fogFactor;
|
||||
uniform float u_fogCurve;
|
||||
uniform bool u_alphaClip;
|
||||
uniform vec3 u_sunDir;
|
||||
|
||||
#include <shadows>
|
||||
|
||||
void main() {
|
||||
vec3 fogColor = texture(u_cubemap, a_dir).rgb;
|
||||
vec4 tex_color = texture(u_texture0, a_texCoord);
|
||||
float alpha = a_color.a * tex_color.a;
|
||||
vec4 texColor = texture(u_texture0, a_texCoord);
|
||||
float alpha = a_color.a * texColor.a;
|
||||
// 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;
|
||||
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_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 = 2) in vec3 v_color;
|
||||
layout (location = 3) in vec4 v_light;
|
||||
layout (location = 4) in vec4 v_normal;
|
||||
|
||||
out vec4 a_color;
|
||||
out vec2 a_texCoord;
|
||||
out float a_distance;
|
||||
out float a_fog;
|
||||
out vec2 a_texCoord;
|
||||
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_proj;
|
||||
@ -16,36 +23,40 @@ uniform mat4 u_view;
|
||||
uniform vec3 u_cameraPos;
|
||||
uniform float u_gamma;
|
||||
uniform float u_opacity;
|
||||
uniform float u_fogFactor;
|
||||
uniform float u_fogCurve;
|
||||
uniform float u_weatherFogOpacity;
|
||||
uniform float u_weatherFogDencity;
|
||||
uniform float u_weatherFogCurve;
|
||||
uniform samplerCube u_cubemap;
|
||||
uniform float u_timer;
|
||||
uniform samplerCube u_skybox;
|
||||
|
||||
uniform vec3 u_torchlightColor;
|
||||
uniform float u_torchlightDistance;
|
||||
|
||||
#include <lighting>
|
||||
#include <fog>
|
||||
|
||||
void main() {
|
||||
vec4 modelpos = u_model * vec4(v_position, 1.0);
|
||||
vec3 pos3d = modelpos.xyz - u_cameraPos;
|
||||
modelpos.xyz = apply_planet_curvature(modelpos.xyz, pos3d);
|
||||
a_modelpos = u_model * vec4(v_position, 1.0);
|
||||
vec3 pos3d = a_modelpos.xyz - u_cameraPos;
|
||||
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;
|
||||
float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) /
|
||||
u_torchlightDistance);
|
||||
float torchlight = calc_torch_light(a_realnormal, a_modelpos.xyz);
|
||||
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_dir = modelpos.xyz - u_cameraPos;
|
||||
vec3 skyLightColor = pick_sky_color(u_cubemap);
|
||||
a_color.rgb = max(a_color.rgb, skyLightColor.rgb*v_light.a) * v_color;
|
||||
a_dir = a_modelpos.xyz - u_cameraPos;
|
||||
vec3 skyLightColor = pick_sky_color(u_skybox);
|
||||
a_color.rgb = max(a_color.rgb, skyLightColor.rgb * v_light.a) * v_color;
|
||||
a_color.a = u_opacity;
|
||||
|
||||
float dist = length(u_view * u_model * vec4(pos3d * FOG_POS_SCALE, 0.0));
|
||||
float depth = (dist / 256.0);
|
||||
a_fog = min(1.0, max(pow(depth * u_fogFactor, u_fogCurve),
|
||||
min(pow(depth * u_weatherFogDencity, u_weatherFogCurve), u_weatherFogOpacity)));
|
||||
gl_Position = u_proj * u_view * modelpos;
|
||||
mat4 viewmodel = u_view * u_model;
|
||||
a_distance = length(viewmodel * vec4(pos3d, 0.0));
|
||||
a_fog = calc_fog(length(viewmodel * vec4(pos3d * FOG_POS_SCALE, 0.0)) / 256.0);
|
||||
a_emission = v_normal.w;
|
||||
|
||||
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;
|
||||
in vec2 a_texCoord;
|
||||
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 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 samplerCube u_cubemap;
|
||||
uniform samplerCube u_skybox;
|
||||
uniform vec3 u_sunDir;
|
||||
|
||||
// flags
|
||||
uniform bool u_alphaClip;
|
||||
uniform bool u_debugLights;
|
||||
uniform bool u_debugNormals;
|
||||
|
||||
#include <shadows>
|
||||
|
||||
void main() {
|
||||
vec3 fogColor = texture(u_cubemap, a_dir).rgb;
|
||||
vec4 tex_color = texture(u_texture0, a_texCoord);
|
||||
if (u_debugLights)
|
||||
tex_color.rgb = vec3(1.0);
|
||||
float alpha = a_color.a * tex_color.a;
|
||||
vec4 texColor = texture(u_texture0, a_texCoord);
|
||||
float alpha = texColor.a;
|
||||
if (u_alphaClip) {
|
||||
if (alpha < 0.2f)
|
||||
discard;
|
||||
@ -23,6 +37,20 @@ void main() {
|
||||
if (alpha < 0.002f)
|
||||
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_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 = 1) in vec2 v_texCoord;
|
||||
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_fog;
|
||||
out vec2 a_texCoord;
|
||||
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_proj;
|
||||
uniform mat4 u_view;
|
||||
uniform vec3 u_cameraPos;
|
||||
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 samplerCube u_cubemap;
|
||||
uniform samplerCube u_skybox;
|
||||
|
||||
uniform vec3 u_torchlightColor;
|
||||
uniform float u_torchlightDistance;
|
||||
|
||||
#include <lighting>
|
||||
#include <fog>
|
||||
|
||||
void main() {
|
||||
vec4 modelpos = u_model * vec4(v_position, 1.0f);
|
||||
vec3 pos3d = modelpos.xyz-u_cameraPos;
|
||||
modelpos.xyz = apply_planet_curvature(modelpos.xyz, pos3d);
|
||||
a_modelpos = u_model * vec4(v_position, 1.0f);
|
||||
vec3 pos3d = a_modelpos.xyz - u_cameraPos;
|
||||
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;
|
||||
float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) /
|
||||
u_torchlightDistance);
|
||||
light += torchlight * u_torchlightColor;
|
||||
a_color = vec4(pow(light, vec3(u_gamma)),1.0f);
|
||||
float torchlight = calc_torch_light(a_realnormal, a_modelpos.xyz);
|
||||
a_torchLight = vec4(pow(light + torchlight * u_torchlightColor, vec3(u_gamma)), 1.0f);
|
||||
|
||||
a_texCoord = v_texCoord;
|
||||
|
||||
a_dir = modelpos.xyz - u_cameraPos;
|
||||
vec3 skyLightColor = pick_sky_color(u_cubemap);
|
||||
a_color.rgb = max(a_color.rgb, skyLightColor.rgb*v_light.a);
|
||||
a_dir = a_modelpos.xyz - u_cameraPos;
|
||||
vec3 skyLightColor = pick_sky_color(u_skybox);
|
||||
a_skyLight = skyLightColor.rgb*v_light.a;
|
||||
|
||||
a_distance = length(u_view * u_model * vec4(pos3d * FOG_POS_SCALE, 0.0));
|
||||
float depth = (a_distance / 256.0);
|
||||
a_fog = min(1.0, max(pow(depth * u_fogFactor, u_fogCurve),
|
||||
min(pow(depth * u_weatherFogDencity, u_weatherFogCurve), u_weatherFogOpacity)));
|
||||
gl_Position = u_proj * u_view * modelpos;
|
||||
mat4 viewmodel = u_view * u_model;
|
||||
a_distance = length(viewmodel * vec4(pos3d, 0.0));
|
||||
a_fog = calc_fog(length(viewmodel * vec4(pos3d * FOG_POS_SCALE, 0.0)) / 256.0);
|
||||
a_emission = v_normal.w;
|
||||
|
||||
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)
|
||||
1e12f, // max dist, essentially the scene depth
|
||||
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
|
||||
PLANET_POS, // position of the planet
|
||||
PLANET_RADIUS, // radius of the planet in meters
|
||||
|
||||
@ -98,6 +98,8 @@ settings.V-Sync=Вертикальная Синхронизация
|
||||
settings.Key=Кнопка
|
||||
settings.Controls Search Mode=Поиск по привязанной кнопки управления
|
||||
settings.Limit Background FPS=Ограничить фоновую частоту кадров
|
||||
settings.Advanced render=Продвинутый рендер
|
||||
settings.Shadows quality=Качество теней
|
||||
|
||||
# Управление
|
||||
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);
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<AssetCfg> config = nullptr;
|
||||
map.at("path").get(path);
|
||||
switch (tag) {
|
||||
case AssetType::SOUND: {
|
||||
bool keepPCM = false;
|
||||
add(tag,
|
||||
path,
|
||||
name,
|
||||
std::make_shared<SoundCfg>(map.at("keep-pcm").get(keepPCM)));
|
||||
config = std::make_shared<SoundCfg>(map.at("keep-pcm").get(keepPCM));
|
||||
break;
|
||||
}
|
||||
case AssetType::ATLAS: {
|
||||
@ -164,13 +162,19 @@ void AssetsLoader::processPreload(
|
||||
if (typeName == "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;
|
||||
}
|
||||
default:
|
||||
add(tag, path, name);
|
||||
break;
|
||||
}
|
||||
add(tag, path, name, std::move(config));
|
||||
}
|
||||
|
||||
void AssetsLoader::processPreloadList(AssetType tag, const dv::value& list) {
|
||||
|
||||
@ -40,8 +40,7 @@ struct LayoutCfg : AssetCfg {
|
||||
struct SoundCfg : AssetCfg {
|
||||
bool keepPCM;
|
||||
|
||||
SoundCfg(bool keepPCM) : keepPCM(keepPCM) {
|
||||
}
|
||||
SoundCfg(bool keepPCM) : keepPCM(keepPCM) {}
|
||||
};
|
||||
|
||||
enum class AtlasType {
|
||||
@ -51,8 +50,13 @@ enum class AtlasType {
|
||||
struct AtlasCfg : AssetCfg {
|
||||
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<
|
||||
|
||||
@ -76,6 +76,14 @@ static auto process_program(const ResPaths& paths, const std::string& filename)
|
||||
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(
|
||||
AssetsLoader*,
|
||||
const ResPaths& paths,
|
||||
@ -83,21 +91,18 @@ assetload::postfunc assetload::shader(
|
||||
const std::string& name,
|
||||
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 fragmentFile = paths.find(filename + ".glslf");
|
||||
|
||||
std::string vertexSource = std::move(vertex.code);
|
||||
std::string fragmentSource = std::move(fragment.code);
|
||||
|
||||
return [=](auto assets) {
|
||||
assets->store(
|
||||
Shader::create(
|
||||
vertexFile.string(),
|
||||
fragmentFile.string(),
|
||||
vertexSource,
|
||||
fragmentSource
|
||||
{vertexFile.string(), vertex},
|
||||
{fragmentFile.string(), fragment}
|
||||
),
|
||||
name
|
||||
);
|
||||
@ -127,13 +132,16 @@ assetload::postfunc assetload::posteffect(
|
||||
|
||||
return [=](auto assets) {
|
||||
auto program = Shader::create(
|
||||
effectFile.string(),
|
||||
effectFile.string(),
|
||||
vertexSource,
|
||||
fragmentSource
|
||||
{effectFile.string(), vertexSource},
|
||||
{effectFile.string(), fragmentSource}
|
||||
);
|
||||
bool advanced = false;
|
||||
if (settings) {
|
||||
advanced = dynamic_cast<const PostEffectCfg*>(settings.get())->advanced;
|
||||
}
|
||||
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(
|
||||
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) {
|
||||
switch (type) {
|
||||
case Type::INT:
|
||||
return 0;
|
||||
case Type::FLOAT:
|
||||
return 0.0f;
|
||||
case Type::VEC2:
|
||||
@ -156,7 +166,6 @@ public:
|
||||
}
|
||||
|
||||
bool processVersionDirective() {
|
||||
parsing_warning(filename, line, "removed #version directive");
|
||||
source_line(ss, line);
|
||||
skipLine();
|
||||
return false;
|
||||
@ -183,6 +192,8 @@ public:
|
||||
|
||||
Value parseDefaultValue(Type type, const std::string& name) {
|
||||
switch (type) {
|
||||
case Type::INT:
|
||||
return static_cast<int>(parseNumber(1).asInteger());
|
||||
case Type::FLOAT:
|
||||
return static_cast<float>(parseNumber(1).asNumber());
|
||||
case Type::VEC2:
|
||||
@ -212,8 +223,22 @@ public:
|
||||
if (params.find(paramName) != params.end()) {
|
||||
throw error("duplicating param " + util::quote(paramName));
|
||||
}
|
||||
|
||||
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);
|
||||
// Parse default value
|
||||
@ -225,7 +250,7 @@ public:
|
||||
|
||||
skipLine();
|
||||
|
||||
params[paramName] = PostEffect::Param(type, std::move(defValue));
|
||||
params[paramName] = PostEffect::Param(type, std::move(defValue), array);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ public:
|
||||
|
||||
void define(const std::string& name, std::string value);
|
||||
void undefine(const std::string& name);
|
||||
void setDefined(const std::string& name, bool defined);
|
||||
void addHeader(const std::string& name, ProcessingResult header);
|
||||
|
||||
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->perspective = false;
|
||||
uicamera->flipped = true;
|
||||
uicamera->near = -1.0f;
|
||||
uicamera->far = 1.0f;
|
||||
|
||||
debugPanel = create_debug_panel(
|
||||
engine, frontend.getLevel(), player, allowDebugCheats
|
||||
|
||||
@ -22,6 +22,8 @@ MenuScreen::MenuScreen(Engine& engine) : Screen(engine) {
|
||||
uicamera =
|
||||
std::make_unique<Camera>(glm::vec3(), engine.getWindow().getSize().y);
|
||||
uicamera->perspective = false;
|
||||
uicamera->near = -1.0f;
|
||||
uicamera->far = 1.0f;
|
||||
uicamera->flipped = true;
|
||||
}
|
||||
|
||||
|
||||
@ -60,17 +60,17 @@ void Batch2D::vertex(
|
||||
index++;
|
||||
}
|
||||
|
||||
void Batch2D::texture(const Texture* new_texture){
|
||||
if (currentTexture == new_texture) {
|
||||
void Batch2D::texture(const Texture* newTexture){
|
||||
if (currentTexture == newTexture) {
|
||||
return;
|
||||
}
|
||||
flush();
|
||||
currentTexture = new_texture;
|
||||
if (new_texture == nullptr) {
|
||||
currentTexture = newTexture;
|
||||
if (newTexture == nullptr) {
|
||||
blank->bind();
|
||||
region = blank->getUVRegion();
|
||||
} else {
|
||||
new_texture->bind();
|
||||
newTexture->bind();
|
||||
region = currentTexture->getUVRegion();
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,8 +13,6 @@ namespace {
|
||||
|
||||
Batch3D::Batch3D(size_t capacity)
|
||||
: capacity(capacity) {
|
||||
|
||||
|
||||
buffer = std::make_unique<Batch3DVertex[]>(capacity);
|
||||
mesh = std::make_unique<Mesh<Batch3DVertex>>(buffer.get(), 0);
|
||||
index = 0;
|
||||
|
||||
@ -100,7 +100,7 @@ void DrawContext::setViewport(const glm::uvec2& viewport) {
|
||||
glViewport(0, 0, viewport.x, viewport.y);
|
||||
}
|
||||
|
||||
void DrawContext::setFramebuffer(Framebuffer* fbo) {
|
||||
void DrawContext::setFramebuffer(Bindable* fbo) {
|
||||
if (this->fbo == fbo)
|
||||
return;
|
||||
this->fbo = fbo;
|
||||
|
||||
@ -16,7 +16,7 @@ class DrawContext {
|
||||
glm::uvec2 viewport;
|
||||
Batch2D* g2d;
|
||||
Flushable* flushable = nullptr;
|
||||
Framebuffer* fbo = nullptr;
|
||||
Bindable* fbo = nullptr;
|
||||
bool depthMask = true;
|
||||
bool depthTest = false;
|
||||
bool cullFace = false;
|
||||
@ -37,7 +37,7 @@ public:
|
||||
[[nodiscard]] DrawContext sub(Flushable* flushable=nullptr) const;
|
||||
|
||||
void setViewport(const glm::uvec2& viewport);
|
||||
void setFramebuffer(Framebuffer* fbo);
|
||||
void setFramebuffer(Bindable* fbo);
|
||||
void setDepthMask(bool flag);
|
||||
void setDepthTest(bool flag);
|
||||
void setCullFace(bool flag);
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include "Texture.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
|
||||
static debug::Logger logger("gl-framebuffer");
|
||||
|
||||
Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture)
|
||||
: fbo(fbo), depth(depth), texture(std::move(texture))
|
||||
@ -38,12 +41,17 @@ Framebuffer::Framebuffer(uint width, uint height, bool alpha)
|
||||
|
||||
// Setup color attachment (texture)
|
||||
texture = create_texture(width, height, format);
|
||||
|
||||
|
||||
// Setup depth attachment
|
||||
glGenRenderbuffers(1, &depth);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depth);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -67,11 +75,12 @@ void Framebuffer::resize(uint width, uint height) {
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depth);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
texture = create_texture(width, height, format);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
@ -87,3 +96,7 @@ uint Framebuffer::getWidth() const {
|
||||
uint Framebuffer::getHeight() const {
|
||||
return height;
|
||||
}
|
||||
|
||||
uint Framebuffer::getFBO() const {
|
||||
return fbo;
|
||||
}
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "typedefs.hpp"
|
||||
#include "commons.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class Texture;
|
||||
|
||||
class Framebuffer {
|
||||
class Framebuffer : public Bindable {
|
||||
uint fbo;
|
||||
uint depth;
|
||||
uint width;
|
||||
@ -19,10 +20,10 @@ public:
|
||||
~Framebuffer();
|
||||
|
||||
/// @brief Use framebuffer
|
||||
void bind();
|
||||
void bind() override;
|
||||
|
||||
/// @brief Stop using framebuffer
|
||||
void unbind();
|
||||
void unbind() override;
|
||||
|
||||
/// @brief Update framebuffer texture size
|
||||
/// @param width new width
|
||||
@ -36,4 +37,6 @@ public:
|
||||
uint getWidth() const;
|
||||
/// @brief Get framebuffer height
|
||||
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 "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, Value defValue)
|
||||
: type(type), defValue(defValue), value(defValue) {
|
||||
PostEffect::Param::Param(Type type, Value defValue, bool array)
|
||||
: type(type), defValue(defValue), value(defValue), array(array) {
|
||||
}
|
||||
|
||||
PostEffect::PostEffect(
|
||||
bool advanced,
|
||||
std::shared_ptr<Shader> shader,
|
||||
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() {
|
||||
@ -23,27 +86,24 @@ Shader& PostEffect::use() {
|
||||
if (!param.dirty) {
|
||||
continue;
|
||||
}
|
||||
switch (param.type) {
|
||||
case Param::Type::FLOAT:
|
||||
shader->uniform1f(name, std::get<float>(param.value));
|
||||
break;
|
||||
case Param::Type::VEC2:
|
||||
shader->uniform2f(name, std::get<glm::vec2>(param.value));
|
||||
break;
|
||||
case Param::Type::VEC3:
|
||||
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);
|
||||
if (param.array) {
|
||||
const auto& found = arrayValues.find(name);
|
||||
if (found == arrayValues.end()) {
|
||||
continue;
|
||||
}
|
||||
apply_uniform_array(param, *shader, name, found->second);
|
||||
} else {
|
||||
apply_uniform_value(param, *shader, name);
|
||||
}
|
||||
param.dirty = false;
|
||||
}
|
||||
return *shader;
|
||||
}
|
||||
|
||||
Shader& PostEffect::getShader() {
|
||||
return *shader;
|
||||
}
|
||||
|
||||
float PostEffect::getIntensity() const {
|
||||
return intensity;
|
||||
}
|
||||
@ -66,6 +126,9 @@ void PostEffect::setParam(const std::string& name, const dv::value& value) {
|
||||
}
|
||||
auto& param = found->second;
|
||||
switch (param.type) {
|
||||
case Param::Type::INT:
|
||||
param.value = static_cast<int>(value.asInteger());
|
||||
break;
|
||||
case Param::Type::FLOAT:
|
||||
param.value = static_cast<float>(value.asNumber());
|
||||
break;
|
||||
@ -81,3 +144,20 @@ void PostEffect::setParam(const std::string& name, const dv::value& value) {
|
||||
}
|
||||
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
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <unordered_map>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "typedefs.hpp"
|
||||
#include "data/dv_fwd.hpp"
|
||||
#include "util/EnumMetadata.hpp"
|
||||
|
||||
@ -14,27 +16,30 @@ class Shader;
|
||||
class PostEffect {
|
||||
public:
|
||||
struct Param {
|
||||
enum class Type { FLOAT, VEC2, VEC3, VEC4 };
|
||||
enum class Type { INT, FLOAT, VEC2, VEC3, VEC4 };
|
||||
|
||||
VC_ENUM_METADATA(Type)
|
||||
{"int", Type::INT},
|
||||
{"float", Type::FLOAT},
|
||||
{"vec2", Type::VEC2},
|
||||
{"vec3", Type::VEC3},
|
||||
{"vec4", Type::VEC4},
|
||||
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;
|
||||
Value defValue;
|
||||
Value value;
|
||||
bool array = false;
|
||||
bool dirty = true;
|
||||
|
||||
Param();
|
||||
Param(Type type, Value defValue);
|
||||
Param(Type type, Value defValue, bool array);
|
||||
};
|
||||
|
||||
PostEffect(
|
||||
bool advanced,
|
||||
std::shared_ptr<Shader> shader,
|
||||
std::unordered_map<std::string, Param> params
|
||||
);
|
||||
@ -43,16 +48,26 @@ public:
|
||||
|
||||
Shader& use();
|
||||
|
||||
Shader& getShader();
|
||||
|
||||
float getIntensity() const;
|
||||
void setIntensity(float 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() {
|
||||
return intensity > 1e-4f;
|
||||
}
|
||||
private:
|
||||
bool advanced = false;
|
||||
std::shared_ptr<Shader> shader;
|
||||
std::unordered_map<std::string, Param> params;
|
||||
std::unordered_map<std::string, std::vector<ubyte>> arrayValues;
|
||||
float intensity = 0.0f;
|
||||
};
|
||||
|
||||
@ -1,58 +1,200 @@
|
||||
#include "PostProcessing.hpp"
|
||||
#include "Mesh.hpp"
|
||||
#include "Shader.hpp"
|
||||
#include "GBuffer.hpp"
|
||||
#include "Texture.hpp"
|
||||
#include "Framebuffer.hpp"
|
||||
#include "DrawContext.hpp"
|
||||
#include "PostEffect.hpp"
|
||||
#include "assets/Assets.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <random>
|
||||
|
||||
// TODO: REFACTOR WHOLE RENDER ENGINE
|
||||
|
||||
using namespace advanced_pipeline;
|
||||
|
||||
PostProcessing::PostProcessing(size_t effectSlotsCount)
|
||||
: effectSlots(effectSlotsCount) {
|
||||
// Fullscreen quad mesh bulding
|
||||
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}},
|
||||
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}},
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
void PostProcessing::use(DrawContext& context) {
|
||||
void PostProcessing::use(DrawContext& context, bool gbufferPipeline) {
|
||||
const auto& vp = context.getViewport();
|
||||
if (fbo) {
|
||||
fbo->resize(vp.x, vp.y);
|
||||
fboSecond->resize(vp.x, vp.y);
|
||||
|
||||
if (gbufferPipeline) {
|
||||
if (gbuffer == nullptr) {
|
||||
gbuffer = std::make_unique<GBuffer>(vp.x, vp.y);
|
||||
} else {
|
||||
gbuffer->resize(vp.x, vp.y);
|
||||
}
|
||||
context.setFramebuffer(gbuffer.get());
|
||||
} else {
|
||||
fbo = std::make_unique<Framebuffer>(vp.x, vp.y);
|
||||
fboSecond = std::make_unique<Framebuffer>(vp.x, vp.y);
|
||||
gbuffer.reset();
|
||||
refreshFbos(vp.x, vp.y);
|
||||
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();
|
||||
}
|
||||
context.setFramebuffer(fbo.get());
|
||||
}
|
||||
|
||||
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) {
|
||||
throw std::runtime_error("'use(...)' was never called");
|
||||
}
|
||||
int totalPasses = 0;
|
||||
for (const auto& effect : effectSlots) {
|
||||
totalPasses += (effect != nullptr && effect->isActive());
|
||||
totalPasses +=
|
||||
(effect != nullptr && effect->isActive() &&
|
||||
!(effect->isAdvanced() && gbuffer == nullptr));
|
||||
}
|
||||
|
||||
const auto& vp = context.getViewport();
|
||||
refreshFbos(vp.x, vp.y);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
fbo->getTexture()->bind();
|
||||
|
||||
if (totalPasses == 0) {
|
||||
// replace 'default' blit shader with glBlitFramebuffer?
|
||||
auto& effect = assets.require<PostEffect>("default");
|
||||
effect.use();
|
||||
fbo->getTexture()->bind();
|
||||
auto& shader = effect.use();
|
||||
configureEffect(
|
||||
context, effect, shader, timer, camera
|
||||
);
|
||||
quadMesh->draw();
|
||||
return;
|
||||
}
|
||||
@ -62,17 +204,26 @@ void PostProcessing::render(
|
||||
if (effect == nullptr || !effect->isActive()) {
|
||||
continue;
|
||||
}
|
||||
if (effect->isAdvanced() && gbuffer == nullptr) {
|
||||
continue;
|
||||
}
|
||||
auto& shader = effect->use();
|
||||
configureEffect(
|
||||
context,
|
||||
*effect,
|
||||
shader,
|
||||
timer,
|
||||
camera
|
||||
);
|
||||
|
||||
const auto& viewport = context.getViewport();
|
||||
shader.uniform1i("u_screen", 0);
|
||||
shader.uniform2i("u_screenSize", viewport);
|
||||
shader.uniform1f("u_timer", timer);
|
||||
if (currentPass > 1) {
|
||||
fbo->getTexture()->bind();
|
||||
}
|
||||
|
||||
fbo->getTexture()->bind();
|
||||
if (currentPass < totalPasses) {
|
||||
fboSecond->bind();
|
||||
}
|
||||
|
||||
quadMesh->draw();
|
||||
if (currentPass < totalPasses) {
|
||||
fboSecond->unbind();
|
||||
|
||||
@ -11,6 +11,9 @@ class Framebuffer;
|
||||
class DrawContext;
|
||||
class ImageData;
|
||||
class PostEffect;
|
||||
class Camera;
|
||||
class GBuffer;
|
||||
class Shader;
|
||||
|
||||
struct PostProcessingVertex {
|
||||
glm::vec2 position;
|
||||
@ -24,25 +27,31 @@ struct PostProcessingVertex {
|
||||
/// @attention Current implementation does not support multiple render passes
|
||||
/// for multiple effects. Will be implemented in v0.21
|
||||
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:
|
||||
PostProcessing(size_t effectSlotsCount);
|
||||
~PostProcessing();
|
||||
|
||||
/// @brief Prepare and bind framebuffer
|
||||
/// @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
|
||||
/// with framebuffer texture bound
|
||||
/// @param context graphics context
|
||||
/// @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);
|
||||
|
||||
@ -52,4 +61,24 @@ public:
|
||||
std::unique_ptr<ImageData> toImage();
|
||||
|
||||
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 "coders/GLSLExtension.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
|
||||
static debug::Logger logger("gl-shader");
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
GLSLExtension* Shader::preprocessor = new GLSLExtension();
|
||||
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);
|
||||
}
|
||||
|
||||
void Shader::use(){
|
||||
void Shader::use() {
|
||||
used = this;
|
||||
glUseProgram(id);
|
||||
}
|
||||
@ -40,8 +45,16 @@ uint Shader::getUniformLocation(const std::string& name) {
|
||||
return found->second;
|
||||
}
|
||||
|
||||
void Shader::uniformMatrix(const std::string& name, const glm::mat4& matrix){
|
||||
glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, glm::value_ptr(matrix));
|
||||
void Shader::uniformMatrix(const std::string& name, const glm::mat4& 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){
|
||||
@ -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);
|
||||
}
|
||||
|
||||
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);
|
||||
delete shader;
|
||||
};
|
||||
@ -93,45 +125,73 @@ glshader compile_shader(GLenum type, const GLchar* source, const std::string& fi
|
||||
glShaderSource(shader, 1, &source, nullptr);
|
||||
glCompileShader(shader);
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
if (!success){
|
||||
if (!success) {
|
||||
GLchar infoLog[GL_LOG_LEN];
|
||||
glGetShaderInfoLog(shader, GL_LOG_LEN, nullptr, infoLog);
|
||||
glDeleteShader(shader);
|
||||
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
|
||||
}
|
||||
|
||||
std::unique_ptr<Shader> Shader::create(
|
||||
const std::string& vertexFile,
|
||||
const std::string& fragmentFile,
|
||||
const std::string& vertexCode,
|
||||
const std::string& fragmentCode
|
||||
static GLuint compile_program(
|
||||
const Shader::Source& vertexSource, const Shader::Source& fragmentSource
|
||||
) {
|
||||
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* fCode = fragmentCode.c_str();
|
||||
|
||||
glshader vertex = compile_shader(GL_VERTEX_SHADER, vCode, vertexFile);
|
||||
glshader fragment = compile_shader(GL_FRAGMENT_SHADER, fCode, fragmentFile);
|
||||
glshader vertex =
|
||||
compile_shader(GL_VERTEX_SHADER, vCode, vertexSource.file);
|
||||
glshader fragment =
|
||||
compile_shader(GL_FRAGMENT_SHADER, fCode, fragmentSource.file);
|
||||
|
||||
// Shader Program
|
||||
GLint success;
|
||||
GLuint id = glCreateProgram();
|
||||
glAttachShader(id, *vertex);
|
||||
glAttachShader(id, *fragment);
|
||||
glLinkProgram(id);
|
||||
GLuint program = glCreateProgram();
|
||||
glAttachShader(program, *vertex);
|
||||
glAttachShader(program, *fragment);
|
||||
glLinkProgram(program);
|
||||
|
||||
glGetProgramiv(id, GL_LINK_STATUS, &success);
|
||||
if (!success){
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
||||
|
||||
if (!success) {
|
||||
GLchar infoLog[GL_LOG_LEN];
|
||||
glGetProgramInfoLog(id, GL_LOG_LEN, nullptr, infoLog);
|
||||
glGetProgramInfoLog(program, GL_LOG_LEN, nullptr, infoLog);
|
||||
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() {
|
||||
|
||||
@ -10,19 +10,30 @@
|
||||
class GLSLExtension;
|
||||
|
||||
class Shader {
|
||||
public:
|
||||
struct Source {
|
||||
std::string file;
|
||||
std::string code;
|
||||
};
|
||||
private:
|
||||
static Shader* used;
|
||||
uint id;
|
||||
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);
|
||||
public:
|
||||
static GLSLExtension* preprocessor;
|
||||
|
||||
Shader(uint id);
|
||||
Shader(uint id, Source&& vertexSource, Source&& fragmentSource);
|
||||
~Shader();
|
||||
|
||||
void use();
|
||||
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 uniform1f(const std::string& name, float x);
|
||||
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 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.
|
||||
/// @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
|
||||
static std::unique_ptr<Shader> create(
|
||||
const std::string& vertexFile,
|
||||
const std::string& fragmentFile,
|
||||
const std::string& vertexSource,
|
||||
const std::string& fragmentSource
|
||||
Source&& vertexSource, Source&& fragmentSource
|
||||
);
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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)
|
||||
{"arrow", CursorShape::ARROW},
|
||||
{"text", CursorShape::TEXT},
|
||||
@ -69,3 +80,11 @@ public:
|
||||
|
||||
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
|
||||
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].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[1] = static_cast<uint8_t>(light.g * 255);
|
||||
vertexBuffer[vertexCount].color[2] = static_cast<uint8_t>(light.b * 255);
|
||||
vertexBuffer[vertexCount].color[3] = static_cast<uint8_t>(light.a * 255);
|
||||
|
||||
vertexCount++;
|
||||
}
|
||||
|
||||
@ -82,10 +92,10 @@ void BlocksRenderer::face(
|
||||
auto Y = axisY * h;
|
||||
auto Z = axisZ * d;
|
||||
float s = 0.5f;
|
||||
vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, lights[0] * tint);
|
||||
vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, lights[1] * tint);
|
||||
vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, lights[2] * tint);
|
||||
vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, lights[3] * 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, axisZ, 0);
|
||||
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, axisZ, 0);
|
||||
index(0, 1, 3, 1, 2, 3);
|
||||
}
|
||||
|
||||
@ -103,7 +113,7 @@ void BlocksRenderer::vertexAO(
|
||||
axisX,
|
||||
axisY
|
||||
);
|
||||
vertex(coord, u, v, light * tint);
|
||||
vertex(coord, u, v, light * tint, axisZ, 0.0f);
|
||||
}
|
||||
|
||||
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.u1, region.v2, tint, axisX, axisY, axisZ);
|
||||
} else {
|
||||
auto axisZ = glm::normalize(Z);
|
||||
glm::vec4 tint(1.0f);
|
||||
vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint);
|
||||
vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint);
|
||||
vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint);
|
||||
vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, 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, axisZ, 1);
|
||||
vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, axisZ, 1);
|
||||
vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, axisZ, 1);
|
||||
}
|
||||
index(0, 1, 2, 0, 2, 3);
|
||||
}
|
||||
@ -163,10 +174,10 @@ void BlocksRenderer::face(
|
||||
d = (1.0f - DIRECTIONAL_LIGHT_FACTOR) + d * DIRECTIONAL_LIGHT_FACTOR;
|
||||
tint *= d;
|
||||
}
|
||||
vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint);
|
||||
vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint);
|
||||
vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint);
|
||||
vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, 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, Z, lights ? 0 : 1);
|
||||
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, Z, lights ? 0 : 1);
|
||||
index(0, 1, 2, 0, 2, 3);
|
||||
}
|
||||
|
||||
@ -198,14 +209,16 @@ void BlocksRenderer::blockXSprite(
|
||||
const float w = size.x / 1.41f;
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -337,7 +350,9 @@ void BlocksRenderer::blockCustomModel(
|
||||
coord + vcoord.x * X + vcoord.y * Y + vcoord.z * Z,
|
||||
vertex.uv.x,
|
||||
vertex.uv.y,
|
||||
glm::vec4(d, d, d, d) * aoColor
|
||||
glm::vec4(d, d, d, d) * aoColor,
|
||||
n,
|
||||
0.0f
|
||||
);
|
||||
indexBuffer[indexCount++] = vertexOffset++;
|
||||
}
|
||||
|
||||
@ -44,7 +44,14 @@ class BlocksRenderer {
|
||||
|
||||
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 vertexAO(
|
||||
|
||||
@ -143,7 +143,7 @@ void ChunksRenderer::update() {
|
||||
}
|
||||
|
||||
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];
|
||||
if (chunk == nullptr) {
|
||||
@ -182,13 +182,39 @@ const Mesh<ChunkVertex>* ChunksRenderer::retrieveChunk(
|
||||
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(
|
||||
const Camera& camera, Shader& shader
|
||||
) {
|
||||
const auto& atlas = assets.require<Atlas>("blocks");
|
||||
|
||||
atlas.getTexture()->bind();
|
||||
update();
|
||||
|
||||
// [warning] this whole method is not thread-safe for chunks
|
||||
|
||||
@ -219,7 +245,7 @@ void ChunksRenderer::drawChunks(
|
||||
// TODO: minimize draw calls number
|
||||
for (int i = indices.size()-1; i >= 0; i--) {
|
||||
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) {
|
||||
glm::vec3 coord(
|
||||
|
||||
@ -50,7 +50,7 @@ class ChunksRenderer {
|
||||
std::vector<ChunksSortEntry> indices;
|
||||
util::ThreadPool<std::shared_ptr<Chunk>, RendererResult> threadPool;
|
||||
const Mesh<ChunkVertex>* retrieveChunk(
|
||||
size_t index, const Camera& camera, Shader& shader, bool culling
|
||||
size_t index, const Camera& camera, bool culling
|
||||
);
|
||||
public:
|
||||
ChunksRenderer(
|
||||
@ -72,6 +72,9 @@ public:
|
||||
const Mesh<ChunkVertex>* getOrRender(
|
||||
const std::shared_ptr<Chunk>& chunk, bool important
|
||||
);
|
||||
|
||||
void drawChunksShadowsPass(const Camera& camera, Shader& shader);
|
||||
|
||||
void drawChunks(const Camera& camera, Shader& shader);
|
||||
|
||||
void drawSortedMeshes(const Camera& camera, Shader& shader);
|
||||
|
||||
@ -94,39 +94,39 @@ void MainBatch::cube(
|
||||
const glm::vec3 Z(0.0f, 0.0f, 1.0f);
|
||||
|
||||
quad(
|
||||
coord + Z * size.z * 0.5f,
|
||||
X, Y, glm::vec2(size.x, size.y),
|
||||
(shading ? do_tint(0.8) * tint : tint),
|
||||
glm::vec3(1.0f), texfaces[5]
|
||||
coord + Z * size.z * 0.5f,
|
||||
X, Y, Z, glm::vec2(size.x, size.y),
|
||||
(shading ? do_tint(0.8) * tint : tint),
|
||||
glm::vec3(1.0f), texfaces[5]
|
||||
);
|
||||
quad(
|
||||
coord - Z * size.z * 0.5f,
|
||||
-X, Y, glm::vec2(size.x, size.y),
|
||||
(shading ? do_tint(0.9f) * tint : tint),
|
||||
glm::vec3(1.0f), texfaces[4]
|
||||
coord - Z * size.z * 0.5f,
|
||||
-X, Y, -Z, glm::vec2(size.x, size.y),
|
||||
(shading ? do_tint(0.9f) * tint : tint),
|
||||
glm::vec3(1.0f), texfaces[4]
|
||||
);
|
||||
quad(
|
||||
coord + Y * size.y * 0.5f,
|
||||
-X, Z, glm::vec2(size.x, size.z),
|
||||
(shading ? do_tint(1.0f) * tint : tint),
|
||||
glm::vec3(1.0f), texfaces[3]
|
||||
coord + Y * size.y * 0.5f,
|
||||
-X, Z, Y, glm::vec2(size.x, size.z),
|
||||
(shading ? do_tint(1.0f) * tint : tint),
|
||||
glm::vec3(1.0f), texfaces[3]
|
||||
);
|
||||
quad(
|
||||
coord - Y * size.y * 0.5f,
|
||||
X, Z, glm::vec2(size.x, size.z),
|
||||
(shading ? do_tint(0.7f) * tint : tint),
|
||||
glm::vec3(1.0f), texfaces[2]
|
||||
coord - Y * size.y * 0.5f,
|
||||
X, Z, -Y, glm::vec2(size.x, size.z),
|
||||
(shading ? do_tint(0.7f) * tint : tint),
|
||||
glm::vec3(1.0f), texfaces[2]
|
||||
);
|
||||
quad(
|
||||
coord + X * size.x * 0.5f,
|
||||
-Z, Y, glm::vec2(size.z, size.y),
|
||||
(shading ? do_tint(0.8f) * tint : tint),
|
||||
glm::vec3(1.0f), texfaces[1]
|
||||
coord + X * size.x * 0.5f,
|
||||
-Z, Y, X, glm::vec2(size.z, size.y),
|
||||
(shading ? do_tint(0.8f) * tint : tint),
|
||||
glm::vec3(1.0f), texfaces[1]
|
||||
);
|
||||
quad(
|
||||
coord - X * size.x * 0.5f,
|
||||
Z, Y, glm::vec2(size.z, size.y),
|
||||
(shading ? do_tint(0.9f) * tint : tint),
|
||||
glm::vec3(1.0f), texfaces[1]
|
||||
coord - X * size.x * 0.5f,
|
||||
Z, Y, -X, glm::vec2(size.z, size.y),
|
||||
(shading ? do_tint(0.9f) * tint : tint),
|
||||
glm::vec3(1.0f), texfaces[1]
|
||||
);
|
||||
}
|
||||
|
||||
@ -18,13 +18,15 @@ struct MainBatchVertex {
|
||||
glm::vec3 position;
|
||||
glm::vec2 uv;
|
||||
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[] = {
|
||||
{VertexAttribute::Type::FLOAT, false, 3},
|
||||
{VertexAttribute::Type::FLOAT, false, 2},
|
||||
{VertexAttribute::Type::FLOAT, false, 3},
|
||||
{VertexAttribute::Type::UNSIGNED_BYTE, true, 4},
|
||||
{VertexAttribute::Type::UNSIGNED_BYTE, true, 4},
|
||||
{{}, 0}};
|
||||
};
|
||||
|
||||
@ -61,7 +63,9 @@ public:
|
||||
const glm::vec3& pos,
|
||||
const glm::vec2& uv,
|
||||
const glm::vec4& light,
|
||||
const glm::vec3& tint
|
||||
const glm::vec3& tint,
|
||||
const glm::vec3& normal,
|
||||
float emission
|
||||
) {
|
||||
MainBatchVertex* buffer = this->buffer.get();
|
||||
buffer[index].position = pos;
|
||||
@ -72,6 +76,11 @@ public:
|
||||
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[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++;
|
||||
}
|
||||
|
||||
@ -79,48 +88,62 @@ public:
|
||||
const glm::vec3& pos,
|
||||
const glm::vec3& right,
|
||||
const glm::vec3& up,
|
||||
const glm::vec3& normal,
|
||||
const glm::vec2& size,
|
||||
const glm::vec4& light,
|
||||
const glm::vec3& tint,
|
||||
const UVRegion& subregion
|
||||
const UVRegion& subregion,
|
||||
float emission = 0.0f
|
||||
) {
|
||||
prepare(6);
|
||||
vertex(
|
||||
pos - right * size.x * 0.5f - up * size.y * 0.5f,
|
||||
{subregion.u1, subregion.v1},
|
||||
light,
|
||||
tint
|
||||
tint,
|
||||
normal,
|
||||
emission
|
||||
);
|
||||
vertex(
|
||||
pos + right * size.x * 0.5f - up * size.y * 0.5f,
|
||||
{subregion.u2, subregion.v1},
|
||||
light,
|
||||
tint
|
||||
tint,
|
||||
normal,
|
||||
emission
|
||||
);
|
||||
vertex(
|
||||
pos + right * size.x * 0.5f + up * size.y * 0.5f,
|
||||
{subregion.u2, subregion.v2},
|
||||
light,
|
||||
tint
|
||||
tint,
|
||||
normal,
|
||||
emission
|
||||
);
|
||||
|
||||
vertex(
|
||||
pos - right * size.x * 0.5f - up * size.y * 0.5f,
|
||||
{subregion.u1, subregion.v1},
|
||||
light,
|
||||
tint
|
||||
tint,
|
||||
normal,
|
||||
emission
|
||||
);
|
||||
vertex(
|
||||
pos + right * size.x * 0.5f + up * size.y * 0.5f,
|
||||
{subregion.u2, subregion.v2},
|
||||
light,
|
||||
tint
|
||||
tint,
|
||||
normal,
|
||||
emission
|
||||
);
|
||||
vertex(
|
||||
pos - right * size.x * 0.5f + up * size.y * 0.5f,
|
||||
{subregion.u1, subregion.v2},
|
||||
light,
|
||||
tint
|
||||
tint,
|
||||
normal,
|
||||
emission
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -57,12 +57,14 @@ ModelBatch::ModelBatch(
|
||||
|
||||
ModelBatch::~ModelBatch() = default;
|
||||
|
||||
void ModelBatch::draw(const model::Mesh& mesh, const glm::mat4& matrix,
|
||||
const glm::mat3& rotation, glm::vec3 tint,
|
||||
const texture_names_map* varTextures,
|
||||
bool backlight) {
|
||||
|
||||
|
||||
void ModelBatch::draw(
|
||||
const model::Mesh& mesh,
|
||||
const glm::mat4& matrix,
|
||||
const glm::mat3& rotation,
|
||||
glm::vec3 tint,
|
||||
const texture_names_map* varTextures,
|
||||
bool backlight
|
||||
) {
|
||||
setTexture(mesh.texture, varTextures);
|
||||
size_t vcount = mesh.vertices.size();
|
||||
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++) {
|
||||
const auto vert = vertexData[i * 3 + j];
|
||||
float d = 1.0f;
|
||||
auto norm = rotation * vert.normal;
|
||||
if (mesh.lighting) {
|
||||
auto norm = rotation * vert.normal;
|
||||
d = glm::dot(norm, SUN_VECTOR);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
glm::vec3 localRight = right;
|
||||
glm::vec3 localUp = preset.globalUpVector ? glm::vec3(0, 1, 0) : up;
|
||||
float angle = particle.angle;
|
||||
@ -134,10 +133,12 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) {
|
||||
particle.position,
|
||||
localRight,
|
||||
localUp,
|
||||
-camera.front,
|
||||
preset.size * scale,
|
||||
light,
|
||||
glm::vec3(1.0f),
|
||||
particle.region
|
||||
particle.region,
|
||||
preset.lighting ? 0.0f : 1.0f
|
||||
);
|
||||
if (particle.lifetime <= 0.0f) {
|
||||
iter = vec.erase(iter);
|
||||
|
||||
@ -146,6 +146,7 @@ void PrecipitationRenderer::render(
|
||||
pos,
|
||||
face.right,
|
||||
{0, 1, 0},
|
||||
glm::cross(glm::vec3(0, 1, 0), face.right),
|
||||
FACE_SIZE,
|
||||
light_at(chunks, pos.x, y, pos.z),
|
||||
glm::vec3(1.0f),
|
||||
|
||||
@ -15,11 +15,10 @@
|
||||
#include <iostream>
|
||||
#include <GL/glew.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/constants.hpp>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592
|
||||
#endif // M_PI
|
||||
using namespace advanced_pipeline;
|
||||
|
||||
const int STARS_COUNT = 3000;
|
||||
const int STARS_SEED = 632;
|
||||
@ -46,18 +45,28 @@ Skybox::Skybox(uint size, Shader& shader)
|
||||
|
||||
mesh = std::make_unique<Mesh<SkyboxVertex>>(vertices, 6);
|
||||
|
||||
sprites.push_back(skysprite {
|
||||
sprites.push_back(SkySprite {
|
||||
"misc/moon",
|
||||
glm::pi<float>()*0.5f,
|
||||
glm::pi<float>() * 0.5f,
|
||||
4.0f,
|
||||
false
|
||||
false,
|
||||
glm::pi<float>() * 0.25f,
|
||||
});
|
||||
|
||||
sprites.push_back(SkySprite {
|
||||
"misc/moon_flare",
|
||||
glm::pi<float>() * 0.5f,
|
||||
0.5f,
|
||||
false,
|
||||
glm::pi<float>() * 0.25f,
|
||||
});
|
||||
|
||||
sprites.push_back(skysprite {
|
||||
sprites.push_back(SkySprite {
|
||||
"misc/sun",
|
||||
glm::pi<float>()*1.5f,
|
||||
glm::pi<float>() * 1.5f,
|
||||
4.0f,
|
||||
true
|
||||
true,
|
||||
glm::pi<float>() * 0.25f,
|
||||
});
|
||||
}
|
||||
|
||||
@ -69,9 +78,11 @@ void Skybox::drawBackground(
|
||||
auto backShader = assets.get<Shader>("background");
|
||||
backShader->use();
|
||||
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->uniform1i("u_cubemap", 1);
|
||||
backShader->uniform1i("u_skybox", 1);
|
||||
bind();
|
||||
mesh->draw();
|
||||
unbind();
|
||||
@ -80,20 +91,29 @@ void Skybox::drawBackground(
|
||||
void Skybox::drawStars(float angle, float opacity) {
|
||||
batch3d->texture(nullptr);
|
||||
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++) {
|
||||
float rx = (random.randFloat()) - 0.5f;
|
||||
float ry = (random.randFloat()) - 0.5f;
|
||||
float z = (random.randFloat()) - 0.5f;
|
||||
float x = rx * std::sin(angle) + ry * -std::cos(angle);
|
||||
float y = rx * std::cos(angle) + ry * std::sin(angle);
|
||||
float rz = (random.randFloat()) - 0.5f;
|
||||
|
||||
glm::vec3 pos = glm::vec4(rx, ry, rz, 1) * rotation;
|
||||
|
||||
float sopacity = random.randFloat();
|
||||
if (y < 0.0f)
|
||||
if (pos.y < 0.0f)
|
||||
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);
|
||||
batch3d->point(glm::vec3(x, y, z), tint);
|
||||
batch3d->point(pos * depth, tint);
|
||||
}
|
||||
batch3d->flushPoints();
|
||||
}
|
||||
@ -107,6 +127,8 @@ void Skybox::draw(
|
||||
{
|
||||
const glm::uvec2& viewport = pctx.getViewport();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
drawBackground(camera, assets, viewport.x, viewport.y);
|
||||
|
||||
DrawContext ctx = pctx.sub();
|
||||
@ -119,24 +141,32 @@ void Skybox::draw(
|
||||
batch3d->begin();
|
||||
|
||||
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) {
|
||||
batch3d->texture(assets.get<Texture>(sprite.texture));
|
||||
|
||||
float sangle = daytime * glm::pi<float>()*2.0 + sprite.phase;
|
||||
float distance = sprite.distance;
|
||||
float sangle = daytime * glm::pi<float>() * 2.0 + sprite.phase;
|
||||
float distance = sprite.distance * depthScale;
|
||||
|
||||
glm::vec3 pos(-std::cos(sangle)*distance, std::sin(sangle)*distance, 0);
|
||||
glm::vec3 up(-std::sin(-sangle), std::cos(-sangle), 0.0f);
|
||||
glm::mat4 rotation = glm::rotate(
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
batch3d->flush();
|
||||
drawStars(angle, opacity);
|
||||
}
|
||||
|
||||
@ -153,12 +183,22 @@ void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality)
|
||||
assert(cubemap != nullptr);
|
||||
|
||||
ready = true;
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glActiveTexture(GL_TEXTURE0 + TARGET_SKYBOX);
|
||||
cubemap->bind();
|
||||
shader.use();
|
||||
t *= glm::pi<float>()*2.0f;
|
||||
t *= glm::two_pi<float>();
|
||||
|
||||
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.uniform1f("u_mie", mie);
|
||||
shader.uniform1f("u_fog", mie - 1.0f);
|
||||
@ -223,13 +263,13 @@ void Skybox::refreshFace(uint face, Cubemap* cubemap) {
|
||||
}
|
||||
|
||||
void Skybox::bind() const {
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glActiveTexture(GL_TEXTURE0 + TARGET_SKYBOX);
|
||||
fbo->getTexture()->bind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void Skybox::unbind() const {
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glActiveTexture(GL_TEXTURE0 + TARGET_SKYBOX);
|
||||
fbo->getTexture()->unbind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
@ -25,11 +25,12 @@ struct SkyboxVertex {
|
||||
{{}, 0}};
|
||||
};
|
||||
|
||||
struct skysprite {
|
||||
struct SkySprite {
|
||||
std::string texture;
|
||||
float phase;
|
||||
float distance;
|
||||
bool emissive;
|
||||
float altitude;
|
||||
};
|
||||
|
||||
class Skybox {
|
||||
@ -42,11 +43,13 @@ class Skybox {
|
||||
|
||||
std::unique_ptr<Mesh<SkyboxVertex>> mesh;
|
||||
std::unique_ptr<Batch3D> batch3d;
|
||||
std::vector<skysprite> sprites;
|
||||
std::vector<SkySprite> sprites;
|
||||
int frameid = 0;
|
||||
|
||||
float prevMie = -1.0f;
|
||||
float prevT = -1.0f;
|
||||
float sunAltitude = 45.0f;
|
||||
glm::mat4 rotation;
|
||||
|
||||
void drawStars(float angle, float opacity);
|
||||
void drawBackground(
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "assets/assets_util.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
#include "coders/GLSLExtension.hpp"
|
||||
#include "frontend/LevelFrontend.hpp"
|
||||
#include "frontend/ContentGfxCache.hpp"
|
||||
#include "items/Inventory.hpp"
|
||||
@ -26,7 +27,6 @@
|
||||
#include "voxels/Block.hpp"
|
||||
#include "voxels/Chunk.hpp"
|
||||
#include "voxels/Chunks.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
#include "window/Window.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "world/LevelEvents.hpp"
|
||||
@ -38,9 +38,12 @@
|
||||
#include "graphics/core/LineBatch.hpp"
|
||||
#include "graphics/core/Mesh.hpp"
|
||||
#include "graphics/core/PostProcessing.hpp"
|
||||
#include "graphics/core/Framebuffer.hpp"
|
||||
#include "graphics/core/Shader.hpp"
|
||||
#include "graphics/core/Texture.hpp"
|
||||
#include "graphics/core/Font.hpp"
|
||||
#include "graphics/core/ShadowMap.hpp"
|
||||
#include "graphics/core/GBuffer.hpp"
|
||||
#include "BlockWrapsRenderer.hpp"
|
||||
#include "ParticlesRenderer.hpp"
|
||||
#include "PrecipitationRenderer.hpp"
|
||||
@ -52,8 +55,12 @@
|
||||
#include "Emitter.hpp"
|
||||
#include "TextNote.hpp"
|
||||
|
||||
using namespace advanced_pipeline;
|
||||
|
||||
inline constexpr size_t BATCH3D_CAPACITY = 4096;
|
||||
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::showEntitiesDebug = false;
|
||||
@ -119,13 +126,37 @@ void WorldRenderer::setupWorldShader(
|
||||
shader.uniform1f("u_fogFactor", fogFactor);
|
||||
shader.uniform1f("u_fogCurve", settings.graphics.fogCurve.get());
|
||||
shader.uniform1i("u_debugLights", lightsDebug);
|
||||
shader.uniform1i("u_debugNormals", false);
|
||||
shader.uniform1f("u_weatherFogOpacity", weather.fogOpacity());
|
||||
shader.uniform1f("u_weatherFogDencity", weather.fogDencity());
|
||||
shader.uniform1f("u_weatherFogCurve", weather.fogCurve());
|
||||
shader.uniform1f("u_dayTime", level.getWorld()->getInfo().daytime);
|
||||
shader.uniform2f("u_lightDir", skybox->getLightDir());
|
||||
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();
|
||||
// Light emission when an emissive item is chosen
|
||||
@ -195,22 +226,6 @@ void WorldRenderer::renderLevel(
|
||||
if (!pause) {
|
||||
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();
|
||||
}
|
||||
|
||||
@ -232,7 +247,7 @@ void WorldRenderer::renderBlockSelection() {
|
||||
const glm::vec3 center = glm::vec3(pos) + hitbox.center();
|
||||
const glm::vec3 size = hitbox.size();
|
||||
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) {
|
||||
lineBatch->line(
|
||||
@ -324,6 +339,79 @@ void WorldRenderer::renderHands(
|
||||
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(
|
||||
const DrawContext& pctx,
|
||||
Camera& camera,
|
||||
@ -332,6 +420,7 @@ void WorldRenderer::draw(
|
||||
float uiDelta,
|
||||
PostProcessing& postProcessing
|
||||
) {
|
||||
// TODO: REFACTOR WHOLE RENDER ENGINE
|
||||
float delta = uiDelta * !pause;
|
||||
timer += delta;
|
||||
weather.update(delta);
|
||||
@ -341,29 +430,75 @@ void WorldRenderer::draw(
|
||||
const auto& vp = pctx.getViewport();
|
||||
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();
|
||||
|
||||
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();
|
||||
|
||||
float sqrtT = glm::sqrt(weather.t);
|
||||
float clouds = weather.b.clouds * sqrtT +
|
||||
weather.a.clouds * (1.0f - sqrtT);
|
||||
float clouds = weather.clouds();
|
||||
clouds = glm::max(worldInfo.fog, clouds);
|
||||
float mie = 1.0f + glm::max(worldInfo.fog, clouds * 0.5f) * 2.0f;
|
||||
|
||||
skybox->refresh(pctx, worldInfo.daytime, mie, 4);
|
||||
|
||||
const auto& assets = *engine.getAssets();
|
||||
auto& linesShader = assets.require<Shader>("lines");
|
||||
chunks->update();
|
||||
|
||||
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 */ {
|
||||
DrawContext wctx = pctx.sub();
|
||||
postProcessing.use(wctx);
|
||||
postProcessing.use(wctx, gbufferPipeline);
|
||||
|
||||
display::clearDepth();
|
||||
|
||||
// Drawing background sky plane
|
||||
skybox->draw(pctx, camera, assets, worldInfo.daytime, clouds);
|
||||
|
||||
/* Actually world render with depth buffer on */ {
|
||||
DrawContext ctx = wctx.sub();
|
||||
ctx.setDepthTest(true);
|
||||
@ -376,19 +511,59 @@ void WorldRenderer::draw(
|
||||
ctx, camera, *lineBatch, linesShader, showChunkBorders
|
||||
);
|
||||
}
|
||||
if (player.currentCamera == player.fpCamera) {
|
||||
renderHands(camera, delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
DrawContext ctx = wctx.sub();
|
||||
texts->render(ctx, camera, settings, hudVisible, true);
|
||||
}
|
||||
renderBlockOverlay(wctx);
|
||||
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 = pctx.sub();
|
||||
ctx.setDepthTest(true);
|
||||
if (gbufferPipeline) {
|
||||
postProcessing.bindDepthBuffer();
|
||||
} else {
|
||||
postProcessing.getFramebuffer()->bind();
|
||||
}
|
||||
// Drawing background sky plane
|
||||
skybox->draw(ctx, camera, assets, worldInfo.daytime, clouds);
|
||||
|
||||
postProcessing.render(pctx, assets, timer);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
|
||||
#include "presets/WeatherPreset.hpp"
|
||||
#include "world/Weather.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
|
||||
class Level;
|
||||
class Player;
|
||||
@ -30,8 +31,16 @@ class PostProcessing;
|
||||
class DrawContext;
|
||||
class ModelBatch;
|
||||
class Assets;
|
||||
class ShadowMap;
|
||||
class GBuffer;
|
||||
struct EngineSettings;
|
||||
|
||||
struct CompileTimeShaderSettings {
|
||||
bool advancedRender = false;
|
||||
bool shadows = false;
|
||||
bool ssao = false;
|
||||
};
|
||||
|
||||
class WorldRenderer {
|
||||
Engine& engine;
|
||||
const Level& level;
|
||||
@ -44,11 +53,19 @@ class WorldRenderer {
|
||||
std::unique_ptr<GuidesRenderer> guides;
|
||||
std::unique_ptr<ChunksRenderer> chunks;
|
||||
std::unique_ptr<Skybox> skybox;
|
||||
std::unique_ptr<ShadowMap> shadowMap;
|
||||
std::unique_ptr<ShadowMap> wideShadowMap;
|
||||
Weather weather {};
|
||||
Camera shadowCamera;
|
||||
Camera wideShadowCamera;
|
||||
|
||||
float timer = 0.0f;
|
||||
bool debug = false;
|
||||
bool lightsDebug = false;
|
||||
bool gbufferPipeline = false;
|
||||
bool shadows = false;
|
||||
|
||||
CompileTimeShaderSettings prevCTShaderSettings {};
|
||||
|
||||
/// @brief Render block selection lines
|
||||
void renderBlockSelection();
|
||||
@ -70,6 +87,14 @@ class WorldRenderer {
|
||||
const EngineSettings& settings,
|
||||
float fogFactor
|
||||
);
|
||||
|
||||
void generateShadowsMap(
|
||||
const Camera& camera,
|
||||
const DrawContext& pctx,
|
||||
ShadowMap& shadowMap,
|
||||
Camera& shadowCamera,
|
||||
float scale
|
||||
);
|
||||
public:
|
||||
std::unique_ptr<ParticlesRenderer> particles;
|
||||
std::unique_ptr<TextsRenderer> texts;
|
||||
|
||||
@ -14,11 +14,13 @@ struct ChunkVertex {
|
||||
glm::vec3 position;
|
||||
glm::vec2 uv;
|
||||
std::array<uint8_t, 4> color;
|
||||
std::array<uint8_t, 4> normal;
|
||||
|
||||
static constexpr VertexAttribute ATTRIBUTES[] = {
|
||||
{VertexAttribute::Type::FLOAT, false, 3},
|
||||
{VertexAttribute::Type::FLOAT, false, 2},
|
||||
{VertexAttribute::Type::UNSIGNED_BYTE, true, 4},
|
||||
{VertexAttribute::Type::UNSIGNED_BYTE, true, 4},
|
||||
{{}, 0}};
|
||||
};
|
||||
|
||||
|
||||
@ -38,6 +38,8 @@ GUI::GUI(Engine& engine)
|
||||
std::make_unique<Camera>(glm::vec3(), engine.getWindow().getSize().y);
|
||||
uicamera->perspective = false;
|
||||
uicamera->flipped = true;
|
||||
uicamera->near = -1.0f;
|
||||
uicamera->far = 1.0f;
|
||||
|
||||
menu = std::make_shared<Menu>(*this);
|
||||
menu->setId("menu");
|
||||
|
||||
@ -74,6 +74,9 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
||||
builder.add("chunk-max-vertices", &settings.graphics.chunkMaxVertices);
|
||||
builder.add("chunk-max-vertices-dense", &settings.graphics.chunkMaxVerticesDense);
|
||||
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.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));
|
||||
auto name = lua::require_string(L, 2);
|
||||
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));
|
||||
return 0;
|
||||
}
|
||||
@ -57,6 +60,22 @@ static int l_set_params(lua::State* L) {
|
||||
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[] = {
|
||||
{"index", lua::wrap<l_index>},
|
||||
{"set_effect", lua::wrap<l_set_effect>},
|
||||
@ -64,5 +83,6 @@ const luaL_Reg posteffectslib[] = {
|
||||
{"set_intensity", lua::wrap<l_set_intensity>},
|
||||
{"is_active", lua::wrap<l_is_active>},
|
||||
{"set_params", lua::wrap<l_set_params>},
|
||||
{"set_array", lua::wrap<l_set_array>},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
|
||||
#include "libs/api_lua.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
@ -149,6 +150,15 @@ int l_debug_print(lua::State* L) {
|
||||
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) {
|
||||
if (lua::getglobal(L, "debug")) {
|
||||
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::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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,6 +75,12 @@ struct GraphicsSettings {
|
||||
IntegerSetting chunkMaxVerticesDense {800'000, 0, 8'000'000};
|
||||
/// @brief Limit of chunk renderers count
|
||||
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 {
|
||||
|
||||
@ -28,12 +28,15 @@ void Camera::rotate(float x, float y, float z) {
|
||||
}
|
||||
|
||||
glm::mat4 Camera::getProjection() const {
|
||||
if (projset) {
|
||||
return projection;
|
||||
}
|
||||
if (perspective) {
|
||||
return glm::perspective(fov * zoom, ar, near, far);
|
||||
} 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 {
|
||||
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) {
|
||||
return glm::lookAt(camera_pos, camera_pos + front, up);
|
||||
} 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;
|
||||
}
|
||||
|
||||
void Camera::setProjection(const glm::mat4& matrix) {
|
||||
projection = matrix;
|
||||
projset = true;
|
||||
}
|
||||
|
||||
float Camera::getAspectRatio() const {
|
||||
return ar;
|
||||
}
|
||||
|
||||
@ -19,7 +19,10 @@ public:
|
||||
bool perspective = true;
|
||||
bool flipped = false;
|
||||
float near = 0.05f;
|
||||
float far = 1500.0f;
|
||||
float far = 1e4f;
|
||||
|
||||
bool projset = false;
|
||||
glm::mat4 projection;
|
||||
|
||||
Camera() {
|
||||
updateVectors();
|
||||
@ -36,6 +39,8 @@ public:
|
||||
void setFov(float fov);
|
||||
float getFov() const;
|
||||
|
||||
void setProjection(const glm::mat4& matrix);
|
||||
|
||||
float getAspectRatio() const;
|
||||
void setAspectRatio(float ar);
|
||||
};
|
||||
|
||||
@ -519,6 +519,7 @@ public:
|
||||
}
|
||||
|
||||
std::unique_ptr<ImageData> takeScreenshot() override {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
auto data = std::make_unique<ubyte[]>(size.x * size.y * 3);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(0, 0, size.x, size.y, GL_RGB, GL_UNSIGNED_BYTE, data.get());
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "presets/WeatherPreset.hpp"
|
||||
@ -45,6 +46,11 @@ struct Weather : Serializable {
|
||||
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;
|
||||
void deserialize(const dv::value& src) override;
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user