From 1abfdfadf843dc510b549d3568e1c795a5c2db81 Mon Sep 17 00:00:00 2001 From: Roz K Date: Sun, 18 Dec 2022 04:53:28 +0100 Subject: [PATCH] Split vertex shader for terrain and tests. --- game/game.py | 57 ++++++++++------- game/shader.py | 13 ++-- ...ain_opengles.frag => common_opengles.frag} | 8 +-- game/shaders/terrain_opengles.vert | 19 +++--- game/shaders/tests_opengles.vert | 62 +++++++++++++++++++ 5 files changed, 115 insertions(+), 44 deletions(-) rename game/shaders/{terrain_opengles.frag => common_opengles.frag} (93%) create mode 100644 game/shaders/tests_opengles.vert diff --git a/game/game.py b/game/game.py index 9c38ea7..359467d 100644 --- a/game/game.py +++ b/game/game.py @@ -30,18 +30,21 @@ def main(): print("Initializing...") window = initialize(b'RK Island', 1600, 900) - terrain_shader = shader.load('terrain') + terrain_shader = shader.load('terrain', 'common') + tests_shader = shader.load('tests', 'common') sky_shader = shader.load('sky') heightmap = create_texture( 1, TEXTURE_FORMAT_32F, 256, 256, 0, TEXTURE_FLAG_MIN_LINEAR | TEXTURE_FLAG_MAG_LINEAR, generated.packed_heights) - heightmap_sampler = resolve_input(terrain_shader, b'u_height_sampler') + terrain_heightmap_sampler = resolve_input(terrain_shader, b'u_height_sampler') + tests_heightmap_sampler = resolve_input(tests_shader, b'u_height_sampler') normalmap = create_texture( 2, TEXTURE_FORMAT_RGB10_A2, 256, 256, 0, TEXTURE_FLAG_MIN_LINEAR | TEXTURE_FLAG_MAG_LINEAR, generated.packed_normals) - normalmap_sampler = resolve_input(terrain_shader, b'u_normal_sampler') + terrain_normalmap_sampler = resolve_input(terrain_shader, b'u_normal_sampler') + tests_normalmap_sampler = resolve_input(tests_shader, b'u_normal_sampler') print("Loading resources...") archive = resources.RuntimeArchive.load('data/rk_island.rkar') @@ -90,7 +93,7 @@ def main(): model.spawn(terrain_batch, (float(((mx - 128) * 8) + 4), float(((127 - my) * 8) + 4), 0.0)) tests_texture = archive.get_texture('tests') - tests_sampler = resolve_input(terrain_shader, b'u_texture_sampler') + tests_sampler = resolve_input(tests_shader, b'u_texture_sampler') tests_vertices = archive.get_vertices('tests') blob = archive.get_model('blob') cube = archive.get_model('cube') @@ -111,11 +114,15 @@ def main(): proj_far_z = 3000.0 terrain_environment_inputs = environment.resolve_inputs(terrain_shader) - terrain_orientation = resolve_param(terrain_shader, b'i_orientation') terrain_camera = camera.Camera() terrain_camera.set_projection(proj_hfov, proj_ratio, proj_near_z, proj_far_z) terrain_camera.resolve_inputs(terrain_shader) + tests_environment_inputs = environment.resolve_inputs(tests_shader) + tests_camera = camera.Camera() + tests_camera.set_projection(proj_hfov, proj_ratio, proj_near_z, proj_far_z) + tests_camera.resolve_inputs(tests_shader) + sky_environment_inputs = environment.resolve_inputs(sky_shader) sea_phase = resolve_input(sky_shader, b'u_sea_phase') sea_polar_textures = sea.load_polar_textures(('data/sea_bump1.png', 'data/sea_bump2.png')) @@ -162,6 +169,11 @@ def main(): mat3_mul_vec3(_origin, _rotation, origin) mat3_mul_vec3(_lookat, _rotation, lookat) + terrain_camera.set_view(_origin, _lookat) + tests_camera.set_view(_origin, _lookat) + sky_camera.set_view(vec3(math.vec3_scale(_origin, 0.001)), vec3(math.vec3_scale(_lookat, 0.001))) + environment_values = environment.from_sun(terrain_camera.view, sun_direction, sun_power) + mat3_rotation(_rotation, up, (current_time * 0.21) % tau) mat3_mul_vec3(_blob_translation, _rotation, blob_translation) tests_batch.set_param(0, blob_id, _blob_translation) @@ -176,39 +188,37 @@ def main(): tests_batch.set_param(1, clouds_id, _clouds_orientation) select_shader(terrain_shader) - select_texture(heightmap, heightmap_sampler) - select_texture(normalmap, normalmap_sampler) - - terrain_camera.set_view(_origin, _lookat) terrain_camera.update_inputs() - environment_values = environment.from_sun(terrain_camera.view, sun_direction, sun_power) environment.update_inputs(terrain_environment_inputs, environment_values) - select_texture(tiles_texture, tiles_sampler) + select_texture(heightmap, terrain_heightmap_sampler) + select_texture(normalmap, terrain_normalmap_sampler) select_vertices(tiles_vertices) - set_param_vec3(terrain_orientation, vec3(vec3_forward)) draw_begin = time.thread_time() terrain_batch.draw() draw_end = time.thread_time() unselect_vertices(tiles_vertices) unselect_texture(tiles_texture) - - select_texture(tests_texture, tests_sampler) - select_vertices(tests_vertices) - tests_batch.draw() - unselect_vertices(tests_vertices) - unselect_texture(tests_texture) - unselect_texture(normalmap) unselect_texture(heightmap) unselect_shader(terrain_shader) + select_shader(tests_shader) + tests_camera.update_inputs() + environment.update_inputs(tests_environment_inputs, environment_values) + select_texture(tests_texture, tests_sampler) + select_texture(heightmap, tests_heightmap_sampler) + select_texture(normalmap, tests_normalmap_sampler) + select_vertices(tests_vertices) + tests_batch.draw() + unselect_vertices(tests_vertices) + unselect_texture(tests_texture) + unselect_texture(normalmap) + unselect_texture(heightmap) + unselect_shader(tests_shader) + select_shader(sky_shader) - sky_camera.set_view( - vec3(math.vec3_scale(_origin, 0.001)), - vec3(math.vec3_scale(_lookat, 0.001))) sky_camera.update_inputs() - environment_values = environment.from_sun(sky_camera.view, sun_direction, sun_power) environment.update_inputs(sky_environment_inputs, environment_values) set_input_float(sea_phase, (current_time * 0.023) % 1.0) select_texture(sea_polar_textures, sea_polar_sampler) @@ -262,5 +272,6 @@ def main(): destroy_triangles(sky_triangles) archive.destroy() destroy_shader(terrain_shader) + destroy_shader(tests_shader) destroy_shader(sky_shader) terminate() diff --git a/game/shader.py b/game/shader.py index 2540c79..33af448 100644 --- a/game/shader.py +++ b/game/shader.py @@ -19,7 +19,10 @@ from engine import load_shader #TODO: preprocessing (at least includes) -def load(name): +def load(vert_name, frag_name = ''): + path = Path('.') / 'game' / 'shaders' + if not frag_name: + frag_name = vert_name def _cleanup(_line): return _line.partition('//')[0].strip() def _filter(_line): @@ -31,13 +34,13 @@ def load(name): print("Cannot find", _path) return None return list(map(_convert, filter(_filter, map(_cleanup, open(_path, 'rt'))))) - print("Loading shader", name) - path = Path('.') / 'game' / 'shaders' - vert_lines = load_source(path / (name + '_opengles.vert')) + print("Loading vertex shader", vert_name) + vert_lines = load_source(path / (vert_name + '_opengles.vert')) if not vert_lines: print("Error: Vertex shader is empty.") return None - frag_lines = load_source(path / (name + '_opengles.frag')) + print("Loading fragment shader", frag_name) + frag_lines = load_source(path / (frag_name + '_opengles.frag')) if not frag_lines: print("Error: Fragment shader is empty.") return None diff --git a/game/shaders/terrain_opengles.frag b/game/shaders/common_opengles.frag similarity index 93% rename from game/shaders/terrain_opengles.frag rename to game/shaders/common_opengles.frag index 520505b..a8ba8cb 100644 --- a/game/shaders/terrain_opengles.frag +++ b/game/shaders/common_opengles.frag @@ -16,8 +16,8 @@ #version 320 es precision highp float; -in vec3 v_position; // view space -in vec3 v_normal; // view space +in vec4 v_position; // view space +in vec4 v_normal; // view space in vec4 v_terrain_normal; // view space (x, y, z, weight) in vec4 v_texcoord; // texture space (s, t, pixel_level, material_level) @@ -36,8 +36,8 @@ void main(void) { #define m_metallic material.x #define m_specular material.y #define m_roughness material.z - vec3 normal = normalize(v_normal); - vec3 eye_dir = -normalize(v_position); + vec3 normal = normalize(v_normal.xyz); + vec3 eye_dir = -normalize(v_position.xyz); float d = dot(normal, u_light_direction); float halfd = 0.5 + d * 0.5; float td = dot(normalize(v_terrain_normal.xyz), u_light_direction); diff --git a/game/shaders/terrain_opengles.vert b/game/shaders/terrain_opengles.vert index abc65d3..6d0469d 100644 --- a/game/shaders/terrain_opengles.vert +++ b/game/shaders/terrain_opengles.vert @@ -21,7 +21,6 @@ layout(location = 1) in vec3 a_normal; // model space layout(location = 2) in vec3 a_texcoord; // texture space layout(location = 3) in vec3 i_translation; // per mesh, model space -> world space -layout(location = 4) in vec3 i_orientation; // per mesh, model space -> world space uniform mat4 u_view; // world space -> view space uniform mat4 u_projection; // view space -> screen space @@ -38,25 +37,21 @@ const float c_weight_scale = 1.0 / 64.f; const vec3 c_world_forward = vec3(0.0, 1.0, 0.0); const vec3 c_world_up = vec3(0.0, 0.0, 1.0); -out vec3 v_position; // view space -out vec3 v_normal; // view space +out vec4 v_position; // view space +out vec4 v_normal; // view space out vec4 v_terrain_normal; // view space (x, y, z, weigth) out vec4 v_texcoord; // texture space (s, t, pixel_level, material_level) void main(void) { - vec3 orientation = normalize(i_orientation); - mat3 rotation = mat3(cross(orientation, c_world_up), orientation, c_world_up); - vec4 world_position = vec4(i_translation.xyz + rotation * a_position, 1.0); - float weight = max(0.0, 1.0 - world_position.z * c_weight_scale); - vec3 world_normal = rotation * normalize(a_normal); + vec4 world_position = vec4(i_translation + a_position, 1.0); vec2 terrain_coords = c_terrain_shift + world_position.xy * c_terrain_scale; world_position.z += texture(u_height_sampler, terrain_coords).r; vec4 view_position = u_view * world_position; vec3 terrain_normal = normalize(c_normal_shift + texture(u_normal_sampler, terrain_coords).rgb * c_normal_scale); - world_normal = mat3(cross(c_world_forward, terrain_normal), c_world_forward, terrain_normal) * world_normal; - v_position = view_position.xyz; - v_normal = (u_view * vec4(world_normal, 0.0)).xyz; - v_terrain_normal = vec4((u_view * vec4(terrain_normal, 0.0)).xyz, weight); + vec3 world_normal = mat3(cross(c_world_forward, terrain_normal), c_world_forward, terrain_normal) * normalize(a_normal); + v_position = view_position; + v_normal = u_view * vec4(world_normal, 0.0); + v_terrain_normal = vec4((u_view * vec4(terrain_normal, 0.0)).xyz, 1.0); v_texcoord = vec4(a_texcoord.st * c_st_scale, a_texcoord.p, a_texcoord.p + 1.0); gl_Position = u_projection * view_position; } diff --git a/game/shaders/tests_opengles.vert b/game/shaders/tests_opengles.vert new file mode 100644 index 0000000..ca37b81 --- /dev/null +++ b/game/shaders/tests_opengles.vert @@ -0,0 +1,62 @@ +// Copyright (C) 2022 RozK +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#version 320 es +precision highp float; + +layout(location = 0) in vec3 a_position; // model space +layout(location = 1) in vec3 a_normal; // model space +layout(location = 2) in vec3 a_texcoord; // texture space + +layout(location = 3) in vec3 i_translation; // per mesh, model space -> world space +layout(location = 4) in vec3 i_orientation; // per mesh, model space -> world space + +uniform mat4 u_view; // world space -> view space +uniform mat4 u_projection; // view space -> screen space + +uniform highp sampler2D u_height_sampler; +uniform highp sampler2D u_normal_sampler; + +const vec3 c_normal_scale = vec3(2.0, 2.0, 1.0); +const vec3 c_normal_shift = vec3(-1.0, -1.0, 0.0); +const vec2 c_st_scale = vec2(1.0 / 1023.0, 1.0 / 1023.0); +const vec2 c_terrain_scale = vec2(1.0 / 2048.0, -1.0 / 2048.0); +const vec2 c_terrain_shift = vec2(0.5, 0.5); +const float c_weight_scale = 1.0 / 64.f; +const vec3 c_world_forward = vec3(0.0, 1.0, 0.0); +const vec3 c_world_up = vec3(0.0, 0.0, 1.0); + +out vec4 v_position; // view space +out vec4 v_normal; // view space +out vec4 v_terrain_normal; // view space (x, y, z, weigth) +out vec4 v_texcoord; // texture space (s, t, pixel_level, material_level) + +void main(void) { + vec3 orientation = normalize(i_orientation); + mat3 rotation = mat3(cross(orientation, c_world_up), orientation, c_world_up); + vec4 world_position = vec4(i_translation + rotation * a_position, 1.0); + float weight = max(0.0, 1.0 - world_position.z * c_weight_scale); + vec3 world_normal = rotation * normalize(a_normal); + vec2 terrain_coords = c_terrain_shift + world_position.xy * c_terrain_scale; + world_position.z += texture(u_height_sampler, terrain_coords).r; + vec4 view_position = u_view * world_position; + vec3 terrain_normal = normalize(c_normal_shift + texture(u_normal_sampler, terrain_coords).rgb * c_normal_scale); + world_normal = mat3(cross(c_world_forward, terrain_normal), c_world_forward, terrain_normal) * world_normal; + v_position = view_position; + v_normal = u_view * vec4(world_normal, 0.0); + v_terrain_normal = vec4((u_view * vec4(terrain_normal, 0.0)).xyz, weight); + v_texcoord = vec4(a_texcoord.st * c_st_scale, a_texcoord.p, a_texcoord.p + 1.0); + gl_Position = u_projection * view_position; +}