Add skybox

master
Elias Fleckenstein 2021-09-27 18:38:36 +02:00
parent a3b2351342
commit d6d852872a
31 changed files with 194 additions and 82 deletions

View File

@ -11,10 +11,9 @@ uniform mat4 MVP;
void main()
{
gl_Position = MVP * vec4(vertexPosition, 1.0);
gl_Position = MVP * vec4(vertexPosition, 1.0);
fragmentTextureIndex = vertexTextureIndex;
fragmentTextureCoords = vertexTextureCoords;
fragmentTextureIndex = vertexTextureIndex;
fragmentTextureCoords = vertexTextureCoords;
fragmentColor = vertexColor;
}

View File

@ -5,5 +5,5 @@ uniform mat4 projection;
void main()
{
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
}

View File

@ -8,6 +8,6 @@ uniform mat4 projection;
void main()
{
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
fragmentTextureCoords = vertexTextureCoords;
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
fragmentTextureCoords = vertexTextureCoords;
}

View File

@ -8,6 +8,6 @@ uniform mat4 projection;
void main()
{
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
fragmentTextureCoords = vertexTextureCoords;
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
fragmentTextureCoords = vertexTextureCoords;
}

View File

@ -0,0 +1,19 @@
in vec3 fragmentTextureCoords;
out vec4 outColor;
uniform bool transparency;
uniform float daylight;
uniform samplerCube textures[2];
void main()
{
outColor = mix(texture(textures[1], fragmentTextureCoords), texture(textures[0], fragmentTextureCoords), daylight);
if (transparency) {
float f = 0.2;
float e = 2.0;
outColor.a = pow((outColor.r + outColor.g) / 2.0 + f, e) / pow(1.0 + f, e);
}
}

12
shaders/sky/skybox/vertex.glsl Executable file
View File

@ -0,0 +1,12 @@
layout(location = 0) in vec3 vertexPosition;
out vec3 fragmentTextureCoords;
uniform mat4 VP;
void main()
{
gl_Position = VP * vec4(vertexPosition, 1.0);
gl_Position.z = gl_Position.w;
fragmentTextureCoords = vertexPosition;
}

View File

@ -7,7 +7,7 @@ uniform mat4 MVP;
void main()
{
gl_Position = MVP * vec4(vertexPosition, 1.0);
gl_Position = MVP * vec4(vertexPosition, 1.0);
gl_Position.z = gl_Position.w;
fragmentTextureCoords = vertexTextureCoords;
}

View File

@ -7,11 +7,6 @@
#define TILES_SIMPLE(path) {.paths = {path, NULL, NULL, NULL, NULL, NULL}, .indices = {0, 0, 0, 0, 0, 0}, .textures = {NULL}}
#define TILES_NONE {.paths = {NULL}, .indices = {0}, .textures = {NULL}}
static f64 clamp(f64 v, f64 min, f64 max)
{
return v < min ? min : v > max ? max : v;
}
static void render_grass(v3s32 pos, unused MapNode *node, Vertex3D *vertex, unused int f, unused int v)
{
f32 hum_min, hum_max, temp_max;

View File

@ -123,7 +123,7 @@ void debug_menu_update_daylight()
void debug_menu_update_sun_angle()
{
char text[BUFSIZ];
sprintf(text, "sun angle = %.1f", get_sun_angle() / M_PI * 180.0);
sprintf(text, "sun angle = %.1f", fmod(get_sun_angle() / M_PI * 180.0, 360.0));
gui_set_text(gui_elements[DME_SUN_ANGLE], text);
}

View File

@ -60,8 +60,6 @@ static void game_loop(Client *client)
frames++;
sky_clear();
glEnable(GL_DEPTH_TEST);
glEnable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
@ -73,8 +71,8 @@ static void game_loop(Client *client)
input_tick();
client_player_tick(dtime);
sky_render();
scene_render();
sky_render();
gui_render();
glfwSwapBuffers(window.handle);

View File

@ -32,7 +32,7 @@ bool scene_init()
glProgramUniform1iv(scene.prog, glGetUniformLocation(scene.prog, "textures"), scene.max_texture_units, texture_indices);
scene.fov = 86.1f;
scene.render_distance = 1000.0f;
scene.render_distance = 255.0f;
return true;
}

View File

@ -3,6 +3,7 @@
#include <GL/gl.h>
#include "client/camera.h"
#include "client/client.h"
#include "client/cube.h"
#include "client/mesh.h"
#include "client/scene.h"
#include "client/shader.h"
@ -12,6 +13,12 @@
static struct
{
GLuint skybox_prog;
GLint skybox_loc_VP;
GLint skybox_loc_transparency;
GLint skybox_loc_daylight;
GLuint skybox_textures[2];
Mesh *skybox_mesh;
GLuint sun_prog;
GLint sun_loc_MVP;
Texture *sun_texture;
@ -64,13 +71,77 @@ static VertexSun sun_vertices[6] = {
{{-0.5, -0.5, +0.0}, {+0.0, +0.0}},
};
typedef struct
{
GLfloat x, y, z;
} __attribute__((packed)) VertexSkyboxPosition;
typedef struct
{
VertexSkyboxPosition position;
} __attribute__((packed)) VertexSkybox;
static VertexAttribute skybox_vertex_attributes[2] = {
// position
{
.type = GL_FLOAT,
.length = 3,
.size = sizeof(VertexSkyboxPosition),
},
};
static VertexLayout skybox_vertex_layout = {
.attributes = skybox_vertex_attributes,
.count = 1,
.size = sizeof(VertexSkybox),
};
static VertexSkybox skybox_vertices[6][6];
bool sky_init()
{
if (! shader_program_create(RESSOURCEPATH "shaders/sky/skybox", &sky.skybox_prog, NULL)) {
fprintf(stderr, "Failed to create skybox shader program\n");
return false;
}
sky.skybox_loc_VP = glGetUniformLocation(sky.skybox_prog, "VP");
sky.skybox_loc_transparency = glGetUniformLocation(sky.skybox_prog, "transparency");
sky.skybox_loc_daylight = glGetUniformLocation(sky.skybox_prog, "daylight");
sky.skybox_textures[0] = texture_create_cubemap(RESSOURCEPATH "textures/skybox/day");
sky.skybox_textures[1] = texture_create_cubemap(RESSOURCEPATH "textures/skybox/night");
GLint texture_indices[2];
for (GLint i = 0; i < 2; i++)
texture_indices[i] = i;
glProgramUniform1iv(sky.skybox_prog, glGetUniformLocation(sky.skybox_prog, "textures"), 2, texture_indices);
for (int f = 0; f < 6; f++) {
for (int v = 0; v < 6; v++) {
skybox_vertices[f][v].position.x = cube_vertices[f][v].position.x;
skybox_vertices[f][v].position.y = cube_vertices[f][v].position.y;
skybox_vertices[f][v].position.z = cube_vertices[f][v].position.z;
}
}
sky.skybox_mesh = mesh_create();
sky.skybox_mesh->textures = sky.skybox_textures;
sky.skybox_mesh->textures_count = 2;
sky.skybox_mesh->free_textures = false;
sky.skybox_mesh->vertices = skybox_vertices;
sky.skybox_mesh->vertices_count = 36;
sky.skybox_mesh->free_vertices = false;
sky.skybox_mesh->layout = &skybox_vertex_layout;
if (! shader_program_create(RESSOURCEPATH "shaders/sky/sun", &sky.sun_prog, NULL)) {
fprintf(stderr, "Failed to create sun shader program\n");
return false;
}
sky.sun_loc_MVP = glGetUniformLocation(sky.sun_prog, "MVP");
sky.sun_texture = texture_get(RESSOURCEPATH "textures/sun.png");
sky.sun_mesh = mesh_create();
@ -87,17 +158,15 @@ bool sky_init()
void sky_deinit()
{
glDeleteProgram(sky.skybox_prog);
glDeleteTextures(1, &sky.skybox_textures[0]);
glDeleteTextures(1, &sky.skybox_textures[1]);
mesh_delete(sky.skybox_mesh);
glDeleteProgram(sky.sun_prog);
mesh_delete(sky.sun_mesh);
}
void sky_clear()
{
// sky color: #030A1A at night -> #87CEEB at day
f64 daylight = get_daylight();
glClearColor((daylight * (0x87 - 0x03) + 0x03) / 0xFF, (daylight * (0xCE - 0x0A) + 0x0A) / 0xFF, (daylight * (0xEB - 0x1A) + 0x1A) / 0xFF, 1.0f);
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
void sky_render()
@ -107,46 +176,38 @@ void sky_render()
vec3 sun_pos = {0.0f, cos(sun_angle), sin(sun_angle)};
vec3_norm(sun_pos, sun_pos);
vec3_scale(sun_pos, sun_pos, 5.0f);
vec3_add(sun_pos, sun_pos, camera.eye);
vec3 forward;
vec3_sub(forward, camera.eye, sun_pos);
vec3_norm(forward, forward);
vec3 up = {0.0f, 0.0f, 0.0f};
if (fabs(forward[0]) == 0.0f && fabs(forward[2]) == 0.0f) {
if (forward[2] > 0.0f)
up[2] = -1.0f;
else
up[2] = 1.0f;
} else {
up[1] = 1.0f;
}
vec3 left;
vec3_mul_cross(left, up, forward);
vec3_norm(left, left);
vec3_mul_cross(up, forward, left);
mat4x4 model = {
{left[0], up[0], forward[0], 0.0f},
{left[1], up[1], forward[1], 0.0f},
{left[2], up[2], forward[2], 0.0f},
{sun_pos[0], sun_pos[1], sun_pos[2], 1.0f},
};
mat4x4 model;
mat4x4_translate(model, sun_pos[0], sun_pos[1], sun_pos[2]);
mat4x4_rotate(model, model, 1.0f, 0.0f, 0.0f, sun_angle + 90);
mat4x4_rotate(model, model, 0.0f, 0.0f, 1.0f, M_PI / 4.0f);
mat4x4 VP, MVP;
mat4x4 view;
mat4x4_dup(view, camera.view);
view[3][0] = 0.0f;
view[3][1] = 0.0f;
view[3][2] = 0.0f;
mat4x4_mul(VP, scene.projection, camera.view);
mat4x4 VP;
mat4x4_mul(VP, scene.projection, view);
mat4x4 MVP;
mat4x4_mul(MVP, VP, model);
glDepthFunc(GL_LEQUAL);
glUseProgram(sky.skybox_prog);
glUniformMatrix4fv(sky.skybox_loc_VP, 1, GL_FALSE, VP[0]);
glUniform1i(sky.skybox_loc_transparency, 0);
glUniform1f(sky.skybox_loc_daylight, get_daylight());
mesh_render(sky.skybox_mesh);
glUseProgram(sky.sun_prog);
glUniformMatrix4fv(sky.sun_loc_MVP, 1, GL_FALSE, MVP[0]);
glDepthMask(GL_FALSE);
mesh_render(sky.sun_mesh);
glDepthMask(GL_TRUE);
glUseProgram(sky.skybox_prog);
glUniform1i(sky.skybox_loc_transparency, 1);
mesh_render(sky.skybox_mesh);
}
#pragma GCC diagnostic pop

View File

@ -5,7 +5,6 @@
bool sky_init();
void sky_deinit();
void sky_clear();
void sky_render();
#endif

View File

@ -9,8 +9,6 @@ static List textures;
__attribute((constructor(101))) static void textures_init()
{
stbi_set_flip_vertically_on_load(true);
textures = list_create(&list_compare_string);
}
@ -47,6 +45,46 @@ Texture *texture_create(unsigned char *data, int width, int height, GLenum forma
return texture;
}
GLuint texture_create_cubemap(char *path)
{
GLuint id;
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
const char *directions[6] = {
"right",
"left",
"top",
"bottom",
"front",
"back",
};
for (int i = 0; i < 6; i++) {
char filename[strlen(path) + 1 + strlen(directions[i]) + 1 + 3 + 1];
sprintf(filename, "%s/%s.png", path, directions[i]);
int width, height, channels;
unsigned char *data = stbi_load(filename, &width, &height, &channels, 0);
if (! data) {
fprintf(stderr, "Failed to load texture %s\n", filename);
return 0;
}
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
return id;
}
void texture_delete(Texture *texture)
{
glDeleteTextures(1, &texture->id);
@ -59,7 +97,7 @@ static void *create_image_texture(void *key)
unsigned char *data = stbi_load(key, &width, &height, &channels, 0);
if (! data) {
printf("Failed to load texture %s\n", (char *) key);
fprintf(stderr, "Failed to load texture %s\n", (char *) key);
return 0;
}

View File

@ -11,6 +11,7 @@ typedef struct
} Texture;
Texture *texture_create(unsigned char *data, int width, int height, GLenum format);
GLuint texture_create_cubemap(char *path);
void texture_delete(Texture *texture);
Texture *texture_get(char *path);

View File

@ -9,7 +9,7 @@ f64 get_time_of_day()
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return fmod((f64) ts.tv_sec - time_of_day_offset + ts.tv_nsec / 1.0e9, MINUTES_PER_DAY);
return fmod((f64) ts.tv_sec - time_of_day_offset + ts.tv_nsec / 1.0e9, MINUTES_PER_DAY);
}
void set_time_of_day(time_t new_time)
{
@ -21,25 +21,9 @@ f64 get_sun_angle()
return 2.0 * M_PI * (f64) get_time_of_day() / MINUTES_PER_DAY + M_PI;
}
// workaround for calculating the nth root of a number x, where x may be negative if n is an odd number
double root(double x, int n)
{
double sign = 1.0;
if (x < 0.0) {
if (n % 2 == 0)
return 0.0 / 0.0;
x = -x;
sign = -sign;
}
return pow(x, 1.0 / (double) n) * sign;
}
f64 get_daylight()
{
return root(cos(get_sun_angle()), 3) / 2.0 + 0.5;
return clamp(cos(get_sun_angle()) * 2.0 + 0.5, 0.0, 1.0);
}
void split_time_of_day(int *hours, int *minutes)

View File

@ -114,3 +114,8 @@ bool within_simulation_distance(v3f64 player_pos, v3s32 block_pos, u32 simulatio
v3s32 player_block_pos = map_node_to_block_pos((v3s32) {player_pos.x, player_pos.y, player_pos.z}, NULL);
return abs(player_block_pos.x - block_pos.x) <= simulation_distance && abs(player_block_pos.y - block_pos.y) <= simulation_distance && abs(player_block_pos.z - block_pos.z) <= simulation_distance;
}
f64 clamp(f64 v, f64 min, f64 max)
{
return v < min ? min : v > max ? max : v;
}

View File

@ -27,5 +27,6 @@ v3f32 html_to_v3f32(const char *html); // convert #RRGGBB c
void my_compress(const void *uncompressed, size_t uncompressed_size, char **compressed, size_t *compressed_size); // compress data using ZLib and store result(buffer allocated by malloc) in compressed
bool my_decompress(const char *compressed, size_t compressed_size, void *decompressed, size_t expected_decompressed_size); // decompress data and put result into decompressed, return false if decompressed size does not match expected_decompressed_size
bool within_simulation_distance(v3f64 player_pos, v3s32 block_pos, u32 simulation_distance); // return true if a player is close enough to a block to access it
f64 clamp(f64 v, f64 min, f64 max);
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

BIN
textures/skybox/day/top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 934 B

After

Width:  |  Height:  |  Size: 114 KiB