tutorial10-lighting
Also switch back to cgmath from nalgebra-glm
This commit is contained in:
parent
56bb19f3c3
commit
e7e251d29d
10 changed files with 754 additions and 460 deletions
291
Cargo.lock
generated
291
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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
114
src/camera.rs
Normal 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
8
src/light.frag
Normal 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
21
src/light.rs
Normal 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
27
src/light.vert
Normal 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;
|
||||
}
|
409
src/main.rs
409
src/main.rs
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
296
src/model.rs
296
src/model.rs
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue