diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c90aa4256..6febfb2b1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - FxUpscale AA mode for higher quality graphics at reduced internal resolutions - Graphics presets - Sword +- Doors now animate opening when entities are near them. ### Changed - Use fluent for translations diff --git a/assets/voxygen/shaders/sprite-vert.glsl b/assets/voxygen/shaders/sprite-vert.glsl index fc1977482b..bcdf3089e3 100644 --- a/assets/voxygen/shaders/sprite-vert.glsl +++ b/assets/voxygen/shaders/sprite-vert.glsl @@ -15,6 +15,7 @@ #include #include #include +#include layout(location = 0) in vec4 inst_mat0; layout(location = 1) in vec4 inst_mat1; @@ -22,7 +23,7 @@ layout(location = 2) in vec4 inst_mat2; layout(location = 3) in vec4 inst_mat3; // TODO: is there a better way to pack the various vertex attributes? // TODO: ori is unused -layout(location = 4) in uint inst_pos_ori; +layout(location = 4) in uint inst_pos_ori_door; layout(location = 5) in uint inst_vert_page; // NOTE: this could fit in less bits // TODO: do we need this many bits for light and glow? layout(location = 6) in float inst_light; @@ -55,6 +56,24 @@ const float EXTRA_NEG_Z = 32768.0; const float VERT_EXTRA_NEG_Z = 128.0; const uint VERT_PAGE_SIZE = 256; +// vec4(vec3(position), distance) +vec4 nearest_entity(in vec3 sprite_pos, const float entity_radius_factor) { + vec4 closest = vec4(vec3(0), 65536); + + for (uint i = 0u; i < light_shadow_count.y; i ++) { + // Only access the array once + Shadow S = shadows[i]; + vec3 shadow_pos = S.shadow_pos_radius.xyz - focus_off.xyz; + float dist_sq = dot(sprite_pos - shadow_pos, sprite_pos - shadow_pos) + - S.shadow_pos_radius.w * S.shadow_pos_radius.w * entity_radius_factor; + if (dist_sq < closest.w) { + closest = vec4(shadow_pos, dist_sq); + } + } + closest.w = sqrt(max(closest.w, 0)); + return closest; +} + void main() { // Matrix to transform this sprite instance from model space to chunk space mat4 inst_mat; @@ -77,6 +96,35 @@ void main() { // Expand the model vertex position bits into float values vec3 v_pos = vec3(v_pos_norm & 0xFFu, (v_pos_norm >> 8) & 0xFFu, float((v_pos_norm >> 16) & 0x0FFFu) - VERT_EXTRA_NEG_Z); + // Position of the sprite block in the chunk + // Used for highlighting the selected sprite, and for opening doors + vec3 inst_chunk_pos = vec3(inst_pos_ori_door & 0x3Fu, (inst_pos_ori_door >> 6) & 0x3Fu, float((inst_pos_ori_door >> 12) & 0xFFFFu) - EXTRA_NEG_Z); + vec3 sprite_pos = inst_chunk_pos + chunk_offs; + float sprite_ori = (inst_pos_ori_door >> 29) & 0x7u; + + #ifndef EXPERIMENTAL_BAREMINIMUM + if((inst_pos_ori_door & (1 << 28)) != 0) { + const float MIN_OPEN_DIST = 0.2; + const float MAX_OPEN_DIST = 1.5; + float min_entity_dist = nearest_entity(sprite_pos + 0.5, 1.0).w; + + if (min_entity_dist < MAX_OPEN_DIST) { + float flip = sprite_ori <= 3 ? 1.0 : -1.0; + float theta = mix(PI/2.0, 0, pow(max(0.0, min_entity_dist - MIN_OPEN_DIST) / (MAX_OPEN_DIST - MIN_OPEN_DIST), 1.0)); + float costheta = cos(flip * theta); + float sintheta = sin(flip * theta); + mat3 rot_z = mat3( + vec3(costheta, -sintheta, 0), + vec3(sintheta, costheta, 0), + vec3(0, 0, 1) + ); + + vec3 delta = vec3(-0.0, -5.5, 0); + v_pos = (rot_z * (v_pos + delta)) - delta; + } + } + #endif + // Transform into chunk space and scale f_pos = (inst_mat * vec4(v_pos, 1.0)).xyz; // Transform info world space @@ -103,6 +151,17 @@ void main() { // NOTE: could potentially replace `v_pos.z * model_z_scale` with a calculation using `inst_chunk_pos` from below //) * pow(abs(v_pos.z * model_z_scale), 1.3) * SCALE_FACTOR; ) * v_pos.z * model_z_scale * SCALE_FACTOR; + + if (model_wind_sway > 0.0) { + vec2 center = sprite_pos.xy + 0.5; + vec4 min_entity = nearest_entity(vec3(center, sprite_pos.z), 0.0); + + const float PUSH_FACTOR = 5; + + float push_dist = max(1.0 - min_entity.w, 0.0); + + f_pos.xy += normalize(center - min_entity.xy) * v_pos.z * model_z_scale * SCALE_FACTOR * PUSH_FACTOR * push_dist; + } #endif // Determine normal @@ -127,11 +186,7 @@ void main() { // NOTE: Could defer to fragment shader if we are vert heavy f_uv_pos = vec2((uvec2(v_atlas_pos) >> uvec2(0, 16)) & uvec2(0xFFFFu, 0xFFFFu));; - // Position of the sprite block in the chunk - // Used solely for highlighting the selected sprite - vec3 inst_chunk_pos = vec3(inst_pos_ori & 0x3Fu, (inst_pos_ori >> 6) & 0x3Fu, float((inst_pos_ori >> 12) & 0xFFFFu) - EXTRA_NEG_Z); // Select glowing - vec3 sprite_pos = inst_chunk_pos + chunk_offs; f_select = (select_pos.w > 0 && select_pos.xyz == sprite_pos) ? 1.0 : 0.0; gl_Position = diff --git a/voxygen/src/render/pipelines/sprite.rs b/voxygen/src/render/pipelines/sprite.rs index b6eacd92a1..d6b4ec9e60 100644 --- a/voxygen/src/render/pipelines/sprite.rs +++ b/voxygen/src/render/pipelines/sprite.rs @@ -99,7 +99,7 @@ pub struct Instance { inst_mat1: [f32; 4], inst_mat2: [f32; 4], inst_mat3: [f32; 4], - pos_ori: u32, + pos_ori_door: u32, inst_vert_page: u32, inst_light: f32, inst_glow: f32, @@ -117,6 +117,7 @@ impl Instance { light: f32, glow: f32, vert_page: u32, + is_door: bool, ) -> Self { const EXTRA_NEG_Z: i32 = 32768; @@ -126,10 +127,11 @@ impl Instance { inst_mat1: mat_arr[1], inst_mat2: mat_arr[2], inst_mat3: mat_arr[3], - pos_ori: ((pos.x as u32) & 0x003F) + pos_ori_door: ((pos.x as u32) & 0x003F) | ((pos.y as u32) & 0x003F) << 6 | (((pos.z + EXTRA_NEG_Z).max(0).min(1 << 16) as u32) & 0xFFFF) << 12 - | (u32::from(ori_bits) & 0x7) << 29, + | (u32::from(ori_bits) & 0x7) << 29 + | (u32::from(is_door) & 1) << 28, inst_vert_page: vert_page, inst_light: light, inst_glow: glow, @@ -160,7 +162,19 @@ impl Instance { } impl Default for Instance { - fn default() -> Self { Self::new(Mat4::identity(), 0.0, 0.0, Vec3::zero(), 0, 1.0, 0.0, 0) } + fn default() -> Self { + Self::new( + Mat4::identity(), + 0.0, + 0.0, + Vec3::zero(), + 0, + 1.0, + 0.0, + 0, + false, + ) + } } // TODO: ColLightsWrapper instead? diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index bbbb9c1111..7045a77f0f 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -330,6 +330,7 @@ fn mesh_worker( light, glow, page, + matches!(sprite, SpriteKind::Door), ); lod_level.push(instance); }