1
0
Fork 0

tutorial10-lighting

Also switch back to cgmath from nalgebra-glm
This commit is contained in:
Adrian Hedqvist 2020-10-09 23:32:31 +02:00
parent 56bb19f3c3
commit e7e251d29d
10 changed files with 754 additions and 460 deletions

291
Cargo.lock generated
View file

@ -82,6 +82,12 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "autocfg"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
[[package]]
name = "autocfg"
version = "1.0.1"
@ -144,6 +150,17 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cgmath"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "283944cdecc44bf0b8dd010ec9af888d3b4f142844fdbe026c20ef68148d6fe7"
dependencies = [
"approx",
"num-traits",
"rand",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
@ -203,9 +220,9 @@ dependencies = [
[[package]]
name = "color_quant"
version = "1.0.1"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "copyless"
@ -318,7 +335,7 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
dependencies = [
"autocfg",
"autocfg 1.0.1",
"cfg-if",
"crossbeam-utils",
"lazy_static",
@ -333,7 +350,7 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
"autocfg",
"autocfg 1.0.1",
"cfg-if",
"lazy_static",
]
@ -431,6 +448,12 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
@ -551,26 +574,6 @@ dependencies = [
"byteorder",
]
[[package]]
name = "generic-array"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ed1e761351b56f54eb9dcd0cfaca9fd0daecf93918e1cfc01c8a3d26ee7adcd"
dependencies = [
"typenum",
]
[[package]]
name = "getrandom"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "gfx-auxil"
version = "0.6.0"
@ -768,7 +771,7 @@ dependencies = [
"gif",
"jpeg-decoder",
"num-iter",
"num-rational 0.3.0",
"num-rational",
"num-traits",
"png",
"scoped_threadpool",
@ -922,15 +925,6 @@ dependencies = [
"libc",
]
[[package]]
name = "matrixmultiply"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4f7ec66360130972f34830bfad9ef05c6610a43938a467bcc9ab9369ab3478f"
dependencies = [
"rawpointer",
]
[[package]]
name = "maybe-uninit"
version = "2.0.0"
@ -959,7 +953,7 @@ version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"
dependencies = [
"autocfg",
"autocfg 1.0.1",
]
[[package]]
@ -1042,36 +1036,6 @@ dependencies = [
"thiserror",
]
[[package]]
name = "nalgebra"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a3f0b89b0a44cb7bb9b62c5e6fd485145ddc6bc14483ab005355e96029b3fbf"
dependencies = [
"approx",
"generic-array",
"matrixmultiply",
"num-complex",
"num-rational 0.2.4",
"num-traits",
"rand",
"rand_distr",
"simba",
"typenum",
]
[[package]]
name = "nalgebra-glm"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e34d489ea638e56cec175e7dd7b253fc3cf21982f37d596a69d7b0cf3b0db235"
dependencies = [
"approx",
"nalgebra",
"num-traits",
"simba",
]
[[package]]
name = "ndk"
version = "0.1.0"
@ -1127,23 +1091,13 @@ dependencies = [
"void",
]
[[package]]
name = "num-complex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
dependencies = [
"autocfg",
"autocfg 1.0.1",
"num-traits",
]
@ -1153,18 +1107,7 @@ version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
dependencies = [
"autocfg",
"autocfg 1.0.1",
"num-integer",
"num-traits",
]
@ -1175,7 +1118,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5b4d7360f362cfb50dde8143501e6940b22f644be75a4cc90b2d81968908138"
dependencies = [
"autocfg",
"autocfg 1.0.1",
"num-integer",
"num-traits",
]
@ -1186,7 +1129,7 @@ version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
dependencies = [
"autocfg",
"autocfg 1.0.1",
]
[[package]]
@ -1305,25 +1248,6 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "paste"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
dependencies = [
"paste-impl",
"proc-macro-hack",
]
[[package]]
name = "paste-impl"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
dependencies = [
"proc-macro-hack",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
@ -1380,12 +1304,6 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "ppv-lite86"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20"
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
@ -1451,52 +1369,108 @@ dependencies = [
[[package]]
name = "rand"
version = "0.7.3"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
dependencies = [
"getrandom",
"autocfg 0.1.7",
"libc",
"rand_chacha",
"rand_core",
"rand_core 0.4.2",
"rand_hc",
"rand_isaac",
"rand_jitter",
"rand_os",
"rand_pcg",
"rand_xorshift",
"winapi 0.3.9",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
dependencies = [
"ppv-lite86",
"rand_core",
"autocfg 0.1.7",
"rand_core 0.3.1",
]
[[package]]
name = "rand_core"
version = "0.5.1"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"getrandom",
"rand_core 0.4.2",
]
[[package]]
name = "rand_distr"
version = "0.2.2"
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2"
dependencies = [
"rand",
]
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_hc"
version = "0.2.0"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
dependencies = [
"rand_core",
"rand_core 0.3.1",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
dependencies = [
"libc",
"rand_core 0.4.2",
"winapi 0.3.9",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
dependencies = [
"cloudabi 0.0.3",
"fuchsia-cprng",
"libc",
"rand_core 0.4.2",
"rdrand",
"winapi 0.3.9",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
dependencies = [
"autocfg 0.1.7",
"rand_core 0.4.2",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
@ -1514,19 +1488,13 @@ dependencies = [
"libc",
]
[[package]]
name = "rawpointer"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
[[package]]
name = "rayon"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf6960dc9a5b4ee8d3e4c5787b4a112a8818e0290a42ff664ad60692fdf2032"
dependencies = [
"autocfg",
"autocfg 1.0.1",
"crossbeam-deque",
"either",
"rayon-core",
@ -1545,6 +1513,15 @@ dependencies = [
"num_cpus",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "redox_syscall"
version = "0.1.57"
@ -1636,18 +1613,6 @@ dependencies = [
"libc",
]
[[package]]
name = "simba"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdec3fb717e5504ecbef1cf4223c334a215f95323092afeae57125ec40e4995b"
dependencies = [
"approx",
"num-complex",
"num-traits",
"paste",
]
[[package]]
name = "slab"
version = "0.4.2"
@ -1717,9 +1682,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.42"
version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c51d92969d209b54a98397e1b91c8ae82d8c87a7bb87df0b29aa2ad81454228"
checksum = "1e2e59c50ed8f6b050b071aa7b6865293957a9af6b58b94f97c1c9434ad440ea"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
@ -1816,12 +1781,6 @@ version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae"
[[package]]
name = "typenum"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
[[package]]
name = "unicode-xid"
version = "0.1.0"
@ -1851,12 +1810,6 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasm-bindgen"
version = "0.2.68"
@ -2055,13 +2008,13 @@ version = "0.1.0"
dependencies = [
"anyhow",
"bytemuck",
"cgmath",
"env_logger",
"fs_extra",
"futures",
"glob",
"image",
"log",
"nalgebra-glm",
"shaderc",
"tobj",
"wgpu",

View file

@ -13,10 +13,10 @@ image = "0.23.9"
futures = "0.3.5"
bytemuck = "1.4.1"
anyhow = "1.0.33"
nalgebra-glm = "0.8.0"
env_logger = "0.7.1"
log = "0.4.11"
tobj = "2.0.2"
cgmath = "0.17.0"
[build-dependencies]
shaderc = "0.6.2"

114
src/camera.rs Normal file
View file

@ -0,0 +1,114 @@
use cgmath::prelude::*;
use winit::event::{ElementState, KeyboardInput, VirtualKeyCode, WindowEvent};
pub struct Camera {
pub eye: cgmath::Point3<f32>,
pub target: cgmath::Point3<f32>,
pub up: cgmath::Vector3<f32>,
pub aspect: f32,
pub fovy: f32,
pub znear: f32,
pub zfar: f32,
}
impl Camera {
pub fn build_view_projection_matrix(&self) -> cgmath::Matrix4<f32> {
let view = cgmath::Matrix4::look_at(self.eye, self.target, self.up);
let proj = cgmath::perspective(cgmath::Deg(self.fovy), self.aspect, self.znear, self.zfar);
return proj * view;
}
}
pub struct CameraController {
speed: f32,
is_up_pressed: bool,
is_down_pressed: bool,
is_forward_pressed: bool,
is_backward_pressed: bool,
is_left_pressed: bool,
is_right_pressed: bool,
}
impl CameraController {
pub fn new(speed: f32) -> Self {
Self {
speed,
is_up_pressed: false,
is_down_pressed: false,
is_forward_pressed: false,
is_backward_pressed: false,
is_left_pressed: false,
is_right_pressed: false,
}
}
pub fn process_events(&mut self, event: &WindowEvent) -> bool {
match event {
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state,
virtual_keycode: Some(keycode),
..
},
..
} => {
let is_pressed = *state == ElementState::Pressed;
match keycode {
VirtualKeyCode::Space => {
self.is_up_pressed = is_pressed;
true
}
VirtualKeyCode::LControl => {
self.is_down_pressed = is_pressed;
true
}
VirtualKeyCode::W | VirtualKeyCode::Up => {
self.is_forward_pressed = is_pressed;
true
}
VirtualKeyCode::A | VirtualKeyCode::Left => {
self.is_left_pressed = is_pressed;
true
}
VirtualKeyCode::S | VirtualKeyCode::Down => {
self.is_backward_pressed = is_pressed;
true
}
VirtualKeyCode::D | VirtualKeyCode::Right => {
self.is_right_pressed = is_pressed;
true
}
_ => false,
}
}
_ => false,
}
}
pub fn update_camera(&self, camera: &mut Camera) {
let forward = camera.target - camera.eye;
let forward_norm = forward.normalize();
let forward_mag = forward.magnitude();
// Prevents glitching when camera gets too close to the
// center of the scene.
if self.is_forward_pressed && forward_mag > self.speed {
camera.eye += forward_norm * self.speed;
}
if self.is_backward_pressed {
camera.eye -= forward_norm * self.speed;
}
let right = forward_norm.cross(camera.up);
if self.is_right_pressed {
camera.eye = camera.target - (forward - right * self.speed).normalize() * forward_mag;
}
if self.is_left_pressed {
camera.eye = camera.target - (forward + right * self.speed).normalize() * forward_mag;
}
}
}

8
src/light.frag Normal file
View file

@ -0,0 +1,8 @@
#version 450
layout(location=0) in vec3 v_color;
layout(location=0) out vec4 f_color;
void main() {
f_color = vec4(v_color, 1.0);
}

21
src/light.rs Normal file
View file

@ -0,0 +1,21 @@
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Light {
pub position: cgmath::Vector3<f32>,
// according to the tutorial I'm following, uniforms require 16 byte padding. So that's why this thing is here.
_padding: u32,
pub color: cgmath::Vector3<f32>,
}
impl Light {
pub fn new(position: cgmath::Vector3<f32>, color: cgmath::Vector3<f32>) -> Self {
Self {
position,
_padding: 0,
color,
}
}
}
unsafe impl bytemuck::Pod for Light {}
unsafe impl bytemuck::Zeroable for Light {}

27
src/light.vert Normal file
View file

@ -0,0 +1,27 @@
#version 450
layout(location=0) in vec3 a_position;
layout(location=0) out vec3 v_color;
layout(set=0, binding=0)
uniform Uniforms {
vec3 u_view_position;
mat4 u_view_proj;
};
layout(set=1, binding=0)
uniform Light {
vec3 u_position;
vec3 u_color;
};
// Let's keep our light smaller than our other objects
float scale = 0.25;
void main() {
vec3 v_position = a_position * scale + u_position;
gl_Position = u_view_proj * vec4(v_position, 1);
v_color = u_color;
}

View file

@ -1,4 +1,4 @@
use model::{DrawModel, Model, Vertex};
use model::{DrawLight, DrawModel, Model, Vertex};
use wgpu::util::DeviceExt;
use winit::{
event::*,
@ -6,11 +6,16 @@ use winit::{
window::{Window, WindowBuilder},
};
use nalgebra_glm as glm;
use cgmath::prelude::*;
mod camera;
mod light;
mod model;
mod texture;
type Vec3 = cgmath::Vector3<f32>;
type Mat4 = cgmath::Matrix4<f32>;
const NUM_INSTANCES_PER_ROW: u32 = 11;
fn main() {
@ -59,137 +64,23 @@ fn main() {
});
}
struct Camera {
eye: glm::Vec3,
target: glm::Vec3,
up: glm::Vec3,
aspect: f32,
fovy: f32,
znear: f32,
zfar: f32,
}
impl Camera {
fn build_view_projection_matrix(&self) -> glm::Mat4 {
let view = glm::look_at(&self.eye, &self.target, &self.up);
let proj = glm::perspective(self.aspect, self.fovy, self.znear, self.zfar);
return proj * view;
}
}
struct CameraController {
speed: f32,
is_up_pressed: bool,
is_down_pressed: bool,
is_forward_pressed: bool,
is_backward_pressed: bool,
is_left_pressed: bool,
is_right_pressed: bool,
}
impl CameraController {
fn new(speed: f32) -> Self {
Self {
speed,
is_up_pressed: false,
is_down_pressed: false,
is_forward_pressed: false,
is_backward_pressed: false,
is_left_pressed: false,
is_right_pressed: false,
}
}
fn process_events(&mut self, event: &WindowEvent) -> bool {
match event {
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state,
virtual_keycode: Some(keycode),
..
},
..
} => {
let is_pressed = *state == ElementState::Pressed;
match keycode {
VirtualKeyCode::Space => {
self.is_up_pressed = is_pressed;
true
}
VirtualKeyCode::LControl => {
self.is_down_pressed = is_pressed;
true
}
VirtualKeyCode::W | VirtualKeyCode::Up => {
self.is_forward_pressed = is_pressed;
true
}
VirtualKeyCode::A | VirtualKeyCode::Left => {
self.is_left_pressed = is_pressed;
true
}
VirtualKeyCode::S | VirtualKeyCode::Down => {
self.is_backward_pressed = is_pressed;
true
}
VirtualKeyCode::D | VirtualKeyCode::Right => {
self.is_right_pressed = is_pressed;
true
}
_ => false,
}
}
_ => false,
}
}
fn update_camera(&self, camera: &mut Camera) {
let forward = camera.target - camera.eye;
let forward_norm = glm::normalize(&forward);
let forward_mag = glm::magnitude(&forward);
// Prevents glitching when camera gets too close to the
// center of the scene.
if self.is_forward_pressed && forward_mag > self.speed {
camera.eye += forward_norm * self.speed;
}
if self.is_backward_pressed {
camera.eye -= forward_norm * self.speed;
}
let right = glm::cross(&forward_norm, &camera.up);
let forward = camera.target - camera.eye;
let forward_mag = glm::magnitude(&forward);
if self.is_right_pressed {
camera.eye =
camera.target - glm::normalize(&(forward + right * self.speed)) * forward_mag;
}
if self.is_left_pressed {
camera.eye =
camera.target - glm::normalize(&(forward - right * self.speed)) * forward_mag;
}
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Uniforms {
view_proj: glm::Mat4,
view_position: cgmath::Vector4<f32>,
view_proj: cgmath::Matrix4<f32>,
}
impl Uniforms {
fn new() -> Self {
Self {
view_proj: glm::identity(),
view_position: Zero::zero(),
view_proj: cgmath::Matrix4::identity(),
}
}
fn update_view_proj(&mut self, camera: &Camera) {
fn update_view_proj(&mut self, camera: &camera::Camera) {
self.view_position = camera.eye.to_homogeneous();
self.view_proj = camera.build_view_projection_matrix();
}
}
@ -198,14 +89,15 @@ unsafe impl bytemuck::Pod for Uniforms {}
unsafe impl bytemuck::Zeroable for Uniforms {}
struct Instance {
position: glm::Vec3,
rotation: glm::Quat,
position: cgmath::Vector3<f32>,
rotation: cgmath::Quaternion<f32>,
}
impl Instance {
fn to_raw(&self) -> InstanceRaw {
InstanceRaw {
model: glm::translation(&self.position) * glm::quat_to_mat4(&self.rotation),
model: cgmath::Matrix4::from_translation(self.position)
* cgmath::Matrix4::from(self.rotation),
}
}
}
@ -213,7 +105,7 @@ impl Instance {
#[repr(C)]
#[derive(Copy, Clone)]
struct InstanceRaw {
model: glm::Mat4,
model: cgmath::Matrix4<f32>,
}
unsafe impl bytemuck::Pod for InstanceRaw {}
@ -230,8 +122,8 @@ struct State {
depth_texture: texture::Texture,
camera: Camera,
camera_controller: CameraController,
camera: camera::Camera,
camera_controller: camera::CameraController,
uniforms: Uniforms,
uniform_buffer: wgpu::Buffer,
@ -241,6 +133,11 @@ struct State {
instances: Vec<Instance>,
instance_buffer: wgpu::Buffer,
light: light::Light,
light_buffer: wgpu::Buffer,
light_bind_group: wgpu::BindGroup,
light_render_pipeline: wgpu::RenderPipeline,
render_pipeline: wgpu::RenderPipeline,
size: winit::dpi::PhysicalSize<u32>,
@ -306,38 +203,27 @@ impl State {
],
});
// Camera
let camera = Camera {
eye: glm::vec3(0.0, 1.0, 2.0),
target: glm::vec3(0.0, 0.0, 0.0),
up: glm::vec3(0.0, 1.0, 0.0),
aspect: sc_desc.width as f32 / sc_desc.height as f32,
fovy: 45.0,
znear: 0.1,
zfar: 100.0,
};
let camera_controller = CameraController::new(0.2);
let res_dir = std::path::Path::new(env!("OUT_DIR")).join("res");
let obj_model = Model::load(
&device, &queue, &texture_bind_group_layout,
res_dir.join("cube.obj")
).unwrap();
&device,
&queue,
&texture_bind_group_layout,
res_dir.join("cube.obj"),
)
.unwrap();
let instance_displacement = glm::vec3(
3.0 * NUM_INSTANCES_PER_ROW as f32 / 2.0,
0.0,
3.0 * NUM_INSTANCES_PER_ROW as f32 / 2.0,
);
const SPACE_BETWEEN: f32 = 3.0;
let instances: Vec<Instance> = (0..NUM_INSTANCES_PER_ROW)
.flat_map(|z| {
(0..NUM_INSTANCES_PER_ROW).map(move |x| {
let position = glm::vec3(x as f32 * 3.0, 0.0, z as f32 * 3.0) - instance_displacement;
let rotation = if glm::zero::<glm::Vec3>() == position {
glm::quat_angle_axis(0.0, &glm::vec3(0.0, 0.0, 1.0))
let x = SPACE_BETWEEN * (x as f32 - NUM_INSTANCES_PER_ROW as f32 / 2.0);
let z = SPACE_BETWEEN * (z as f32 - NUM_INSTANCES_PER_ROW as f32 / 2.0);
let position: Vec3 = (x, 0.0, z).into();
let rotation = if Vec3::zero() == position {
cgmath::Quaternion::from_axis_angle(Vec3::unit_z(), cgmath::Deg(0.0))
} else {
glm::quat_angle_axis(45.0, &glm::normalize(&position))
cgmath::Quaternion::from_axis_angle(position.normalize(), cgmath::Deg(45.0))
};
Instance { position, rotation }
@ -351,10 +237,18 @@ impl State {
usage: wgpu::BufferUsage::STORAGE,
});
let depth_texture =
texture::Texture::create_depth_texture(&device, &sc_desc, "depth_texture");
let camera = camera::Camera {
eye: (0.0, 1.0, 2.0).into(),
target: (0.0, 0.0, 0.0).into(),
up: (0.0, 1.0, 0.0).into(),
aspect: sc_desc.width as f32 / sc_desc.height as f32,
fovy: 45.0,
znear: 0.1,
zfar: 100.0,
};
let camera_controller = camera::CameraController::new(0.2);
// Uniforms
let mut uniforms = Uniforms::new();
uniforms.update_view_proj(&camera);
@ -370,7 +264,7 @@ impl State {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStage::VERTEX,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::UniformBuffer {
dynamic: false,
min_binding_size: None,
@ -396,10 +290,7 @@ impl State {
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(
uniform_buffer
.slice(0..std::mem::size_of_val(&uniforms) as wgpu::BufferAddress),
),
resource: wgpu::BindingResource::Buffer(uniform_buffer.slice(..)),
},
wgpu::BindGroupEntry {
binding: 1,
@ -408,58 +299,80 @@ impl State {
],
});
// Load shaders
let vs_module = device.create_shader_module(wgpu::include_spirv!("shader.vert.spv"));
let fs_module = device.create_shader_module(wgpu::include_spirv!("shader.frag.spv"));
// Lights
let light = light::Light::new((2.0, 2.0, 2.0).into(), (1.0, 1.0, 1.0).into());
// Setup render pipeline
let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
let light_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Light VB"),
contents: bytemuck::cast_slice(&[light]),
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
});
let light_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::UniformBuffer {
dynamic: false,
min_binding_size: None,
},
count: None,
}],
label: None,
});
let light_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &light_bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(light_buffer.slice(..)),
}],
label: None,
});
let render_pipeline = {
let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("render_pipeline_layout"),
bind_group_layouts: &[&texture_bind_group_layout, &uniform_bind_group_layout],
bind_group_layouts: &[
&texture_bind_group_layout,
&uniform_bind_group_layout,
&light_bind_group_layout,
],
push_constant_ranges: &[],
});
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("render_pipeline"),
layout: Some(&render_pipeline_layout),
vertex_stage: wgpu::ProgrammableStageDescriptor {
module: &vs_module,
entry_point: "main",
},
fragment_stage: Some(wgpu::ProgrammableStageDescriptor {
module: &fs_module,
entry_point: "main",
}),
rasterization_state: Some(wgpu::RasterizationStateDescriptor {
front_face: wgpu::FrontFace::Ccw,
cull_mode: wgpu::CullMode::Back,
clamp_depth: false,
depth_bias: 0,
depth_bias_slope_scale: 0.0,
depth_bias_clamp: 0.0,
}),
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
color_states: &[wgpu::ColorStateDescriptor {
format: sc_desc.format,
alpha_blend: wgpu::BlendDescriptor::REPLACE,
color_blend: wgpu::BlendDescriptor::REPLACE,
write_mask: wgpu::ColorWrite::ALL,
}],
depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor {
format: texture::Texture::DEPTH_FORMAT,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilStateDescriptor::default(),
}),
vertex_state: wgpu::VertexStateDescriptor {
index_format: wgpu::IndexFormat::Uint32,
vertex_buffers: &[model::ModelVertex::desc()],
},
sample_count: 1,
sample_mask: !0,
alpha_to_coverage_enabled: false,
});
create_render_pipeline(
&device,
&layout,
sc_desc.format,
Some(texture::Texture::DEPTH_FORMAT),
&[model::ModelVertex::desc()],
wgpu::include_spirv!("shader.vert.spv"),
wgpu::include_spirv!("shader.frag.spv"),
)
};
let light_render_pipeline = {
let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("light_render_pipeline_layout"),
bind_group_layouts: &[&uniform_bind_group_layout, &light_bind_group_layout],
push_constant_ranges: &[],
});
create_render_pipeline(
&device,
&layout,
sc_desc.format,
Some(texture::Texture::DEPTH_FORMAT),
&[model::ModelVertex::desc()],
wgpu::include_spirv!("light.vert.spv"),
wgpu::include_spirv!("light.frag.spv"),
)
};
let depth_texture =
texture::Texture::create_depth_texture(&device, &sc_desc, "depth_texture");
Self {
instance,
@ -476,6 +389,10 @@ impl State {
uniform_buffer,
uniform_bind_group,
obj_model,
light,
light_buffer,
light_bind_group,
light_render_pipeline,
instances,
instance_buffer,
render_pipeline,
@ -523,6 +440,12 @@ impl State {
std::mem::size_of::<Uniforms>() as wgpu::BufferAddress,
);
self.light.position =
cgmath::Quaternion::from_axis_angle((0.0, 1.0, 0.0).into(), cgmath::Deg(1.0))
* self.light.position;
self.queue
.write_buffer(&self.light_buffer, 0, bytemuck::cast_slice(&[self.light]));
self.queue.submit(Some(encoder.finish()));
}
@ -562,12 +485,78 @@ impl State {
}),
});
render_pass.set_pipeline(&self.render_pipeline);
render_pass.set_pipeline(&self.light_render_pipeline);
render_pass.draw_light_model_instanced(
&self.obj_model,
&self.uniform_bind_group,
&self.light_bind_group,
0..self.instances.len() as u32,
);
render_pass.draw_model_instanced(&self.obj_model, 0..self.instances.len() as u32, &self.uniform_bind_group);
render_pass.set_pipeline(&self.render_pipeline);
render_pass.draw_model_instanced(
&self.obj_model,
&self.uniform_bind_group,
&self.light_bind_group,
0..self.instances.len() as u32,
);
drop(render_pass);
self.queue.submit(Some(encoder.finish()));
}
}
fn create_render_pipeline(
device: &wgpu::Device,
layout: &wgpu::PipelineLayout,
color_format: wgpu::TextureFormat,
depth_format: Option<wgpu::TextureFormat>,
vertex_descs: &[wgpu::VertexBufferDescriptor],
vs_src: wgpu::ShaderModuleSource,
fs_src: wgpu::ShaderModuleSource,
) -> wgpu::RenderPipeline {
let vs_module = device.create_shader_module(vs_src);
let fs_module = device.create_shader_module(fs_src);
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("render_pipeline"),
layout: Some(layout),
vertex_stage: wgpu::ProgrammableStageDescriptor {
module: &vs_module,
entry_point: "main",
},
fragment_stage: Some(wgpu::ProgrammableStageDescriptor {
module: &fs_module,
entry_point: "main",
}),
rasterization_state: Some(wgpu::RasterizationStateDescriptor {
front_face: wgpu::FrontFace::Ccw,
cull_mode: wgpu::CullMode::Back,
clamp_depth: false,
depth_bias: 0,
depth_bias_slope_scale: 0.0,
depth_bias_clamp: 0.0,
}),
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
color_states: &[wgpu::ColorStateDescriptor {
format: color_format,
alpha_blend: wgpu::BlendDescriptor::REPLACE,
color_blend: wgpu::BlendDescriptor::REPLACE,
write_mask: wgpu::ColorWrite::ALL,
}],
depth_stencil_state: depth_format.map(|format| wgpu::DepthStencilStateDescriptor {
format,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilStateDescriptor::default(),
}),
vertex_state: wgpu::VertexStateDescriptor {
index_format: wgpu::IndexFormat::Uint32,
vertex_buffers: vertex_descs,
},
sample_count: 1,
sample_mask: !0,
alpha_to_coverage_enabled: false,
})
}

View file

@ -11,9 +11,9 @@ pub trait Vertex {
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct ModelVertex {
position: [f32; 3],
tex_coords: [f32; 2],
normal: [f32; 3],
position: cgmath::Vector3<f32>,
tex_coords: cgmath::Vector2<f32>,
normal: cgmath::Vector3<f32>,
}
impl Vertex for ModelVertex {
@ -29,12 +29,14 @@ impl Vertex for ModelVertex {
format: wgpu::VertexFormat::Float3,
},
wgpu::VertexAttributeDescriptor {
offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
offset: mem::size_of::<cgmath::Vector3<f32>>() as wgpu::BufferAddress,
shader_location: 1,
format: wgpu::VertexFormat::Float2,
},
wgpu::VertexAttributeDescriptor {
offset: mem::size_of::<[f32; 5]>() as wgpu::BufferAddress,
offset: (mem::size_of::<cgmath::Vector3<f32>>()
+ mem::size_of::<cgmath::Vector2<f32>>())
as wgpu::BufferAddress,
shader_location: 2,
format: wgpu::VertexFormat::Float3,
},
@ -74,78 +76,82 @@ impl Model {
) -> Result<Self> {
let (obj_models, obj_materials) = tobj::load_obj(path.as_ref(), true)?;
let containing_folder = path.as_ref().parent()
.context("Directory has no parent")?;
let containing_folder = path.as_ref().parent().context("Directory has no parent")?;
let materials: Result<Vec<_>> = obj_materials.into_iter().map(|mat| {
let diffuse_texture = texture::Texture::load(device, queue, containing_folder.join(mat.diffuse_texture))?;
let materials: Result<Vec<_>> = obj_materials
.into_iter()
.map(|mat| {
let diffuse_texture = texture::Texture::load(
device,
queue,
containing_folder.join(mat.diffuse_texture),
)?;
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: None,
layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&diffuse_texture.view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler),
}
],
});
Ok(Material {
name: mat.name,
diffuse_texture,
bind_group
})
}).collect();
let meshes: Result<Vec<_>> = obj_models.into_iter().map(|m| {
let mut vertices = Vec::with_capacity(m.mesh.positions.len() / 3);
for i in 0..m.mesh.positions.len() / 3 {
vertices.push(ModelVertex {
position: [
m.mesh.positions[i * 3],
m.mesh.positions[i * 3 + 1],
m.mesh.positions[i * 3 + 2],
],
tex_coords: [
m.mesh.texcoords[i * 2],
m.mesh.texcoords[i * 2 + 1],
],
normal: [
m.mesh.normals[i * 3],
m.mesh.normals[i * 3 + 1],
m.mesh.normals[i * 3 + 2],
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: None,
layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&diffuse_texture.view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler),
},
],
});
}
let vertex_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
Ok(Material {
name: mat.name,
diffuse_texture,
bind_group,
})
})
.collect();
let meshes: Result<Vec<_>> = obj_models
.into_iter()
.map(|m| {
let mut vertices = Vec::with_capacity(m.mesh.positions.len() / 3);
for i in 0..m.mesh.positions.len() / 3 {
vertices.push(ModelVertex {
position: (
m.mesh.positions[i * 3],
m.mesh.positions[i * 3 + 1],
m.mesh.positions[i * 3 + 2],
)
.into(),
tex_coords: (m.mesh.texcoords[i * 2], m.mesh.texcoords[i * 2 + 1]).into(),
normal: (
m.mesh.normals[i * 3],
m.mesh.normals[i * 3 + 1],
m.mesh.normals[i * 3 + 2],
)
.into(),
});
}
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Vertex Buffer", path.as_ref())),
contents: bytemuck::cast_slice(&vertices),
usage: wgpu::BufferUsage::VERTEX,
}
);
let index_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
});
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Index Buffer", path.as_ref())),
contents: bytemuck::cast_slice(&m.mesh.indices),
usage: wgpu::BufferUsage::INDEX,
}
);
});
Ok(Mesh {
name: m.name,
vertex_buffer,
index_buffer,
num_elements: m.mesh.indices.len() as u32,
material: m.mesh.material_id.unwrap_or(0),
Ok(Mesh {
name: m.name,
vertex_buffer,
index_buffer,
num_elements: m.mesh.indices.len() as u32,
material: m.mesh.material_id.unwrap_or(0),
})
})
}).collect();
.collect();
Ok(Self {
meshes: meshes?,
@ -154,34 +160,170 @@ impl Model {
}
}
pub trait DrawModel<'a, 'b> where 'b: 'a {
fn draw_model(&mut self, model: &'b Model, uniforms: &'b wgpu::BindGroup);
fn draw_model_instanced(&mut self, model: &'b Model, instances: Range<u32>, uniforms: &'b wgpu::BindGroup);
fn draw_mesh(&mut self, mesh: &'b Mesh, material: &'b Material, uniforms: &'b wgpu::BindGroup);
fn draw_mesh_instanced(&mut self, mesh: &'b Mesh, material: &'b Material, uniforms: &'b wgpu::BindGroup, instances: Range<u32>);
pub trait DrawModel<'a, 'b>
where
'b: 'a,
{
fn draw_model(
&mut self,
model: &'b Model,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
);
fn draw_model_instanced(
&mut self,
model: &'b Model,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
instances: Range<u32>,
);
fn draw_mesh(
&mut self,
mesh: &'b Mesh,
material: &'b Material,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
);
fn draw_mesh_instanced(
&mut self,
mesh: &'b Mesh,
material: &'b Material,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
instances: Range<u32>,
);
}
impl<'a, 'b> DrawModel<'a, 'b> for wgpu::RenderPass<'a> where 'b: 'a {
fn draw_mesh(&mut self, mesh: &'b Mesh, material: &'b Material, uniforms: &'b wgpu::BindGroup) {
self.draw_mesh_instanced(mesh, material, uniforms, 0..1)
impl<'a, 'b> DrawModel<'a, 'b> for wgpu::RenderPass<'a>
where
'b: 'a,
{
fn draw_mesh(
&mut self,
mesh: &'b Mesh,
material: &'b Material,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
) {
self.draw_mesh_instanced(mesh, material, uniforms, light, 0..1)
}
fn draw_mesh_instanced(&mut self, mesh: &'b Mesh, material: &'b Material, uniforms: &'b wgpu::BindGroup, instances: Range<u32>) {
fn draw_mesh_instanced(
&mut self,
mesh: &'b Mesh,
material: &'b Material,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
instances: Range<u32>,
) {
self.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
self.set_index_buffer(mesh.index_buffer.slice(..));
self.set_bind_group(0, &material.bind_group, &[]);
self.set_bind_group(1, uniforms, &[]);
self.set_bind_group(2, light, &[]);
self.draw_indexed(0..mesh.num_elements, 0, instances);
}
fn draw_model(&mut self, model: &'b Model, uniforms: &'b wgpu::BindGroup) {
self.draw_model_instanced(model, 0..1, uniforms)
fn draw_model(
&mut self,
model: &'b Model,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
) {
self.draw_model_instanced(model, light, uniforms, 0..1)
}
fn draw_model_instanced(&mut self, model: &'b Model, instances: Range<u32>, uniforms: &'b wgpu::BindGroup) {
fn draw_model_instanced(
&mut self,
model: &'b Model,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
instances: Range<u32>,
) {
for mesh in &model.meshes {
let material = &model.materials[mesh.material];
self.draw_mesh_instanced(mesh, material, uniforms, instances.clone());
self.draw_mesh_instanced(mesh, material, uniforms, light, instances.clone());
}
}
}
pub trait DrawLight<'a, 'b>
where
'b: 'a,
{
fn draw_light_mesh(
&mut self,
mesh: &'b Mesh,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
);
fn draw_light_mesh_instanced(
&mut self,
mesh: &'b Mesh,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
instances: Range<u32>,
);
fn draw_light_model(
&mut self,
model: &'b Model,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
);
fn draw_light_model_instanced(
&mut self,
model: &'b Model,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
instances: Range<u32>,
);
}
impl<'a, 'b> DrawLight<'a, 'b> for wgpu::RenderPass<'a>
where
'b: 'a,
{
fn draw_light_mesh(
&mut self,
mesh: &'b Mesh,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
) {
self.draw_light_mesh_instanced(mesh, light, uniforms, 0..1)
}
fn draw_light_mesh_instanced(
&mut self,
mesh: &'b Mesh,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
instances: Range<u32>,
) {
self.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
self.set_index_buffer(mesh.index_buffer.slice(..));
self.set_bind_group(0, uniforms, &[]);
self.set_bind_group(1, light, &[]);
self.draw_indexed(0..mesh.num_elements, 0, instances);
}
fn draw_light_model(
&mut self,
model: &'b Model,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
) {
self.draw_light_model_instanced(model, light, uniforms, 0..1)
}
fn draw_light_model_instanced(
&mut self,
model: &'b Model,
uniforms: &'b wgpu::BindGroup,
light: &'b wgpu::BindGroup,
instances: Range<u32>,
) {
for mesh in &model.meshes {
self.draw_light_mesh_instanced(mesh, uniforms, light, instances.clone());
}
}
}

View file

@ -1,11 +1,42 @@
#version 450
layout(location=0) in vec2 v_tex_coords;
layout(location=1) in vec3 v_normal;
layout(location=2) in vec3 v_position;
layout(location=0) out vec4 f_color;
layout(set = 0, binding = 0) uniform texture2D t_diffuse;
layout(set = 0, binding = 1) uniform sampler s_diffuse;
layout(set=1, binding=0)
uniform Uniforms {
vec3 u_view_position;
mat4 u_view_proj; // unused
};
layout(set=2, binding=0) uniform Light {
vec3 light_position;
vec3 light_color;
};
void main() {
f_color = texture(sampler2D(t_diffuse, s_diffuse), v_tex_coords);
vec4 object_color = texture(sampler2D(t_diffuse, s_diffuse), v_tex_coords);
vec3 normal = normalize(v_normal);
vec3 light_dir = normalize(light_position - v_position);
vec3 view_dir = normalize(u_view_position - v_position);
vec3 half_dir = normalize(view_dir + light_dir);
float specular_strength = pow(max(dot(normal, half_dir), 0.0), 32);
vec3 specular_color = specular_strength * light_color;
float diffuse_strength = max(dot(normal, light_dir), 0.0);
vec3 diffuse_color = light_color * diffuse_strength;
float ambient_strength = 0.1;
vec3 ambient_color = light_color * ambient_strength;
vec3 result = (diffuse_color + ambient_color + specular_color) * object_color.xyz;
f_color = vec4(result, object_color.a);
}

View file

@ -2,11 +2,15 @@
layout(location=0) in vec3 a_position;
layout(location=1) in vec2 a_tex_coords;
layout(location=2) in vec3 a_normal;
layout(location=0) out vec2 v_tex_coords;
layout(location=1) out vec3 v_normal;
layout(location=2) out vec3 v_position;
layout(set=1, binding=0) uniform Uniforms {
mat4 u_view_proj;
vec3 u_view_position;
mat4 u_view_proj; // TODO: pass in view and projection matrix seperately
};
layout(set=1, binding=1) buffer Instances {
@ -15,5 +19,10 @@ layout(set=1, binding=1) buffer Instances {
void main() {
v_tex_coords = a_tex_coords;
gl_Position = u_view_proj * s_models[gl_InstanceIndex] * vec4(a_position, 1.0);
mat4 model_matrix = s_models[gl_InstanceIndex];
mat3 normal_matrix = mat3(transpose(inverse(model_matrix))); // TODO: calculate this on CPU and pass in as an uniform
vec4 model_space = model_matrix * vec4(a_position, 1.0);
v_normal = normal_matrix * a_normal;
v_position = model_space.xyz;
gl_Position = u_view_proj * model_space;
}