Fixed panorama skybox shader and reflections, experimenting with the world physics map. World map is half-written.
This commit is contained in:
parent
383b17b41f
commit
b6b0382bcc
6 changed files with 228 additions and 130 deletions
25
src/app.rs
25
src/app.rs
|
|
@ -40,7 +40,7 @@ pub struct AppState {
|
|||
clients: Vec<SimpleObject>,
|
||||
}
|
||||
|
||||
const BLOCKS: i32 = 1;
|
||||
const BLOCKS: i32 = 4;
|
||||
|
||||
impl AppState {
|
||||
// We don't need this to be async right now,
|
||||
|
|
@ -54,17 +54,24 @@ impl AppState {
|
|||
.renderer
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.load_from_gltf(include_bytes!("assets/cube.glb"));
|
||||
.load_from_gltf(include_bytes!("assets/sphere.glb"));
|
||||
let block = file.first_object().unwrap();
|
||||
let skybox = world.renderer.as_mut().unwrap().load_texture_from_bytes(
|
||||
include_bytes!("assets/skybox1.png"),
|
||||
include_bytes!("assets/skybox2.png"),
|
||||
Some(image::ImageFormat::Png),
|
||||
);
|
||||
world.renderer.as_mut().unwrap().set_skybox(skybox);
|
||||
//let color = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/color.png"));
|
||||
//let normal = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/normal.png"));
|
||||
//let roughness = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/roughness.png"));
|
||||
//let mat = renderer.new_material(color,normal,roughness);
|
||||
world.renderer().set_skybox(skybox);
|
||||
let color = world
|
||||
.renderer()
|
||||
.load_texture_from_bytes(include_bytes!("assets/plank/color.png"), None);
|
||||
let normal = world
|
||||
.renderer()
|
||||
.load_texture_from_bytes(include_bytes!("assets/plank/normal.png"), None);
|
||||
let roughness = world
|
||||
.renderer()
|
||||
.load_texture_from_bytes(include_bytes!("assets/plank/roughness.png"), None);
|
||||
let mat = world.renderer().new_material(&color, &normal, &roughness);
|
||||
block.0.borrow_mut().model.as_mut().unwrap().material = mat;
|
||||
for x in -BLOCKS..BLOCKS {
|
||||
for y in -BLOCKS..BLOCKS {
|
||||
let block = block.hard_clone();
|
||||
|
|
@ -72,7 +79,7 @@ impl AppState {
|
|||
{
|
||||
let mut model = block.0.borrow_mut();
|
||||
model.model.as_mut().unwrap().instance.transform = Mat4::from_translation(
|
||||
Vec3::new(-x as f32 * 3.0, -8.0, -y as f32 * 3.0),
|
||||
Vec3::new(-x as f32 * 3.0, -2.0, -y as f32 * 3.0),
|
||||
)
|
||||
* Mat4::from_rotation_z((x * y) as f32 / 1.23);
|
||||
model.model.as_mut().unwrap().instance.color = Vec4::new(
|
||||
|
|
|
|||
|
|
@ -88,9 +88,9 @@ var t_rough: texture_2d<f32>;
|
|||
fn sky_aspect(look: vec3<f32>) -> vec4<f32> {
|
||||
var pi = 3.14159;
|
||||
let u_angle = atan2(look.x,look.z);
|
||||
let u = (u_angle/pi) + 0.5; // from -pi/2 -> pi/2 into 0 -> 1
|
||||
let u = (u_angle/pi) * 0.5 + 0.5; // from -pi/2 -> pi/2 into 0 -> 1
|
||||
let v_angle = atan2(-look.y,sqrt(look.x * look.x + look.z * look.z));
|
||||
let v = (v_angle/pi) + 0.5;//(v_angle/pi) + 0.5; // from -pi/2 -> pi/2 into 0 -> 1
|
||||
let v = (v_angle/pi) - 0.5;//(v_angle/pi) + 0.5; // from -pi/2 -> pi/2 into 0 -> 1
|
||||
let uv = vec2<f32>(u,v); // Get UV on skybox
|
||||
return textureSample(sky_texture, sky_sampler, uv);
|
||||
}
|
||||
|
|
@ -112,7 +112,9 @@ fn translation(mat: mat4x4<f32>) -> vec4<f32> {
|
|||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
let object_color: vec4<f32> = textureSample(t_diffuse, s_diffuse, in.tex_coords);
|
||||
let object_normal: vec4<f32> = textureSample(t_normal, s_diffuse, in.tex_coords);
|
||||
let object_rough: vec4<f32> = textureSample(t_rough, s_diffuse, in.tex_coords);
|
||||
|
||||
let diffuse_result = object_color.xyz * environment.ambient.xyz;
|
||||
let diffuse_color = object_color.xyz;
|
||||
let specular_color = vec3<f32>(0.0,0.0,0.0);
|
||||
let reflection = sky_aspect(reflect(normalize(in.world_position-translation(eye.frame).xyz),normalize(in.world_normal)));
|
||||
|
|
@ -129,9 +131,15 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
|||
//let specular_strength = pow(max(dot(tangent_normal, half_dir), 0.0), 32.0);
|
||||
//let specular_color = specular_strength * environment.light.xyz;
|
||||
|
||||
let result = (environment.ambient.xyz + diffuse_color.xyz + specular_color.xyz) * object_color.xyz;
|
||||
let reflect_factor = max(object_rough.x * 0.5,object_rough.y);
|
||||
|
||||
return vec4<f32>(reflection.xyz,object_color.a);
|
||||
let diffuse_brightness = length(diffuse_color);
|
||||
|
||||
let diffuse_effect = (diffuse_result * (1 - reflect_factor)) + reflection.xyz * reflect_factor * diffuse_brightness;
|
||||
|
||||
let result = (diffuse_effect.xyz + specular_color.xyz);
|
||||
|
||||
return vec4<f32>(result.xyz,object_color.a);
|
||||
}
|
||||
|
||||
struct SkyOutput {
|
||||
|
|
|
|||
BIN
src/assets/skybox2.png
Normal file
BIN
src/assets/skybox2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 892 KiB |
|
|
@ -63,7 +63,7 @@ impl Eye {
|
|||
|
||||
let dir = Vec3::new(1.0, 0.5, 1.0).normalize();
|
||||
let environment = Environment {
|
||||
ambient: Vec4::new(0.15, 0.15, 0.15, 0.0),
|
||||
ambient: Vec4::new(0.1, 0.1, 0.1, 0.0),
|
||||
light: Vec4::new(1.0, 1.0, 1.0, 0.0),
|
||||
dir: Vec4::new(dir.x, dir.y, dir.z, 0.0),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -826,7 +826,6 @@ impl Renderer {
|
|||
collider: SimpleColliderData {
|
||||
transform: Mat4::default(),
|
||||
shape: Shape::None,
|
||||
radius: 0.0,
|
||||
},
|
||||
})));
|
||||
if len == 1 {
|
||||
|
|
|
|||
314
src/world/mod.rs
314
src/world/mod.rs
|
|
@ -1,8 +1,7 @@
|
|||
use crate::render::{Renderer, SimpleLightData, SimpleModelData};
|
||||
use glam::{DVec3, IVec3, Mat4, UVec3, Vec3, Vec4Swizzles};
|
||||
use glam::{IVec3, Mat4, Vec3};
|
||||
use std::cell::RefCell;
|
||||
use std::hash::{BuildHasherDefault, Hash, Hasher};
|
||||
use std::ops::{Div, Mul};
|
||||
use std::rc::Rc;
|
||||
use wgpu::naga::{FastHashMap, FastHashSet};
|
||||
|
||||
|
|
@ -17,7 +16,29 @@ pub enum Shape {
|
|||
pub struct SimpleColliderData {
|
||||
pub transform: Mat4,
|
||||
pub shape: Shape,
|
||||
pub radius: f32,
|
||||
}
|
||||
|
||||
impl SimpleColliderData {
|
||||
fn aabb(&self) -> Option<AABB> {
|
||||
let (_scale, _rotation, translation) = self.transform.to_scale_rotation_translation();
|
||||
match self.shape {
|
||||
Shape::Block(size) => {
|
||||
let radius_offset = Vec3::splat(size.length());
|
||||
Some(AABB(
|
||||
translation - radius_offset,
|
||||
translation + radius_offset,
|
||||
))
|
||||
}
|
||||
Shape::Sphere(radius) => {
|
||||
let radius_offset = Vec3::splat(radius);
|
||||
Some(AABB(
|
||||
translation - radius_offset,
|
||||
translation + radius_offset,
|
||||
))
|
||||
}
|
||||
Shape::None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -72,157 +93,220 @@ impl Hash for SimpleObject {
|
|||
}
|
||||
|
||||
#[derive(Eq, Hash, PartialEq, Clone)]
|
||||
enum Interest {
|
||||
pub enum Interest {
|
||||
Light(SimpleLight),
|
||||
Object(SimpleObject),
|
||||
}
|
||||
|
||||
struct Block {
|
||||
debug: Option<SimpleObject>,
|
||||
impl Interest {
|
||||
fn aabb(&self) -> Option<AABB> {
|
||||
match self {
|
||||
Interest::Light(light) => {
|
||||
let data = light.0.borrow();
|
||||
Some(AABB::new(
|
||||
data.transform.to_scale_rotation_translation().2,
|
||||
Vec3::splat(data.instance.color.length()),
|
||||
))
|
||||
}
|
||||
Interest::Object(object) => object.0.borrow().collider.aabb(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Material {
|
||||
volume: u8,
|
||||
velocity: Vec3,
|
||||
material: u8,
|
||||
interests: FastHashSet<Interest>,
|
||||
blocks: [Option<Box<Block>>; 64],
|
||||
}
|
||||
|
||||
const TREE_ATTACK: usize = 4;
|
||||
const TREE_FLOOR: usize = 4;
|
||||
impl Block {
|
||||
fn new() -> Block {
|
||||
Block {
|
||||
debug: None,
|
||||
impl Material {
|
||||
const fn new() -> Material {
|
||||
Material {
|
||||
volume: 0,
|
||||
velocity: Vec3::ZERO,
|
||||
material: 0,
|
||||
interests: FastHashSet::with_hasher(BuildHasherDefault::default()),
|
||||
blocks: [const { None }; const { TREE_ATTACK * TREE_ATTACK * TREE_ATTACK }],
|
||||
}
|
||||
}
|
||||
fn place_pos(&mut self, interest: Interest, pos: Vec3, rad: f32, block_size: f32) {
|
||||
let cs = block_size / const { TREE_ATTACK as f32 };
|
||||
if rad < cs || block_size >= TREE_FLOOR as f32 {
|
||||
let rel = ((pos + block_size / 2.0) / cs).round().as_uvec3();
|
||||
let new_pos = pos - (rel.as_vec3() + cs / 2.0);
|
||||
let index = (rel.x + rel.y * 4 + rel.z * 16) as usize;
|
||||
match self.blocks[index] {
|
||||
Some(ref mut block) => {
|
||||
block.place_pos(interest, new_pos, rad, cs);
|
||||
}
|
||||
None => {
|
||||
let mut block = Box::new(Block::new());
|
||||
block.place_pos(interest, new_pos, rad, cs);
|
||||
self.blocks[index] = Some(block);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.interests.insert(interest);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct AABB(Vec3, Vec3);
|
||||
|
||||
impl AABB {
|
||||
fn new(translation: Vec3, size: Vec3) -> AABB {
|
||||
AABB(translation - size, translation + size)
|
||||
}
|
||||
fn debug_step(&mut self, value: bool) {
|
||||
match self.debug {
|
||||
Some(ref mut debug) => {
|
||||
if value {
|
||||
} else {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if value {
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
for maybe_block in self.blocks.iter_mut() {
|
||||
if let Some(block) = maybe_block {
|
||||
block.debug_step(value)
|
||||
}
|
||||
}
|
||||
fn bounded_by(&self, aabb: AABB) -> AABB {
|
||||
AABB(self.0.max(aabb.0), self.1.min(aabb.1))
|
||||
}
|
||||
fn offset(&self) -> Vec3 {
|
||||
self.1 - self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct World {
|
||||
chunk_size: u32,
|
||||
map: FastHashMap<IVec3, Block>,
|
||||
map: HashedMap,
|
||||
pub renderer: Option<Renderer>,
|
||||
debug_world_map: bool,
|
||||
debug_world_map_object: Option<SimpleObject>,
|
||||
}
|
||||
|
||||
impl World {
|
||||
pub fn new() -> World {
|
||||
World {
|
||||
chunk_size: 512,
|
||||
map: FastHashMap::with_hasher(BuildHasherDefault::default()),
|
||||
map: HashedMap::new(),
|
||||
renderer: None,
|
||||
debug_world_map: false,
|
||||
debug_world_map_object: None,
|
||||
}
|
||||
}
|
||||
pub fn renderer(&mut self) -> &mut Renderer {
|
||||
self.renderer.as_mut().unwrap()
|
||||
}
|
||||
pub fn add_renderer(&mut self, renderer: Renderer) {
|
||||
self.renderer = Some(renderer);
|
||||
self.debug_world_map_object = self
|
||||
.renderer
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.load_from_gltf(include_bytes!("../assets/cube.glb"))
|
||||
.first_object()
|
||||
}
|
||||
pub fn add_object(&mut self, object: SimpleObject) {
|
||||
self.place(Interest::Object(object.clone()));
|
||||
if let Some(ref mut renderer) = self.renderer {
|
||||
renderer.instances.add_object(object)
|
||||
if let Some(aabb) = object.0.borrow().collider.aabb() {
|
||||
self.map
|
||||
.place_with_aabb(Interest::Object(object.clone()), aabb);
|
||||
}
|
||||
if let Some(ref mut renderer) = self.renderer
|
||||
&& object.0.borrow().model.is_some()
|
||||
{
|
||||
renderer.instances.add_object(object.clone())
|
||||
}
|
||||
}
|
||||
pub fn set_debug(&mut self, value: bool) {
|
||||
self.debug_world_map = value;
|
||||
pub fn remove_object(&mut self, object: SimpleObject) {}
|
||||
pub fn set_debug(&mut self, value: Option<SimpleObject>) {
|
||||
for (index, item) in self.map.it.iter_mut() {}
|
||||
}
|
||||
pub fn light_step(&mut self) {}
|
||||
pub fn object_step(&mut self) {}
|
||||
pub fn debug_step(&mut self) {
|
||||
self.light_step();
|
||||
self.object_step();
|
||||
for (index, item) in self.map.iter_mut() {
|
||||
item.debug_step(self.debug_world_map);
|
||||
fn step(&mut self) {}
|
||||
fn sync(&mut self) {}
|
||||
}
|
||||
|
||||
type VecMap<T> = FastHashMap<IVec3,T>;
|
||||
|
||||
struct Level<T,S> {
|
||||
sub_level:
|
||||
entries: T
|
||||
}
|
||||
|
||||
struct MatterLevel<T> {
|
||||
blocks: Option<VecMap<Material>>
|
||||
}
|
||||
|
||||
struct InterestLevel<T> {
|
||||
blocks: Option<VecMap<Interest>>
|
||||
}
|
||||
|
||||
struct HashedMap {
|
||||
matter:
|
||||
}
|
||||
|
||||
impl HashedMap {
|
||||
fn new() -> HashedMap {
|
||||
HashedMap {
|
||||
it: FastHashMap::default()
|
||||
}
|
||||
}
|
||||
fn place_pos(&mut self, interest: Interest, pos: Vec3, rad: f32) {
|
||||
let cs = self.chunk_size as f32;
|
||||
let c_rad = ((cs / 2.0) * (cs / 2.0)) * 3.0;
|
||||
for x in (pos.x - rad).div(cs) as i32..=(pos.x + rad).div(cs).ceil() as i32 {
|
||||
for y in (pos.y - rad).div(cs) as i32..=(pos.y + rad).div(cs).ceil() as i32 {
|
||||
for z in (pos.z - rad).div(cs) as i32..=(pos.z + rad).div(cs).ceil() as i32 {
|
||||
let block_pos = IVec3::new(x, y, z);
|
||||
let block_pos_f32 = block_pos.as_vec3();
|
||||
if block_pos_f32.distance_squared(pos) < rad + c_rad {
|
||||
self.map.entry(block_pos).or_insert_with(|| {
|
||||
let mut block = Block::new();
|
||||
block.place_pos(
|
||||
interest.clone(),
|
||||
pos - block_pos_f32,
|
||||
rad,
|
||||
self.chunk_size as f32,
|
||||
);
|
||||
block
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*impl Block {
|
||||
const FLOOR: i32 = 4;
|
||||
const CHUNK_SIZE: i32 = Block::FLOOR * 64;
|
||||
const MAX_IDEAL_INTEREST: usize = 4;
|
||||
fn new() -> Block {
|
||||
Block {
|
||||
debug: None,
|
||||
material: Material::new(),
|
||||
interests: FastHashSet::default(),
|
||||
blocks: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Blocks = Box<[Block; 8]>;
|
||||
|
||||
struct Block {
|
||||
debug: Option<SimpleObject>,
|
||||
interests: FastHashSet<Interest>,
|
||||
material: Material,
|
||||
blocks: Option<Blocks>,
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn set_debug(&mut self, value: Option<SimpleObject>, pos: Vec3, size: f32) {}
|
||||
}
|
||||
|
||||
pub trait WorldMap {
|
||||
fn new() -> Self;
|
||||
fn place_with_aabb(&mut self, interest: Interest, aabb: AABB);
|
||||
}
|
||||
|
||||
struct OctreeMap {
|
||||
it: FastHashMap<IVec3, Block>,
|
||||
}
|
||||
|
||||
impl OctreeMap {
|
||||
fn place_with_index(&mut self, interest: Interest, mut index: IVec3) {
|
||||
let chunk_index = (index + IVec3::splat(Block::CHUNK_SIZE / 2)) / Block::CHUNK_SIZE;
|
||||
let mut block = self.it.entry(chunk_index).or_insert_with(|| Block::new());
|
||||
let mut offset_size = Block::CHUNK_SIZE / 4;
|
||||
index = index - chunk_index * Block::CHUNK_SIZE;
|
||||
while index != IVec3::ZERO {
|
||||
let blocks = if let Some(ref mut blocks) = block.blocks {
|
||||
blocks
|
||||
} else if block.interests.len() < Block::MAX_IDEAL_INTEREST {
|
||||
block.interests.insert(interest.clone());
|
||||
return;
|
||||
} else {
|
||||
block.blocks = Some(Box::new(core::array::from_fn(|_| Block::new())));
|
||||
block.blocks.as_mut().unwrap()
|
||||
};
|
||||
let mut block_index = 0;
|
||||
if index.x < 0 {
|
||||
index.x += offset_size;
|
||||
} else {
|
||||
index.x -= offset_size;
|
||||
block_index += 1;
|
||||
}
|
||||
if index.y < 0 {
|
||||
index.y += offset_size;
|
||||
} else {
|
||||
index.y -= offset_size;
|
||||
block_index += 2;
|
||||
}
|
||||
if index.z < 0 {
|
||||
index.z += offset_size;
|
||||
} else {
|
||||
index.z -= offset_size;
|
||||
block_index += 4;
|
||||
}
|
||||
block = &mut blocks[block_index];
|
||||
offset_size /= 2;
|
||||
}
|
||||
block.interests.insert(interest.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl WorldMap for OctreeMap {
|
||||
fn place_with_aabb(&mut self, interest: Interest, aabb: AABB) {
|
||||
let mut d = 4;
|
||||
let offset = aabb.1 - aabb.0;
|
||||
while offset.element_sum() > (d * 2) as f32 {
|
||||
d *= 2
|
||||
}
|
||||
let iaabb0 = (aabb.0 / d as f32).floor().as_ivec3();
|
||||
let iaabb1 = (aabb.1 / d as f32).ceil().as_ivec3();
|
||||
for x in iaabb0.x..iaabb1.x {
|
||||
for y in iaabb0.y..iaabb1.y {
|
||||
for z in iaabb0.z..iaabb1.z {
|
||||
self.place_with_index(interest.clone(), IVec3::new(x, y, z) * d as i32);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn place(&mut self, interest: Interest) {
|
||||
let (pos, rad) = match &interest {
|
||||
Interest::Light(light) => {
|
||||
let light = light.0.borrow();
|
||||
(light.instance.location.xyz(), light.instance.color.length())
|
||||
}
|
||||
Interest::Object(object) => {
|
||||
let collider = &object.0.borrow().collider;
|
||||
(
|
||||
collider.transform.to_scale_rotation_translation().2,
|
||||
collider.radius,
|
||||
)
|
||||
}
|
||||
};
|
||||
self.place_pos(interest, pos, rad);
|
||||
fn new() -> OctreeMap {
|
||||
OctreeMap {
|
||||
it: FastHashMap::with_hasher(BuildHasherDefault::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue