Almost implement instance merging for sprites (validation error), rebase

fix
This commit is contained in:
Imbris 2021-01-30 22:50:03 -05:00
parent cfd8606b04
commit b85e9eae89
16 changed files with 726 additions and 544 deletions

105
Cargo.lock generated
View File

@ -211,11 +211,11 @@ dependencies = [
[[package]]
name = "ash"
version = "0.31.0"
version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c69a8137596e84c22d57f3da1b5de1d4230b1742a710091c85f4d7ce50f00f38"
checksum = "06063a002a77d2734631db74e8f4ce7148b77fe522e6bca46f2ae7774fd48112"
dependencies = [
"libloading 0.6.7",
"libloading 0.7.0",
]
[[package]]
@ -693,6 +693,16 @@ dependencies = [
"objc",
]
[[package]]
name = "codespan-reporting"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
dependencies = [
"termcolor",
"unicode-width",
]
[[package]]
name = "color_quant"
version = "1.1.0"
@ -1227,11 +1237,10 @@ dependencies = [
[[package]]
name = "d3d12"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a60cceb22c7c53035f8980524fdc7f17cf49681a3c154e6757d30afbec6ec4"
source = "git+https://github.com/gfx-rs/d3d12-rs?rev=be19a243b86e0bafb9937d661fc8eabb3e42b44e#be19a243b86e0bafb9937d661fc8eabb3e42b44e"
dependencies = [
"bitflags",
"libloading 0.6.7",
"libloading 0.7.0",
"winapi 0.3.9",
]
@ -1886,8 +1895,7 @@ dependencies = [
[[package]]
name = "gfx-auxil"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7b33ecf067f2117668d91c9b0f2e5f223ebd1ffec314caa2f3de27bb580186d"
source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45"
dependencies = [
"fxhash",
"gfx-hal",
@ -1897,14 +1905,13 @@ dependencies = [
[[package]]
name = "gfx-backend-dx11"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f851d03c2e8f117e3702bf41201a4fafa447d5cb1276d5375870ae7573d069dd"
source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45"
dependencies = [
"arrayvec",
"bitflags",
"gfx-auxil",
"gfx-hal",
"libloading 0.6.7",
"libloading 0.7.0",
"log",
"parking_lot 0.11.1",
"range-alloc",
@ -1918,9 +1925,8 @@ dependencies = [
[[package]]
name = "gfx-backend-dx12"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5032d716a2a5f4dafb4675a794c5dc32081af8fbc7303c93ad93ff5413c6559f"
version = "0.7.0"
source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45"
dependencies = [
"arrayvec",
"bit-set",
@ -1941,8 +1947,7 @@ dependencies = [
[[package]]
name = "gfx-backend-empty"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f07ef26a65954cfdd7b4c587f485100d1bb3b0bd6a51b02d817d6c87cca7a91"
source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45"
dependencies = [
"gfx-hal",
"log",
@ -1951,18 +1956,18 @@ dependencies = [
[[package]]
name = "gfx-backend-gl"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6717c50ab601efe4a669bfb44db615e3888695ac8263222aeaa702642b9fbc2"
version = "0.7.0"
source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45"
dependencies = [
"arrayvec",
"bitflags",
"fxhash",
"gfx-auxil",
"gfx-hal",
"glow",
"js-sys",
"khronos-egl",
"libloading 0.6.7",
"libloading 0.7.0",
"log",
"naga",
"parking_lot 0.11.1",
@ -1975,8 +1980,7 @@ dependencies = [
[[package]]
name = "gfx-backend-metal"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dc54b456ece69ef49f8893269ebf24ac70969ed34ba2719c3f3abcc8fbff14e"
source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45"
dependencies = [
"arrayvec",
"bitflags",
@ -1984,6 +1988,7 @@ dependencies = [
"cocoa-foundation",
"copyless",
"foreign-types",
"fxhash",
"gfx-auxil",
"gfx-hal",
"log",
@ -2000,8 +2005,7 @@ dependencies = [
[[package]]
name = "gfx-backend-vulkan"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dabe88b1a5c91e0f969b441cc57e70364858066e4ba937deeb62065654ef9bd9"
source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45"
dependencies = [
"arrayvec",
"ash",
@ -2021,8 +2025,7 @@ dependencies = [
[[package]]
name = "gfx-hal"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1d9cc8d3b573dda62d0baca4f02e0209786e22c562caff001d77c389008781d"
source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45"
dependencies = [
"bitflags",
"naga",
@ -2170,7 +2173,6 @@ checksum = "1e7724b9aef57ea36d70faf54e0ee6265f86e41de16bed8333efdeab5b00e16b"
dependencies = [
"bitflags",
"gpu-alloc-types",
"tracing",
]
[[package]]
@ -2191,7 +2193,6 @@ dependencies = [
"bitflags",
"gpu-descriptor-types",
"hashbrown",
"tracing",
]
[[package]]
@ -2656,12 +2657,12 @@ dependencies = [
[[package]]
name = "khronos-egl"
version = "3.0.2"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b19cc4a81304db2a0ad69740e83cdc3a9364e3f9bd6d88a87288a4c2deec927b"
checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3"
dependencies = [
"libc",
"libloading 0.6.7",
"libloading 0.7.0",
]
[[package]]
@ -2957,8 +2958,7 @@ dependencies = [
[[package]]
name = "metal"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4598d719460ade24c7d91f335daf055bf2a7eec030728ce751814c50cdd6a26c"
source = "git+https://github.com/gfx-rs/metal-rs?rev=439c986eb7a9b91e88b61def2daa66e4043fcbef#439c986eb7a9b91e88b61def2daa66e4043fcbef"
dependencies = [
"bitflags",
"block",
@ -3085,12 +3085,12 @@ checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238"
[[package]]
name = "naga"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05089b2acdf0e6a962cdbf5e328402345a27f59fcde1a59fe97a73e8149d416f"
version = "0.3.1"
source = "git+https://github.com/gfx-rs/naga?tag=gfx-15#196523de7820d4907a14bd22517c4d572d26b0be"
dependencies = [
"bit-set",
"bitflags",
"codespan-reporting",
"fxhash",
"log",
"num-traits",
@ -3973,6 +3973,12 @@ dependencies = [
"unicode-xid 0.2.1",
]
[[package]]
name = "profiling"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c71198452babfbba7419e716d29853c462d59da73c41485ab7dc8b4dc0c4be"
[[package]]
name = "prometheus"
version = "0.12.0"
@ -4136,8 +4142,7 @@ dependencies = [
[[package]]
name = "range-alloc"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6"
source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45"
[[package]]
name = "raw-window-handle"
@ -6531,18 +6536,16 @@ dependencies = [
[[package]]
name = "wgpu"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79a0a0a63fac9492cfaf6e7e4bdf9729c128f1e94124b9e4cbc4004b8cb6d1d8"
version = "0.7.0"
source = "git+https://github.com/gfx-rs/wgpu-rs.git?rev=a7e03546c1584cefef5b926f923108ea2cd1c146#a7e03546c1584cefef5b926f923108ea2cd1c146"
dependencies = [
"arrayvec",
"js-sys",
"naga",
"parking_lot 0.11.1",
"profiling",
"raw-window-handle",
"smallvec",
"syn 1.0.65",
"tracing",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
@ -6552,9 +6555,8 @@ dependencies = [
[[package]]
name = "wgpu-core"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c89fa2cc5d72236461ac09c5be967012663e29cb62f1a972654cbf35e49dffa8"
version = "0.7.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=2f3b398e3887a336c963c43e7954f94cae42dd31#2f3b398e3887a336c963c43e7954f94cae42dd31"
dependencies = [
"arrayvec",
"bitflags",
@ -6570,12 +6572,13 @@ dependencies = [
"gfx-hal",
"gpu-alloc",
"gpu-descriptor",
"log",
"naga",
"parking_lot 0.11.1",
"profiling",
"raw-window-handle",
"smallvec",
"thiserror",
"tracing",
"wgpu-types",
]
@ -6592,8 +6595,7 @@ dependencies = [
[[package]]
name = "wgpu-types"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72fa9ba80626278fd87351555c363378d08122d7601e58319be3d6fa85a87747"
source = "git+https://github.com/gfx-rs/wgpu?rev=2f3b398e3887a336c963c43e7954f94cae42dd31#2f3b398e3887a336c963c43e7954f94cae42dd31"
dependencies = [
"bitflags",
]
@ -6862,8 +6864,3 @@ name = "xml-rs"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"
[[patch.unused]]
name = "wgpu"
version = "0.7.0"
source = "git+https://github.com/gfx-rs/wgpu-rs.git?rev=a7e03546c1584cefef5b926f923108ea2cd1c146#a7e03546c1584cefef5b926f923108ea2cd1c146"

View File

@ -22,9 +22,9 @@ layout(location = 2) flat in float f_select;
layout(location = 3) in vec2 f_uv_pos;
layout(location = 4) in vec2 f_inst_light;
layout(set = 4, binding = 0)
layout(set = 3, binding = 0)
uniform texture2D t_col_light;
layout(set = 4, binding = 1)
layout(set = 3, binding = 1)
uniform sampler s_col_light;
layout(location = 0) out vec4 tgt_color;

View File

@ -16,29 +16,22 @@
#include <srgb.glsl>
#include <sky.glsl>
layout(location = 0) in vec3 v_pos;
layout(location = 1) in uint v_atlas_pos;
layout(location = 2) in uint v_norm_ao;
layout(location = 3) in uint inst_pos_ori;
layout(location = 4) in vec4 inst_mat0;
layout(location = 5) in vec4 inst_mat1;
layout(location = 6) in vec4 inst_mat2;
layout(location = 7) in vec4 inst_mat3;
layout(location = 8) in vec4 inst_light;
layout(location = 9) in float inst_wind_sway;
layout(location = 0) in vec4 inst_mat0;
layout(location = 1) in vec4 inst_mat1;
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 = 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;
layout(location = 7) in float inst_glow;
layout(location = 8) in float model_wind_sway; // NOTE: this only varies per model
layout(location = 9) in float model_z_scale; // NOTE: this only varies per model
struct SpriteLocals {
mat4 mat;
vec4 wind_sway;
vec4 offs;
};
layout(std140, set = 3, binding = 0)
uniform u_locals {
mat4 mat;
vec4 wind_sway;
vec4 offs;
};
layout(set = 0, binding = 12) uniform utexture2D t_sprite_verts;
layout(set = 0, binding = 13) uniform sampler s_sprite_verts;
layout (std140, set = 2, binding = 0)
uniform u_terrain_locals {
@ -47,6 +40,7 @@ uniform u_terrain_locals {
ivec4 atlas_offs;
};
// TODO: consider grouping into vec4's
layout(location = 0) out vec3 f_pos;
layout(location = 1) flat out vec3 f_norm;
layout(location = 2) flat out float f_select;
@ -57,40 +51,64 @@ const float SCALE = 1.0 / 11.0;
const float SCALE_FACTOR = pow(SCALE, 1.3) * 0.2;
const int EXTRA_NEG_Z = 32768;
//const int VERT_EXTRA_NEG_Z = 128;
const int VERT_EXTRA_NEG_Z = 128;
const int VERT_PAGE_SIZE = 256;
//const int VERT_PAGE_SIZE = 256;
void main() {
// Matrix to transform this sprite instance from model space to chunk space
mat4 inst_mat;
inst_mat[0] = inst_mat0;
inst_mat[1] = inst_mat1;
inst_mat[2] = inst_mat2;
inst_mat[3] = inst_mat3;
vec3 inst_offs = model_offs - focus_off.xyz;
f_inst_light = inst_light.xy;
// Worldpos of the chunk that this sprite is in
vec3 chunk_offs = model_offs - focus_off.xyz;
vec3 v_pos_ = wind_sway.xyz * v_pos;
f_inst_light = vec2(inst_light, inst_glow);
f_pos = (inst_mat * vec4(v_pos_, 1.0)).xyz * SCALE + inst_offs;
// Index of the vertex data in the 1D vertex texture
int vertex_index = int(gl_VertexIndex % VERT_PAGE_SIZE + inst_vert_page);
const int WIDTH = 16384; // TODO: temp
ivec2 tex_coords = ivec2(vertex_index % WIDTH, vertex_index / WIDTH);
uvec2 pos_atlas_pos_norm_ao = texelFetch(usampler2D(t_sprite_verts, s_sprite_verts), tex_coords, 0).xy;
uint v_pos_norm = pos_atlas_pos_norm_ao.x;
uint v_atlas_pos = pos_atlas_pos_norm_ao.y;
// Expand the model vertex position bits into float values
vec3 v_pos = vec3(ivec3((uvec3(v_pos_norm) >> uvec3(0, 8, 16)) & uvec3(0xFu, 0xFu, 0x0FFFu)) - ivec3(0, 0, VERT_EXTRA_NEG_Z));
// Transform into chunk space and scale
f_pos = (inst_mat * vec4(v_pos, 1.0)).xyz;
// Transform info world space
f_pos += chunk_offs;
// Terrain 'pop-in' effect
f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0));
f_pos += wind_sway.w * vec3(
// Wind sway effect
f_pos += model_wind_sway * vec3(
sin(tick.x * 1.5 + f_pos.y * 0.1) * sin(tick.x * 0.35),
sin(tick.x * 1.5 + f_pos.x * 0.1) * sin(tick.x * 0.25),
0.0
//) * pow(abs(v_pos_.z), 1.3) * SCALE_FACTOR;
) * v_pos_.z * SCALE_FACTOR;
// 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;
vec3 norm = (inst_mat[(v_norm_ao >> 1u) & 3u].xyz);
f_norm = mix(-norm, norm, v_norm_ao & 1u);
// Determine normal
vec3 norm = (inst_mat[(v_pos_norm >> 30u) & 3u].xyz);
f_norm = mix(-norm, norm, v_pos_norm >> 29u & 1u);
f_uv_pos = vec2((uvec2(v_atlas_pos) >> uvec2(0, 16)) & uvec2(0xFFFFu, 0xFFFFu));/* + 0.5*/;
// Expand atlas tex coords to floats
// 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(ivec3((uvec3(inst_pos_ori) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0xFFFFu)) - ivec3(0, 0, EXTRA_NEG_Z));
// Select glowing
vec3 sprite_pos = floor(((inst_mat * vec4(-offs.xyz, 1)).xyz) * SCALE) + inst_offs;
vec3 sprite_pos = inst_chunk_pos + chunk_offs;
f_light = (select_pos.w > 0 && select_pos.xyz == sprite_pos) ? 1.0 : 0.0;
gl_Position =

View File

@ -28,6 +28,9 @@ impl<V: Vertex> Mesh<V> {
/// Get a mutable slice referencing the vertices of this mesh.
pub fn vertices_mut(&mut self) -> &mut [V] { &mut self.verts }
/// Get a mutable vec referencing the vertices of this mesh.
pub fn vertices_mut_vec(&mut self) -> &mut Vec<V> { &mut self.verts }
/// Push a new vertex onto the end of this mesh.
pub fn push(&mut self, vert: V) { self.verts.push(vert); }

View File

@ -31,7 +31,11 @@ pub use self::{
postprocess::Locals as PostProcessLocals,
shadow::{Locals as ShadowLocals, PointLightMatrix},
skybox::{create_mesh as create_skybox_mesh, Vertex as SkyboxVertex},
sprite::{Instance as SpriteInstance, Locals as SpriteLocals, Vertex as SpriteVertex},
sprite::{
create_verts_texture as create_sprite_verts_texture, Instance as SpriteInstance,
SpriteGlobalsBindGroup, Vertex as SpriteVertex,
VERT_PAGE_SIZE as SPRITE_VERT_PAGE_SIZE,
},
terrain::{Locals as TerrainLocals, TerrainLayout, Vertex as TerrainVertex},
ui::{
create_quad as create_ui_quad,
@ -43,9 +47,9 @@ pub use self::{
},
renderer::{
drawer::{
ChunkSpriteDrawer, Drawer, FigureDrawer, FigureShadowDrawer, FirstPassDrawer,
ParticleDrawer, PreparedUiDrawer, SecondPassDrawer, ShadowPassDrawer, SpriteDrawer,
TerrainDrawer, TerrainShadowDrawer, ThirdPassDrawer, UiDrawer,
Drawer, FigureDrawer, FigureShadowDrawer, FirstPassDrawer, ParticleDrawer,
PreparedUiDrawer, SecondPassDrawer, ShadowPassDrawer, SpriteDrawer, TerrainDrawer,
TerrainShadowDrawer, ThirdPassDrawer, UiDrawer,
},
ColLightInfo, Renderer,
},

View File

@ -105,7 +105,7 @@ impl LodData {
array_layer_count: None,
};
renderer.create_texture_with_data_raw(
renderer.create_texture_with_data_raw::<4>(
&texture_info,
&view_info,
&sampler_info,

View File

@ -253,142 +253,146 @@ pub struct GlobalsLayouts {
}
pub struct ColLights<Locals> {
pub bind_group: wgpu::BindGroup,
pub(super) bind_group: wgpu::BindGroup,
pub texture: Texture,
phantom: std::marker::PhantomData<Locals>,
}
impl GlobalsLayouts {
pub fn base_globals_layout() -> Vec<wgpu::BindGroupLayoutEntry> {
vec![
// Global uniform
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
// Noise tex
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler {
filtering: true,
comparison: false,
},
count: None,
},
// Light uniform
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
// Shadow uniform
wgpu::BindGroupLayoutEntry {
binding: 4,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
// Alt texture
wgpu::BindGroupLayoutEntry {
binding: 5,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 6,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler {
filtering: true,
comparison: false,
},
count: None,
},
// Horizon texture
wgpu::BindGroupLayoutEntry {
binding: 7,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 8,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler {
filtering: true,
comparison: false,
},
count: None,
},
// light shadows (ie shadows from a light?)
wgpu::BindGroupLayoutEntry {
binding: 9,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
// TODO: is this relevant?
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
// lod map (t_map)
wgpu::BindGroupLayoutEntry {
binding: 10,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 11,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler {
filtering: true,
comparison: false,
},
count: None,
},
]
}
pub fn new(device: &wgpu::Device) -> Self {
let globals = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Globals layout"),
entries: &[
// Global uniform
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
// Noise tex
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler {
filtering: true,
comparison: false,
},
count: None,
},
// Light uniform
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
// Shadow uniform
wgpu::BindGroupLayoutEntry {
binding: 4,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
// Alt texture
wgpu::BindGroupLayoutEntry {
binding: 5,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 6,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler {
filtering: true,
comparison: false,
},
count: None,
},
// Horizon texture
wgpu::BindGroupLayoutEntry {
binding: 7,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 8,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler {
filtering: true,
comparison: false,
},
count: None,
},
// light shadows (ie shadows from a light?)
wgpu::BindGroupLayoutEntry {
binding: 9,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
// TODO: is this relevant?
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
// lod map (t_map)
wgpu::BindGroupLayoutEntry {
binding: 10,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 11,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler {
filtering: true,
comparison: false,
},
count: None,
},
],
entries: &Self::base_globals_layout(),
});
let col_light = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@ -470,6 +474,72 @@ impl GlobalsLayouts {
}
}
// Note: this allocation serves the purpose of not having to duplicate code
pub fn bind_base_globals<'a>(
global_model: &'a GlobalModel,
lod_data: &'a lod_terrain::LodData,
noise: &'a Texture,
) -> Vec<wgpu::BindGroupEntry<'a>> {
vec![
// Global uniform
wgpu::BindGroupEntry {
binding: 0,
resource: global_model.globals.buf().as_entire_binding(),
},
// Noise tex
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(&noise.view),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::Sampler(&noise.sampler),
},
// Light uniform
wgpu::BindGroupEntry {
binding: 3,
resource: global_model.lights.buf().as_entire_binding(),
},
// Shadow uniform
wgpu::BindGroupEntry {
binding: 4,
resource: global_model.shadows.buf().as_entire_binding(),
},
// Alt texture
wgpu::BindGroupEntry {
binding: 5,
resource: wgpu::BindingResource::TextureView(&lod_data.alt.view),
},
wgpu::BindGroupEntry {
binding: 6,
resource: wgpu::BindingResource::Sampler(&lod_data.alt.sampler),
},
// Horizon texture
wgpu::BindGroupEntry {
binding: 7,
resource: wgpu::BindingResource::TextureView(&lod_data.horizon.view),
},
wgpu::BindGroupEntry {
binding: 8,
resource: wgpu::BindingResource::Sampler(&lod_data.horizon.sampler),
},
// light shadows
wgpu::BindGroupEntry {
binding: 9,
resource: global_model.shadow_mats.buf().as_entire_binding(),
},
// lod map (t_map)
wgpu::BindGroupEntry {
binding: 10,
resource: wgpu::BindingResource::TextureView(&lod_data.map.view),
},
wgpu::BindGroupEntry {
binding: 11,
resource: wgpu::BindingResource::Sampler(&lod_data.map.sampler),
},
]
}
pub fn bind(
&self,
device: &wgpu::Device,
@ -480,64 +550,7 @@ impl GlobalsLayouts {
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: None,
layout: &self.globals,
entries: &[
// Global uniform
wgpu::BindGroupEntry {
binding: 0,
resource: global_model.globals.buf().as_entire_binding(),
},
// Noise tex
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(&noise.view),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::Sampler(&noise.sampler),
},
// Light uniform
wgpu::BindGroupEntry {
binding: 3,
resource: global_model.lights.buf().as_entire_binding(),
},
// Shadow uniform
wgpu::BindGroupEntry {
binding: 4,
resource: global_model.shadows.buf().as_entire_binding(),
},
// Alt texture
wgpu::BindGroupEntry {
binding: 5,
resource: wgpu::BindingResource::TextureView(&lod_data.alt.view),
},
wgpu::BindGroupEntry {
binding: 6,
resource: wgpu::BindingResource::Sampler(&lod_data.alt.sampler),
},
// Horizon texture
wgpu::BindGroupEntry {
binding: 7,
resource: wgpu::BindingResource::TextureView(&lod_data.horizon.view),
},
wgpu::BindGroupEntry {
binding: 8,
resource: wgpu::BindingResource::Sampler(&lod_data.horizon.sampler),
},
// light shadows
wgpu::BindGroupEntry {
binding: 9,
resource: global_model.shadow_mats.buf().as_entire_binding(),
},
// lod map (t_map)
wgpu::BindGroupEntry {
binding: 10,
resource: wgpu::BindingResource::TextureView(&lod_data.map.view),
},
wgpu::BindGroupEntry {
binding: 11,
resource: wgpu::BindingResource::Sampler(&lod_data.map.sampler),
},
],
entries: &Self::bind_base_globals(global_model, lod_data, noise),
});
GlobalsBindGroup { bind_group }

View File

@ -116,7 +116,7 @@ pub fn create_col_lights(
array_layer_count: None,
};
renderer.create_texture_with_data_raw(
renderer.create_texture_with_data_raw::<4>(
&texture_info,
&view_info,
&sampler_info,

View File

@ -1,47 +1,52 @@
use super::super::{AaMode, Bound, Consts, GlobalsLayouts, TerrainLayout, Vertex as VertexTrait};
use super::{
super::{
AaMode, Bound, Consts, GlobalsLayouts, Mesh, Renderer, TerrainLayout, Texture,
Vertex as VertexTrait,
},
lod_terrain, GlobalModel,
};
use bytemuck::{Pod, Zeroable};
use core::fmt;
use std::mem;
use vek::*;
pub const VERT_PAGE_SIZE: u32 = 256;
// pub const VERT_PAGE_SIZE: u32 = 256;
#[repr(C)]
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
pub struct Vertex {
pos: [f32; 3],
pos_norm: u32,
// Because we try to restrict terrain sprite data to a 128×128 block
// we need an offset into the texture atlas.
atlas_pos: u32,
// ____BBBBBBBBGGGGGGGGRRRRRRRR
// col: u32 = "v_col",
// ...AANNN
// A = AO
// N = Normal
norm_ao: u32,
/* ____BBBBBBBBGGGGGGGGRRRRRRRR
* col: u32 = "v_col",
* .....NNN
* A = AO
* N = Normal
*norm: u32, */
}
impl fmt::Display for Vertex {
// TODO: fix?
/*impl fmt::Display for Vertex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Vertex")
.field("pos", &Vec3::<f32>::from(self.pos))
.field("pos_norm", &Vec3::<f32>::from(self.pos))
.field(
"atlas_pos",
&Vec2::new(self.atlas_pos & 0xFFFF, (self.atlas_pos >> 16) & 0xFFFF),
)
.field("norm_ao", &self.norm_ao)
.finish()
}
}
}*/
impl Vertex {
// NOTE: Limit to 16 (x) × 16 (y) × 32 (z).
#[allow(clippy::collapsible_else_if)]
pub fn new(
atlas_pos: Vec2<u16>,
pos: Vec3<f32>,
norm: Vec3<f32>, /* , col: Rgb<f32>, ao: f32 */
) -> Self {
pub fn new(atlas_pos: Vec2<u16>, pos: Vec3<f32>, norm: Vec3<f32>) -> Self {
const VERT_EXTRA_NEG_Z: i32 = 128; // NOTE: change if number of bits changes below, also we might not need this if meshing always produces positives values for sprites (I have no idea)
let norm_bits = if norm.x != 0.0 {
if norm.x < 0.0 { 0 } else { 1 }
} else if norm.y != 0.0 {
@ -56,13 +61,15 @@ impl Vertex {
// | (((pos + EXTRA_NEG_Z).z.max(0.0).min((1 << 16) as f32) as u32) & 0xFFFF) << 12
// | if meta { 1 } else { 0 } << 28
// | (norm_bits & 0x7) << 29,
pos: pos.into_array(),
pos_norm: ((pos.x as u32) & 0x00FF) // NOTE: temp hack, this doesn't need 8 bits
| ((pos.y as u32) & 0x00FF) << 8
| (((pos.z as i32 + VERT_EXTRA_NEG_Z).max(0).min(1 << 12) as u32) & 0x0FFF) << 16
| (norm_bits & 0x7) << 29,
atlas_pos: ((atlas_pos.x as u32) & 0xFFFF) | ((atlas_pos.y as u32) & 0xFFFF) << 16,
norm_ao: norm_bits,
}
}
fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
/*fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
const ATTRIBUTES: [wgpu::VertexAttribute; 3] =
wgpu::vertex_attr_array![0 => Float32x3, 1 => Uint32, 2 => Uint32];
wgpu::VertexBufferLayout {
@ -70,7 +77,11 @@ impl Vertex {
step_mode: wgpu::InputStepMode::Vertex,
attributes: &ATTRIBUTES,
}
}
}*/
}
impl Default for Vertex {
fn default() -> Self { Self::new(Vec2::zero(), Vec3::zero(), Vec3::zero()) }
}
impl VertexTrait for Vertex {
@ -78,29 +89,29 @@ impl VertexTrait for Vertex {
const STRIDE: wgpu::BufferAddress = mem::size_of::<Self>() as wgpu::BufferAddress;
}
/* pub fn create_verts_buffer(renderer: &mut Renderer, mut mesh: Mesh<Vertex>) -> Buffer<Vertex> {
renderer.ensure_sufficient_index_length::<Vertex>(VERT_PAGE_SIZE as usize);
pub fn create_verts_texture(renderer: &mut Renderer, mut mesh: Mesh<Vertex>) -> Texture {
//renderer.ensure_sufficient_index_length::<Vertex>(VERT_PAGE_SIZE as usize);
// TODO: type buffer by Usage
Buffer::new(
/*Buffer::new(
&renderer.device,
wgpu::BufferUsage::STORAGE,
mesh.vertices(),
)
//let mut verts = mesh.vertices_mut_vec();
//let format = wgpu::TextureFormat::Rg32Uint;
)*/
let mut verts = mesh.vertices_mut_vec();
let format = wgpu::TextureFormat::Rg32Uint;
// TODO: temp
//const WIDTH: u32 = 8192;
//let height = verts.len() as u32 / WIDTH;
const WIDTH: u32 = 16384;
let height = verts.len() as u32 / WIDTH;
// Fill in verts to full texture size
//verts.resize_with(height as usize * WIDTH as usize, Vertex::default);
verts.resize_with(height as usize * WIDTH as usize, Vertex::default);
/*let texture_info = wgpu::TextureDescriptor {
let texture_info = wgpu::TextureDescriptor {
label: Some("Sprite verts"),
size: wgpu::Extent3d {
width: WIDTH,
height,
depth: 1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
@ -136,56 +147,66 @@ impl VertexTrait for Vertex {
&view_info,
&sampler_info,
bytemuck::cast_slice(verts),
)*/
)
}
*/
#[repr(C)]
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
pub struct Instance {
pos_ori: u32,
inst_mat0: [f32; 4],
inst_mat1: [f32; 4],
inst_mat2: [f32; 4],
inst_mat3: [f32; 4],
inst_light: [f32; 4],
inst_wind_sway: f32,
pos_ori: u32,
inst_vert_page: u32,
inst_light: f32,
inst_glow: f32,
model_wind_sway: f32,
model_z_scale: f32,
}
impl Instance {
pub fn new(
mat: Mat4<f32>,
wind_sway: f32,
z_scale: f32,
pos: Vec3<i32>,
ori_bits: u8,
light: f32,
glow: f32,
vert_page: u32,
) -> Self {
const EXTRA_NEG_Z: i32 = 32768;
let mat_arr = mat.into_col_arrays();
Self {
pos_ori: ((pos.x as u32) & 0x003F)
| ((pos.y as u32) & 0x003F) << 6
| (((pos + EXTRA_NEG_Z).z.max(0).min(1 << 16) as u32) & 0xFFFF) << 12
| (u32::from(ori_bits) & 0x7) << 29,
inst_mat0: mat_arr[0],
inst_mat1: mat_arr[1],
inst_mat2: mat_arr[2],
inst_mat3: mat_arr[3],
inst_light: [light, glow, 1.0, 1.0],
inst_wind_sway: wind_sway,
pos_ori: ((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,
inst_vert_page: vert_page,
inst_light: light,
inst_glow: glow,
model_wind_sway: wind_sway,
model_z_scale: z_scale,
}
}
fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
const ATTRIBUTES: [wgpu::VertexAttribute; 7] = wgpu::vertex_attr_array![
3 => Uint32,
4 => Float32x4,
5 => Float32x4,
6 => Float32x4,
7 => Float32x4,
8 => Float32x4,
const ATTRIBUTES: [wgpu::VertexAttribute; 10] = wgpu::vertex_attr_array![
0 => Float32x4,
1 => Float32x4,
2 => Float32x4,
3 => Float32x4,
4 => Uint32,
5 => Uint32,
6 => Float32,
7 => Float32,
8 => Float32,
9 => Float32,
];
wgpu::VertexBufferLayout {
@ -197,10 +218,12 @@ impl Instance {
}
impl Default for Instance {
fn default() -> Self { Self::new(Mat4::identity(), 0.0, Vec3::zero(), 0, 1.0, 0.0) }
fn default() -> Self { Self::new(Mat4::identity(), 0.0, 0.0, Vec3::zero(), 0, 1.0, 0.0, 0) }
}
#[repr(C)]
// TODO: ColLightsWrapper instead?
pub struct Locals;
/*#[repr(C)]
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
pub struct Locals {
// Each matrix performs rotatation, translation, and scaling, relative to the sprite
@ -211,8 +234,6 @@ pub struct Locals {
offs: [f32; 4],
}
pub type BoundLocals = Bound<Consts<Locals>>;
impl Default for Locals {
fn default() -> Self { Self::new(Mat4::identity(), Vec3::one(), Vec3::zero(), 0.0) }
}
@ -225,16 +246,52 @@ impl Locals {
offs: [offs.x, offs.y, offs.z, 0.0],
}
}
}*/
pub struct SpriteGlobalsBindGroup {
pub(in super::super) bind_group: wgpu::BindGroup,
}
//pub type BoundLocals = Bound<Consts<Locals>>;
pub struct SpriteLayout {
pub locals: wgpu::BindGroupLayout,
pub globals: wgpu::BindGroupLayout,
//pub locals: wgpu::BindGroupLayout,
}
impl SpriteLayout {
pub fn new(device: &wgpu::Device) -> Self {
let mut entries = GlobalsLayouts::base_globals_layout();
debug_assert_eq!(12, entries.len()); // To remember to adjust the bindings below
entries.extend_from_slice(&[
// sprite verts (t_sprite_verts)
wgpu::BindGroupLayoutEntry {
binding: 12,
visibility: wgpu::ShaderStage::VERTEX,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Uint,
view_dimension: wgpu::TextureViewDimension::D1,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 13,
visibility: wgpu::ShaderStage::VERTEX,
ty: wgpu::BindingType::Sampler {
filtering: false,
comparison: false,
},
count: None,
},
]);
Self {
locals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
globals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: None,
entries: &entries,
}),
/*locals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: None,
entries: &[
// locals
@ -250,18 +307,61 @@ impl SpriteLayout {
},
// instance buffer
wgpu::BindGroupLayoutEntry {
binding: 1,
binding: 1,
visibility: wgpu::ShaderStage::Vertex,
ty: wgpu::BufferBindingType::Buffer {
ty: wgpu::BufferBindingType::
ty: wgpu::BufferBindingType::
}
},
],
}),
}),*/
}
}
pub fn bind_locals(&self, device: &wgpu::Device, locals: Consts<Locals>) -> BoundLocals {
fn bind_globals_inner(
&self,
device: &wgpu::Device,
global_model: &GlobalModel,
lod_data: &lod_terrain::LodData,
noise: &Texture,
sprite_verts: &Texture,
) -> wgpu::BindGroup {
let mut entries = GlobalsLayouts::bind_base_globals(global_model, lod_data, noise);
entries.extend_from_slice(&[
// sprite verts (t_sprite_verts)
wgpu::BindGroupEntry {
binding: 12,
resource: wgpu::BindingResource::TextureView(&sprite_verts.view),
},
wgpu::BindGroupEntry {
binding: 13,
resource: wgpu::BindingResource::Sampler(&sprite_verts.sampler),
},
]);
device.create_bind_group(&wgpu::BindGroupDescriptor {
label: None,
layout: &self.globals,
entries: &entries,
})
}
pub fn bind_globals(
&self,
device: &wgpu::Device,
global_model: &GlobalModel,
lod_data: &lod_terrain::LodData,
noise: &Texture,
sprite_verts: &Texture,
) -> SpriteGlobalsBindGroup {
let bind_group =
self.bind_globals_inner(device, global_model, lod_data, noise, sprite_verts);
SpriteGlobalsBindGroup { bind_group }
}
/*pub fn bind_locals(&self, device: &wgpu::Device, locals: Consts<Locals>) -> BoundLocals {
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: None,
layout: &self.locals,
@ -275,7 +375,7 @@ impl SpriteLayout {
bind_group,
with: locals,
}
}
}*/
}
pub struct SpritePipeline {
@ -299,10 +399,11 @@ impl SpritePipeline {
label: Some("Sprite pipeline layout"),
push_constant_ranges: &[],
bind_group_layouts: &[
&global_layout.globals,
&layout.globals,
&global_layout.shadow_textures,
&terrain_layout.locals,
&layout.locals,
//&layout.locals,
// Note: mergable with globals
&global_layout.col_light,
],
});
@ -321,7 +422,7 @@ impl SpritePipeline {
vertex: wgpu::VertexState {
module: vs_module,
entry_point: "main",
buffers: &[],
buffers: &[Instance::desc()],
},
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,

View File

@ -152,7 +152,6 @@ impl Renderer {
.ok_or(RenderError::CouldNotFindAdapter)?;
let limits = wgpu::Limits {
max_bind_groups: 5,
max_push_constant_size: 64,
..Default::default()
};
@ -1009,7 +1008,7 @@ impl Renderer {
}
/// Create a new immutable texture from the provided image.
pub fn create_texture_with_data_raw(
pub fn create_texture_with_data_raw<const BYTES_PER_PIXEL: u32>(
&mut self,
texture_info: &wgpu::TextureDescriptor,
view_info: &wgpu::TextureViewDescriptor,
@ -1018,7 +1017,7 @@ impl Renderer {
) -> Texture {
let tex = Texture::new_raw(&self.device, &texture_info, &view_info, &sampler_info);
tex.update(
tex.update::<BYTES_PER_PIXEL>(
&self.device,
&self.queue,
[0; 2],
@ -1084,7 +1083,7 @@ impl Renderer {
// texture.update(&mut self.encoder, offset, size, data)
data: &[[u8; 4]],
) {
texture.update(
texture.update::<4>(
&self.device,
&self.queue,
offset,

View File

@ -20,6 +20,21 @@ impl Renderer {
.bind(&self.device, global_model, lod_data, &self.noise_tex)
}
pub fn bind_sprite_globals(
&self,
global_model: &GlobalModel,
lod_data: &lod_terrain::LodData,
sprite_verts: &Texture,
) -> sprite::SpriteGlobalsBindGroup {
self.layouts.sprite.bind_globals(
&self.device,
global_model,
lod_data,
&self.noise_tex,
sprite_verts,
)
}
pub fn create_ui_bound_locals(&mut self, vals: &[ui::Locals]) -> ui::BoundLocals {
let locals = self.create_consts(vals);
self.layouts.ui.bind_locals(&self.device, locals)
@ -54,10 +69,10 @@ impl Renderer {
self.layouts.shadow.bind_locals(&self.device, locals)
}
pub fn create_sprite_bound_locals(&mut self, locals: &[sprite::Locals]) -> sprite::BoundLocals {
let locals = self.create_consts(locals);
self.layouts.sprite.bind_locals(&self.device, locals)
}
//pub fn create_sprite_bound_locals(&mut self, locals: &[sprite::Locals]) ->
// sprite::BoundLocals { let locals = self.create_consts(locals);
// self.layouts.sprite.bind_locals(&self.device, locals)
//}
pub fn figure_bind_col_light(&self, col_light: Texture) -> ColLights<figure::Locals> {
self.layouts.global.bind_col_light(&self.device, col_light)

View File

@ -132,6 +132,7 @@ impl<'frame> Drawer<'frame> {
FirstPassDrawer {
render_pass,
borrow: &self.borrow,
globals: self.globals,
}
}
@ -406,6 +407,7 @@ impl<'pass_ref, 'pass: 'pass_ref> TerrainShadowDrawer<'pass_ref, 'pass> {
pub struct FirstPassDrawer<'pass> {
pub(super) render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
borrow: &'pass RendererBorrow<'pass>,
globals: &'pass GlobalsBindGroup,
}
impl<'pass> FirstPassDrawer<'pass> {
@ -459,15 +461,20 @@ impl<'pass> FirstPassDrawer<'pass> {
pub fn draw_sprites<'data: 'pass>(
&mut self,
globals: &'data sprite::SpriteGlobalsBindGroup,
col_lights: &'data ColLights<sprite::Locals>,
) -> SpriteDrawer<'_, 'pass> {
let mut render_pass = self.render_pass.scope(self.borrow.device, "sprites");
render_pass.set_pipeline(&self.borrow.pipelines.sprite.pipeline);
set_quad_index_buffer::<particle::Vertex>(&mut render_pass, &self.borrow);
render_pass.set_bind_group(4, &col_lights.bind_group, &[]);
render_pass.set_bind_group(0, &globals.bind_group, &[]);
render_pass.set_bind_group(3, &col_lights.bind_group, &[]);
SpriteDrawer { render_pass }
SpriteDrawer {
render_pass,
globals: self.globals,
}
}
pub fn draw_fluid<'data: 'pass>(
@ -561,49 +568,37 @@ impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> {
pub struct SpriteDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
globals: &'pass GlobalsBindGroup,
}
impl<'pass_ref, 'pass: 'pass_ref> SpriteDrawer<'pass_ref, 'pass> {
pub fn in_chunk<'data: 'pass>(
pub fn draw<'data: 'pass>(
&mut self,
terrain_locals: &'data terrain::BoundLocals,
) -> ChunkSpriteDrawer<'_, 'pass> {
//model: &'data Model<sprite::Vertex>,
//locals: &'data sprite::BoundLocals,
instances: &'data Instances<sprite::Instance>,
) {
self.render_pass
.set_bind_group(2, &terrain_locals.bind_group, &[]);
//self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
ChunkSpriteDrawer {
render_pass: &mut self.render_pass,
}
/* //self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
//self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
self.render_pass
.set_vertex_buffer(0, instances.buf().slice(..));
self.render_pass.draw_indexed(
0..sprite::VERT_PAGE_SIZE / 4 * 6,
0,
0..instances.count() as u32,
); */
);
}
}
pub struct ChunkSpriteDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
}
impl<'pass_ref, 'pass: 'pass_ref> ChunkSpriteDrawer<'pass_ref, 'pass> {
pub fn draw<'data: 'pass>(
&mut self,
model: &'data Model<sprite::Vertex>,
instances: &'data Instances<sprite::Instance>,
locals: &'data sprite::BoundLocals,
) {
self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
impl<'pass_ref, 'pass: 'pass_ref> Drop for SpriteDrawer<'pass_ref, 'pass> {
fn drop(&mut self) {
// Reset to regular globals
self.render_pass
.set_vertex_buffer(1, instances.buf().slice(..));
self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
self.render_pass.draw_indexed(
0..model.len() as u32 / 4 * 6,
0,
0..instances.count() as u32,
);
.set_bind_group(0, &self.globals.bind_group, &[]);
}
}

View File

@ -170,7 +170,9 @@ impl Texture {
/// Update a texture with the given data (used for updating the glyph cache
/// texture).
pub fn update(
/// TODO: using generic here seems a bit hacky, consider storing this info
/// in the texture type or pass in wgpu::TextureFormat
pub fn update<const BYTES_PER_PIXEL: u32>(
&self,
device: &wgpu::Device,
queue: &wgpu::Queue,
@ -178,9 +180,10 @@ impl Texture {
size: [u32; 2],
data: &[u8],
) {
// Note: we only accept 4 bytes per pixel
// (enforce this in API?)
debug_assert_eq!(data.len(), size[0] as usize * size[1] as usize * 4);
debug_assert_eq!(
data.len(),
size[0] as usize * size[1] as usize * BYTES_PER_PIXEL as usize
);
// TODO: Only works for 2D images
queue.write_texture(
wgpu::TextureCopyViewBase {
@ -195,7 +198,7 @@ impl Texture {
data,
wgpu::TextureDataLayout {
offset: 0,
bytes_per_row: size[0] * 4,
bytes_per_row: size[0] * BYTES_PER_PIXEL,
rows_per_image: size[1],
},
wgpu::Extent3d {

View File

@ -276,6 +276,8 @@ impl Scene {
let globals_bind_group = renderer.bind_globals(&data, lod.get_data());
let terrain = Terrain::new(renderer, &data, lod.get_data(), sprite_render_context);
Self {
data,
globals_bind_group,
@ -286,7 +288,7 @@ impl Scene {
skybox: Skybox {
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
},
terrain: Terrain::new(renderer, sprite_render_context),
terrain,
lod,
loaded_distance: 0.0,
map_bounds: Vec2::new(

View File

@ -1,4 +1,5 @@
mod watcher;
pub use self::watcher::{BlocksOfInterest, Interaction};
use crate::{
@ -8,10 +9,11 @@ use crate::{
terrain::{generate_mesh, SUNLIGHT},
},
render::{
create_sprite_verts_texture,
pipelines::{self, ColLights},
ColLightInfo, Consts, Drawer, FirstPassDrawer, FluidVertex, FluidWaves, GlobalModel,
Instances, LodData, Mesh, Model, RenderError, Renderer, SpriteInstance, SpriteLocals,
SpriteVertex, TerrainLocals, TerrainShadowDrawer, TerrainVertex, Texture,
Instances, LodData, Mesh, Model, RenderError, Renderer, SpriteGlobalsBindGroup,
SpriteInstance, SpriteVertex, TerrainLocals, TerrainShadowDrawer, TerrainVertex, Texture,
},
};
@ -42,6 +44,8 @@ use treeculler::{BVol, Frustum, AABB};
use vek::*;
const SPRITE_SCALE: Vec3<f32> = Vec3::new(1.0 / 11.0, 1.0 / 11.0, 1.0 / 11.0);
const SPRITE_LOD_LEVELS: usize = 5;
const SPRITE_VERT_PAGE_SIZE: usize = 256;
#[derive(Clone, Copy, Debug)]
struct Visibility {
@ -79,7 +83,7 @@ pub struct TerrainChunkData {
col_lights: Arc<ColLights<pipelines::terrain::Locals>>,
light_map: Box<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
glow_map: Box<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
sprite_instances: HashMap<(SpriteKind, usize), Instances<SpriteInstance>>,
sprite_instances: [Instances<SpriteInstance>; SPRITE_LOD_LEVELS],
locals: pipelines::terrain::BoundLocals,
pub blocks_of_interest: BlocksOfInterest,
@ -107,7 +111,7 @@ struct MeshWorkerResponse {
col_lights_info: ColLightInfo,
light_map: Box<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
glow_map: Box<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
sprite_instances: HashMap<(SpriteKind, usize), Vec<SpriteInstance>>,
sprite_instances: [Vec<SpriteInstance>; SPRITE_LOD_LEVELS],
started_tick: u64,
blocks_of_interest: BlocksOfInterest,
}
@ -162,7 +166,7 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug + '
max_texture_size: u16,
chunk: Arc<TerrainChunk>,
range: Aabb<i32>,
sprite_data: &HashMap<(SpriteKind, usize), Vec<SpriteData>>,
sprite_data: &HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>,
sprite_config: &SpriteSpec,
) -> MeshWorkerResponse {
span!(_guard, "mesh_worker");
@ -185,7 +189,7 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug + '
// Extract sprite locations from volume
sprite_instances: {
span!(_guard, "extract sprite_instances");
let mut instances = HashMap::new();
let mut instances = [Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new()];
for x in 0..V::RECT_SIZE.x as i32 {
for y in 0..V::RECT_SIZE.y as i32 {
@ -213,23 +217,43 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug + '
let key = (sprite, variation);
// NOTE: Safe because we called sprite_config_for already.
// NOTE: Safe because 0 ≤ ori < 8
let sprite_data = &sprite_data[&key][0];
let instance = SpriteInstance::new(
Mat4::identity()
.translated_3d(sprite_data.offset)
let sprite_data_lod_0 = &sprite_data[&key][0];
let mat = Mat4::identity()
// NOTE: offset doesn't change with lod level
// TODO: pull out of per lod level info or remove lod levels
// for sprites entirely
.translated_3d(sprite_data_lod_0.offset)
// Lod scaling etc is baked during meshing
.scaled_3d(SPRITE_SCALE)
.rotated_z(f32::consts::PI * 0.25 * ori as f32)
.translated_3d(
(rel_pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0))
/ SPRITE_SCALE,
),
cfg.wind_sway,
rel_pos,
ori,
light_map(wpos),
glow_map(wpos),
);
);
let light = light_map(wpos);
let glow = glow_map(wpos);
instances.entry(key).or_insert(Vec::new()).push(instance);
for lod_level in 0..SPRITE_LOD_LEVELS {
let sprite_data = &sprite_data[&key][lod_level];
// Add an instance for each page in the sprite model
for page in sprite_data.vert_pages.clone() {
// TODO: could be more efficient to create once and clone while
// modifying vert_page
let instance = SpriteInstance::new(
mat,
cfg.wind_sway,
sprite_data.scale.z,
rel_pos,
ori,
light,
glow,
page,
);
instances[lod_level].push(instance);
}
}
//instances.entry(key).or_insert(Vec::new()).
// push(instance);
}
}
}
@ -244,11 +268,18 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug + '
}
}
// TODO: may be unecessary
struct ChunkSpriteData {
// Instances
model: Instances<SpriteInstance>,
}
struct SpriteData {
/* mat: Mat4<f32>, */
locals: pipelines::sprite::BoundLocals,
model: Model<SpriteVertex>,
/* scale: Vec3<f32>, */
// Sprite vert page ranges that need to be drawn
vert_pages: core::ops::Range<u32>,
// Scale
scale: Vec3<f32>,
// Offset
offset: Vec3<f32>,
}
@ -298,8 +329,10 @@ pub struct Terrain<V: RectRasterableVol = TerrainChunk> {
mesh_todos_active: Arc<AtomicU64>,
// GPU data
sprite_data: Arc<HashMap<(SpriteKind, usize), Vec<SpriteData>>>,
sprite_col_lights: ColLights<pipelines::sprite::Locals>,
// Maps sprite kind + variant to data detailing how to render it
sprite_data: Arc<HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>>,
sprite_globals: SpriteGlobalsBindGroup,
sprite_col_lights: Arc<ColLights<pipelines::sprite::Locals>>,
/// As stated previously, this is always the very latest texture into which
/// we allocate. Code cannot assume that this is the assigned texture
/// for any particular chunk; look at the `texture` field in
@ -317,8 +350,10 @@ impl TerrainChunkData {
#[derive(Clone)]
pub struct SpriteRenderContext {
sprite_config: Arc<SpriteSpec>,
sprite_data: Arc<HashMap<(SpriteKind, usize), Vec<SpriteData>>>,
sprite_col_lights: Texture, /* <ColLightFmt> */
// Maps sprite kind + variant to data detailing how to render it
sprite_data: Arc<HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>>,
sprite_col_lights: Arc<ColLights<pipelines::sprite::Locals>>,
sprite_verts_texture: Arc<Texture>,
}
pub type SpriteRenderContextLazy = Box<dyn FnMut(&mut Renderer) -> SpriteRenderContext>;
@ -328,16 +363,11 @@ impl SpriteRenderContext {
pub fn new(renderer: &mut Renderer) -> SpriteRenderContextLazy {
let max_texture_size = renderer.max_texture_size();
struct SpriteDataResponse {
locals: [SpriteLocals; 8],
model: Mesh<SpriteVertex>,
offset: Vec3<f32>,
}
struct SpriteWorkerResponse {
sprite_config: Arc<SpriteSpec>,
sprite_data: HashMap<(SpriteKind, usize), Vec<SpriteDataResponse>>,
sprite_data: HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>,
sprite_col_lights: ColLightInfo,
sprite_mesh: Mesh<SpriteVertex>,
}
let join_handle = std::thread::spawn(move || {
@ -347,7 +377,8 @@ impl SpriteRenderContext {
let max_size = guillotiere::Size::new(max_texture_size as i32, max_texture_size as i32);
let mut greedy = GreedyMesh::new(max_size);
let mut locals_buffer = [SpriteLocals::default(); 8];
// let mut locals_buffer = [SpriteLocals::default(); 8];
let mut sprite_mesh = Mesh::new();
let sprite_config_ = &sprite_config;
// NOTE: Tracks the start vertex of the next model to be meshed.
let sprite_data: HashMap<(SpriteKind, usize), _> = SpriteKind::into_enum_iter()
@ -390,62 +421,68 @@ impl SpriteRenderContext {
scale
}
});
let sprite_mat: Mat4<f32> =
Mat4::translation_3d(offset).scaled_3d(SPRITE_SCALE);
move |greedy: &mut GreedyMesh| {
(
(kind, variation),
scaled
.iter()
.map(|&lod_scale_orig| {
let lod_scale = model_scale
* if lod_scale_orig == 1.0 {
Vec3::broadcast(1.0)
} else {
lod_axes * lod_scale_orig
+ lod_axes.map(|e| {
if e == 0.0 { 1.0 } else { 0.0 }
})
};
// Mesh generation exclusively acts using side effects;
// it has no
// interesting return value, but updates the mesh.
let mut opaque_mesh = Mesh::new();
generate_mesh_base_vol_sprite(
Segment::from(&model.read().0).scaled_by(lod_scale),
(greedy, &mut opaque_mesh, false),
);
//let sprite_mat: Mat4<f32> =
// Mat4::translation_3d(offset).scaled_3d(SPRITE_SCALE);
move |greedy: &mut GreedyMesh, sprite_mesh: &mut Mesh<SpriteVertex>| {
let lod_sprite_data = scaled.map(|lod_scale_orig| {
let lod_scale = model_scale
* if lod_scale_orig == 1.0 {
Vec3::broadcast(1.0)
} else {
lod_axes * lod_scale_orig
+ lod_axes.map(|e| if e == 0.0 { 1.0 } else { 0.0 })
};
let sprite_scale = Vec3::one() / lod_scale;
let sprite_mat: Mat4<f32> =
sprite_mat * Mat4::scaling_3d(sprite_scale);
locals_buffer.iter_mut().enumerate().for_each(
|(ori, locals)| {
let sprite_mat = sprite_mat.rotated_z(
f32::consts::PI * 0.25 * ori as f32,
);
*locals = SpriteLocals::new(
sprite_mat,
sprite_scale,
offset,
wind_sway,
);
},
);
// Get starting page count of opaque mesh
let start_page_num =
sprite_mesh.vertices().len() / SPRITE_VERT_PAGE_SIZE;
// Mesh generation exclusively acts using side effects; it
// has no interesting return value, but updates the mesh.
generate_mesh_base_vol_sprite(
Segment::from(&model.read().0).scaled_by(lod_scale),
(greedy, sprite_mesh, false),
);
// Get the number of pages after the model was meshed
let end_page_num =
(sprite_mesh.vertices().len() + SPRITE_VERT_PAGE_SIZE - 1)
/ SPRITE_VERT_PAGE_SIZE;
// Fill the current last page up with degenerate verts
sprite_mesh.vertices_mut_vec().resize_with(
end_page_num * SPRITE_VERT_PAGE_SIZE,
SpriteVertex::default,
);
SpriteDataResponse {
model: opaque_mesh,
let sprite_scale = Vec3::one() / lod_scale;
//let sprite_mat: Mat4<f32> =
// sprite_mat * Mat4::scaling_3d(sprite_scale);
/*locals_buffer.iter_mut().enumerate().for_each(
|(ori, locals)| {
let sprite_mat = sprite_mat.rotated_z(
f32::consts::PI * 0.25 * ori as f32,
);
*locals = SpriteLocals::new(
sprite_mat,
sprite_scale,
offset,
locals: locals_buffer,
}
})
.collect::<Vec<_>>(),
)
wind_sway,
);
},
);*/
SpriteData {
vert_pages: start_page_num as u32..end_page_num as u32,
scale: sprite_scale,
offset,
//locals: locals_buffer,
}
});
((kind, variation), lod_sprite_data)
}
},
)
})
.map(|mut f| f(&mut greedy))
.map(|mut f| f(&mut greedy, &mut sprite_mesh))
.collect();
let sprite_col_lights = greedy.finalize();
@ -454,6 +491,7 @@ impl SpriteRenderContext {
sprite_config,
sprite_data,
sprite_col_lights,
sprite_mesh,
}
});
@ -468,6 +506,7 @@ impl SpriteRenderContext {
sprite_config,
sprite_data,
sprite_col_lights,
sprite_mesh,
} = join_handle
.take()
.expect(
@ -477,39 +516,19 @@ impl SpriteRenderContext {
.join()
.unwrap();
let sprite_data = sprite_data
.into_iter()
.map(|(key, models)| {
(
key,
models
.into_iter()
.map(
|SpriteDataResponse {
locals: locals_buffer,
model,
offset,
}| {
SpriteData {
locals: renderer.create_sprite_bound_locals(&locals_buffer),
model: renderer.create_model(&model).expect(
"Failed to upload sprite model data to the GPU!",
),
offset,
}
},
)
.collect(),
)
})
.collect();
let sprite_col_lights =
pipelines::shadow::create_col_lights(renderer, &sprite_col_lights);
let sprite_col_lights = renderer.sprite_bind_col_light(sprite_col_lights);
// Write sprite model to a 1D texture
let sprite_verts_texture = create_sprite_verts_texture(renderer, sprite_mesh);
Self {
// TODO: this are all Arcs, would it makes sense to factor out the Arc?
sprite_config: Arc::clone(&sprite_config),
sprite_data: Arc::new(sprite_data),
sprite_col_lights,
sprite_col_lights: Arc::new(sprite_col_lights),
sprite_verts_texture: Arc::new(sprite_verts_texture),
}
};
Box::new(move |renderer| init.get_or_init(|| closure(renderer)).clone())
@ -517,7 +536,12 @@ impl SpriteRenderContext {
}
impl<V: RectRasterableVol> Terrain<V> {
pub fn new(renderer: &mut Renderer, sprite_render_context: SpriteRenderContext) -> Self {
pub fn new(
renderer: &mut Renderer,
global_model: &GlobalModel,
lod_data: &LodData,
sprite_render_context: SpriteRenderContext,
) -> Self {
// Create a new mpsc (Multiple Produced, Single Consumer) pair for communicating
// with worker threads that are meshing chunks.
let (send, recv) = channel::unbounded();
@ -535,8 +559,13 @@ impl<V: RectRasterableVol> Terrain<V> {
mesh_todo: HashMap::default(),
mesh_todos_active: Arc::new(AtomicU64::new(0)),
sprite_data: sprite_render_context.sprite_data,
sprite_col_lights: renderer
.sprite_bind_col_light(sprite_render_context.sprite_col_lights),
sprite_col_lights: sprite_render_context.sprite_col_lights,
sprite_globals: renderer.bind_sprite_globals(
global_model,
lod_data,
&sprite_render_context.sprite_verts_texture,
),
col_lights: Arc::new(col_lights),
waves: {
let waves_tex = renderer
.create_texture(
@ -548,7 +577,6 @@ impl<V: RectRasterableVol> Terrain<V> {
renderer.fluid_bind_waves(waves_tex)
},
col_lights: Arc::new(col_lights),
phantom: PhantomData,
}
}
@ -1027,18 +1055,20 @@ impl<V: RectRasterableVol> Terrain<V> {
col_lights: Arc::clone(&self.col_lights),
light_map: response.light_map,
glow_map: response.glow_map,
sprite_instances: response
.sprite_instances
.into_iter()
.map(|(kind, instances)| {
(
kind,
renderer.create_instances(&instances).expect(
"Failed to upload chunk sprite instances to the GPU!",
),
)
})
.collect(),
sprite_instances: {
let mut iter = response.sprite_instances.iter().map(|instances| {
renderer
.create_instances(instances)
.expect("Failed to upload chunk sprite instances to the GPU!")
});
[
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
]
},
locals: renderer.create_terrain_bound_locals(&[TerrainLocals {
model_offs: Vec3::from(
response.pos.map2(VolGrid2d::<V>::chunk_size(), |e, sz| {
@ -1363,15 +1393,21 @@ impl<V: RectRasterableVol> Terrain<V> {
span!(guard, "Terrain sprites");
let chunk_size = V::RECT_SIZE.map(|e| e as f32);
let chunk_mag = (chunk_size * (f32::consts::SQRT_2 * 0.5)).magnitude_squared();
let mut sprite_drawer = drawer.draw_sprites(&self.sprite_col_lights);
let sprite_low_detail_distance = sprite_render_distance * 0.75;
let sprite_mid_detail_distance = sprite_render_distance * 0.5;
let sprite_hid_detail_distance = sprite_render_distance * 0.35;
let sprite_high_detail_distance = sprite_render_distance * 0.15;
let mut sprite_drawer = drawer.draw_sprites(&self.sprite_globals, &self.sprite_col_lights);
chunk_iter
.clone()
.filter(|(_, c)| c.visible.is_visible())
.for_each(|(pos, chunk)| {
let sprite_low_detail_distance = sprite_render_distance * 0.75;
let sprite_mid_detail_distance = sprite_render_distance * 0.5;
let sprite_hid_detail_distance = sprite_render_distance * 0.35;
let sprite_high_detail_distance = sprite_render_distance * 0.15;
// Skip chunk if it has no sprites
if chunk.sprite_instances[0].count() == 0 {
return;
}
let chunk_center = pos.map2(chunk_size, |e, sz| (e as f32 + 0.5) * sz);
let focus_dist_sqrd = Vec2::from(focus_pos).distance_squared(chunk_center);
@ -1389,31 +1425,27 @@ impl<V: RectRasterableVol> Terrain<V> {
chunk_center + chunk_size.x * 0.5 - chunk_size.y * 0.5,
));
if focus_dist_sqrd < sprite_render_distance.powi(2) {
// TODO: skip if sprite_instances is empty
let mut chunk_sprite_drawer = sprite_drawer.in_chunk(&chunk.locals);
for (kind, instances) in (&chunk.sprite_instances).into_iter() {
let SpriteData { model, locals, .. } = if kind
.0
.elim_case_pure(&self.sprite_config.0)
.as_ref()
.map(|config| config.wind_sway >= 0.4)
.unwrap_or(false)
&& dist_sqrd <= chunk_mag
|| dist_sqrd < sprite_high_detail_distance.powi(2)
{
&self.sprite_data[&kind][0]
} else if dist_sqrd < sprite_hid_detail_distance.powi(2) {
&self.sprite_data[&kind][1]
} else if dist_sqrd < sprite_mid_detail_distance.powi(2) {
&self.sprite_data[&kind][2]
} else if dist_sqrd < sprite_low_detail_distance.powi(2) {
&self.sprite_data[&kind][3]
} else {
&self.sprite_data[&kind][4]
};
let lod_level = /*let SpriteData { model, locals, .. } = if kind
.0
.elim_case_pure(&self.sprite_config.0)
.as_ref()
.map(|config| config.wind_sway >= 0.4)
.unwrap_or(false)
&&*/ if dist_sqrd <= chunk_mag
|| dist_sqrd < sprite_high_detail_distance.powi(2)
{
0
} else if dist_sqrd < sprite_hid_detail_distance.powi(2) {
1
} else if dist_sqrd < sprite_mid_detail_distance.powi(2) {
2
} else if dist_sqrd < sprite_low_detail_distance.powi(2) {
3
} else {
4
};
chunk_sprite_drawer.draw(model, instances, locals);
}
sprite_drawer.draw(&chunk.locals, &chunk.sprite_instances[lod_level]);
}
});
drop(sprite_drawer);

View File

@ -598,7 +598,7 @@ impl Window {
let scale_factor = window.scale_factor();
let key_layout = match KeyLayout::new_from_window(window.window()) {
let key_layout = match KeyLayout::new_from_window(&window) {
Ok(kl) => Some(kl),
Err(err) => {
warn!(