diff --git a/engine/world_generation/src/lib.rs b/engine/world_generation/src/lib.rs index 3722b68..b1b0bc7 100644 --- a/engine/world_generation/src/lib.rs +++ b/engine/world_generation/src/lib.rs @@ -2,6 +2,8 @@ pub mod prelude { use crate::hex_utils::HexCoord; use bevy::math::{IVec2, UVec2}; use bevy::prelude::Resource; + use bevy::render::mesh::MeshVertexAttribute; + use bevy::render::render_resource::VertexFormat; pub struct GenerationConfig { pub noise_scale: f64, @@ -10,6 +12,7 @@ pub mod prelude { pub size: UVec2, pub layers: Vec, } + pub struct GeneratorLayer { pub strength: f64, pub min_value: f64, @@ -22,6 +25,7 @@ pub mod prelude { pub layers: usize, pub first_layer_mask: bool, } + pub struct Chunk { pub points: [f32; Chunk::SIZE * Chunk::SIZE], pub chunk_offset: IVec2, @@ -57,6 +61,9 @@ pub mod prelude { return results; } } + + pub const ATTRIBUTE_TEXTURE_INDEX: MeshVertexAttribute = + MeshVertexAttribute::new("TextureIndex", 988540917, VertexFormat::Uint32); } pub mod heightmap; diff --git a/engine/world_generation/src/mesh_generator.rs b/engine/world_generation/src/mesh_generator.rs index 310d8dd..d41dd8f 100644 --- a/engine/world_generation/src/mesh_generator.rs +++ b/engine/world_generation/src/mesh_generator.rs @@ -11,6 +11,8 @@ use bevy::{ }, }; use std::vec::Vec; +use bevy::render::mesh::MeshVertexAttribute; +use bevy::render::render_resource::VertexFormat; const HEX_CORNERS: [Vec3; 6] = [ Vec3::new(0., 0., OUTER_RADIUS), @@ -21,11 +23,13 @@ const HEX_CORNERS: [Vec3; 6] = [ Vec3::new(-INNER_RADIUS, 0., 0.5 * OUTER_RADIUS), ]; + pub fn generate_chunk_mesh(chunk: &Chunk, map: &Map) -> Mesh { let vertex_count: usize = Chunk::SIZE * Chunk::SIZE * 6; let mut verts = Vec::with_capacity(vertex_count); let mut uvs = Vec::with_capacity(vertex_count); let mut indices = Vec::with_capacity(vertex_count); + let mut tex = Vec::with_capacity(vertex_count); for z in 0..Chunk::SIZE { for x in 0..Chunk::SIZE { @@ -42,7 +46,8 @@ pub fn generate_chunk_mesh(chunk: &Chunk, map: &Map) -> Mesh { &mut verts, &mut uvs, &mut indices, - ((x + z * Chunk::SIZE) % 32) as u32, + &mut tex, + (height % 7.) as u32, ); } } @@ -51,34 +56,31 @@ pub fn generate_chunk_mesh(chunk: &Chunk, map: &Map) -> Mesh { PrimitiveTopology::TriangleList, RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD, ) - .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, verts) - .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) - .with_inserted_indices(Indices::U32(indices)) - .with_duplicated_vertices() - .with_computed_flat_normals(); + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, verts) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_1, tex) + .with_inserted_indices(Indices::U32(indices)) + // .with_inserted_attribute(ATTRIBUTE_TEXTURE_INDEX, tex) + .with_duplicated_vertices() + .with_computed_flat_normals(); return mesh; } -//TODO: figure out texture index fn create_tile( pos: Vec3, neighbors: &[Option; 6], verts: &mut Vec, uvs: &mut Vec, indices: &mut Vec, + tex: &mut Vec, texture_index: u32, ) { - let tex_x = texture_index % 11; - let tex_y = texture_index / 11; - let x_min = tex_x as f32 / 11.; - let y_min = tex_y as f32 / 8.; - const TX_UNIT: Vec2 = Vec2::new(1. / 11., 1. / 8.); - let uv_offset = Vec2::splat(0.5); let idx = verts.len() as u32; uvs.push(uv_offset); verts.push(pos); + tex.push(Vec2::splat(texture_index as f32)); for i in 0..6 { let p = pos + HEX_CORNERS[i]; verts.push(p); @@ -87,6 +89,7 @@ fn create_tile( indices.push(idx); indices.push(idx + 1 + i as u32); indices.push(idx + 1 + ((i as u32 + 1) % 6)); + tex.push(Vec2::splat(texture_index as f32)); } for i in 0..neighbors.len() { @@ -94,7 +97,7 @@ fn create_tile( match cur_n { Some(n_height) => { if n_height < pos.y { - create_tile_wall(pos, i, n_height, verts, uvs, indices, Vec2::ZERO, Vec2::ONE); + create_tile_wall(pos, i, n_height, verts, uvs, indices, tex, texture_index); } } _ => {} @@ -109,8 +112,8 @@ fn create_tile_wall( verts: &mut Vec, uvs: &mut Vec, indices: &mut Vec, - tx_min: Vec2, - tx_max: Vec2, + tex: &mut Vec, + texture_index: u32, ) { let p1 = HEX_CORNERS[(dir) % 6] + pos; let p2 = HEX_CORNERS[(dir + 1) % 6] + pos; @@ -132,9 +135,13 @@ fn create_tile_wall( indices.push(idx + 2); indices.push(idx + 3); - //TODO: scale texture based on height - uvs.push(tx_min); - uvs.push(Vec2::new(tx_max.x, tx_min.y)); - uvs.push(Vec2::new(tx_min.x, tx_max.y)); - uvs.push(tx_max); + tex.push(Vec2::splat(texture_index as f32)); + tex.push(Vec2::splat(texture_index as f32)); + tex.push(Vec2::splat(texture_index as f32)); + tex.push(Vec2::splat(texture_index as f32)); + + uvs.push(Vec2::ZERO); + uvs.push(Vec2::new(1., 0.)); + uvs.push(Vec2::new(0., pos.y - height)); + uvs.push(Vec2::new(1., pos.y - height)); } diff --git a/game/main/assets/shaders/world/chunk.wgsl b/game/main/assets/shaders/world/chunk.wgsl index 5d4cfe7..a7b8887 100644 --- a/game/main/assets/shaders/world/chunk.wgsl +++ b/game/main/assets/shaders/world/chunk.wgsl @@ -2,6 +2,8 @@ pbr_fragment::pbr_input_from_standard_material, pbr_functions::alpha_discard, } +#import bevy_pbr::mesh_functions::{mesh_position_local_to_world,get_model_matrix,mesh_normal_local_to_world} +#import bevy_pbr::view_transformations::position_world_to_clip; #ifdef PREPASS_PIPELINE #import bevy_pbr::{ @@ -15,19 +17,19 @@ } #endif -struct ChunkMaterial { - array_texture: texture_2d_array, - array_texture_sampler: sampler, -} - -@group(2) @binding(100) -var chunk_material: ChunkMaterial; +@group(2) @binding(100) var array_texture: texture_2d_array; +@group(2) @binding(101) var array_texture_sampler: sampler; @fragment fn fragment( in: VertexOutput, @builtin(front_facing) is_front: bool, ) -> FragmentOutput { +// var vin : VertexOutput; +// vin.position = in.position; +// vin.world_position = in.world_position; +// vin.world_normal = in.world_normal; +// vin.uv = in.uv; // generate a PbrInput struct from the StandardMaterial bindings var pbr_input = pbr_input_from_standard_material(in, is_front); @@ -41,10 +43,13 @@ fn fragment( #else var out: FragmentOutput; // apply lighting - out.color = apply_pbr_lighting(pbr_input); - let layer = i32(in.world_position.x) & 0x7; - out.color = textureSample(chunk_material.array_texture, chunk_material.array_texture_sampler, in.uv, layer); + let layer = u32(in.uv_b.x); + out.color = textureSample(array_texture, array_texture_sampler, in.uv, layer); + + out.color *= apply_pbr_lighting(pbr_input); + + // apply in-shader post processing (fog, alpha-premultiply, and also tonemapping, debanding if the camera is non-hdr) // note this does not include fullscreen postprocessing effects like bloom. @@ -55,4 +60,31 @@ fn fragment( #endif return out; -} \ No newline at end of file +} + +//struct Vertex { +// @builtin(instance_index) instance_index: u32, +// @location(0) position: vec3, +// @location(1) uv: vec2, +// @location(2) normal: vec3, +// @location(3) texture_index: u32, +//}; +// +//struct VOut { +// @builtin(position) position: vec4, +// @location(0) world_position: vec4, +// @location(1) world_normal: vec3, +// @location(2) uv: vec2, +//// @location(7) @interpolate(flat) texture_index: u32, +//}; +// +//@vertex +//fn vertex(vertex: Vertex) -> VOut { +// var out: VOut; +// out.world_position = mesh_position_local_to_world(get_model_matrix(vertex.instance_index), vec4(vertex.position, 1.0)); +// out.position = position_world_to_clip(out.world_position.xyz); +//// out.texture_index = vertex.texture_index; +// out.uv = vertex.uv; +// out.world_normal = mesh_normal_local_to_world(vertex.normal, vertex.instance_index); +// return out; +//} diff --git a/game/main/src/main.rs b/game/main/src/main.rs index 05026e8..bdeec35 100644 --- a/game/main/src/main.rs +++ b/game/main/src/main.rs @@ -1,6 +1,8 @@ use bevy::prelude::*; +use bevy::render::texture::{ImageAddressMode, ImageFilterMode, ImageSamplerDescriptor}; use bevy::window::PresentMode; use bevy_inspector_egui::quick::WorldInspectorPlugin; + mod phos; mod prelude; @@ -19,6 +21,13 @@ fn main() { ..default() }), ..default() + }).set(ImagePlugin { + default_sampler: ImageSamplerDescriptor { + address_mode_u: ImageAddressMode::Repeat, + address_mode_v: ImageAddressMode::Repeat, + mag_filter: ImageFilterMode::Nearest, + ..default() + } }), WorldInspectorPlugin::new(), PhosGamePlugin, diff --git a/game/main/src/phos.rs b/game/main/src/phos.rs index 3dab997..89fa2d6 100644 --- a/game/main/src/phos.rs +++ b/game/main/src/phos.rs @@ -1,6 +1,5 @@ use bevy::asset::LoadState; -use bevy::pbr::{ExtendedMaterial, MaterialExtension}; -use bevy::render::render_resource::{AsBindGroup, ShaderRef}; +use bevy::pbr::{ExtendedMaterial}; use bevy::{pbr::CascadeShadowConfig, prelude::*}; use camera_system::PhosCameraPlugin; use iyes_perf_ui::prelude::*; @@ -8,7 +7,6 @@ use world_generation::hex_utils::{offset_to_world, HexCoord}; use world_generation::{ heightmap::generate_heightmap, mesh_generator::generate_chunk_mesh, prelude::*, }; - use crate::prelude::*; pub struct PhosGamePlugin; @@ -82,6 +80,7 @@ fn check_texture( let array_layers = 7; image.reinterpret_stacked_2d_as_array(array_layers); + atlas.is_loaded = true; map.ready = true; map.regenerate = true; @@ -175,7 +174,7 @@ fn create_map(mut commands: Commands) { border_size: 64., size: UVec2::splat(1024 / Chunk::SIZE as u32), }, - 2, + 4, ); commands.insert_resource(heightmap); @@ -218,15 +217,3 @@ fn spawn_map( } } -#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)] -struct ChunkMaterial { - #[texture(100, dimension = "2d_array")] - #[sampler(101)] - array_texture: Handle, -} - -impl MaterialExtension for ChunkMaterial { - fn fragment_shader() -> ShaderRef { - "shaders/world/chunk.wgsl".into() - } -} diff --git a/game/main/src/prelude.rs b/game/main/src/prelude.rs index cfac76c..2f60177 100644 --- a/game/main/src/prelude.rs +++ b/game/main/src/prelude.rs @@ -1,5 +1,9 @@ -use bevy::asset::Handle; -use bevy::prelude::{Component, Image, Resource}; +use bevy::asset::{Asset, Handle}; +use bevy::pbr::{MaterialExtension, MaterialExtensionKey, MaterialExtensionPipeline, MaterialPipeline, MaterialPipelineKey}; +use bevy::prelude::{Component, Image, Mesh, Resource, TypePath}; +use bevy::render::mesh::{Indices, MeshVertexBufferLayout}; +use bevy::render::render_resource::{AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError}; +use world_generation::prelude::ATTRIBUTE_TEXTURE_INDEX; #[derive(Resource)] pub struct ChunkAtlas { @@ -15,3 +19,33 @@ pub struct PhosMap { #[derive(Component)] pub struct PhosChunk; + + +#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)] +pub struct ChunkMaterial { + #[texture(100, dimension = "2d_array")] + #[sampler(101)] + pub array_texture: Handle, +} + +impl MaterialExtension for ChunkMaterial { + fn fragment_shader() -> ShaderRef { + "shaders/world/chunk.wgsl".into() + } + + // fn specialize( + // _pipeline: &MaterialExtensionPipeline, + // descriptor: &mut RenderPipelineDescriptor, + // layout: &MeshVertexBufferLayout, + // _key: MaterialExtensionKey, + // ) -> Result<(), SpecializedMeshPipelineError> { + // let vertex_layout = layout.get_layout(&[ + // Mesh::ATTRIBUTE_POSITION.at_shader_location(0), + // Mesh::ATTRIBUTE_UV_0.at_shader_location(1), + // Mesh::ATTRIBUTE_NORMAL.at_shader_location(2), + // ATTRIBUTE_TEXTURE_INDEX.at_shader_location(3), + // ])?; + // descriptor.vertex.buffers = vec![vertex_layout]; + // Ok(()) + // } +}