day-night loop, dynamic skybox, clock on debug panel
This commit is contained in:
parent
4a9a4ddd14
commit
c08c31b0ad
11
res/shaders/background.glslf
Normal file
11
res/shaders/background.glslf
Normal file
@ -0,0 +1,11 @@
|
||||
#version 330 core
|
||||
|
||||
in vec3 v_coord;
|
||||
out vec4 f_color;
|
||||
|
||||
uniform samplerCube u_cubemap;
|
||||
|
||||
void main(){
|
||||
vec3 dir = normalize(v_coord);
|
||||
f_color = texture(u_cubemap, dir);
|
||||
}
|
||||
14
res/shaders/background.glslv
Normal file
14
res/shaders/background.glslv
Normal file
@ -0,0 +1,14 @@
|
||||
#version 330 core
|
||||
|
||||
layout (location = 0) in vec2 v_position;
|
||||
|
||||
out vec3 v_coord;
|
||||
|
||||
uniform mat4 u_view;
|
||||
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);
|
||||
}
|
||||
@ -3,20 +3,23 @@
|
||||
in vec4 a_color;
|
||||
in vec2 a_texCoord;
|
||||
in float a_distance;
|
||||
in vec3 a_dir;
|
||||
out vec4 f_color;
|
||||
|
||||
uniform sampler2D u_texture0;
|
||||
uniform samplerCube u_cubemap;
|
||||
uniform vec3 u_fogColor;
|
||||
uniform float u_fogFactor;
|
||||
uniform float u_fogCurve;
|
||||
|
||||
void main(){
|
||||
vec3 fogColor = texture(u_cubemap, a_dir).rgb;
|
||||
vec4 tex_color = texture(u_texture0, a_texCoord);
|
||||
float depth = (a_distance/256.0);
|
||||
float alpha = a_color.a * tex_color.a;
|
||||
// anyway it's any alpha-test alternative required
|
||||
if (alpha < 0.1f)
|
||||
discard;
|
||||
f_color = mix(a_color * tex_color, vec4(u_fogColor,1.0), min(1.0, pow(depth*u_fogFactor, u_fogCurve)));
|
||||
f_color = mix(a_color * tex_color, vec4(fogColor,1.0), min(1.0, pow(depth*u_fogFactor, u_fogCurve)));
|
||||
f_color.a = alpha;
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ layout (location = 2) in float v_light;
|
||||
out vec4 a_color;
|
||||
out vec2 a_texCoord;
|
||||
out float a_distance;
|
||||
out vec3 a_dir;
|
||||
|
||||
uniform mat4 u_model;
|
||||
uniform mat4 u_proj;
|
||||
@ -14,10 +15,13 @@ uniform mat4 u_view;
|
||||
uniform vec3 u_skyLightColor;
|
||||
uniform vec3 u_cameraPos;
|
||||
uniform float u_gamma;
|
||||
uniform samplerCube u_cubemap;
|
||||
|
||||
uniform vec3 u_torchlightColor;
|
||||
uniform float u_torchlightDistance;
|
||||
|
||||
#define SKY_LIGHT_MUL 2.5
|
||||
|
||||
vec4 decompress_light(float compressed_light) {
|
||||
vec4 result;
|
||||
int compressed = floatBitsToInt(compressed_light);
|
||||
@ -30,15 +34,22 @@ vec4 decompress_light(float compressed_light) {
|
||||
|
||||
void main(){
|
||||
vec2 pos2d = (u_model * vec4(v_position, 1.0)).xz-u_cameraPos.xz;
|
||||
vec4 modelpos = u_model * vec4(v_position+vec3(0,pow(length(pos2d)*0.0, 3.0),0), 1.0);
|
||||
vec4 modelpos = u_model * vec4(v_position, 1.0);
|
||||
vec4 viewmodelpos = u_view * modelpos;
|
||||
vec4 decomp_light = decompress_light(v_light);
|
||||
vec3 light = decomp_light.rgb;
|
||||
float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz)/u_torchlightDistance);
|
||||
a_dir = modelpos.xyz - u_cameraPos;
|
||||
light += torchlight * u_torchlightColor;
|
||||
a_color = vec4(pow(light, vec3(u_gamma)),1.0f);
|
||||
a_texCoord = v_texCoord;
|
||||
a_color.rgb = max(a_color.rgb, u_skyLightColor.rgb*decomp_light.a);
|
||||
|
||||
vec3 skyLightColor = texture(u_cubemap, vec3(-0.4f, -0.4f, -0.4f)).rgb;
|
||||
skyLightColor.g *= 0.9;
|
||||
skyLightColor.b *= 0.8;
|
||||
skyLightColor = min(vec3(1.0), skyLightColor*SKY_LIGHT_MUL);
|
||||
|
||||
a_color.rgb = max(a_color.rgb, skyLightColor.rgb*decomp_light.a);
|
||||
a_distance = length(viewmodelpos);
|
||||
gl_Position = u_proj * viewmodelpos;
|
||||
}
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
#version 330 core
|
||||
|
||||
in vec2 v_coord;
|
||||
out vec4 f_color;
|
||||
|
||||
uniform sampler2D u_texture;
|
||||
|
||||
void main(){
|
||||
f_color = texture(u_texture, v_coord);
|
||||
}
|
||||
291
res/shaders/skybox_gen.glslf
Normal file
291
res/shaders/skybox_gen.glslf
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Dimas Leenman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#version 330 core
|
||||
|
||||
// first, lets define some constants to use (planet radius, position, and scattering coefficients)
|
||||
#define PLANET_POS vec3(0.0) /* the position of the planet */
|
||||
#define PLANET_RADIUS 6371e3 /* radius of the planet */
|
||||
#define ATMOS_RADIUS 6471e3 /* radius of the atmosphere */
|
||||
// scattering coeffs
|
||||
#define RAY_BETA vec3(5.5e-6, 13.0e-6, 22.4e-6) /* rayleigh, affects the color of the sky */
|
||||
#define MIE_BETA vec3(21e-6) /* mie, affects the color of the blob around the sun */
|
||||
#define AMBIENT_BETA vec3(0.0) /* ambient, affects the scattering color when there is no lighting from the sun */
|
||||
#define ABSORPTION_BETA vec3(2.04e-5, 4.97e-5, 1.95e-6) /* what color gets absorbed by the atmosphere (Due to things like ozone) */
|
||||
#define G 0.9 /* mie scattering direction, or how big the blob around the sun is */
|
||||
// and the heights (how far to go up before the scattering has no effect)
|
||||
#define HEIGHT_RAY 8e3 /* rayleigh height */
|
||||
#define HEIGHT_MIE 1.2e3 /* and mie */
|
||||
#define HEIGHT_ABSORPTION 30e3 /* at what height the absorption is at it's maximum */
|
||||
#define ABSORPTION_FALLOFF 4e3 /* how much the absorption decreases the further away it gets from the maximum height */
|
||||
// and the steps (more looks better, but is slower)
|
||||
// the primary step has the most effect on looks
|
||||
#define PRIMARY_STEPS 12
|
||||
#define LIGHT_STEPS 4
|
||||
|
||||
vec3 calculate_scattering(
|
||||
vec3 start, // the start of the ray (the camera position)
|
||||
vec3 dir, // the direction of the ray (the camera vector)
|
||||
float max_dist, // the maximum distance the ray can travel (because something is in the way, like an object)
|
||||
vec3 scene_color, // the color of the scene
|
||||
vec3 light_dir, // the direction of the light
|
||||
vec3 light_intensity, // how bright the light is, affects the brightness of the atmosphere
|
||||
vec3 planet_position, // the position of the planet
|
||||
float planet_radius, // the radius of the planet
|
||||
float atmo_radius, // the radius of the atmosphere
|
||||
vec3 beta_ray, // the amount rayleigh scattering scatters the colors (for earth: causes the blue atmosphere)
|
||||
vec3 beta_mie, // the amount mie scattering scatters colors
|
||||
vec3 beta_absorption, // how much air is absorbed
|
||||
vec3 beta_ambient, // the amount of scattering that always occurs, cna help make the back side of the atmosphere a bit brighter
|
||||
float g, // the direction mie scatters the light in (like a cone). closer to -1 means more towards a single direction
|
||||
float height_ray, // how high do you have to go before there is no rayleigh scattering?
|
||||
float height_mie, // the same, but for mie
|
||||
float height_absorption, // the height at which the most absorption happens
|
||||
float absorption_falloff, // how fast the absorption falls off from the absorption height
|
||||
int steps_i, // the amount of steps along the 'primary' ray, more looks better but slower
|
||||
int steps_l // the amount of steps along the light ray, more looks better but slower
|
||||
) {
|
||||
// add an offset to the camera position, so that the atmosphere is in the correct position
|
||||
start -= planet_position;
|
||||
// calculate the start and end position of the ray, as a distance along the ray
|
||||
// we do this with a ray sphere intersect
|
||||
float a = dot(dir, dir);
|
||||
float b = 2.0 * dot(dir, start);
|
||||
float c = dot(start, start) - (atmo_radius * atmo_radius);
|
||||
float d = (b * b) - 4.0 * a * c;
|
||||
|
||||
// stop early if there is no intersect
|
||||
if (d < 0.0) return scene_color;
|
||||
|
||||
// calculate the ray length
|
||||
vec2 ray_length = vec2(
|
||||
max((-b - sqrt(d)) / (2.0 * a), 0.0),
|
||||
min((-b + sqrt(d)) / (2.0 * a), max_dist)
|
||||
);
|
||||
|
||||
// if the ray did not hit the atmosphere, return a black color
|
||||
if (ray_length.x > ray_length.y) return scene_color;
|
||||
// prevent the mie glow from appearing if there's an object in front of the camera
|
||||
bool allow_mie = max_dist > ray_length.y;
|
||||
// make sure the ray is no longer than allowed
|
||||
ray_length.y = min(ray_length.y, max_dist);
|
||||
ray_length.x = max(ray_length.x, 0.0);
|
||||
// get the step size of the ray
|
||||
float step_size_i = (ray_length.y - ray_length.x) / float(steps_i);
|
||||
|
||||
// next, set how far we are along the ray, so we can calculate the position of the sample
|
||||
// if the camera is outside the atmosphere, the ray should start at the edge of the atmosphere
|
||||
// if it's inside, it should start at the position of the camera
|
||||
// the min statement makes sure of that
|
||||
float ray_pos_i = ray_length.x + step_size_i * 0.5;
|
||||
|
||||
// these are the values we use to gather all the scattered light
|
||||
vec3 total_ray = vec3(0.0); // for rayleigh
|
||||
vec3 total_mie = vec3(0.0); // for mie
|
||||
|
||||
// initialize the optical depth. This is used to calculate how much air was in the ray
|
||||
vec3 opt_i = vec3(0.0);
|
||||
|
||||
// also init the scale height, avoids some vec2's later on
|
||||
vec2 scale_height = vec2(height_ray, height_mie);
|
||||
|
||||
// Calculate the Rayleigh and Mie phases.
|
||||
// This is the color that will be scattered for this ray
|
||||
// mu, mumu and gg are used quite a lot in the calculation, so to speed it up, precalculate them
|
||||
float mu = dot(dir, light_dir);
|
||||
float mumu = mu * mu;
|
||||
float gg = g * g;
|
||||
float phase_ray = 3.0 / (50.2654824574 /* (16 * pi) */) * (1.0 + mumu);
|
||||
float phase_mie = allow_mie ? 3.0 / (25.1327412287 /* (8 * pi) */) * ((1.0 - gg) * (mumu + 1.0)) / (pow(1.0 + gg - 2.0 * mu * g, 1.5) * (2.0 + gg)) : 0.0;
|
||||
|
||||
// now we need to sample the 'primary' ray. this ray gathers the light that gets scattered onto it
|
||||
for (int i = 0; i < steps_i; ++i) {
|
||||
|
||||
// calculate where we are along this ray
|
||||
vec3 pos_i = start + dir * ray_pos_i;
|
||||
|
||||
// and how high we are above the surface
|
||||
float height_i = length(pos_i) - planet_radius;
|
||||
|
||||
// now calculate the density of the particles (both for rayleigh and mie)
|
||||
vec3 density = vec3(exp(-height_i / scale_height), 0.0);
|
||||
|
||||
// and the absorption density. this is for ozone, which scales together with the rayleigh,
|
||||
// but absorbs the most at a specific height, so use the sech function for a nice curve falloff for this height
|
||||
// clamp it to avoid it going out of bounds. This prevents weird black spheres on the night side
|
||||
float denom = (height_absorption - height_i) / absorption_falloff;
|
||||
density.z = (1.0 / (denom * denom + 1.0)) * density.x;
|
||||
|
||||
// multiply it by the step size here
|
||||
// we are going to use the density later on as well
|
||||
density *= step_size_i;
|
||||
|
||||
// Add these densities to the optical depth, so that we know how many particles are on this ray.
|
||||
opt_i += density;
|
||||
|
||||
// Calculate the step size of the light ray.
|
||||
// again with a ray sphere intersect
|
||||
// a, b, c and d are already defined
|
||||
a = dot(light_dir, light_dir);
|
||||
b = 2.0 * dot(light_dir, pos_i);
|
||||
c = dot(pos_i, pos_i) - (atmo_radius * atmo_radius);
|
||||
d = (b * b) - 4.0 * a * c;
|
||||
|
||||
// no early stopping, this one should always be inside the atmosphere
|
||||
// calculate the ray length
|
||||
float step_size_l = (-b + sqrt(d)) / (2.0 * a * float(steps_l));
|
||||
|
||||
// and the position along this ray
|
||||
// this time we are sure the ray is in the atmosphere, so set it to 0
|
||||
float ray_pos_l = step_size_l * 0.5;
|
||||
|
||||
// and the optical depth of this ray
|
||||
vec3 opt_l = vec3(0.0);
|
||||
|
||||
// now sample the light ray
|
||||
// this is similar to what we did before
|
||||
for (int l = 0; l < steps_l; ++l) {
|
||||
|
||||
// calculate where we are along this ray
|
||||
vec3 pos_l = pos_i + light_dir * ray_pos_l;
|
||||
|
||||
// the heigth of the position
|
||||
float height_l = length(pos_l) - planet_radius;
|
||||
|
||||
// calculate the particle density, and add it
|
||||
// this is a bit verbose
|
||||
// first, set the density for ray and mie
|
||||
vec3 density_l = vec3(exp(-height_l / scale_height), 0.0);
|
||||
|
||||
// then, the absorption
|
||||
float denom = (height_absorption - height_l) / absorption_falloff;
|
||||
density_l.z = (1.0 / (denom * denom + 1.0)) * density_l.x;
|
||||
|
||||
// multiply the density by the step size
|
||||
density_l *= step_size_l;
|
||||
|
||||
// and add it to the total optical depth
|
||||
opt_l += density_l;
|
||||
|
||||
// and increment where we are along the light ray.
|
||||
ray_pos_l += step_size_l;
|
||||
|
||||
}
|
||||
|
||||
// Now we need to calculate the attenuation
|
||||
// this is essentially how much light reaches the current sample point due to scattering
|
||||
vec3 attn = exp(-beta_ray * (opt_i.x + opt_l.x) - beta_mie * (opt_i.y + opt_l.y) - beta_absorption * (opt_i.z + opt_l.z));
|
||||
|
||||
// accumulate the scattered light (how much will be scattered towards the camera)
|
||||
total_ray += density.x * attn;
|
||||
total_mie += density.y * attn;
|
||||
|
||||
// and increment the position on this ray
|
||||
ray_pos_i += step_size_i;
|
||||
|
||||
}
|
||||
|
||||
// calculate how much light can pass through the atmosphere
|
||||
vec3 opacity = exp(-(beta_mie * opt_i.y + beta_ray * opt_i.x + beta_absorption * opt_i.z));
|
||||
|
||||
// calculate and return the final color
|
||||
return (
|
||||
phase_ray * beta_ray * total_ray // rayleigh color
|
||||
+ phase_mie * beta_mie * total_mie // mie
|
||||
+ opt_i.x * beta_ambient // and ambient
|
||||
) * light_intensity + scene_color * opacity; // now make sure the background is rendered correctly
|
||||
}
|
||||
|
||||
vec2 ray_sphere_intersect(
|
||||
vec3 start, // starting position of the ray
|
||||
vec3 dir, // the direction of the ray
|
||||
float radius // and the sphere radius
|
||||
) {
|
||||
// ray-sphere intersection that assumes
|
||||
// the sphere is centered at the origin.
|
||||
// No intersection when result.x > result.y
|
||||
float a = dot(dir, dir);
|
||||
float b = 2.0 * dot(dir, start);
|
||||
float c = dot(start, start) - (radius * radius);
|
||||
float d = (b*b) - 4.0*a*c;
|
||||
if (d < 0.0) return vec2(1e5,-1e5);
|
||||
return vec2(
|
||||
(-b - sqrt(d))/(2.0*a),
|
||||
(-b + sqrt(d))/(2.0*a)
|
||||
);
|
||||
}
|
||||
|
||||
in vec2 v_coord;
|
||||
out vec4 f_color;
|
||||
|
||||
uniform vec3 u_xaxis;
|
||||
uniform vec3 u_yaxis;
|
||||
uniform vec3 u_zaxis;
|
||||
uniform vec3 u_lightDir;
|
||||
uniform int u_quality;
|
||||
uniform float u_mie;
|
||||
|
||||
void main() {
|
||||
vec3 camera_position = vec3(0.0f, PLANET_RADIUS+1.0f, 0.0f);
|
||||
vec3 camera_vector = normalize(u_xaxis * v_coord.x +
|
||||
u_yaxis * -v_coord.y -
|
||||
u_zaxis);
|
||||
// hide darkness at horizon
|
||||
camera_vector.y = max(0.01, camera_vector.y)*(1.0-u_mie*0.08) + 0.08*u_mie;
|
||||
camera_vector = normalize(camera_vector);
|
||||
|
||||
// the color of this pixel
|
||||
vec3 col = vec3(0.0);//scene.xyz;
|
||||
|
||||
// get the atmosphere color
|
||||
col += calculate_scattering(
|
||||
camera_position, // the position of the camera
|
||||
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(40.0), // light intensity, 40 looks nice
|
||||
PLANET_POS, // position of the planet
|
||||
PLANET_RADIUS, // radius of the planet in meters
|
||||
ATMOS_RADIUS, // radius of the atmosphere in meters
|
||||
RAY_BETA, // Rayleigh scattering coefficient
|
||||
MIE_BETA, // Mie scattering coefficient
|
||||
ABSORPTION_BETA, // Absorbtion coefficient
|
||||
AMBIENT_BETA, // ambient scattering, turned off for now. This causes the air to glow a bit when no light reaches it
|
||||
G, // Mie preferred scattering direction
|
||||
HEIGHT_RAY, // Rayleigh scale height
|
||||
HEIGHT_MIE*u_mie*u_mie, // Mie scale height
|
||||
HEIGHT_ABSORPTION, // the height at which the most absorption happens
|
||||
ABSORPTION_FALLOFF, // how fast the absorption falls off from the absorption height
|
||||
PRIMARY_STEPS*u_quality, // steps in the ray direction
|
||||
LIGHT_STEPS*u_quality // steps in the light direction
|
||||
);
|
||||
|
||||
// apply exposure, removing this makes the brighter colors look ugly
|
||||
// you can play around with removing this
|
||||
col = 1.0 - exp(-col);
|
||||
|
||||
// Output to screen
|
||||
f_color = vec4(col, 1.0);
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
#version 330 core
|
||||
|
||||
layout (location = 0) in vec2 v_position;
|
||||
|
||||
out vec2 v_coord;
|
||||
|
||||
void main(){
|
||||
v_coord = v_position*0.5+0.5;
|
||||
gl_Position = vec4(v_position, 0.0, 1.0);
|
||||
}
|
||||
#version 330 core
|
||||
|
||||
layout (location = 0) in vec2 v_position;
|
||||
|
||||
out vec2 v_coord;
|
||||
|
||||
void main(){
|
||||
v_coord = v_position;
|
||||
gl_Position = vec4(v_position, 0.0, 1.0);
|
||||
}
|
||||
@ -110,6 +110,8 @@ void AssetsLoader::addDefaults(AssetsLoader& loader) {
|
||||
loader.add(ASSET_SHADER, resdir/path(SHADERS_FOLDER"/main"), "main");
|
||||
loader.add(ASSET_SHADER, resdir/path(SHADERS_FOLDER"/lines"), "lines");
|
||||
loader.add(ASSET_SHADER, resdir/path(SHADERS_FOLDER"/ui"), "ui");
|
||||
loader.add(ASSET_SHADER, resdir/path(SHADERS_FOLDER"/background"), "background");
|
||||
loader.add(ASSET_SHADER, resdir/path(SHADERS_FOLDER"/skybox_gen"), "skybox_gen");
|
||||
|
||||
loader.add(ASSET_ATLAS, resdir/path(TEXTURES_FOLDER"/blocks"), "blocks");
|
||||
loader.add(ASSET_TEXTURE, resdir/path(TEXTURES_FOLDER"/menubg.png"), "menubg");
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#define PLAYER_FLAG_NOCLIP 0x2
|
||||
|
||||
#define WORLD_SECTION_MAIN 1
|
||||
#define WORLD_SECTION_DAYNIGHT 2
|
||||
|
||||
using glm::ivec2;
|
||||
using glm::vec3;
|
||||
@ -235,11 +236,15 @@ void WorldFiles::writeWorldInfo(const WorldInfo& info) {
|
||||
BinaryWriter out;
|
||||
out.putCStr(WORLD_FORMAT_MAGIC);
|
||||
out.put(WORLD_FORMAT_VERSION);
|
||||
|
||||
out.put(WORLD_SECTION_MAIN);
|
||||
|
||||
out.putInt64(info.seed);
|
||||
out.put(info.name);
|
||||
|
||||
out.put(WORLD_SECTION_DAYNIGHT);
|
||||
out.putFloat32(info.daytime);
|
||||
out.putFloat32(info.daytimeSpeed);
|
||||
|
||||
files::write_bytes(getWorldFile(), (const char*)out.data(), out.size());
|
||||
}
|
||||
|
||||
@ -260,6 +265,10 @@ bool WorldFiles::readWorldInfo(WorldInfo& info) {
|
||||
info.seed = inp.getInt64();
|
||||
info.name = inp.getString();
|
||||
break;
|
||||
case WORLD_SECTION_DAYNIGHT:
|
||||
info.daytime = inp.getFloat32();
|
||||
info.daytimeSpeed = inp.getFloat32();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@ -36,6 +36,8 @@ struct WorldInfo {
|
||||
std::string name;
|
||||
std::filesystem::path directory;
|
||||
uint64_t seed;
|
||||
float daytime;
|
||||
float daytimeSpeed;
|
||||
};
|
||||
|
||||
class WorldFiles {
|
||||
|
||||
111
src/frontend/graphics/Skybox.cpp
Normal file
111
src/frontend/graphics/Skybox.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
#include "Skybox.h"
|
||||
#include <GL/glew.h>
|
||||
#include <iostream>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "../../graphics/Shader.h"
|
||||
#include "../../graphics/Mesh.h"
|
||||
#include "../../window/Window.h"
|
||||
|
||||
using glm::vec3;
|
||||
|
||||
Skybox::Skybox(uint size, Shader* shader) : size(size), shader(shader) {
|
||||
glGenTextures(1, &cubemap);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);
|
||||
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
for (uint face = 0; face < 6; face++) {
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
}
|
||||
glGenFramebuffers(1, &fbo);
|
||||
|
||||
float vertices[] {
|
||||
-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
|
||||
-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f
|
||||
};
|
||||
vattr attrs[] {2, 0};
|
||||
mesh = new Mesh(vertices, 6, attrs);
|
||||
}
|
||||
|
||||
Skybox::~Skybox() {
|
||||
glDeleteTextures(1, &cubemap);
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
void Skybox::draw(Shader* shader) {
|
||||
shader->uniform1i("u_cubemap", 1);
|
||||
bind();
|
||||
mesh->draw();
|
||||
unbind();
|
||||
}
|
||||
|
||||
void Skybox::refresh(float t, float mie, uint quality) {
|
||||
ready = true;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);
|
||||
shader->use();
|
||||
Window::viewport(0,0, size,size);
|
||||
const vec3 xaxs[] = {
|
||||
{0.0f, 0.0f, -1.0f},
|
||||
{0.0f, 0.0f, 1.0f},
|
||||
{-1.0f, 0.0f, 0.0f},
|
||||
|
||||
{-1.0f, 0.0f, 0.0f},
|
||||
{-1.0f, 0.0f, 0.0f},
|
||||
{1.0f, 0.0f, 0.0f},
|
||||
};
|
||||
const vec3 yaxs[] = {
|
||||
{0.0f, 1.0f, 0.0f},
|
||||
{0.0f, 1.0f, 0.0f},
|
||||
{0.0f, 0.0f, -1.0f},
|
||||
|
||||
{0.0f, 0.0f, 1.0f},
|
||||
{0.0f, 1.0f, 0.0f},
|
||||
{0.0f, 1.0f, 0.0f},
|
||||
};
|
||||
|
||||
const vec3 zaxs[] = {
|
||||
{1.0f, 0.0f, 0.0f},
|
||||
{-1.0f, 0.0f, 0.0f},
|
||||
{0.0f, -1.0f, 0.0f},
|
||||
|
||||
{0.0f, 1.0f, 0.0f},
|
||||
{0.0f, 0.0f, -1.0f},
|
||||
{0.0f, 0.0f, 1.0f},
|
||||
};
|
||||
t *= M_PI*2.0f;
|
||||
|
||||
shader->uniform1i("u_quality", quality);
|
||||
shader->uniform1f("u_mie", mie);
|
||||
shader->uniform3f("u_lightDir", glm::normalize(vec3(sin(t), -cos(t), 0.7f)));
|
||||
for (uint face = 0; face < 6; face++) {
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, cubemap, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
shader->uniform3f("u_xaxis", xaxs[face]);
|
||||
shader->uniform3f("u_yaxis", yaxs[face]);
|
||||
shader->uniform3f("u_zaxis", zaxs[face]);
|
||||
mesh->draw(GL_TRIANGLES);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
Window::viewport(0, 0, Window::width, Window::height);
|
||||
}
|
||||
|
||||
void Skybox::bind() const {
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void Skybox::unbind() const {
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
30
src/frontend/graphics/Skybox.h
Normal file
30
src/frontend/graphics/Skybox.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef FRONTEND_GRAPHICS_SKYBOX_H_
|
||||
#define FRONTEND_GRAPHICS_SKYBOX_H_
|
||||
|
||||
#include "../../typedefs.h"
|
||||
|
||||
class Mesh;
|
||||
class Shader;
|
||||
|
||||
class Skybox {
|
||||
uint fbo;
|
||||
uint cubemap;
|
||||
uint size;
|
||||
Mesh* mesh;
|
||||
Shader* shader;
|
||||
bool ready = false;
|
||||
public:
|
||||
Skybox(uint size, Shader* shader);
|
||||
~Skybox();
|
||||
|
||||
void draw(Shader* shader);
|
||||
|
||||
void refresh(float t, float mie, uint quality);
|
||||
void bind() const;
|
||||
void unbind() const;
|
||||
bool isReady() const {
|
||||
return ready;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // FRONTEND_GRAPHICS_SKYBOX_H_
|
||||
@ -11,6 +11,7 @@
|
||||
#include "../typedefs.h"
|
||||
#include "../content/Content.h"
|
||||
#include "../util/stringutil.h"
|
||||
#include "../util/timeutil.h"
|
||||
#include "../assets/Assets.h"
|
||||
#include "../graphics/Shader.h"
|
||||
#include "../graphics/Batch2D.h"
|
||||
@ -128,13 +129,22 @@ HudRenderer::HudRenderer(Engine* engine,
|
||||
sub->add(box);
|
||||
panel->add(sub);
|
||||
}
|
||||
panel->add(shared_ptr<Label>(create_label([this](){
|
||||
int hour, minute, second;
|
||||
timeutil::from_value(this->level->world->daytime, hour, minute, second);
|
||||
|
||||
std::wstring timeString =
|
||||
util::lfill(std::to_wstring(hour), 2, L'0') + L":" +
|
||||
util::lfill(std::to_wstring(minute), 2, L'0');
|
||||
return L"time: "+timeString;
|
||||
})));
|
||||
{
|
||||
TrackBar* bar = new TrackBar(0.0f, 1.0f, 1.0f, 0.02f, 2);
|
||||
TrackBar* bar = new TrackBar(0.0f, 1.0f, 1.0f, 0.005f, 8);
|
||||
bar->supplier([=]() {
|
||||
return renderer->skyLightMutliplier;
|
||||
return level->world->daytime;
|
||||
});
|
||||
bar->consumer([=](double val) {
|
||||
renderer->skyLightMutliplier = val;
|
||||
level->world->daytime = val;
|
||||
});
|
||||
panel->add(bar);
|
||||
}
|
||||
|
||||
@ -136,6 +136,9 @@ void LevelScreen::update(float delta) {
|
||||
level->chunks->saveAndClear();
|
||||
backlight = settings.graphics.backlight;
|
||||
}
|
||||
if (!hud->isPause()) {
|
||||
level->world->updateTimers(delta);
|
||||
}
|
||||
level->updatePlayer(delta, !inputLocked, hud->isPause(), !inputLocked);
|
||||
level->update();
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "../settings.h"
|
||||
#include "../engine.h"
|
||||
#include "ContentGfxCache.h"
|
||||
#include "graphics/Skybox.h"
|
||||
|
||||
using glm::vec3;
|
||||
using std::string;
|
||||
@ -35,15 +36,19 @@ using std::shared_ptr;
|
||||
|
||||
WorldRenderer::WorldRenderer(Engine* engine, Level* level, const ContentGfxCache* cache)
|
||||
: engine(engine), level(level) {
|
||||
EngineSettings& settings = engine->getSettings();
|
||||
|
||||
lineBatch = new LineBatch(4096);
|
||||
renderer = new ChunksRenderer(level, cache, engine->getSettings());
|
||||
renderer = new ChunksRenderer(level, cache, settings);
|
||||
frustumCulling = new Frustum();
|
||||
level->events->listen(EVT_CHUNK_HIDDEN, [this](lvl_event_type type, Chunk* chunk) {
|
||||
renderer->unload(chunk);
|
||||
});
|
||||
skybox = new Skybox(64, engine->getAssets()->getShader("skybox_gen"));
|
||||
}
|
||||
|
||||
WorldRenderer::~WorldRenderer() {
|
||||
delete skybox;
|
||||
delete lineBatch;
|
||||
delete renderer;
|
||||
delete frustumCulling;
|
||||
@ -100,6 +105,10 @@ void WorldRenderer::drawChunks(Chunks* chunks,
|
||||
|
||||
|
||||
void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool occlusion){
|
||||
EngineSettings& settings = engine->getSettings();
|
||||
skybox->refresh(level->world->daytime,
|
||||
fmax(1.0f, 18.0f/settings.chunks.loadDistance), 4);
|
||||
|
||||
const Content* content = level->content;
|
||||
const ContentIndices* contentIds = content->indices;
|
||||
Assets* assets = engine->getAssets();
|
||||
@ -110,32 +119,32 @@ void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool occlusion)
|
||||
const Viewport& viewport = pctx.getViewport();
|
||||
int displayWidth = viewport.getWidth();
|
||||
int displayHeight = viewport.getHeight();
|
||||
Window::clearDepth();
|
||||
Window::viewport(0, 0, displayWidth, displayHeight);
|
||||
|
||||
Shader* backShader = assets->getShader("background");
|
||||
backShader->use();
|
||||
backShader->uniformMatrix("u_view", camera->getView(false));
|
||||
backShader->uniform1f("u_zoom", camera->zoom);
|
||||
backShader->uniform1f("u_ar", (float)Window::width/(float)Window::height);
|
||||
skybox->draw(backShader);
|
||||
|
||||
{
|
||||
GfxContext ctx = pctx.sub();
|
||||
ctx.depthTest(true);
|
||||
ctx.cullFace(true);
|
||||
|
||||
EngineSettings& settings = engine->getSettings();
|
||||
|
||||
vec3 skyColor(0.7f, 0.81f, 1.0f);
|
||||
skyColor *= skyLightMutliplier;
|
||||
|
||||
Window::setBgColor(skyColor);
|
||||
Window::clear();
|
||||
Window::viewport(0, 0, displayWidth, displayHeight);
|
||||
|
||||
float fogFactor = 18.0f / (float)settings.chunks.loadDistance;
|
||||
|
||||
shader->use();
|
||||
skybox->bind();
|
||||
shader->uniformMatrix("u_proj", camera->getProjection());
|
||||
shader->uniformMatrix("u_view", camera->getView());
|
||||
shader->uniform1f("u_gamma", 1.0f);
|
||||
shader->uniform3f("u_skyLightColor", vec3(1.1f) * skyLightMutliplier);
|
||||
shader->uniform3f("u_fogColor", skyColor);
|
||||
shader->uniform1f("u_fogFactor", fogFactor);
|
||||
shader->uniform1f("u_fogCurve", settings.graphics.fogCurve);
|
||||
shader->uniform3f("u_cameraPos", camera->position);
|
||||
shader->uniform1i("u_cubemap", 1);
|
||||
|
||||
Block* cblock = contentIds->getBlockDef(level->player->choosenBlock);
|
||||
assert(cblock != nullptr);
|
||||
@ -168,6 +177,7 @@ void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool occlusion)
|
||||
}
|
||||
lineBatch->render();
|
||||
}
|
||||
skybox->unbind();
|
||||
}
|
||||
|
||||
if (level->player->debug) {
|
||||
@ -175,7 +185,7 @@ void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool occlusion)
|
||||
ctx.depthTest(true);
|
||||
|
||||
linesShader->use();
|
||||
if (engine->getSettings().debug.showChunkBorders){
|
||||
if (settings.debug.showChunkBorders){
|
||||
linesShader->uniformMatrix("u_projview", camera->getProjView());
|
||||
vec3 coord = level->player->camera->position;
|
||||
if (coord.x < 0) coord.x--;
|
||||
|
||||
@ -22,6 +22,7 @@ class Frustum;
|
||||
class Engine;
|
||||
class Chunks;
|
||||
class ContentGfxCache;
|
||||
class Skybox;
|
||||
|
||||
class WorldRenderer {
|
||||
Engine* engine;
|
||||
@ -29,11 +30,10 @@ class WorldRenderer {
|
||||
Frustum* frustumCulling;
|
||||
LineBatch* lineBatch;
|
||||
ChunksRenderer* renderer;
|
||||
Skybox* skybox;
|
||||
bool drawChunk(size_t index, Camera* camera, Shader* shader, bool occlusion);
|
||||
void drawChunks(Chunks* chunks, Camera* camera, Shader* shader, bool occlusion);
|
||||
public:
|
||||
float skyLightMutliplier = 1.0f; // will be replaced with day-night cycle
|
||||
|
||||
WorldRenderer(Engine* engine, Level* level, const ContentGfxCache* cache);
|
||||
~WorldRenderer();
|
||||
|
||||
|
||||
14
src/util/timeutil.cpp
Normal file
14
src/util/timeutil.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include "timeutil.h"
|
||||
|
||||
float timeutil::time_value(float hour, float minute, float second) {
|
||||
return (hour + (minute + second / 60.0f) / 60.0f) / 24.0f;
|
||||
}
|
||||
|
||||
void timeutil::from_value(float value, int& hour, int& minute, int& second) {
|
||||
value *= 24;
|
||||
hour = value;
|
||||
value *= 60;
|
||||
minute = int(value) % 60;
|
||||
value *= 60;
|
||||
second = int(value) % 60;
|
||||
}
|
||||
9
src/util/timeutil.h
Normal file
9
src/util/timeutil.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef UTIL_TIMEUTIL_H_
|
||||
#define UTIL_TIMEUTIL_H_
|
||||
|
||||
namespace timeutil {
|
||||
float time_value(float hour, float minute, float second);
|
||||
void from_value(float value, int& hour, int& minute, int& second);
|
||||
}
|
||||
|
||||
#endif // UTIL_TIMEUTIL_H_
|
||||
@ -42,11 +42,16 @@ mat4 Camera::getProjection(){
|
||||
return glm::ortho(0.0f, fov*aspect, 0.0f, fov);
|
||||
}
|
||||
|
||||
mat4 Camera::getView(){
|
||||
if (perspective)
|
||||
mat4 Camera::getView(bool pos){
|
||||
vec3 position = this->position;
|
||||
if (!pos) {
|
||||
position = vec3(0.0f);
|
||||
}
|
||||
if (perspective) {
|
||||
return glm::lookAt(position, position+front, up);
|
||||
else
|
||||
} else {
|
||||
return glm::translate(glm::mat4(1.0f), position);
|
||||
}
|
||||
}
|
||||
|
||||
mat4 Camera::getProjView(){
|
||||
|
||||
@ -24,7 +24,7 @@ public:
|
||||
void rotate(float x, float y, float z);
|
||||
|
||||
mat4 getProjection();
|
||||
mat4 getView();
|
||||
mat4 getView(bool position=true);
|
||||
mat4 getProjView();
|
||||
};
|
||||
|
||||
|
||||
@ -127,6 +127,10 @@ int Window::initialize(DisplaySettings& settings){
|
||||
glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, GLFW_DONT_CARE);
|
||||
}
|
||||
glfwSwapInterval(settings.swapInterval);
|
||||
const GLubyte* vendor = glGetString(GL_VENDOR);
|
||||
const GLubyte* renderer = glGetString(GL_RENDERER);
|
||||
std::cout << "GL Vendor: " << (char*)vendor << std::endl;
|
||||
std::cout << "GL Renderer: " << (char*)renderer << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -134,6 +138,10 @@ void Window::clear() {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void Window::clearDepth() {
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void Window::setBgColor(glm::vec3 color) {
|
||||
glClearColor(color.r, color.g, color.b, 1.0f);
|
||||
}
|
||||
@ -252,6 +260,7 @@ DisplaySettings* Window::getSettings() {
|
||||
|
||||
ImageData* Window::takeScreenshot() {
|
||||
ubyte* data = new ubyte[width * height * 3];
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
|
||||
return new ImageData(ImageFormat::rgb888, width, height, data);
|
||||
}
|
||||
|
||||
@ -44,6 +44,7 @@ public:
|
||||
static void resetScissor();
|
||||
|
||||
static void clear();
|
||||
static void clearDepth();
|
||||
static void setBgColor(glm::vec3 color);
|
||||
static double time();
|
||||
static DisplaySettings* getSettings();
|
||||
|
||||
@ -29,6 +29,11 @@ World::~World(){
|
||||
delete wfile;
|
||||
}
|
||||
|
||||
void World::updateTimers(float delta) {
|
||||
daytime += delta * daytimeSpeed;
|
||||
daytime = fmod(daytime, 1.0f);
|
||||
}
|
||||
|
||||
void World::write(Level* level) {
|
||||
const Content* content = level->content;
|
||||
|
||||
@ -41,15 +46,17 @@ void World::write(Level* level) {
|
||||
wfile->put(chunk.get());
|
||||
}
|
||||
|
||||
wfile->write(WorldInfo {name, wfile->directory, seed}, content);
|
||||
wfile->write(WorldInfo {name, wfile->directory, seed, daytime, daytimeSpeed}, content);
|
||||
wfile->writePlayer(level->player);
|
||||
}
|
||||
|
||||
Level* World::load(EngineSettings& settings, const Content* content) {
|
||||
WorldInfo info {name, wfile->directory, seed};
|
||||
WorldInfo info {name, wfile->directory, seed, daytime, daytimeSpeed};
|
||||
wfile->readWorldInfo(info);
|
||||
seed = info.seed;
|
||||
name = info.name;
|
||||
daytime = info.daytime;
|
||||
daytimeSpeed = info.daytimeSpeed;
|
||||
|
||||
vec3 playerPosition = vec3(0, 100, 0);
|
||||
Camera* camera = new Camera(playerPosition, glm::radians(90.0f));
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <filesystem>
|
||||
#include "../typedefs.h"
|
||||
#include "../settings.h"
|
||||
#include "../util/timeutil.h"
|
||||
|
||||
class Content;
|
||||
class WorldFiles;
|
||||
@ -18,12 +19,20 @@ public:
|
||||
WorldFiles* wfile;
|
||||
uint64_t seed;
|
||||
|
||||
/* Day/night loop timer in range 0..1
|
||||
0.0 - is midnight
|
||||
0.5 - is noon
|
||||
*/
|
||||
float daytime = timeutil::time_value(10, 00, 00);
|
||||
float daytimeSpeed = 1.0f/60.0f/24.0f;
|
||||
|
||||
World(std::string name,
|
||||
std::filesystem::path directory,
|
||||
uint64_t seed,
|
||||
EngineSettings& settings);
|
||||
~World();
|
||||
|
||||
void updateTimers(float delta);
|
||||
void write(Level* level);
|
||||
Level* load(EngineSettings& settings, const Content* content);
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user