├── .gitignore ├── .gitmodules ├── LICENSE.md ├── materials ├── PGS120_LCPCG60_NNCG85.png ├── PGS_105iters_vs_LCPCG_50iters.png └── PGSvsLCPCGvsNNCG_convergence.png ├── readme.md ├── vkEngine.sln └── vkEngine ├── PropertySheet.props ├── shaders ├── debug_vis.fs ├── debug_vis.vs ├── fs_blobs.fs ├── fs_blobs.vs ├── mesh.fs ├── mesh.vs ├── pathtracer.fs ├── shader_bindings.h ├── shadowmap.fs ├── shadowmap.vs └── test.vs ├── source ├── app.cpp ├── app.h ├── camera.cpp ├── camera.h ├── drawing_primitives.h ├── main.cpp ├── physics_scenes.h ├── sim.h └── vulkan │ ├── definitions.h │ ├── helpers.cpp │ ├── helpers.h │ ├── manager.cpp │ ├── manager.h │ ├── mesh.cpp │ └── mesh.h ├── vkEngine.vcxproj └── vkEngine.vcxproj.filters /.gitignore: -------------------------------------------------------------------------------- 1 | /_interm/* 2 | /_out/* 3 | /.vs/* 4 | /vkEngine.VC.db 5 | /vkEngine.VC.VC.opendb 6 | /vkEngine/shaders/bin/* 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "core"] 2 | path = core 3 | url = https://github.com/avoroshilov/core.git 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License 2 | 3 | By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. 4 | 5 | ## Section 1 – Definitions. 6 | 7 | a. **Adapted Material** means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. 8 | 9 | b. **Adapter's License** means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. 10 | 11 | c. **BY-NC-SA Compatible License** means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. 12 | 13 | d. **Copyright and Similar Rights** means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. 14 | 15 | e. **Effective Technological Measures** means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. 16 | 17 | f. **Exceptions and Limitations** means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. 18 | 19 | g. **License Elements** means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution, NonCommercial, and ShareAlike. 20 | 21 | h. **Licensed Material** means the artistic or literary work, database, or other material to which the Licensor applied this Public License. 22 | 23 | i. **Licensed Rights** means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. 24 | 25 | j. **Licensor** means the individual(s) or entity(ies) granting rights under this Public License. 26 | 27 | k. **NonCommercial** means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. 28 | 29 | l. **Share** means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. 30 | 31 | m. **Sui Generis Database Rights** means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. 32 | 33 | n. **You** means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. 34 | 35 | ## Section 2 – Scope. 36 | 37 | a. **License grant.** 38 | 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
39 |   A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and
40 |   B. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. 41 | 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 42 | 3. Term. The term of this Public License is specified in Section 6(a). 43 | 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. 44 | 5. Downstream recipients.
45 |   A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.
46 |   B. Additional offer from the Licensor – Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply.
47 |   C. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 48 | 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). 49 | 50 | b. **Other rights.** 51 | 52 | 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 53 | 2. Patent and trademark rights are not licensed under this Public License. 54 | 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. 55 | 56 | ## Section 3 – License Conditions. 57 | 58 | Your exercise of the Licensed Rights is expressly made subject to the following conditions. 59 | 60 | a. **Attribution.** 61 | 62 | 1. If You Share the Licensed Material (including in modified form), You must:
63 | A. retain the following if it is supplied by the Licensor with the Licensed Material:
64 |   i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
65 |   ii. a copyright notice;
66 |   iii. a notice that refers to this Public License;
67 |   iv. a notice that refers to the disclaimer of warranties;
68 |   v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
69 | B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
70 | C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.
71 | 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 72 | 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. 73 | 74 | b. **ShareAlike.** 75 | 76 | In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. 77 | 78 | 1. The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC-SA Compatible License. 79 | 2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. 80 | 3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. 81 | 82 | ## Section 4 – Sui Generis Database Rights. 83 | 84 | Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: 85 | 86 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; 87 | 88 | b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and 89 | 90 | c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. 91 | 92 | For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. 93 | 94 | ## Section 5 – Disclaimer of Warranties and Limitation of Liability. 95 | 96 | **a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.** 97 | 98 | **b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.** 99 | 100 | c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. 101 | 102 | ## Section 6 – Term and Termination. 103 | 104 | a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. 105 | 106 | b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:
107 | 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or
108 | 2. upon express reinstatement by the Licensor.
109 | For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. 110 | 111 | c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. 112 | 113 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. 114 | 115 | ## Section 7 – Other Terms and Conditions. 116 | 117 | a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. 118 | 119 | b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. 120 | 121 | ## Section 8 – Interpretation. 122 | 123 | a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. 124 | 125 | b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. 126 | 127 | c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. 128 | 129 | d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. 130 | -------------------------------------------------------------------------------- /materials/PGS120_LCPCG60_NNCG85.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avoroshilov/physics_playground/06208f51d1b1a6a62a0c6cd5f54270b6ec0e42fe/materials/PGS120_LCPCG60_NNCG85.png -------------------------------------------------------------------------------- /materials/PGS_105iters_vs_LCPCG_50iters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avoroshilov/physics_playground/06208f51d1b1a6a62a0c6cd5f54270b6ec0e42fe/materials/PGS_105iters_vs_LCPCG_50iters.png -------------------------------------------------------------------------------- /materials/PGSvsLCPCGvsNNCG_convergence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avoroshilov/physics_playground/06208f51d1b1a6a62a0c6cd5f54270b6ec0e42fe/materials/PGSvsLCPCGvsNNCG_convergence.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Enhanced version of coupled FEM and constrained rigid body simulation 2 | 3 | ## Description 4 | This little playground aimed to test our Conjugate Gradients based MLCP solver versus some other types of solvers (at the moment, conventional Projected Gauss Seidel, and its modification that changes constraint order), as well as some hacks that improve joints stiffness - for example local mass scaling. 5 | 6 | The simulation framework capabilities: 7 | 1. Old-fashioned linearized dynamics, meaning: 8 | * calculates constraint properties, such as effective mass, correction parameters, etc - twice per timestep, first time frictionless solve to estimate normal force, second time - full solve with friction limits; both solves use same MLCP solver; 9 | * uses canonical matrix form with decomposition (`[J]*[M]^-1*[J]^T + [D]`), and not applied form like Sequential/Split Impulses - to facilitate custom solvers implementation. 10 | 1. MLCP solvers: **PGS**, **shuffled PGS** (shuffle types: random, forward/backward, even-odd local, even-odd global, could also be more than just 2-tuple shuffle), **CG-based** and **NNCG**. 11 | 1. Local mass scaling (see below). 12 | 1. Gyroscopic forces effect calculation - better handling of rotating oblong objects, enabling Dzhanibekov effect. 13 | 1. Coupled rigid body and corotational FEM-based deformables simulation (see below). 14 | 1. General convex collision detection, convex hull represented via support mapping, Minkowski Portal Refinement is used to calculate contact normal. 15 | 1. Several basic joint types (ball joint, slider, fixed rotation, limits/motors, etc.). 16 | 1. Composite bodies with mass properties calculation. 17 | 1. Baumgarte correction (no pseudo-velocities or nonlinear correction) and regularization (a.k.a. constraint force mixing) 18 | 19 | The framework is more of a research framework than physics engine ready for release, it requires quite some work to reach the product-eligible state: island detection, sleeping, to name a few. Additionally, data layout is not the most cache-friendly. 20 | 21 | ## Local mass scaling 22 | Technique, similar to shock propagation - allows to set mass scaling per joint (per constraint row, to be precise); by making joints in an open loop system (such as ragdoll, or a tree) scale masses higher for bodies closer to root - one could improve system stability and stiffness. Similarly, there is n option to scale masses for contact joints, based on their relative positions in the gravity field. It is still a hack however, so artifacts could arise; one example is stack being too stable and resisting tumbling, but the effect is barely noticeable if mass scaling is low (around 2.0 total). 23 | 24 | ## Preconditioned Conjugate Gradients MLCP solver 25 | Port from an earlier research collaboration (available [on github](https://github.com/avoroshilov/physics_fem_rbd) as well). Since it was developed to solve MLCPs - supports contacts with friction pyramid, limits, constraint forces boundaries, etc. Preconditioned using double-Jacobi preconditioner to maintain desired matrix properties. Solver that has better convergence characteristics than conventional Projected Gauss-Seidel. 26 | 27 | The solver is based on the `MPRGP` (Modified Proportioning with Reduced Gradient Projections) by **Z. Dostál**; we modified the original MPRGP to support box limits (low/high, instead of just lower limit), and incorporated preconditioner that is fairly cheap - double (left+right) Jacobi preconditioner. Solver also benefits from the `J*M^-1*J^T` decomposition that significantly speeds up matrix-vector multiplications. 28 | 29 | **Pros**: 30 | * Significantly better convergence characteristics 31 | * Naturally parallel (as opposed to sequential PGS), not requiring colorizing or splitting to utilize highly-parallel HW (e.g. GPUs) 32 | 33 | **Cons**: 34 | * Requires spectral radius calculation (estimated using several Power Iterations, each iteration is also inherently parallel) 35 | * Provides noisy solution on low iteration count 36 | * One iteration is more expensive than one iteration of PGS 37 | 38 | These properties make it worse candidate than PGS for game-like scenarios when accuracy is not important, but much better candidate when joint stiffness is required, or just for very complex systems. 39 | 40 | Details of the maths behind the solver design available in the [project paper](https://github.com/avoroshilov/physics_fem_rbd/raw/master/materials/fem_paper.pdf). 41 | 42 | Example convergence of conventional PGS vs our CG-based MLCP solver vs the NNCG (NNCG described in "A nonsmooth nonlinear conjugate gradient method for interactive contact force problems" by M. Silcowitz-Hansen et al.) - stiff FEM rod, made of `(48x2x1)*5=480` FEM tetrahedra, making total `2880` constraint rows. The amount of iterations is not equal, but set so that the total frametime is equal (20ms on ultrabook Core i7-6500U). Red is PGS 180 iterations, and Green is LCPCG 90 iterations (plus 15 iterations overhead for Power Iteration) and Blue is NNCG 127 iterations. 43 | 44 | PGS 120i vs LCPCG 60i vs NNCG 85i 45 | 46 | This scene clearly shows advantage of our CG-based solver over PGS in relatively complex systems. 47 | 48 | Our solver shows better results than NNCG as well; NNCG comes close, but our solver shows better convergence/stiffness, and will show much better results when optimized for parallel hardware (e.g., GPU), as NNCG depends on the PGS iteration, which would require either colorization or splitting, both ways have their drawbacks. On the other hand, NNCG is much simpler to implement, and seems to be more suitable for lower iteration count scenarios. 49 | 50 | ## FEM-based deformables w/ coupling 51 | As the PCG-based MLCP solver described above, port of the [earlier research collaboration](https://github.com/avoroshilov/physics_fem_rbd), which formulates corotational FEM joints, that connects 4 linear nodes (mass points), thus allowing the deformable bodies to be part of a single system with rigid bodies, and providing natural two-way coupling. Additional ball joint that connects rigid body and FE face (3 linear nodes) is implemented. 52 | 53 | Details of the approach are also described in the [project paper](https://github.com/avoroshilov/physics_fem_rbd/raw/master/materials/fem_paper.pdf). 54 | 55 | ## Build/run 56 | The sample uses Vulkan graphics API, and one needs to perform following steps in order to build and run the sample: 57 | 1. Download and install [LunarG Vulkan SDK](https://vulkan.lunarg.com/sdk/home) (for the reference, the framework uses 1.0.61.1, but any recent should do); 58 | 2. Update `vkEngine\PropertySheet.props` to contain correct SDK installation path, like this: 59 | ``` 60 | d:\Program Files\VulkanSDK\1.0.61.1 61 | ``` 62 | 3. Run `vkEngine.sln` and build as usual. 63 | 64 | ## Controls: 65 | * `WASD`+`PgDn`/`PgUp`+mouse - control camera, use `[shift]` to move faster and `[ctrl]` to move slower 66 | * `q` to pause/unpause 67 | * `p` to perform a single step 68 | * `e` to throw a box 69 | * `RMB` (right mouse button) to switch mouse modes (default is camera control mode, alternative is picking mode - use `LMB` to pick bodies when in alternative mouse mode) 70 | 71 | ## License 72 | [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode) 73 | -------------------------------------------------------------------------------- /vkEngine.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vkEngine", "vkEngine\vkEngine.vcxproj", "{35C0E3E4-4770-4581-98DC-8A7D4178BDEC}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Core", "core\Core.vcxproj", "{4504335C-7145-485F-AE40-6824DA670A3E}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {35C0E3E4-4770-4581-98DC-8A7D4178BDEC}.Debug|x64.ActiveCfg = Debug|x64 19 | {35C0E3E4-4770-4581-98DC-8A7D4178BDEC}.Debug|x64.Build.0 = Debug|x64 20 | {35C0E3E4-4770-4581-98DC-8A7D4178BDEC}.Debug|x86.ActiveCfg = Debug|Win32 21 | {35C0E3E4-4770-4581-98DC-8A7D4178BDEC}.Debug|x86.Build.0 = Debug|Win32 22 | {35C0E3E4-4770-4581-98DC-8A7D4178BDEC}.Release|x64.ActiveCfg = Release|x64 23 | {35C0E3E4-4770-4581-98DC-8A7D4178BDEC}.Release|x64.Build.0 = Release|x64 24 | {35C0E3E4-4770-4581-98DC-8A7D4178BDEC}.Release|x86.ActiveCfg = Release|Win32 25 | {35C0E3E4-4770-4581-98DC-8A7D4178BDEC}.Release|x86.Build.0 = Release|Win32 26 | {4504335C-7145-485F-AE40-6824DA670A3E}.Debug|x64.ActiveCfg = Debug|x64 27 | {4504335C-7145-485F-AE40-6824DA670A3E}.Debug|x64.Build.0 = Debug|x64 28 | {4504335C-7145-485F-AE40-6824DA670A3E}.Debug|x86.ActiveCfg = Debug|Win32 29 | {4504335C-7145-485F-AE40-6824DA670A3E}.Debug|x86.Build.0 = Debug|Win32 30 | {4504335C-7145-485F-AE40-6824DA670A3E}.Release|x64.ActiveCfg = Release|x64 31 | {4504335C-7145-485F-AE40-6824DA670A3E}.Release|x64.Build.0 = Release|x64 32 | {4504335C-7145-485F-AE40-6824DA670A3E}.Release|x86.ActiveCfg = Release|Win32 33 | {4504335C-7145-485F-AE40-6824DA670A3E}.Release|x86.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /vkEngine/PropertySheet.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | c:\Program Files\VulkanSDK\1.0.61.1 6 | 7 | 8 | 9 | 10 | $(VulkanSDKRoot) 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /vkEngine/shaders/debug_vis.fs: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_bindings.h" 6 | 7 | layout(location = 0) in vec4 in_color; 8 | 9 | layout(location = 0) out vec4 outColor; 10 | 11 | layout(set = 0, binding = SH_BIND_GLOBAL_CONSTANTS) uniform UniformBufferObject 12 | { 13 | float time; 14 | } ubo; 15 | 16 | layout(set = 0, binding = SH_BIND_TRANSFORM) uniform TransformUBO 17 | { 18 | mat4 view; 19 | mat4 proj; 20 | } transformUBO; 21 | 22 | layout(set = 0, binding = 2) uniform sampler2D texSampler; 23 | 24 | void main() 25 | { 26 | outColor = in_color; 27 | } -------------------------------------------------------------------------------- /vkEngine/shaders/debug_vis.vs: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_bindings.h" 6 | 7 | layout(location = 0) in vec3 in_position; 8 | layout(location = 1) in vec4 in_color; 9 | 10 | layout(set = 0, binding = SH_BIND_GLOBAL_CONSTANTS) uniform UniformBufferObject 11 | { 12 | float time; 13 | } ubo; 14 | 15 | layout(set = 0, binding = SH_BIND_TRANSFORM) uniform TransformUBO 16 | { 17 | mat4 view; 18 | mat4 proj; 19 | } transformUBO; 20 | 21 | out gl_PerVertex 22 | { 23 | vec4 gl_Position; 24 | }; 25 | 26 | layout(location = 0) out vec4 out_color; 27 | 28 | void main() 29 | { 30 | vec4 modelVertex = vec4(in_position, 1.0); 31 | gl_Position = transformUBO.proj * transformUBO.view * modelVertex; 32 | out_color = in_color; 33 | //out_time = ubo.time; 34 | } -------------------------------------------------------------------------------- /vkEngine/shaders/fs_blobs.fs: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_bindings.h" 6 | 7 | layout(location = 0) in vec4 in_color; 8 | layout(location = 1) in vec2 in_texCoords; 9 | layout(location = 2) in float in_time; 10 | layout(location = 3) in vec2 blobCenters[5]; 11 | 12 | layout(location = 0) out vec4 outColor; 13 | 14 | layout(set = 0, binding = SH_BIND_GLOBAL_CONSTANTS) uniform UniformBufferObject 15 | { 16 | float time; 17 | } ubo; 18 | 19 | layout(set = 0, binding = SH_BIND_TRANSFORM) uniform TransformUBO 20 | { 21 | mat4 view; 22 | mat4 proj; 23 | } transformUBO; 24 | 25 | void main() 26 | { 27 | const float width = 800.0; 28 | const float height = 600.0; 29 | const float aspect = width/height; 30 | 31 | const float radii[5] = { 0.4, 0.3, 0.2, 0.35, 0.25 }; 32 | 33 | float scalar = 0.0; 34 | for (int i = 0; i < 5; ++i) 35 | { 36 | vec2 blobCenter = blobCenters[i]; 37 | scalar += smoothstep(0.0, 1.0, clamp(1.0 - length(in_texCoords*vec2(aspect,1.0) - blobCenter) / radii[i], 0.0, 1.0)); 38 | } 39 | 40 | #define PI_DIV2 1.57079632679 41 | 42 | const float base = 0.2, range = 0.2; 43 | if (scalar > base && scalar < (base + range)) 44 | scalar = sin(PI_DIV2 / (range/2.0) * (scalar - base)); 45 | else if (scalar < base) 46 | scalar = 0.0; 47 | else 48 | scalar = sin(scalar - (base + range)); 49 | 50 | outColor = vec4(scalar, scalar, scalar, 1.0); 51 | } -------------------------------------------------------------------------------- /vkEngine/shaders/fs_blobs.vs: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_bindings.h" 6 | 7 | layout(location = 0) in vec3 in_position; 8 | layout(location = 1) in vec3 in_normal; 9 | layout(location = 2) in vec4 in_color; 10 | layout(location = 3) in vec2 in_texCoords; 11 | 12 | layout(set = 0, binding = SH_BIND_GLOBAL_CONSTANTS) uniform UniformBufferObject 13 | { 14 | float time; 15 | } ubo; 16 | 17 | layout(set = 0, binding = SH_BIND_TRANSFORM) uniform TransformUBO 18 | { 19 | mat4 view; 20 | mat4 proj; 21 | } transformUBO; 22 | 23 | layout(push_constant) uniform MeshPushConst 24 | { 25 | mat4 model; 26 | } meshPushConst; 27 | 28 | out gl_PerVertex 29 | { 30 | vec4 gl_Position; 31 | }; 32 | 33 | layout(location = 0) out vec4 out_color; 34 | layout(location = 1) out vec2 out_texCoords; 35 | layout(location = 2) out float out_time; 36 | layout(location = 3) out vec2 blobCenters[5]; 37 | 38 | void main() 39 | { 40 | gl_Position = vec4(in_position, 1.0); 41 | out_texCoords = in_texCoords; 42 | out_color = in_color; 43 | out_time = ubo.time; 44 | 45 | const float mulX[5] = { 0.5, 0.7, 0.8, 0.3, 0.6 }; 46 | const float mulY[5] = { 0.8, 0.6, 0.5, 0.7, 0.4 }; 47 | const float shiftX1[5] = { 0.1, 1.5, 3.5, 0.6, 1.9 }; 48 | const float shiftY1[5] = { 0.6, 1.6, 2.8, 0.1, 1.3 }; 49 | const float shiftX2[5] = { 0.9, 1.3, 2.9, 0.4, 2.3 }; 50 | const float shiftY2[5] = { 0.3, 1.9, 3.2, 0.9, 2.4 }; 51 | const float timeMulX1[5] = { 1.0, 1.2, 0.5, 0.6, 0.9 }; 52 | const float timeMulY1[5] = { 1.0, 1.3, 0.8, 1.1, 1.3 }; 53 | 54 | const float blobTime = ubo.time * 0.001; 55 | for (int i = 0; i < 5; ++i) 56 | { 57 | blobCenters[i] = vec2( 58 | mulX[i] * cos(timeMulX1[i] * blobTime + shiftX1[i]) * sin(blobTime + shiftX2[i]) + 0.5, 59 | mulY[i] * sin(timeMulY1[i] * blobTime + shiftY1[i]) * sin(blobTime + shiftY2[i]) + 0.25 60 | ); 61 | } 62 | } -------------------------------------------------------------------------------- /vkEngine/shaders/mesh.fs: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_bindings.h" 6 | 7 | layout(location = 0) in vec4 in_color; 8 | layout(location = 1) in vec3 in_normal_cam; 9 | layout(location = 2) in vec2 in_texCoords; 10 | layout(location = 3) in float in_time; 11 | layout(location = 4) in vec3 in_L_cam; 12 | layout(location = 5) in vec3 in_worldPos; 13 | 14 | layout(location = 0) out vec4 outColor; 15 | 16 | layout(set = 0, binding = SH_BIND_GLOBAL_CONSTANTS) uniform UniformBufferObject 17 | { 18 | float time; 19 | } ubo; 20 | 21 | layout(set = 0, binding = SH_BIND_TRANSFORM) uniform TransformUBO 22 | { 23 | mat4 view; 24 | mat4 proj; 25 | } transformUBO; 26 | 27 | layout(set = 0, binding = SH_BIND_FWDSH_ALBEDO_TEX) uniform sampler2D texSampler; 28 | layout(set = 0, binding = SH_BIND_FWDSH_SHADOWMAP_TEX) uniform sampler2DShadow shadowmapSampler; 29 | layout(set = 0, binding = SH_BIND_FWDSH_LIGHTPROJ_TEX) uniform sampler2D lightSampler; 30 | 31 | layout(set = 0, binding = SH_BIND_FWDSH_LIGHTMATRIX) uniform LightMatrixUBO 32 | { 33 | mat4 view; 34 | mat4 proj; 35 | } lightMatrixUBO; 36 | 37 | void main() 38 | { 39 | mat4 shadowMatrix = lightMatrixUBO.proj * lightMatrixUBO.view; 40 | vec4 shadowmapPos = shadowMatrix * vec4(in_worldPos, 1.0); 41 | shadowmapPos /= shadowmapPos.w; 42 | 43 | vec4 lightProjColor = vec4(0.0, 0.0, 0.0, 0.0); 44 | vec4 shadowMaskColor = vec4(0.0, 0.0, 0.0, 0.0); 45 | 46 | if (shadowmapPos.x > -1.0 && shadowmapPos.x < 1.0 && 47 | shadowmapPos.y > -1.0 && shadowmapPos.y < 1.0) 48 | { 49 | ivec2 shadowMapSize = textureSize(shadowmapSampler, 0); 50 | vec2 stepSize = vec2(1.0 / shadowMapSize.x, 1.0 / shadowMapSize.y); 51 | 52 | float depthBias = 0.0; 53 | 54 | #define MANUAL_DEPTH_BIAS 0 55 | #if (MANUAL_DEPTH_BIAS == 1) 56 | depthBias = 0.00017; 57 | #endif 58 | 59 | shadowmapPos.x = 0.5 * shadowmapPos.x + 0.5; 60 | shadowmapPos.y = 0.5 * shadowmapPos.y + 0.5; 61 | shadowmapPos.z -= depthBias; 62 | // Central 63 | float shadowMapCmp = texture(shadowmapSampler, shadowmapPos.xyz); 64 | shadowMaskColor += vec4(shadowMapCmp, shadowMapCmp, shadowMapCmp, 1.0); 65 | 66 | #define MORE_SHADOWMAP_FILTERING 1 67 | #if (MORE_SHADOWMAP_FILTERING == 1) 68 | shadowMapCmp = texture(shadowmapSampler, vec3(-stepSize.x, 0.0, 0.0) + shadowmapPos.xyz); 69 | shadowMaskColor += vec4(shadowMapCmp, shadowMapCmp, shadowMapCmp, 1.0); 70 | shadowMapCmp = texture(shadowmapSampler, vec3( stepSize.x, 0.0, 0.0) + shadowmapPos.xyz); 71 | shadowMaskColor += vec4(shadowMapCmp, shadowMapCmp, shadowMapCmp, 1.0); 72 | shadowMapCmp = texture(shadowmapSampler, vec3(0.0, -stepSize.y, 0.0) + shadowmapPos.xyz); 73 | shadowMaskColor += vec4(shadowMapCmp, shadowMapCmp, shadowMapCmp, 1.0); 74 | shadowMapCmp = texture(shadowmapSampler, vec3(0.0, stepSize.y, 0.0) + shadowmapPos.xyz); 75 | shadowMaskColor += vec4(shadowMapCmp, shadowMapCmp, shadowMapCmp, 1.0); 76 | 77 | shadowMaskColor /= 5.0; 78 | #endif 79 | 80 | lightProjColor = texture(lightSampler, shadowmapPos.xy); 81 | } 82 | else 83 | { 84 | shadowMaskColor = vec4(1.0, 1.0, 1.0, 1.0); 85 | } 86 | 87 | shadowMaskColor = lightProjColor*shadowMaskColor; 88 | 89 | vec4 colorTex = texture(texSampler, in_texCoords); 90 | #if 0 91 | //outColor = in_color * vec4(0.5 * in_normal + 0.5, 1.0); 92 | outColor = in_color * colorTex; 93 | #else 94 | // Working in camera (rather than in world) space 95 | 96 | // Renormalize vectors after the interpolator 97 | vec3 normal_cam = normalize(in_normal_cam); 98 | vec3 L_cam = normalize(in_L_cam); 99 | 100 | float cosLightDir = dot(L_cam, normal_cam); 101 | 102 | #define PI 3.14159265 103 | 104 | // Lambertian diffuse 105 | vec4 lightColor = vec4(0.9, 1.0, 0.85, 1.0); 106 | float lambertN = 1.0 / PI; 107 | // Two sided diffuse (abs instead of max(..., 0.0)) 108 | vec4 diffuse = (lambertN * abs(cosLightDir)) * shadowMaskColor*lightColor; 109 | 110 | // Blinn-phong reflectance 111 | float shininess = 20.0; 112 | vec4 lightSpecularColor = vec4(0.8, 1.0, 0.6, 1.0); 113 | 114 | vec3 viewer_cam = vec3(0.0, 0.0, 1.0); 115 | 116 | vec4 specular; 117 | if (cosLightDir > 0.0) 118 | { 119 | vec3 halfVec_cam = L_cam + viewer_cam; 120 | halfVec_cam = normalize(halfVec_cam); 121 | float blinnPhongN = (shininess + 2) / (4 * PI * (2 - exp2(-shininess/2.0))); 122 | specular = blinnPhongN * vec4(pow( max(dot(halfVec_cam, normal_cam), 0.0), shininess )) * shadowMaskColor*lightSpecularColor; 123 | } 124 | else 125 | { 126 | specular = vec4(0.0, 0.0, 0.0, 0.0); 127 | } 128 | 129 | vec4 ambient = vec4(0.5, 0.5, 0.5, 0.5); 130 | outColor = in_color * ((diffuse + ambient) * colorTex + specular); 131 | #endif 132 | } -------------------------------------------------------------------------------- /vkEngine/shaders/mesh.vs: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_bindings.h" 6 | 7 | layout(location = 0) in vec3 in_position; 8 | layout(location = 1) in vec3 in_normal; 9 | layout(location = 2) in vec4 in_color; 10 | layout(location = 3) in vec2 in_texCoords; 11 | 12 | layout(set = 0, binding = SH_BIND_GLOBAL_CONSTANTS) uniform UniformBufferObject 13 | { 14 | float time; 15 | } ubo; 16 | 17 | layout(set = 0, binding = SH_BIND_TRANSFORM) uniform TransformUBO 18 | { 19 | mat4 view; 20 | mat4 proj; 21 | } transformUBO; 22 | 23 | layout(set = 0, binding = SH_BIND_FWDSH_LIGHTMATRIX) uniform LightMatrixUBO 24 | { 25 | mat4 view; 26 | mat4 proj; 27 | } lightMatrixUBO; 28 | 29 | layout(push_constant) uniform MeshPushConst 30 | { 31 | mat4 model; 32 | } meshPushConst; 33 | 34 | out gl_PerVertex 35 | { 36 | vec4 gl_Position; 37 | }; 38 | 39 | layout(location = 0) out vec4 out_color; 40 | layout(location = 1) out vec3 out_normal_cam; 41 | layout(location = 2) out vec2 out_texCoords; 42 | layout(location = 3) out float out_time; 43 | layout(location = 4) out vec3 out_L_cam; 44 | layout(location = 5) out vec3 out_worldPos; 45 | 46 | void main() 47 | { 48 | vec4 vertexWorldPos = meshPushConst.model * vec4(in_position, 1.0); 49 | out_worldPos = vertexWorldPos.xyz / vertexWorldPos.w; 50 | gl_Position = transformUBO.proj * transformUBO.view * vertexWorldPos; 51 | out_texCoords = in_texCoords; 52 | out_color = in_color; 53 | // Suppose view is orthonormal 54 | out_normal_cam = mat3(transformUBO.view) * mat3(meshPushConst.model) * in_normal; 55 | out_time = ubo.time; 56 | 57 | // 58 | mat4 lightToWorld = inverse(lightMatrixUBO.view); 59 | vec3 light_pos = (lightToWorld[3]).xyz;//vec3(3.0, 3.0, 3.0); 60 | out_L_cam = normalize((transformUBO.view * (vec4(light_pos, 1.0) - vertexWorldPos)).xyz); 61 | } -------------------------------------------------------------------------------- /vkEngine/shaders/pathtracer.fs: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_bindings.h" 6 | 7 | layout(location = 0) in vec4 in_color; 8 | layout(location = 1) in vec2 in_texCoords; 9 | layout(location = 2) in float in_time; 10 | 11 | layout(location = 0) out vec4 outColor; 12 | 13 | layout(set = 0, binding = SH_BIND_GLOBAL_CONSTANTS) uniform UniformBufferObject 14 | { 15 | float time; 16 | } ubo; 17 | 18 | layout(set = 0, binding = SH_BIND_TRANSFORM) uniform TransformUBO 19 | { 20 | mat4 view; 21 | mat4 proj; 22 | } transformUBO; 23 | 24 | layout(set = 0, binding = SH_BIND_PATHTRACER_NOISE_TEX) uniform sampler2D texSampler; 25 | 26 | float fakeRand(vec2 co, float time) 27 | { 28 | return fract(sin(dot(time * co.xy, vec2(12.9898, 78.233))) * 43758.5453); 29 | } 30 | 31 | #define PI 3.14159265358979323846 32 | #define _2PI 6.28318530717958647692 33 | 34 | vec3 randInUnitSphere(vec2 co, float time) 35 | { 36 | float angTheta = _2PI*fakeRand(co, time); 37 | float angPhi = _2PI*fakeRand(12.3456*co, time); 38 | float rad = fakeRand(45.6789*co, time); 39 | 40 | return vec3(rad*sin(angTheta)*cos(angPhi), rad*sin(angTheta)*sin(angPhi), rad*cos(angTheta)); 41 | } 42 | vec2 randOnDisk(vec2 co, float time) 43 | { 44 | float ang = _2PI*fakeRand(co, time); 45 | float rad = fakeRand(34.5678*co, time); 46 | 47 | return vec2(rad*cos(ang), rad*sin(ang)); 48 | } 49 | 50 | /* Ray */ 51 | struct Ray 52 | { 53 | vec3 O; 54 | vec3 D; 55 | }; 56 | 57 | Ray getRay(vec3 O, vec3 D) 58 | { 59 | Ray r; 60 | r.O = O; 61 | r.D = D; 62 | return r; 63 | } 64 | 65 | vec3 getRayPoint(Ray ray, float t) 66 | { 67 | return ray.O + t * ray.D; 68 | } 69 | /* End of Ray */ 70 | 71 | /* Hitting Routines */ 72 | struct HitData 73 | { 74 | vec3 p; 75 | vec3 n; 76 | float t; 77 | int materialIndex; 78 | }; 79 | 80 | bool hitSphere(vec3 center, float radius, int materialIndex, Ray r, float t_min, float t_max, out HitData hitData) 81 | { 82 | /* 83 | 84 | Sphere eqn: dot( (p-c), (p-c) ) = rad*rad 85 | where p - point, c - sphere center, rad - sphere radius 86 | subs p for r(t)=r.O+r.D*t - ray: 87 | dot( (r(t)-c), (r(t)-c) ) = rad*rad 88 | dot( (r.O+r.D*t-c), (r.O+r.D*t-c) ) = rad*rad 89 | => 90 | + - + + - - - + = rad*rad 91 | + t* - + t* + t* - t* - - t* + = rad*rad 92 | 93 | t*t* + t*( + - - ) + ( - - + ) = rad*rad 94 | t*t* + t*(2* - 2*) + ( - 2* + ) = rad*rad 95 | 96 | also, 97 | 2* - 2* = 2* 98 | = - - + = - 2* + 99 | 100 | and, 101 | rayO2sphC = r.O-c 102 | 103 | hence, 104 | t*t* + t*(2*) + () = rad*rad 105 | 106 | */ 107 | 108 | vec3 rayO2sphC = r.O - center; 109 | float a = dot(r.D, r.D); 110 | float b = 2.0 * dot(r.D, rayO2sphC); 111 | float c = dot(rayO2sphC, rayO2sphC) - radius*radius; 112 | float discriminant = b*b - 4*a*c; 113 | 114 | if (discriminant < 0) 115 | { 116 | return false; 117 | } 118 | 119 | // x0,x1 = [-b +- sqrt(D)] / [2*a] 120 | float sqrtD_div2a = sqrt(discriminant) / (2*a); 121 | float negB_div2a = -b / (2*a); 122 | 123 | float hitT1 = negB_div2a - sqrtD_div2a; 124 | if (hitT1 > t_min && hitT1 < t_max) 125 | { 126 | hitData.t = hitT1; 127 | hitData.p = getRayPoint(r, hitT1); 128 | hitData.n = (hitData.p - center) / radius; 129 | hitData.materialIndex = materialIndex; 130 | return true; 131 | } 132 | 133 | float hitT2 = negB_div2a + sqrtD_div2a; 134 | if (hitT2 > t_min && hitT2 < t_max) 135 | { 136 | hitData.t = hitT2; 137 | hitData.p = getRayPoint(r, hitT2); 138 | hitData.n = (hitData.p - center) / radius; 139 | hitData.materialIndex = materialIndex; 140 | return true; 141 | } 142 | 143 | return false; 144 | } 145 | 146 | bool refract(vec3 v, vec3 n, float ni_over_nt, out vec3 outV) 147 | { 148 | // Snell's law of refraction 149 | // n1 * sin(theta1) = n2 * sin(theta2) 150 | // where n - refractive index, theta - is the angle measured from the normal of the boundary 151 | 152 | vec3 v_nrm = normalize(v); 153 | float vdotn = dot(v_nrm, n); 154 | float discriminant = 1.0 - ni_over_nt*ni_over_nt * (1.0 - vdotn*vdotn); 155 | if (discriminant <= 0) 156 | return false; 157 | 158 | outV = ni_over_nt * (v_nrm - vdotn*n) - n*sqrt(discriminant); 159 | return true; 160 | } 161 | 162 | float schlick(float cosine, float refIdx) 163 | { 164 | float r0 = (1.0 - refIdx) / (1.0 + refIdx); 165 | r0 = r0*r0; 166 | float one_minus_cos = 1.0 - cosine; 167 | // Cannot use pow() here as per spec, it's undefined for x < 0 168 | float one_minus_cos_sq = one_minus_cos*one_minus_cos; 169 | return r0 + (1.0 - r0) * one_minus_cos*one_minus_cos_sq*one_minus_cos_sq; 170 | } 171 | 172 | #define MaterialTypeLambert 1 173 | #define MaterialTypeMetal 2 174 | #define MaterialTypeGlass 3 175 | struct Material 176 | { 177 | int type; 178 | vec3 albedo; 179 | float roughness; 180 | }; 181 | 182 | const int numMaterials = 5; 183 | #define MaterialIdxBlueLambert 0 184 | #define MaterialIdxGreyMetal 1 185 | #define MaterialIdxOrangeMetal2 2 186 | #define MaterialIdxGlass 3 187 | #define MaterialIdxOrangeLambert 4 188 | 189 | bool materialScatterRay(int materialIndex, Ray inR, HitData hitData, vec2 uv, float times, out vec3 attenuation, out Ray outR) 190 | { 191 | Material materials[numMaterials]; 192 | 193 | materials[MaterialIdxBlueLambert].type = MaterialTypeLambert; 194 | materials[MaterialIdxBlueLambert].albedo = vec3(0.1, 0.2, 0.4); 195 | materials[MaterialIdxBlueLambert].roughness = 0.0; 196 | 197 | materials[MaterialIdxGreyMetal].type = MaterialTypeMetal; 198 | materials[MaterialIdxGreyMetal].albedo = vec3(0.45, 0.45, 0.45); 199 | materials[MaterialIdxGreyMetal].roughness = 0.55; 200 | 201 | materials[MaterialIdxOrangeLambert].type = MaterialTypeLambert; 202 | materials[MaterialIdxOrangeLambert].albedo = vec3(0.5, 0.45, 0.05); 203 | materials[MaterialIdxOrangeLambert].roughness = 0.0; 204 | 205 | materials[MaterialIdxOrangeMetal2].type = MaterialTypeMetal; 206 | materials[MaterialIdxOrangeMetal2].albedo = vec3(0.75, 0.45, 0.05); 207 | materials[MaterialIdxOrangeMetal2].roughness = 0.1; 208 | 209 | materials[MaterialIdxGlass].type = MaterialTypeGlass; 210 | materials[MaterialIdxGlass].albedo = vec3(0.95, 0.95, 0.95); 211 | materials[MaterialIdxGlass].roughness = 0.0; 212 | 213 | if (materialIndex >= numMaterials || materialIndex < 0) 214 | return false; 215 | 216 | int materialType = materials[materialIndex].type; 217 | if (materialType == MaterialTypeLambert) 218 | { 219 | vec3 target = hitData.p + hitData.n + randInUnitSphere(uv, times); 220 | outR.O = hitData.p; 221 | outR.D = target - hitData.p; 222 | attenuation = materials[materialIndex].albedo; 223 | return true; 224 | } 225 | else if (materialType == MaterialTypeMetal) 226 | { 227 | vec3 reflected = reflect(normalize(inR.D), hitData.n); 228 | outR.O = hitData.p; 229 | outR.D = reflected + materials[materialIndex].roughness*randInUnitSphere(uv, times); 230 | attenuation = materials[materialIndex].albedo; 231 | return (dot(outR.D, hitData.n) > 0); 232 | } 233 | else if (materialType == MaterialTypeGlass) 234 | { 235 | vec3 rayD_nrm = normalize(inR.D); 236 | vec3 reflected = reflect(rayD_nrm, hitData.n); 237 | float ni_over_nt; 238 | attenuation = materials[materialIndex].albedo; 239 | 240 | const float refIdx = 1.5; 241 | 242 | vec3 outNormal; 243 | float cosine; 244 | if (dot(rayD_nrm, hitData.n) > 0) 245 | { 246 | outNormal = -hitData.n; 247 | ni_over_nt = refIdx; 248 | cosine = refIdx*dot(rayD_nrm, hitData.n); 249 | } 250 | else 251 | { 252 | outNormal = hitData.n; 253 | ni_over_nt = 1.0 / refIdx; 254 | cosine = -dot(rayD_nrm, hitData.n); 255 | } 256 | 257 | vec3 refracted; 258 | float reflProb; 259 | if (refract(rayD_nrm, outNormal, ni_over_nt, refracted)) 260 | { 261 | reflProb = schlick(cosine, refIdx); 262 | } 263 | else 264 | { 265 | reflProb = 1.0; 266 | } 267 | 268 | if (fakeRand(uv, 23.45*times) > reflProb) 269 | { 270 | outR.O = hitData.p; 271 | outR.D = refracted + materials[materialIndex].roughness*randInUnitSphere(uv, times); 272 | return true; 273 | } 274 | else 275 | { 276 | outR.O = hitData.p; 277 | outR.D = reflected; 278 | return true; 279 | } 280 | } 281 | return false; 282 | } 283 | 284 | #define HitObjectSphere 1 285 | struct HitObject 286 | { 287 | int type; 288 | int materialIndex; 289 | vec4 param0; 290 | vec4 param1; 291 | }; 292 | 293 | bool hitWorld(Ray r, out HitData hitData) 294 | { 295 | // We need non-zero t_min, as sometimes due to FP errors, reflecting rays will hit the same 296 | // surface they were reflected from, causing artifacts and inf-loops 297 | const float t_min = 0.00001; 298 | const float t_max = 10000.0; 299 | 300 | #define MANY_OBJECTS 0 301 | 302 | #if (MANY_OBJECTS == 1) 303 | const int numHitObjects = 106; 304 | #else 305 | const int numHitObjects = 6; 306 | #endif 307 | HitObject hitObjects[numHitObjects]; 308 | 309 | hitObjects[0].type = HitObjectSphere; 310 | hitObjects[0].materialIndex = MaterialIdxBlueLambert; 311 | hitObjects[0].param0 = vec4(vec3(0.0, 0.0, -1.0), 0.5); 312 | 313 | hitObjects[1].type = HitObjectSphere; 314 | hitObjects[1].materialIndex = MaterialIdxOrangeLambert; 315 | hitObjects[1].param0 = vec4(vec3(0.0, -100.5, -1.0), 100.0); 316 | 317 | hitObjects[2].type = HitObjectSphere; 318 | hitObjects[2].materialIndex = MaterialIdxOrangeMetal2; 319 | hitObjects[2].param0 = vec4(vec3( 1.0, 0.0, -1.0), 0.5); 320 | 321 | hitObjects[3].type = HitObjectSphere; 322 | hitObjects[3].materialIndex = MaterialIdxGlass; 323 | hitObjects[3].param0 = vec4(vec3(-1.0, 0.0, -1.0), 0.5); 324 | 325 | hitObjects[4].type = HitObjectSphere; 326 | hitObjects[4].materialIndex = MaterialIdxGreyMetal; 327 | hitObjects[4].param0 = vec4(vec3( 0.0, -0.5, -2.0), 0.5); 328 | 329 | hitObjects[5].type = HitObjectSphere; 330 | hitObjects[5].materialIndex = MaterialIdxGreyMetal; 331 | hitObjects[5].param0 = vec4(vec3( 0.0, -0.5, 0.0), 0.5); 332 | 333 | #if (MANY_OBJECTS == 1) 334 | int offsetCnt = 0; 335 | for (int i = 0; i < 10; ++i) 336 | { 337 | for (int j = 0; j < 10; ++j) 338 | { 339 | int objIndex = 4+i*10+j; 340 | int materialIndex = MaterialIdxGlass; 341 | 342 | materialIndex = ((i+j+1) & 3); 343 | 344 | ++offsetCnt; 345 | if (offsetCnt > 5) 346 | offsetCnt = 0; 347 | 348 | vec3 offset; 349 | if (offsetCnt == 0) 350 | { 351 | offset = vec3(-0.25, 0.15, 0.88); 352 | } 353 | else if (offsetCnt == 1) 354 | { 355 | offset = vec3(0.12, -0.73, -0.45); 356 | } 357 | else if (offsetCnt == 2) 358 | { 359 | offset = vec3(-0.49, 0.33, -0.57); 360 | } 361 | else if (offsetCnt == 3) 362 | { 363 | offset = vec3(0.92, -0.15, 0.41); 364 | } 365 | else if (offsetCnt == 4) 366 | { 367 | offset = vec3(0.26, 0.53, 0.29); 368 | } 369 | else 370 | { 371 | offset = vec3(-0.39, -0.25, -0.72); 372 | } 373 | 374 | if (j < 5) 375 | offset.z -= 0.5; 376 | else 377 | offset.z += 0.5; 378 | 379 | hitObjects[objIndex].type = HitObjectSphere; 380 | hitObjects[objIndex].materialIndex = materialIndex; 381 | hitObjects[objIndex].param0 = vec4(vec3((i*0.1 - 0.5)*7.5, -0.3, (j*0.1 - 0.5)*7.5) + vec3(0.3, 0.1, 0.3)*offset, 0.1); 382 | } 383 | } 384 | #endif 385 | 386 | bool anyHit = false; 387 | HitData hitDataTemp; 388 | float closestHit = t_max; 389 | 390 | for (int i = 0; i < numHitObjects; ++i) 391 | { 392 | if (hitObjects[i].type == HitObjectSphere) 393 | { 394 | bool isSphereHit = hitSphere(hitObjects[i].param0.xyz, hitObjects[i].param0.w, hitObjects[i].materialIndex, r, t_min, closestHit, hitDataTemp); 395 | if (isSphereHit && (hitDataTemp.t < closestHit)) 396 | { 397 | anyHit = true; 398 | closestHit = hitDataTemp.t; 399 | hitData = hitDataTemp; 400 | } 401 | } 402 | } 403 | 404 | return anyHit; 405 | } 406 | /* End of Hitting Routines */ 407 | 408 | vec3 getColor(Ray r, vec2 uv, float times) 409 | { 410 | Ray curRay = r; 411 | bool needRayCast = true; 412 | HitData hitData; 413 | float recastCount = 0.0; 414 | 415 | vec3 dissipation = vec3(1.0, 1.0, 1.0); 416 | 417 | while (needRayCast) 418 | { 419 | recastCount += 1.0; 420 | if (recastCount > 16.0) 421 | break; 422 | 423 | bool isAnythingHit = hitWorld(curRay, hitData); 424 | if (isAnythingHit) 425 | { 426 | Ray inRay = curRay; 427 | vec3 attenuation; 428 | needRayCast = materialScatterRay(hitData.materialIndex, inRay, hitData, uv, times + recastCount*1000, attenuation, curRay); 429 | dissipation *= attenuation; 430 | } 431 | else 432 | { 433 | break; 434 | } 435 | } 436 | 437 | vec3 nrmD = normalize(curRay.D); 438 | float t = clamp(0.5*(nrmD.y + 1.0), 0.0, 1.0); 439 | return dissipation*((1-t)*vec3(1.0, 1.0, 1.0) + t*vec3(0.5, 0.7, 1.0)) + vec3(0.1, 0.1, 0.1); 440 | } 441 | 442 | void main() 443 | { 444 | const float fov = 90 * (PI / 180.0); 445 | const float width = 800.0; 446 | const float height = 600.0; 447 | const float aspect = width/height; 448 | 449 | const float aperture = 0.25; 450 | 451 | const vec2 rndShift = vec2(fract(ubo.time*0.001), fract(ubo.time*0.0013)); 452 | const vec3 viewup = vec3(0.0, 1.0, 0.0); 453 | const vec3 viewpoint = vec3(-2.0 * sin(ubo.time*0.001), 1.0, 1.0); 454 | const vec3 viewtarget = vec3(0.0, 0.0, -1.0); 455 | 456 | vec3 origin = viewpoint; 457 | 458 | // Basis vectors 459 | vec3 basZ = normalize(viewpoint - viewtarget); 460 | vec3 basX = normalize(cross(viewup, basZ)); 461 | vec3 basY = normalize(cross(basZ, basX)); 462 | 463 | // Since range is [-1; 1] 464 | float fov_tan = tan(fov/2.0); 465 | vec3 axisX = aspect*fov_tan*basX; 466 | vec3 axisY = fov_tan*basY; 467 | 468 | float lensRad = aperture / 2.0; 469 | float focusDist = length(viewpoint - viewtarget); 470 | 471 | // Lower left corner 472 | vec3 llc = origin - 0.5*focusDist*axisX - 0.5*focusDist*axisY - focusDist*basZ; 473 | 474 | const int numSubSamples = 32; 475 | vec4 color = vec4(0.0, 0.0, 0.0, 0.0); 476 | for (int i = 0; i < numSubSamples; ++i) 477 | { 478 | vec2 rndDisk = lensRad*randOnDisk(in_texCoords.xy+rndShift, 12.3*(i+23.4)); 479 | vec3 offset = basX*rndDisk.x + basY*rndDisk.y; 480 | vec3 rayTarget = llc + focusDist*(in_texCoords.x + fakeRand(in_texCoords.xy+rndShift, i)/width) * axisX + focusDist*(in_texCoords.y + fakeRand(in_texCoords.xy+rndShift, i+numSubSamples)/height) * axisY; 481 | Ray r = getRay(origin + offset, rayTarget - origin - offset); 482 | color += vec4(getColor(r, in_texCoords.xy+rndShift, i), 1.0); 483 | } 484 | 485 | #if 0 486 | vec4 colorTex = texture(texSampler, in_texCoords); 487 | 488 | float interp = 0.5; 489 | outColor = in_color * ((1.0 - interp) * (color / numSubSamples) + interp * colorTex); 490 | #else 491 | outColor = in_color * (color / numSubSamples); 492 | #endif 493 | } -------------------------------------------------------------------------------- /vkEngine/shaders/shader_bindings.h: -------------------------------------------------------------------------------- 1 | #ifndef IG_SHADER_BINDINGS_H 2 | #define IG_SHADER_BINDINGS_H 3 | 4 | #define SH_BIND_GLOBAL_CONSTANTS 0 5 | #define SH_BIND_TRANSFORM 1 6 | 7 | // Forward shading 8 | #define SH_BIND_FWDSH_ALBEDO_TEX 2 9 | #define SH_BIND_FWDSH_SHADOWMAP_TEX 3 10 | #define SH_BIND_FWDSH_LIGHTPROJ_TEX 4 11 | #define SH_BIND_FWDSH_LIGHTMATRIX 5 12 | 13 | // Pathtracer 14 | #define SH_BIND_PATHTRACER_NOISE_TEX 2 15 | 16 | 17 | #endif // IG_SHADER_BINDINGS_H -------------------------------------------------------------------------------- /vkEngine/shaders/shadowmap.fs: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_bindings.h" 6 | 7 | layout(location = 0) in vec4 in_color; 8 | layout(location = 1) in vec3 in_normal_cam; 9 | layout(location = 2) in vec2 in_texCoords; 10 | layout(location = 3) in float in_time; 11 | 12 | layout(set = 0, binding = SH_BIND_GLOBAL_CONSTANTS) uniform UniformBufferObject 13 | { 14 | float time; 15 | } ubo; 16 | 17 | layout(set = 0, binding = SH_BIND_TRANSFORM) uniform TransformUBO 18 | { 19 | mat4 view; 20 | mat4 proj; 21 | } transformUBO; 22 | 23 | void main() 24 | { 25 | } -------------------------------------------------------------------------------- /vkEngine/shaders/shadowmap.vs: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_bindings.h" 6 | 7 | layout(location = 0) in vec3 in_position; 8 | layout(location = 1) in vec3 in_normal; 9 | layout(location = 2) in vec4 in_color; 10 | layout(location = 3) in vec2 in_texCoords; 11 | 12 | layout(set = 0, binding = SH_BIND_GLOBAL_CONSTANTS) uniform UniformBufferObject 13 | { 14 | float time; 15 | } ubo; 16 | 17 | layout(set = 0, binding = SH_BIND_TRANSFORM) uniform TransformUBO 18 | { 19 | mat4 view; 20 | mat4 proj; 21 | } transformUBO; 22 | 23 | layout(push_constant) uniform MeshPushConst 24 | { 25 | mat4 model; 26 | } meshPushConst; 27 | 28 | out gl_PerVertex 29 | { 30 | vec4 gl_Position; 31 | }; 32 | 33 | layout(location = 0) out vec4 out_color; 34 | layout(location = 1) out vec3 out_normal_cam; 35 | layout(location = 2) out vec2 out_texCoords; 36 | layout(location = 3) out float out_time; 37 | 38 | void main() 39 | { 40 | vec4 modelVertex = meshPushConst.model * vec4(in_position, 1.0); 41 | gl_Position = transformUBO.proj * transformUBO.view * modelVertex; 42 | out_texCoords = in_texCoords; 43 | out_color = in_color; 44 | // Suppose view is orthonormal 45 | out_normal_cam = mat3(transformUBO.view) * mat3(meshPushConst.model) * in_normal; 46 | out_time = ubo.time; 47 | } -------------------------------------------------------------------------------- /vkEngine/shaders/test.vs: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_bindings.h" 6 | 7 | layout(location = 0) in vec3 in_position; 8 | layout(location = 1) in vec3 in_normal; 9 | layout(location = 2) in vec4 in_color; 10 | layout(location = 3) in vec2 in_texCoords; 11 | 12 | layout(set = 0, binding = SH_BIND_GLOBAL_CONSTANTS) uniform UniformBufferObject 13 | { 14 | float time; 15 | } ubo; 16 | 17 | layout(set = 0, binding = SH_BIND_TRANSFORM) uniform TransformUBO 18 | { 19 | mat4 view; 20 | mat4 proj; 21 | } transformUBO; 22 | 23 | layout(push_constant) uniform MeshPushConst 24 | { 25 | mat4 model; 26 | } meshPushConst; 27 | 28 | out gl_PerVertex 29 | { 30 | vec4 gl_Position; 31 | }; 32 | 33 | layout(location = 0) out vec4 out_color; 34 | layout(location = 1) out vec2 out_texCoords; 35 | layout(location = 2) out float out_time; 36 | 37 | void main() 38 | { 39 | gl_Position = vec4(in_position, 1.0); 40 | out_texCoords = in_texCoords; 41 | out_color = in_color; 42 | out_time = ubo.time; 43 | } -------------------------------------------------------------------------------- /vkEngine/source/app.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avoroshilov/physics_playground/06208f51d1b1a6a62a0c6cd5f54270b6ec0e42fe/vkEngine/source/app.cpp -------------------------------------------------------------------------------- /vkEngine/source/app.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "vulkan\manager.h" 4 | 5 | class App 6 | { 7 | protected: 8 | 9 | bool m_isExitting = false; 10 | 11 | int m_width = -1, m_height = -1; 12 | HWND m_hWnd = nullptr; 13 | vulkan::Wrapper * m_renderingWrapper; 14 | 15 | double m_elapsedTimeMS = 0.0; 16 | 17 | public: 18 | 19 | void setRenderManager(vulkan::Wrapper * renderingWrapper) 20 | { 21 | m_renderingWrapper = renderingWrapper; 22 | } 23 | 24 | void init(HWND hWnd, int width, int height) 25 | { 26 | m_width = width; 27 | m_height = height; 28 | m_hWnd = hWnd; 29 | m_renderingWrapper->init(m_hWnd, m_width, m_height); 30 | } 31 | void deinit() 32 | { 33 | m_renderingWrapper->deinit(); 34 | } 35 | 36 | double getElapsedTime() const { return m_elapsedTimeMS; } 37 | 38 | void update(double dtMS) 39 | { 40 | m_elapsedTimeMS += dtMS; 41 | m_renderingWrapper->increaseDTime(dtMS); 42 | } 43 | 44 | void onWindowResize(int width, int height) 45 | { 46 | if (width == 0 || height == 0) 47 | return; 48 | 49 | m_width = width; 50 | m_height = height; 51 | 52 | m_renderingWrapper->onWindowResize(width, height); 53 | } 54 | 55 | void setIsExitting(bool isExitting) { m_isExitting = isExitting; } 56 | bool getIsExitting() const { return m_isExitting; } 57 | 58 | void requestCapture(bool captureRequested) 59 | { 60 | m_renderingWrapper->requestCapture(captureRequested); 61 | } 62 | 63 | static const int c_titleBufSize = 256; 64 | wchar_t m_titleBuf[c_titleBufSize]; 65 | void setWindowTitle(wchar_t * title) 66 | { 67 | swprintf_s(m_titleBuf, c_titleBufSize, L"%s", title); 68 | SetWindowText(m_hWnd, m_titleBuf); 69 | } 70 | 71 | void setDTime(double dtimeMS) 72 | { 73 | const int titleBufSizeAdditional = 16; 74 | const int titleBufSizeAugmented = c_titleBufSize + titleBufSizeAdditional; 75 | wchar_t titleBuf[titleBufSizeAugmented]; 76 | swprintf_s(titleBuf, titleBufSizeAugmented, L"%s: %.1f (%.3f ms)", m_titleBuf, 1000.0 / dtimeMS, dtimeMS); 77 | SetWindowText(m_hWnd, titleBuf); 78 | } 79 | }; 80 | 81 | struct CallbackData 82 | { 83 | App * app; 84 | 85 | enum class MovementKindBits 86 | { 87 | eForward = (1 << 0), 88 | eBackward = (1 << 1), 89 | eLeft = (1 << 2), 90 | eRight = (1 << 3), 91 | eUp = (1 << 4), 92 | eDown = (1 << 5), 93 | eAccel = (1 << 6), 94 | eDeccel = (1 << 7), 95 | }; 96 | uint32_t movementFlags; 97 | 98 | bool reqDropBox; 99 | 100 | bool isActive; 101 | bool isPaused; 102 | bool isAnimStep; 103 | 104 | enum class MouseMode 105 | { 106 | eCamera = 0, 107 | ePicking = 1, 108 | 109 | eNUM_ENTRIES, 110 | eStartingMode = eCamera 111 | }; 112 | MouseMode mouseMode; 113 | 114 | int lmbState; 115 | 116 | // Mouse coordinates 117 | int mx, my; 118 | 119 | int dmx, dmy; 120 | int dwheel; 121 | }; 122 | -------------------------------------------------------------------------------- /vkEngine/source/camera.cpp: -------------------------------------------------------------------------------- 1 | #include "camera.h" 2 | 3 | void Camera::update(const math::Vec3 & posOffset, float rotX, float rotY) 4 | { 5 | using namespace math; 6 | 7 | m_angX += rotX; 8 | m_angY += rotY; 9 | 10 | const float angYLimit = 0.99f * _PI2; 11 | if (m_angY > angYLimit) 12 | m_angY = angYLimit; 13 | else if (m_angY < -angYLimit) 14 | m_angY = -angYLimit; 15 | 16 | float angX = m_angX; 17 | float angY = m_angY; 18 | 19 | const bool invert = false; 20 | if (!invert) 21 | { 22 | angX = -angX; 23 | angY = -angY; 24 | } 25 | angY += _PI2; 26 | 27 | m_view = Vec3C(sinf(angX)*sinf(angY), cosf(angY), cosf(angX)*sinf(angY)); 28 | m_view.normalize(); 29 | 30 | Vec3 right = m_up.cross(m_view); 31 | right.normalize(); 32 | 33 | Vec3 up = m_view.cross(right); 34 | up.normalize(); 35 | 36 | m_pos += right * posOffset.x + up * posOffset.y + m_view * posOffset.z; 37 | } 38 | 39 | void Camera::fillMatrix(math::Mat34 * mat) const 40 | { 41 | if (!mat) 42 | return; 43 | 44 | using namespace math; 45 | 46 | Vec3 right = m_up.cross(m_view); 47 | right.normalize(); 48 | 49 | Vec3 up = m_view.cross(right); 50 | up.normalize(); 51 | 52 | mat->setBasis0(right); 53 | mat->setBasis1(up); 54 | mat->setBasis2(m_view); 55 | mat->setBasis3(m_pos); 56 | 57 | *mat = mat->invertRTCopy(); 58 | } 59 | -------------------------------------------------------------------------------- /vkEngine/source/camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "math/AuxMath.h" 5 | #include "math/Vec3.h" 6 | #include "math/Mat34.h" 7 | 8 | #include 9 | 10 | class Camera 11 | { 12 | protected: 13 | 14 | math::Vec3 m_pos = math::Vec3C(0.0f, 0.0f, 0.0f); 15 | math::Vec3 m_up = math::Vec3C(0.0f, 1.0f, 0.0f), m_view = math::Vec3C(0.0f, 0.0f, -1.0f); 16 | 17 | float m_angX = 0.0f, m_angY = 0.0f; 18 | 19 | public: 20 | 21 | void setPosition(const math::Vec3 & pos) { m_pos = pos; } 22 | 23 | math::Vec3 getPosition() const { return m_pos; } 24 | math::Vec3 getUp() const { return m_up; } 25 | math::Vec3 getView() const { return m_view; } 26 | 27 | void update(const math::Vec3 & posOffset, float rotX, float rotY); 28 | void fillMatrix(math::Mat34 * mat) const; 29 | }; -------------------------------------------------------------------------------- /vkEngine/source/drawing_primitives.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | static void buildBoxVertices(std::vector * outVertices, const math::Mat34 & modelMatrix, const math::Vec3 & cubeSize, const math::Vec4 & color) 9 | { 10 | using namespace math; 11 | 12 | vulkan::Vertex faceVtx[6]; 13 | auto finalizeFace = [&faceVtx, &outVertices](const Mat34 & modelMatrix, const Vec3 & normal, const Vec4 & faceColor) 14 | { 15 | faceVtx[0].tc = Vec2C( 0.0f, 0.0f); // 0 16 | faceVtx[1].tc = Vec2C( 0.0f, 1.0f); // 3 17 | faceVtx[2].tc = Vec2C( 1.0f, 1.0f); // 2 18 | 19 | faceVtx[3].tc = Vec2C( 0.0f, 0.0f); // 0 20 | faceVtx[4].tc = Vec2C( 1.0f, 1.0f); // 2 21 | faceVtx[5].tc = Vec2C( 1.0f, 0.0f); // 1 22 | 23 | for (int fi = 0; fi < 6; ++fi) 24 | { 25 | faceVtx[fi].pos = modelMatrix * faceVtx[fi].pos; 26 | faceVtx[fi].nrm = normal; 27 | faceVtx[fi].col = faceColor; 28 | 29 | outVertices->push_back(faceVtx[fi]); 30 | } 31 | }; 32 | 33 | Vec3 vecOffset = Vec3C(0.0f, 0.0f, 0.0f); 34 | 35 | outVertices->reserve(36); 36 | outVertices->resize(0); 37 | 38 | // Vertices 39 | // Front 40 | faceVtx[0].pos = Vec3C(-cubeSize.x, -cubeSize.y, cubeSize.z); 41 | faceVtx[1].pos = Vec3C(-cubeSize.x, cubeSize.y, cubeSize.z); 42 | faceVtx[2].pos = Vec3C( cubeSize.x, cubeSize.y, cubeSize.z); 43 | faceVtx[3].pos = Vec3C(-cubeSize.x, -cubeSize.y, cubeSize.z); 44 | faceVtx[4].pos = Vec3C( cubeSize.x, cubeSize.y, cubeSize.z); 45 | faceVtx[5].pos = Vec3C( cubeSize.x, -cubeSize.y, cubeSize.z); 46 | finalizeFace(modelMatrix, Vec3C( 0.0f, 0.0f, 1.0f), color); 47 | 48 | // Back 49 | faceVtx[0].pos = Vec3C(-cubeSize.x, -cubeSize.y, -cubeSize.z); 50 | faceVtx[1].pos = Vec3C( cubeSize.x, -cubeSize.y, -cubeSize.z); 51 | faceVtx[2].pos = Vec3C( cubeSize.x, cubeSize.y, -cubeSize.z); 52 | faceVtx[3].pos = Vec3C(-cubeSize.x, -cubeSize.y, -cubeSize.z); 53 | faceVtx[4].pos = Vec3C( cubeSize.x, cubeSize.y, -cubeSize.z); 54 | faceVtx[5].pos = Vec3C(-cubeSize.x, cubeSize.y, -cubeSize.z); 55 | finalizeFace(modelMatrix, Vec3C( 0.0f, 0.0f, -1.0f), color); 56 | 57 | // Left 58 | faceVtx[0].pos = Vec3C(-cubeSize.x, -cubeSize.y, -cubeSize.z); 59 | faceVtx[1].pos = Vec3C(-cubeSize.x, cubeSize.y, -cubeSize.z); 60 | faceVtx[2].pos = Vec3C(-cubeSize.x, cubeSize.y, cubeSize.z); 61 | faceVtx[3].pos = Vec3C(-cubeSize.x, -cubeSize.y, -cubeSize.z); 62 | faceVtx[4].pos = Vec3C(-cubeSize.x, cubeSize.y, cubeSize.z); 63 | faceVtx[5].pos = Vec3C(-cubeSize.x, -cubeSize.y, cubeSize.z); 64 | finalizeFace(modelMatrix, Vec3C(-1.0f, 0.0f, 0.0f), color); 65 | 66 | // Right 67 | faceVtx[0].pos = Vec3C( cubeSize.x, -cubeSize.y, -cubeSize.z); 68 | faceVtx[1].pos = Vec3C( cubeSize.x, -cubeSize.y, cubeSize.z); 69 | faceVtx[2].pos = Vec3C( cubeSize.x, cubeSize.y, cubeSize.z); 70 | faceVtx[3].pos = Vec3C( cubeSize.x, -cubeSize.y, -cubeSize.z); 71 | faceVtx[4].pos = Vec3C( cubeSize.x, cubeSize.y, cubeSize.z); 72 | faceVtx[5].pos = Vec3C( cubeSize.x, cubeSize.y, -cubeSize.z); 73 | finalizeFace(modelMatrix, Vec3C( 1.0f, 0.0f, 0.0f), color); 74 | 75 | // Top 76 | faceVtx[0].pos = Vec3C(-cubeSize.x, cubeSize.y, -cubeSize.z); 77 | faceVtx[1].pos = Vec3C( cubeSize.x, cubeSize.y, -cubeSize.z); 78 | faceVtx[2].pos = Vec3C( cubeSize.x, cubeSize.y, cubeSize.z); 79 | faceVtx[3].pos = Vec3C(-cubeSize.x, cubeSize.y, -cubeSize.z); 80 | faceVtx[4].pos = Vec3C( cubeSize.x, cubeSize.y, cubeSize.z); 81 | faceVtx[5].pos = Vec3C(-cubeSize.x, cubeSize.y, cubeSize.z); 82 | finalizeFace(modelMatrix, Vec3C( 0.0f, 1.0f, 0.0f), color); 83 | 84 | // Bottom 85 | faceVtx[0].pos = Vec3C(-cubeSize.x, -cubeSize.y, -cubeSize.z); 86 | faceVtx[1].pos = Vec3C(-cubeSize.x, -cubeSize.y, cubeSize.z); 87 | faceVtx[2].pos = Vec3C( cubeSize.x, -cubeSize.y, cubeSize.z); 88 | faceVtx[3].pos = Vec3C(-cubeSize.x, -cubeSize.y, -cubeSize.z); 89 | faceVtx[4].pos = Vec3C( cubeSize.x, -cubeSize.y, cubeSize.z); 90 | faceVtx[5].pos = Vec3C( cubeSize.x, -cubeSize.y, -cubeSize.z); 91 | finalizeFace(modelMatrix, Vec3C( 0.0f, -1.0f, 0.0f), color); 92 | } 93 | 94 | static void buildSphereVertices(std::vector * outVertices, const math::Mat34 & modelMatrix, const float radius, const math::Vec4 & color) 95 | { 96 | using namespace math; 97 | 98 | const uint32_t detI = 24; 99 | const uint32_t detJ = 24; 100 | 101 | std::vector verticesStorage; 102 | verticesStorage.resize(detI*detJ); 103 | vulkan::Vertex * vertices = verticesStorage.data(); 104 | 105 | for (uint32_t vj = 0; vj < detJ; ++vj) 106 | { 107 | const float nrm_vj = vj/(float)(detJ - 1); 108 | const float angJ = PI*nrm_vj - _PI2; 109 | 110 | for (uint32_t vi = 0; vi < detI; ++vi) 111 | { 112 | const float nrm_vi = vi/(float)(detI - 1); 113 | const float angI = _2PI*nrm_vi; 114 | 115 | vulkan::Vertex & curVertex = vertices[vi+vj*detI]; 116 | Vec3 unitSphere = Vec3C(cosf(angJ)*cosf(angI), sinf(angJ), cosf(angJ)*sinf(angI)); 117 | curVertex.pos = modelMatrix * (radius * unitSphere); 118 | 119 | curVertex.tc = Vec2C(nrm_vi, nrm_vj); 120 | curVertex.col = Vec4C(1.0f, 1.0f, 1.0f, 1.0f); 121 | 122 | curVertex.nrm = unitSphere; 123 | } 124 | } 125 | 126 | const uint32_t numQuadsI = detI - 1; 127 | const uint32_t numQuadsJ = detJ - 1; 128 | const uint32_t numTrisPerQuad = 2; 129 | const uint32_t numTris = numQuadsI*numQuadsJ*numTrisPerQuad; 130 | const uint32_t numIdxPerTri = 3; 131 | const size_t numIndices = numTris * numIdxPerTri; 132 | 133 | outVertices->reserve(numQuadsI*numQuadsJ*6); 134 | outVertices->resize(0); 135 | for (uint32_t qj = 0; qj < numQuadsJ; ++qj) 136 | { 137 | for (uint32_t qi = 0; qi < numQuadsI; ++qi) 138 | { 139 | outVertices->push_back(vertices[qi+qj*detI]); 140 | outVertices->push_back(vertices[(qi+1)+qj*detI]); 141 | outVertices->push_back(vertices[qi+(qj+1)*detI]); 142 | 143 | outVertices->push_back(vertices[(qi+1)+qj*detI]); 144 | outVertices->push_back(vertices[(qi+1)+(qj+1)*detI]); 145 | outVertices->push_back(vertices[qi+(qj+1)*detI]); 146 | } 147 | } 148 | } 149 | 150 | static void buildHemiSphereVertices(std::vector * outVertices, const math::Mat34 & modelMatrix, const float radius, const math::Vec4 & color) 151 | { 152 | using namespace math; 153 | 154 | const uint32_t detI = 24; 155 | const uint32_t detJ = 12; 156 | 157 | std::vector verticesStorage; 158 | verticesStorage.resize(detI*detJ); 159 | vulkan::Vertex * vertices = verticesStorage.data(); 160 | 161 | for (uint32_t vj = 0; vj < detJ; ++vj) 162 | { 163 | const float nrm_vj = vj/(float)(detJ - 1); 164 | const float angJ = PI*(nrm_vj*0.5f + 0.5f) - _PI2; 165 | 166 | for (uint32_t vi = 0; vi < detI; ++vi) 167 | { 168 | const float nrm_vi = vi/(float)(detI - 1); 169 | const float angI = _2PI*nrm_vi; 170 | 171 | vulkan::Vertex & curVertex = vertices[vi+vj*detI]; 172 | Vec3 unitSphere = Vec3C(cosf(angJ)*cosf(angI), sinf(angJ), cosf(angJ)*sinf(angI)); 173 | curVertex.pos = modelMatrix * (radius * unitSphere); 174 | 175 | curVertex.tc = Vec2C(nrm_vi, nrm_vj); 176 | curVertex.col = Vec4C(1.0f, 1.0f, 1.0f, 1.0f); 177 | 178 | curVertex.nrm = unitSphere; 179 | } 180 | } 181 | 182 | const uint32_t numQuadsI = detI - 1; 183 | const uint32_t numQuadsJ = detJ - 1; 184 | const uint32_t numTrisPerQuad = 2; 185 | const uint32_t numTris = numQuadsI*numQuadsJ*numTrisPerQuad; 186 | const uint32_t numIdxPerTri = 3; 187 | const size_t numIndices = numTris * numIdxPerTri; 188 | 189 | outVertices->reserve(numQuadsI*numQuadsJ*6); 190 | outVertices->resize(0); 191 | for (uint32_t qj = 0; qj < numQuadsJ; ++qj) 192 | { 193 | for (uint32_t qi = 0; qi < numQuadsI; ++qi) 194 | { 195 | outVertices->push_back(vertices[qi+qj*detI]); 196 | outVertices->push_back(vertices[(qi+1)+qj*detI]); 197 | outVertices->push_back(vertices[qi+(qj+1)*detI]); 198 | 199 | outVertices->push_back(vertices[(qi+1)+qj*detI]); 200 | outVertices->push_back(vertices[(qi+1)+(qj+1)*detI]); 201 | outVertices->push_back(vertices[qi+(qj+1)*detI]); 202 | } 203 | } 204 | } 205 | 206 | static void buildCylinderVertices(std::vector * outVertices, const math::Mat34 & modelMatrix, const float height, const float radius, const math::Vec4 & color) 207 | { 208 | using namespace math; 209 | 210 | const uint32_t detI = 24; 211 | const uint32_t detJ = 2; 212 | 213 | std::vector verticesStorage; 214 | verticesStorage.resize(detI*detJ); 215 | vulkan::Vertex * vertices = verticesStorage.data(); 216 | 217 | for (uint32_t vj = 0; vj < detJ; ++vj) 218 | { 219 | const float nrm_vj = vj/(float)(detJ - 1); 220 | 221 | for (uint32_t vi = 0; vi < detI; ++vi) 222 | { 223 | const float nrm_vi = vi/(float)(detI - 1); 224 | const float angI = _2PI*nrm_vi; 225 | 226 | vulkan::Vertex & curVertex = vertices[vi+vj*detI]; 227 | Vec3 unitCircle = Vec3C(cosf(angI), 0.0f, sinf(angI)); 228 | curVertex.pos = modelMatrix * (radius * unitCircle + Vec3C(0.0f, (2 * nrm_vj - 1.0f) * height, 0.0f)); 229 | 230 | curVertex.tc = Vec2C(nrm_vi, nrm_vj); 231 | curVertex.col = Vec4C(1.0f, 1.0f, 1.0f, 1.0f); 232 | 233 | curVertex.nrm = unitCircle; 234 | } 235 | } 236 | 237 | const uint32_t numQuadsI = detI - 1; 238 | const uint32_t numQuadsJ = detJ - 1; 239 | const uint32_t numTrisPerQuad = 2; 240 | const uint32_t numTris = numQuadsI*numQuadsJ*numTrisPerQuad; 241 | const uint32_t numIdxPerTri = 3; 242 | const size_t numIndices = numTris * numIdxPerTri; 243 | 244 | outVertices->reserve(numQuadsI*numQuadsJ*6); 245 | outVertices->resize(0); 246 | for (uint32_t qj = 0; qj < numQuadsJ; ++qj) 247 | { 248 | for (uint32_t qi = 0; qi < numQuadsI; ++qi) 249 | { 250 | outVertices->push_back(vertices[qi+qj*detI]); 251 | outVertices->push_back(vertices[(qi+1)+qj*detI]); 252 | outVertices->push_back(vertices[qi+(qj+1)*detI]); 253 | 254 | outVertices->push_back(vertices[(qi+1)+qj*detI]); 255 | outVertices->push_back(vertices[(qi+1)+(qj+1)*detI]); 256 | outVertices->push_back(vertices[qi+(qj+1)*detI]); 257 | } 258 | } 259 | } 260 | 261 | static void buildConeVertices(std::vector * outVertices, const math::Mat34 & modelMatrix, const float height, const float radius, const math::Vec4 & color) 262 | { 263 | using namespace math; 264 | 265 | const uint32_t detI = 24; 266 | const uint32_t detJ = 2; 267 | 268 | std::vector verticesStorage; 269 | verticesStorage.resize(detI*detJ); 270 | vulkan::Vertex * vertices = verticesStorage.data(); 271 | 272 | for (uint32_t vj = 0; vj < detJ; ++vj) 273 | { 274 | const float nrm_vj = vj/(float)(detJ - 1); 275 | 276 | for (uint32_t vi = 0; vi < detI; ++vi) 277 | { 278 | const float nrm_vi = vi/(float)(detI - 1); 279 | const float angI = _2PI*nrm_vi; 280 | 281 | vulkan::Vertex & curVertex = vertices[vi+vj*detI]; 282 | Vec3 unitCircle = Vec3C(cosf(angI), 0.0f, sinf(angI)); 283 | curVertex.pos = modelMatrix * ((1.0f - nrm_vj)*radius * unitCircle + Vec3C(0.0f, (2 * nrm_vj - 1.0f) * height, 0.0f)); 284 | 285 | curVertex.tc = Vec2C(nrm_vi, nrm_vj); 286 | curVertex.col = Vec4C(1.0f, 1.0f, 1.0f, 1.0f); 287 | 288 | // Handwavy normal approximation 289 | if (height != 0.0f) 290 | { 291 | curVertex.nrm = Vec3C(unitCircle.x, radius/height, unitCircle.y); 292 | curVertex.nrm.normalize(); 293 | } 294 | else 295 | { 296 | curVertex.nrm = Vec3C(0.0f, 1.0f, 0.0f); 297 | } 298 | } 299 | } 300 | 301 | const uint32_t numQuadsI = detI - 1; 302 | const uint32_t numQuadsJ = detJ - 1; 303 | const uint32_t numTrisPerQuad = 2; 304 | const uint32_t numTris = numQuadsI*numQuadsJ*numTrisPerQuad; 305 | const uint32_t numIdxPerTri = 3; 306 | const size_t numIndices = numTris * numIdxPerTri; 307 | 308 | outVertices->reserve(numQuadsI*numQuadsJ*6); 309 | outVertices->resize(0); 310 | for (uint32_t qj = 0; qj < numQuadsJ; ++qj) 311 | { 312 | for (uint32_t qi = 0; qi < numQuadsI; ++qi) 313 | { 314 | outVertices->push_back(vertices[qi+qj*detI]); 315 | outVertices->push_back(vertices[(qi+1)+qj*detI]); 316 | outVertices->push_back(vertices[qi+(qj+1)*detI]); 317 | 318 | outVertices->push_back(vertices[(qi+1)+qj*detI]); 319 | outVertices->push_back(vertices[(qi+1)+(qj+1)*detI]); 320 | outVertices->push_back(vertices[qi+(qj+1)*detI]); 321 | } 322 | } 323 | } 324 | 325 | static void buildDiskVertices(std::vector * outVertices, const math::Mat34 & modelMatrix, const float radius, const math::Vec4 & color, bool radialTC = false) 326 | { 327 | using namespace math; 328 | 329 | const uint32_t detI = 24; 330 | const uint32_t detJ = 2; 331 | 332 | std::vector verticesStorage; 333 | verticesStorage.resize(detI*detJ); 334 | vulkan::Vertex * vertices = verticesStorage.data(); 335 | 336 | for (uint32_t vj = 0; vj < detJ; ++vj) 337 | { 338 | const float nrm_vj = vj/(float)(detJ - 1); 339 | 340 | for (uint32_t vi = 0; vi < detI; ++vi) 341 | { 342 | const float nrm_vi = vi/(float)(detI - 1); 343 | const float angI = _2PI*nrm_vi; 344 | 345 | vulkan::Vertex & curVertex = vertices[vi+vj*detI]; 346 | Vec3 unitCircle = Vec3C((1.0f - nrm_vj) * cosf(angI), 0.0f, (1.0f - nrm_vj) * sinf(angI)); 347 | curVertex.pos = modelMatrix * (radius * unitCircle); 348 | 349 | if (radialTC) 350 | curVertex.tc = Vec2C(nrm_vi, nrm_vj); 351 | else 352 | curVertex.tc = Vec2C(unitCircle.x, unitCircle.z); 353 | curVertex.col = Vec4C(1.0f, 1.0f, 1.0f, 1.0f); 354 | 355 | curVertex.nrm = Vec3C(0.0f, 1.0f, 0.0f); 356 | } 357 | } 358 | 359 | const uint32_t numQuadsI = detI - 1; 360 | const uint32_t numQuadsJ = detJ - 1; 361 | const uint32_t numTrisPerQuad = 2; 362 | const uint32_t numTris = numQuadsI*numQuadsJ*numTrisPerQuad; 363 | const uint32_t numIdxPerTri = 3; 364 | const size_t numIndices = numTris * numIdxPerTri; 365 | 366 | outVertices->reserve(numQuadsI*numQuadsJ*6); 367 | outVertices->resize(0); 368 | for (uint32_t qj = 0; qj < numQuadsJ; ++qj) 369 | { 370 | for (uint32_t qi = 0; qi < numQuadsI; ++qi) 371 | { 372 | outVertices->push_back(vertices[qi+qj*detI]); 373 | outVertices->push_back(vertices[(qi+1)+qj*detI]); 374 | outVertices->push_back(vertices[qi+(qj+1)*detI]); 375 | 376 | outVertices->push_back(vertices[(qi+1)+qj*detI]); 377 | outVertices->push_back(vertices[(qi+1)+(qj+1)*detI]); 378 | outVertices->push_back(vertices[qi+(qj+1)*detI]); 379 | } 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /vkEngine/source/main.cpp: -------------------------------------------------------------------------------- 1 | #include "app.h" 2 | 3 | #include 4 | #include 5 | #include "vulkan/manager.h" 6 | #include "camera.h" 7 | 8 | #include "drawing_primitives.h" 9 | 10 | // Physics simulation framework includes 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "sim.h" 24 | #include "physics_scenes.h" 25 | 26 | // All physics-related code in this file is guarded with this preprocessor definition 27 | #define ENABLE_PHYSICS 1 28 | 29 | #define MOUSE_USE_RAWINPUT 1 30 | 31 | static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( 32 | VkDebugReportFlagsEXT flags, 33 | VkDebugReportObjectTypeEXT objType, 34 | uint64_t obj, 35 | size_t location, 36 | int32_t code, 37 | const char * layerPrefix, 38 | const char * msg, 39 | void * userData 40 | ) 41 | { 42 | printf("[VAL] %s\n", msg); 43 | return VK_FALSE; 44 | } 45 | 46 | void resizeCallback(void * pUserData, int width, int height) 47 | { 48 | if (pUserData) 49 | { 50 | CallbackData * callbackData = reinterpret_cast(pUserData); 51 | callbackData->app->onWindowResize(width, height); 52 | } 53 | } 54 | void chageFocusCallback(void * pUserData, bool isInFocus) 55 | { 56 | } 57 | void chageActiveCallback(void * pUserData, bool isActive) 58 | { 59 | printf("Active: %s\n", isActive ? "true" : "false"); 60 | if (pUserData) 61 | { 62 | CallbackData * callbackData = reinterpret_cast(pUserData); 63 | if (isActive) 64 | { 65 | windows::hideMouse(); 66 | windows::setMouseCoordinates(callbackData->mx, callbackData->my); 67 | } 68 | else 69 | { 70 | windows::showMouse(); 71 | } 72 | callbackData->isActive = isActive; 73 | } 74 | } 75 | void keyStateCallback(void * pUserData, windows::KeyCode keyCode, windows::KeyState keyState) 76 | { 77 | using namespace windows; 78 | 79 | #define DBG_KEY_TESTING 0 80 | 81 | #if (DBG_KEY_TESTING == 1) 82 | char * keyStatus = "UNKNOWN"; 83 | if (keyState == KeyState::ePressed) 84 | { 85 | keyStatus = "pressed"; 86 | } 87 | else if (keyState == KeyState::eHeldDown) 88 | { 89 | keyStatus = "held down"; 90 | } 91 | else if (keyState == KeyState::eReleased) 92 | { 93 | keyStatus = "released"; 94 | } 95 | #endif 96 | 97 | if (!pUserData) 98 | return; 99 | 100 | CallbackData * callbackData = reinterpret_cast(pUserData); 101 | App * app = callbackData->app; 102 | 103 | if (!app) 104 | return; 105 | 106 | switch (keyCode) 107 | { 108 | case KeyCode::eEscape: 109 | { 110 | app->setIsExitting(true); 111 | break; 112 | } 113 | case KeyCode::eF12: 114 | { 115 | if (keyState == KeyState::ePressed) 116 | { 117 | app->requestCapture(true); 118 | } 119 | break; 120 | } 121 | case (KeyCode)'E': 122 | { 123 | if (keyState == KeyState::ePressed || keyState == KeyState::eHeldDown) 124 | callbackData->reqDropBox |= true; 125 | 126 | break; 127 | } 128 | case (KeyCode)'Q': 129 | { 130 | if (keyState == KeyState::ePressed) 131 | { 132 | callbackData->isPaused = !callbackData->isPaused; 133 | } 134 | break; 135 | } 136 | case (KeyCode)'P': 137 | { 138 | if (keyState == KeyState::ePressed || keyState == KeyState::eHeldDown) 139 | { 140 | callbackData->isAnimStep = true; 141 | callbackData->isPaused = false; 142 | } 143 | break; 144 | } 145 | case (KeyCode)'W': 146 | { 147 | if (keyState == KeyState::ePressed || keyState == KeyState::eHeldDown) 148 | callbackData->movementFlags |= (uint32_t)CallbackData::MovementKindBits::eForward; 149 | else 150 | callbackData->movementFlags &= ~(uint32_t)CallbackData::MovementKindBits::eForward; 151 | 152 | break; 153 | } 154 | case (KeyCode)'S': 155 | { 156 | if (keyState == KeyState::ePressed || keyState == KeyState::eHeldDown) 157 | callbackData->movementFlags |= (uint32_t)CallbackData::MovementKindBits::eBackward; 158 | else 159 | callbackData->movementFlags &= ~(uint32_t)CallbackData::MovementKindBits::eBackward; 160 | 161 | break; 162 | } 163 | case (KeyCode)'A': 164 | { 165 | if (keyState == KeyState::ePressed || keyState == KeyState::eHeldDown) 166 | callbackData->movementFlags |= (uint32_t)CallbackData::MovementKindBits::eLeft; 167 | else 168 | callbackData->movementFlags &= ~(uint32_t)CallbackData::MovementKindBits::eLeft; 169 | 170 | break; 171 | } 172 | case (KeyCode)'D': 173 | { 174 | if (keyState == KeyState::ePressed || keyState == KeyState::eHeldDown) 175 | callbackData->movementFlags |= (uint32_t)CallbackData::MovementKindBits::eRight; 176 | else 177 | callbackData->movementFlags &= ~(uint32_t)CallbackData::MovementKindBits::eRight; 178 | 179 | break; 180 | } 181 | case KeyCode::ePgDown: 182 | { 183 | if (keyState == KeyState::ePressed || keyState == KeyState::eHeldDown) 184 | callbackData->movementFlags |= (uint32_t)CallbackData::MovementKindBits::eDown; 185 | else 186 | callbackData->movementFlags &= ~(uint32_t)CallbackData::MovementKindBits::eDown; 187 | 188 | break; 189 | } 190 | case KeyCode::ePgUp: 191 | { 192 | if (keyState == KeyState::ePressed || keyState == KeyState::eHeldDown) 193 | callbackData->movementFlags |= (uint32_t)CallbackData::MovementKindBits::eUp; 194 | else 195 | callbackData->movementFlags &= ~(uint32_t)CallbackData::MovementKindBits::eUp; 196 | 197 | break; 198 | } 199 | case KeyCode::eLShift: 200 | { 201 | if (keyState == KeyState::ePressed || keyState == KeyState::eHeldDown) 202 | callbackData->movementFlags |= (uint32_t)CallbackData::MovementKindBits::eAccel; 203 | else 204 | callbackData->movementFlags &= ~(uint32_t)CallbackData::MovementKindBits::eAccel; 205 | 206 | break; 207 | } 208 | case KeyCode::eLCtrl: 209 | { 210 | if (keyState == KeyState::ePressed || keyState == KeyState::eHeldDown) 211 | callbackData->movementFlags |= (uint32_t)CallbackData::MovementKindBits::eDeccel; 212 | else 213 | callbackData->movementFlags &= ~(uint32_t)CallbackData::MovementKindBits::eDeccel; 214 | 215 | break; 216 | } 217 | #if (DBG_KEY_TESTING == 1) 218 | case KeyCode::eEnter: 219 | { 220 | printf("Enter %s\n", keyStatus); 221 | break; 222 | } 223 | case KeyCode::eRCtrl: 224 | { 225 | printf("RCtrl %s\n", keyStatus); 226 | break; 227 | } 228 | case KeyCode::eRShift: 229 | { 230 | printf("RShift %s\n", keyStatus); 231 | break; 232 | } 233 | case KeyCode::eLAlt: 234 | { 235 | printf("LAlt %s\n", keyStatus); 236 | break; 237 | } 238 | case KeyCode::eRAlt: 239 | { 240 | printf("RAlt %s\n", keyStatus); 241 | break; 242 | } 243 | default: 244 | { 245 | printf("Key %d %s\n", (int)keyCode, keyStatus); 246 | break; 247 | } 248 | #endif 249 | } 250 | } 251 | 252 | void mouseEventCallback(void * pUserData, windows::MouseEvent mouseEvent) 253 | { 254 | if (!pUserData) 255 | return; 256 | 257 | CallbackData * callbackData = reinterpret_cast(pUserData); 258 | App * app = callbackData->app; 259 | 260 | if (!app) 261 | return; 262 | 263 | if (mouseEvent.type == windows::MouseEvent::Type::eMove) 264 | { 265 | callbackData->dmx += mouseEvent.dX; 266 | callbackData->dmy += mouseEvent.dY; 267 | } 268 | else if (mouseEvent.type == windows::MouseEvent::Type::eLBDown) 269 | { 270 | callbackData->lmbState = 1; 271 | } 272 | else if (mouseEvent.type == windows::MouseEvent::Type::eLBUp) 273 | { 274 | callbackData->lmbState = 0; 275 | } 276 | else if (mouseEvent.type == windows::MouseEvent::Type::eRBDown) 277 | { 278 | callbackData->mouseMode = (CallbackData::MouseMode)((uint32_t)callbackData->mouseMode + 1); 279 | if (callbackData->mouseMode == CallbackData::MouseMode::eNUM_ENTRIES) 280 | callbackData->mouseMode = CallbackData::MouseMode::eStartingMode; 281 | } 282 | else if (mouseEvent.type == windows::MouseEvent::Type::eWheel) 283 | { 284 | callbackData->dwheel += mouseEvent.dX; 285 | } 286 | } 287 | 288 | class CubeMesh 289 | { 290 | vulkan::Mesh * m_mesh = nullptr; 291 | 292 | public: 293 | 294 | void init(vulkan::Mesh * mesh, const math::Vec3 & offset, const math::Vec3 & cubeSize, const math::Vec4 & color) 295 | { 296 | using namespace math; 297 | 298 | m_mesh = mesh; 299 | 300 | const size_t numVertices = 24; 301 | std::vector vertices; 302 | vertices.resize(numVertices); 303 | 304 | const size_t numIndices = 36; 305 | std::vector indices; 306 | indices.resize(numIndices); 307 | 308 | m_mesh->initBuffers( 309 | vulkan::BufferUsage::eStatic, (uint32_t)numVertices, sizeof(vulkan::Vertex), 310 | vulkan::BufferUsage::eStatic, (uint32_t)numIndices 311 | ); 312 | 313 | Mat44 modelMatrix; 314 | modelMatrix.identity(); 315 | modelMatrix.fillTranslation(offset); 316 | m_mesh->setModelMatrix(modelMatrix); 317 | 318 | auto finalizeFace = [&vertices](int vtxOffset, const Vec3 & offset, const Vec3 & normal, const Vec4 & faceColor) 319 | { 320 | vertices[vtxOffset+0].pos += offset; 321 | vertices[vtxOffset+1].pos += offset; 322 | vertices[vtxOffset+2].pos += offset; 323 | vertices[vtxOffset+3].pos += offset; 324 | 325 | vertices[vtxOffset+0].nrm = normal; 326 | vertices[vtxOffset+1].nrm = normal; 327 | vertices[vtxOffset+2].nrm = normal; 328 | vertices[vtxOffset+3].nrm = normal; 329 | 330 | vertices[vtxOffset+0].col = faceColor; 331 | vertices[vtxOffset+1].col = faceColor; 332 | vertices[vtxOffset+2].col = faceColor; 333 | vertices[vtxOffset+3].col = faceColor; 334 | 335 | vertices[vtxOffset+0].tc = Vec2C( 0.0f, 0.0f); 336 | vertices[vtxOffset+1].tc = Vec2C( 1.0f, 0.0f); 337 | vertices[vtxOffset+2].tc = Vec2C( 1.0f, 1.0f); 338 | vertices[vtxOffset+3].tc = Vec2C( 0.0f, 1.0f); 339 | }; 340 | 341 | Vec3 vecOffset = Vec3C(0.0f, 0.0f, 0.0f); 342 | 343 | // Vertices 344 | // Front 345 | vertices[ 0].pos = Vec3C(-cubeSize.x, -cubeSize.y, cubeSize.z); 346 | vertices[ 1].pos = Vec3C(-cubeSize.x, cubeSize.y, cubeSize.z); 347 | vertices[ 2].pos = Vec3C( cubeSize.x, cubeSize.y, cubeSize.z); 348 | vertices[ 3].pos = Vec3C( cubeSize.x, -cubeSize.y, cubeSize.z); 349 | finalizeFace( 0, vecOffset, Vec3C( 0.0f, 0.0f, 1.0f), color); 350 | 351 | // Back 352 | vertices[ 4].pos = Vec3C(-cubeSize.x, -cubeSize.y, -cubeSize.z); 353 | vertices[ 5].pos = Vec3C(-cubeSize.x, cubeSize.y, -cubeSize.z); 354 | vertices[ 6].pos = Vec3C( cubeSize.x, cubeSize.y, -cubeSize.z); 355 | vertices[ 7].pos = Vec3C( cubeSize.x, -cubeSize.y, -cubeSize.z); 356 | finalizeFace( 4, vecOffset, Vec3C( 0.0f, 0.0f, -1.0f), color); 357 | 358 | // Left 359 | vertices[ 8].pos = Vec3C(-cubeSize.x, -cubeSize.y, -cubeSize.z); 360 | vertices[ 9].pos = Vec3C(-cubeSize.x, -cubeSize.y, cubeSize.z); 361 | vertices[10].pos = Vec3C(-cubeSize.x, cubeSize.y, cubeSize.z); 362 | vertices[11].pos = Vec3C(-cubeSize.x, cubeSize.y, -cubeSize.z); 363 | finalizeFace( 8, vecOffset, Vec3C(-1.0f, 0.0f, 0.0f), color); 364 | 365 | // Right 366 | vertices[12].pos = Vec3C( cubeSize.x, -cubeSize.y, -cubeSize.z); 367 | vertices[13].pos = Vec3C( cubeSize.x, -cubeSize.y, cubeSize.z); 368 | vertices[14].pos = Vec3C( cubeSize.x, cubeSize.y, cubeSize.z); 369 | vertices[15].pos = Vec3C( cubeSize.x, cubeSize.y, -cubeSize.z); 370 | finalizeFace(12, vecOffset, Vec3C( 1.0f, 0.0f, 0.0f), color); 371 | 372 | // Top 373 | vertices[16].pos = Vec3C(-cubeSize.x, cubeSize.y, -cubeSize.z); 374 | vertices[17].pos = Vec3C(-cubeSize.x, cubeSize.y, cubeSize.z); 375 | vertices[18].pos = Vec3C( cubeSize.x, cubeSize.y, cubeSize.z); 376 | vertices[19].pos = Vec3C( cubeSize.x, cubeSize.y, -cubeSize.z); 377 | finalizeFace(16, vecOffset, Vec3C( 0.0f, 1.0f, 0.0f), color); 378 | 379 | // Bottom 380 | vertices[20].pos = Vec3C(-cubeSize.x, -cubeSize.y, -cubeSize.z); 381 | vertices[21].pos = Vec3C(-cubeSize.x, -cubeSize.y, cubeSize.z); 382 | vertices[22].pos = Vec3C( cubeSize.x, -cubeSize.y, cubeSize.z); 383 | vertices[23].pos = Vec3C( cubeSize.x, -cubeSize.y, -cubeSize.z); 384 | finalizeFace(20, vecOffset, Vec3C( 0.0f, -1.0f, 0.0f), color); 385 | 386 | // Indices 387 | int vtxOffset; 388 | int idxOffset; 389 | 390 | // Front 391 | vtxOffset = 0; 392 | idxOffset = 0; 393 | indices[idxOffset+0] = vtxOffset + 0; indices[idxOffset+1] = vtxOffset + 1; indices[idxOffset+2] = vtxOffset + 2; 394 | indices[idxOffset+3] = vtxOffset + 0; indices[idxOffset+4] = vtxOffset + 2; indices[idxOffset+5] = vtxOffset + 3; 395 | 396 | // Back 397 | vtxOffset = 4; 398 | idxOffset = 6; 399 | indices[idxOffset+0] = vtxOffset + 0; indices[idxOffset+1] = vtxOffset + 2; indices[idxOffset+2] = vtxOffset + 1; 400 | indices[idxOffset+3] = vtxOffset + 0; indices[idxOffset+4] = vtxOffset + 3; indices[idxOffset+5] = vtxOffset + 2; 401 | 402 | // Left 403 | vtxOffset = 8; 404 | idxOffset = 12; 405 | indices[idxOffset+0] = vtxOffset + 0; indices[idxOffset+1] = vtxOffset + 2; indices[idxOffset+2] = vtxOffset + 1; 406 | indices[idxOffset+3] = vtxOffset + 0; indices[idxOffset+4] = vtxOffset + 3; indices[idxOffset+5] = vtxOffset + 2; 407 | 408 | // Right 409 | vtxOffset = 12; 410 | idxOffset = 18; 411 | indices[idxOffset+0] = vtxOffset + 0; indices[idxOffset+1] = vtxOffset + 1; indices[idxOffset+2] = vtxOffset + 2; 412 | indices[idxOffset+3] = vtxOffset + 0; indices[idxOffset+4] = vtxOffset + 2; indices[idxOffset+5] = vtxOffset + 3; 413 | 414 | // Top 415 | vtxOffset = 16; 416 | idxOffset = 24; 417 | indices[idxOffset+0] = vtxOffset + 0; indices[idxOffset+1] = vtxOffset + 2; indices[idxOffset+2] = vtxOffset + 1; 418 | indices[idxOffset+3] = vtxOffset + 0; indices[idxOffset+4] = vtxOffset + 3; indices[idxOffset+5] = vtxOffset + 2; 419 | 420 | // Bottom 421 | vtxOffset = 20; 422 | idxOffset = 30; 423 | indices[idxOffset+0] = vtxOffset + 0; indices[idxOffset+1] = vtxOffset + 1; indices[idxOffset+2] = vtxOffset + 2; 424 | indices[idxOffset+3] = vtxOffset + 0; indices[idxOffset+4] = vtxOffset + 2; indices[idxOffset+5] = vtxOffset + 3; 425 | 426 | m_mesh->updateVertexBuffer(vertices.data()); 427 | m_mesh->updateIndexBuffer(indices.data()); 428 | } 429 | }; 430 | 431 | struct ExtDrawLine 432 | { 433 | math::Vec3 p0; 434 | math::Vec3 p1; 435 | math::Vec4 c0; 436 | math::Vec4 c1; 437 | }; 438 | struct ExtDrawPoint 439 | { 440 | math::Vec3 p; 441 | math::Vec4 c; 442 | }; 443 | 444 | std::vector g_simLines; 445 | std::vector g_simPoints; 446 | 447 | void simResetDrawing() 448 | { 449 | g_simLines.resize(0); 450 | g_simPoints.resize(0); 451 | } 452 | void simDrawLine(const math::Vec3 & p0, const math::Vec3 & p1, const math::Vec4 & c0, const math::Vec4 & c1) 453 | { 454 | g_simLines.push_back({ p0, p1, c0, c1 }); 455 | } 456 | void simDrawPoint(const math::Vec3 & p, const math::Vec4 & c) 457 | { 458 | g_simPoints.push_back({ p, c }); 459 | } 460 | 461 | void projPerspective(float fovRad, float aspect, float zNear, float zFar, float width, float height, math::Mat44 * projection) 462 | { 463 | projection->zero(); 464 | 465 | math::Vec2 scale; 466 | scale.x = width * 1.0f / tanf(fovRad / 2); 467 | scale.y = height * aspect * scale.x; 468 | 469 | float zDiff = zNear - zFar; 470 | float m[] = { 471 | scale.x, 0, 0, 0, 472 | 0, scale.y, 0, 0, 473 | 0, 0, (zFar + zNear) / zDiff, 2*zFar*zNear / zDiff, 474 | 0, 0, -1, 0 475 | }; 476 | memcpy(projection->m, m, sizeof(float)*16); 477 | } 478 | 479 | int main() 480 | { 481 | using namespace windows; 482 | using namespace math; 483 | 484 | Timer perfTimer; 485 | 486 | Window window; 487 | window.setParameters(800, 600, Window::Kind::eWindowed); 488 | window.init(); 489 | 490 | MSG msg; 491 | 492 | physics::g_simCallbacks.resetDrawingFn = simResetDrawing; 493 | physics::g_simCallbacks.drawLineFn = simDrawLine; 494 | physics::g_simCallbacks.drawPointFn = simDrawPoint; 495 | 496 | vulkan::Wrapper renderManager; 497 | renderManager.setDebugCallback(debugCallback); 498 | 499 | App sampleApp; 500 | sampleApp.setRenderManager(&renderManager); 501 | sampleApp.init(window.getHWnd(), window.getWidth(), window.getHeight()); 502 | sampleApp.setWindowTitle(L"Vulkan app"); 503 | 504 | CallbackData callbackData = {}; 505 | callbackData.app = &sampleApp; 506 | callbackData.movementFlags = 0; 507 | callbackData.isActive = true; 508 | callbackData.isPaused = false;//true; 509 | callbackData.isAnimStep = false; 510 | callbackData.reqDropBox = false; 511 | getMouseCoordinates(&callbackData.mx, &callbackData.my); 512 | callbackData.dmx = 0; 513 | callbackData.dmy = 0; 514 | callbackData.dwheel = 0; 515 | callbackData.mouseMode = CallbackData::MouseMode::eStartingMode; 516 | callbackData.lmbState = 0; 517 | hideMouse(); 518 | 519 | setUserDataPointer(&callbackData); 520 | setResizeCallback(resizeCallback); 521 | setChangeFocusCallback(chageFocusCallback); 522 | setChangeActiveCallback(chageActiveCallback); 523 | setKeyStateCallback(keyStateCallback); 524 | setMouseEventCallback(mouseEventCallback); 525 | 526 | Camera mainCamera; 527 | mainCamera.setPosition(Vec3C(0.0f, 2.0f, 10.0f)); 528 | 529 | #if 0 530 | const Vec3 basisOffset = Vec3C(1.0f, 0.0f, 0.0f); 531 | const Vec2 basisHalfSize = Vec2C(0.5f, 0.02f); 532 | CubeMesh basisMesh[3]; 533 | basisMesh[0].init(renderManager.createMesh(), basisOffset+Vec3C(0.5f-basisHalfSize.y, 0.0f, 0.0f), Vec3C(basisHalfSize.x, basisHalfSize.y, basisHalfSize.y), Vec4C(1.0f, 0.0f, 0.0f, 1.0f)); 534 | basisMesh[1].init(renderManager.createMesh(), basisOffset+Vec3C(0.0f, 0.5f-basisHalfSize.y, 0.0f), Vec3C(basisHalfSize.y, basisHalfSize.x, basisHalfSize.y), Vec4C(0.0f, 1.0f, 0.0f, 1.0f)); 535 | basisMesh[2].init(renderManager.createMesh(), basisOffset+Vec3C(0.0f, 0.0f, 0.5f-basisHalfSize.y), Vec3C(basisHalfSize.y, basisHalfSize.y, basisHalfSize.x), Vec4C(0.0f, 0.0f, 1.0f, 1.0f)); 536 | 537 | const bool renderUnitCubeMesh = false; 538 | if (renderUnitCubeMesh) 539 | { 540 | CubeMesh unitCubeMesh; 541 | unitCubeMesh.init(renderManager.createMesh(), Vec3C(.0f, .0f, .0f), Vec3C(.4f, .4f, .4f), Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 542 | } 543 | 544 | const bool renderShadowMapBiasTestingMeshes = true; 545 | if (renderShadowMapBiasTestingMeshes) 546 | { 547 | CubeMesh shadowTestMesh01; 548 | shadowTestMesh01.init(renderManager.createMesh(), Vec3C(-2.5f, -0.5f, 0.0f), Vec3C(0.1f, 1.0f, 1.0f), Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 549 | CubeMesh shadowTestMesh02; 550 | shadowTestMesh02.init(renderManager.createMesh(), Vec3C( 0.0f, -0.5f, 2.0f), Vec3C(0.05f, 1.0f, 0.05f), Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 551 | } 552 | 553 | const Vec3 floorSize = Vec3C(10.0f, 0.5f, 10.0f); 554 | CubeMesh floorMesh; 555 | floorMesh.init(renderManager.createMesh(), Vec3C(0.0f, -2.0f, 0.0f), floorSize, Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 556 | #endif 557 | 558 | // Light setup 559 | renderManager.setLightPerspProjParams(PI * 0.5f, 1.0f, 0.1f, 100.0f, 1.0f, 1.0f); 560 | 561 | #if (ENABLE_PHYSICS == 1) 562 | 563 | // FEM stress test similar visual stiffness: LCPCG 36ms, 40iter; PGS 100ms, 260iter; 564 | //physics::SolverPGS FEMTestSolver(20, 1e-10f); 565 | //physics::SolverPGSOrdered FEMTestSolver(20, 1e-10f); 566 | physics::SolverLCPCG FEMTestSolver(20, 1e-10f); 567 | //physics::SolverNNCG FEMTestSolver(40, 1e-10f); 568 | 569 | FEMTestSolver.setInitialGuessCutFlag(false); 570 | FEMTestSolver.setInitialGuessCutThreshold(0.0f); 571 | 572 | float pickingDistance = 0.0f; 573 | physics::JointBase * pickingJoint = nullptr; 574 | 575 | physics::initPhysics(); 576 | 577 | // Scene selection 578 | #if 0 579 | sceneSample(FEMTestSolver); 580 | #elif 0 581 | sceneSimpleBallsocket(FEMTestSolver); 582 | #elif 0 583 | sceneBallSocketCoMTest(FEMTestSolver); 584 | #elif 0 585 | sceneBoxContact(FEMTestSolver); 586 | #elif 0 587 | sceneCompoundBodyTest(FEMTestSolver); 588 | #elif 0 589 | sceneSpinningTest(FEMTestSolver); 590 | #elif 0 591 | sceneGyro(FEMTestSolver); 592 | #elif 1 593 | // Collision test 594 | sceneStackCollisionTest(FEMTestSolver); 595 | #elif 0 596 | sceneStackCollisionTestMassive(FEMTestSolver); 597 | #elif 0 598 | sceneShapesCollisionTest(FEMTestSolver); 599 | #elif 0 600 | // For local mass scale options, check 601 | // const bool applyLocalMassScale = true; 602 | // const float localMassScaleRatio = 1.2f; 603 | // in the test setup function 604 | 605 | // For CG-based solver, increased number of iterations recommended (base iter 40+) 606 | 607 | sceneJointsTest(FEMTestSolver); 608 | #elif 0 609 | sceneFEMBeam(FEMTestSolver); 610 | #elif 0 611 | sceneFEMBeamSwirl(FEMTestSolver); 612 | #elif 0 613 | sceneFEMChain(FEMTestSolver); 614 | #elif 0 615 | sceneFEMPlayground(FEMTestSolver); 616 | #endif 617 | 618 | #endif 619 | 620 | vulkan::LinePoint auxP0, auxP1; 621 | auxP0.col = Vec4C(1.0f, 1.0f, 1.0f, 1.0f); 622 | auxP1.col = Vec4C(1.0f, 1.0f, 1.0f, 1.0f); 623 | 624 | auto drawPoint = [&renderManager, &auxP0, &auxP1](const Vec3 & pos, const Vec4C & color = Vec4C(1.0f, 0.0f, 0.0f, 1.0f)) 625 | { 626 | auxP0.col = color; 627 | auxP1.col = color; 628 | 629 | const Vec3 size = Vec3C(0.1f, 0.1f, 0.1f); 630 | auxP0.pos = pos - Vec3C(size.x, 0.0f, 0.0f); 631 | auxP1.pos = pos + Vec3C(size.x, 0.0f, 0.0f); 632 | renderManager.m_debugLines.push_back(auxP0); 633 | renderManager.m_debugLines.push_back(auxP1); 634 | auxP0.pos = pos - Vec3C(0.0f, size.y, 0.0f); 635 | auxP1.pos = pos + Vec3C(0.0f, size.y, 0.0f); 636 | renderManager.m_debugLines.push_back(auxP0); 637 | renderManager.m_debugLines.push_back(auxP1); 638 | auxP0.pos = pos - Vec3C(0.0f, 0.0f, size.z); 639 | auxP1.pos = pos + Vec3C(0.0f, 0.0f, size.z); 640 | renderManager.m_debugLines.push_back(auxP0); 641 | renderManager.m_debugLines.push_back(auxP1); 642 | }; 643 | 644 | auto drawLine = [&renderManager, &auxP0, &auxP1](const Vec3 & pos0, const Vec3 & pos1, const Vec4 & color = Vec4C(1.0f, 1.0f, 0.0f, 1.0f)) 645 | { 646 | auxP0.col = color; 647 | auxP1.col = color; 648 | 649 | auxP0.pos = pos0; 650 | auxP1.pos = pos1; 651 | renderManager.m_debugLines.push_back(auxP0); 652 | renderManager.m_debugLines.push_back(auxP1); 653 | }; 654 | 655 | auto drawLineAux = [&renderManager](const vulkan::LinePoint & p0, const vulkan::LinePoint & p1) 656 | { 657 | renderManager.m_debugLines.push_back(p0); 658 | renderManager.m_debugLines.push_back(p1); 659 | }; 660 | 661 | // Preparing rendering arrays 662 | // In this debug-oriented playground, the rendering is happening using the debug 663 | // renderering mode, which is similar to immediate mode rendering in older graphics 664 | // APIs, and this method is not exactly the best performance-wise. 665 | // TODO: use CubeMesh and the like to render physics objects 666 | std::vector unitBoxVertices; 667 | std::vector unitSphereVertices; 668 | std::vector unitHemiSphereVertices; 669 | std::vector unitCylinderVertices; 670 | std::vector unitConeVertices; 671 | std::vector unitDiskVertices; 672 | 673 | const Vec4 whiteColor = Vec4C(1.0f, 1.0f, 1.0f, 1.0f); 674 | buildBoxVertices(&unitBoxVertices, Mat34().identity(), Vec3C(1.0f, 1.0f, 1.0f), whiteColor); 675 | buildSphereVertices(&unitSphereVertices, Mat34().identity(), 1.0f, whiteColor); 676 | buildHemiSphereVertices(&unitHemiSphereVertices, Mat34().identity(), 1.0f, whiteColor); 677 | buildCylinderVertices(&unitCylinderVertices, Mat34().identity(), 1.0f, 1.0f, whiteColor); 678 | buildConeVertices(&unitConeVertices, Mat34().identity(), 1.0f, 1.0f, whiteColor); 679 | buildDiskVertices(&unitDiskVertices, Mat34().identity(), 1.0f, whiteColor, true); 680 | 681 | // Scale could be incorporated into transform, but for the sake of convenience 682 | // scale is passed as a separate argument 683 | auto drawVerticesScaled = [&renderManager](const std::vector & inVertices, const Mat34 & transform, const Vec3 & scale) 684 | { 685 | const size_t vtxNum = inVertices.size(); 686 | const vulkan::Vertex * vertices = inVertices.data(); 687 | 688 | const size_t numStartVertices = renderManager.m_debugTris.size(); 689 | renderManager.m_debugTris.resize(numStartVertices + inVertices.size()); 690 | vulkan::Vertex * debugTrisVertices = &renderManager.m_debugTris[numStartVertices]; 691 | 692 | vulkan::Vertex curVertex; 693 | for (size_t vi = 0; vi < vtxNum; ++vi) 694 | { 695 | curVertex = vertices[vi]; 696 | curVertex.pos = transform * Vec3C(scale.x * curVertex.pos.x, scale.y * curVertex.pos.y, scale.z * curVertex.pos.z); 697 | curVertex.nrm = transform.rotateCopy(curVertex.nrm); 698 | debugTrisVertices[vi] = curVertex; 699 | } 700 | }; 701 | 702 | double physicsTime = 0.0; 703 | double accumTimeMS = 0.0; 704 | int accumFrames = 0; 705 | perfTimer.start(); 706 | double dtMS = 0.0; 707 | 708 | int internalMouseX = window.getWidth() / 2, internalMouseY = window.getHeight() / 2; 709 | 710 | bool isRunning = true; 711 | while (isRunning) 712 | { 713 | while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 714 | { 715 | TranslateMessage(&msg); 716 | DispatchMessage(&msg); 717 | if (msg.message == WM_QUIT) 718 | { 719 | isRunning = false; 720 | break; 721 | } 722 | } 723 | 724 | if (sampleApp.getIsExitting()) 725 | { 726 | isRunning = false; 727 | } 728 | 729 | if (!isRunning) 730 | { 731 | break; 732 | } 733 | 734 | if (callbackData.isActive) 735 | { 736 | int nmx, nmy; 737 | getMouseCoordinates(&nmx, &nmy); 738 | setMouseCoordinates(callbackData.mx, callbackData.my); 739 | 740 | float sens = 0.01f; 741 | float movementSpeed = 0.005f; 742 | Vec3 posOffset = Vec3C(0.0f, 0.0f, 0.0f); 743 | 744 | const float movementAccelFactor = 5.0f; 745 | const float movementDeccelFactor = 0.2f; 746 | if (callbackData.movementFlags & (uint32_t)CallbackData::MovementKindBits::eAccel) 747 | { 748 | movementSpeed *= movementAccelFactor; 749 | } 750 | if (callbackData.movementFlags & (uint32_t)CallbackData::MovementKindBits::eDeccel) 751 | { 752 | movementSpeed *= movementDeccelFactor; 753 | } 754 | 755 | if (callbackData.movementFlags & (uint32_t)CallbackData::MovementKindBits::eForward) 756 | { 757 | posOffset.z -= movementSpeed; 758 | } 759 | if (callbackData.movementFlags & (uint32_t)CallbackData::MovementKindBits::eBackward) 760 | { 761 | posOffset.z += movementSpeed; 762 | } 763 | if (callbackData.movementFlags & (uint32_t)CallbackData::MovementKindBits::eLeft) 764 | { 765 | posOffset.x -= movementSpeed; 766 | } 767 | if (callbackData.movementFlags & (uint32_t)CallbackData::MovementKindBits::eRight) 768 | { 769 | posOffset.x += movementSpeed; 770 | } 771 | if (callbackData.movementFlags & (uint32_t)CallbackData::MovementKindBits::eDown) 772 | { 773 | posOffset.y -= movementSpeed; 774 | } 775 | if (callbackData.movementFlags & (uint32_t)CallbackData::MovementKindBits::eUp) 776 | { 777 | posOffset.y += movementSpeed; 778 | } 779 | 780 | if (callbackData.dwheel != 0) 781 | { 782 | float fovRad = renderManager.getViewFOV(); 783 | fovRad += callbackData.dwheel * 0.1f; 784 | fovRad = clamp(fovRad, PI / 4.0f, PI / 1.5f); 785 | renderManager.setViewFOV(fovRad); 786 | } 787 | 788 | #if (MOUSE_USE_RAWINPUT == 1) 789 | int dMouseX = callbackData.dmx; 790 | int dMouseY = callbackData.dmy; 791 | 792 | callbackData.dmx = 0; 793 | callbackData.dmy = 0; 794 | 795 | callbackData.dwheel = 0; 796 | #else 797 | int dMouseX = nmx - callbackData.mx; 798 | int dMouseY = nmy - callbackData.my; 799 | #endif 800 | 801 | if (callbackData.mouseMode == CallbackData::MouseMode::ePicking) 802 | { 803 | internalMouseX += dMouseX; 804 | if (internalMouseX < 0) 805 | internalMouseX = 0; 806 | if (internalMouseX > (int)window.getWidth()-1) 807 | internalMouseX = (int)window.getWidth()-1; 808 | internalMouseY -= dMouseY; 809 | if (internalMouseY < 0) 810 | internalMouseY = 0; 811 | if (internalMouseY > (int)window.getHeight()-1) 812 | internalMouseY = (int)window.getHeight()-1; 813 | 814 | // Mouse used for picking, do not propagate these values to the camera 815 | dMouseX = 0; 816 | dMouseY = 0; 817 | } 818 | mainCamera.update((float)dtMS * posOffset, sens*dMouseX, sens*dMouseY); 819 | mainCamera.fillMatrix(&renderManager.getViewMatrix()); 820 | } 821 | 822 | { 823 | Mat44 lightView, lightProj; 824 | 825 | const Vec3 lightPos = Vec3C(10.0f * sinf((float)sampleApp.getElapsedTime() * 0.001f), 3.0f, 3.0f); 826 | const Vec3 lightDir = Vec3C(0.0f, 0.0f, 0.0f); 827 | 828 | Vec3 lightRight, lightUp, lightViewDir; 829 | lightViewDir = -(lightDir - lightPos).normalize(); 830 | lightRight = Vec3C(0.0f, 1.0f, 0.0f).cross(lightViewDir).normalize(); 831 | lightUp = lightViewDir.cross(lightRight).normalize(); 832 | lightView.setBasis0(lightRight); 833 | lightView.setBasis1(lightUp); 834 | lightView.setBasis2(lightViewDir); 835 | lightView.setBasis3(lightPos); 836 | lightView = lightView.invertRTCopy(); 837 | 838 | renderManager.setLightViewMatrix(lightView); 839 | 840 | const bool renderLightFrustum = true; 841 | if (renderLightFrustum) 842 | { 843 | float fovRad, aspect, zNear, zFar, width, height; 844 | renderManager.getLightPerspProjParams(&fovRad, &aspect, &zNear, &zFar, &width, &height); 845 | projPerspective(fovRad, aspect, zNear, zFar, width, height, &lightProj); 846 | 847 | Vec3 meshOBBMin = Vec3C(-1.0f, -1.0f, -1.0f), meshOBBMax = Vec3C(1.0f, 1.0f, 1.0f); 848 | 849 | Mat44 lightMatrixInv = lightProj * lightView; 850 | lightMatrixInv.invert(); 851 | 852 | Vec3 meshOBB[8]; 853 | meshOBB[0] = lightMatrixInv.homogTransformCopy(Vec3C(meshOBBMin.x, meshOBBMin.y, meshOBBMin.z)); 854 | meshOBB[1] = lightMatrixInv.homogTransformCopy(Vec3C(meshOBBMax.x, meshOBBMin.y, meshOBBMin.z)); 855 | meshOBB[2] = lightMatrixInv.homogTransformCopy(Vec3C(meshOBBMax.x, meshOBBMax.y, meshOBBMin.z)); 856 | meshOBB[3] = lightMatrixInv.homogTransformCopy(Vec3C(meshOBBMin.x, meshOBBMax.y, meshOBBMin.z)); 857 | meshOBB[4] = lightMatrixInv.homogTransformCopy(Vec3C(meshOBBMin.x, meshOBBMin.y, meshOBBMax.z)); 858 | meshOBB[5] = lightMatrixInv.homogTransformCopy(Vec3C(meshOBBMax.x, meshOBBMin.y, meshOBBMax.z)); 859 | meshOBB[6] = lightMatrixInv.homogTransformCopy(Vec3C(meshOBBMax.x, meshOBBMax.y, meshOBBMax.z)); 860 | meshOBB[7] = lightMatrixInv.homogTransformCopy(Vec3C(meshOBBMin.x, meshOBBMax.y, meshOBBMax.z)); 861 | 862 | vulkan::LinePoint lp0, lp1; 863 | lp0.col = Vec4C(1.0f, 1.0f, 0.0f, 1.0f); 864 | lp1.col = Vec4C(1.0f, 1.0f, 0.0f, 1.0f); 865 | 866 | auto addLine = [&renderManager, &lp0, &lp1](const Vec3 & pos0, const Vec3 & pos1) 867 | { 868 | lp0.pos = pos0; 869 | lp1.pos = pos1; 870 | renderManager.m_debugLines.push_back(lp0); 871 | renderManager.m_debugLines.push_back(lp1); 872 | }; 873 | 874 | { 875 | addLine(meshOBB[0], meshOBB[1]); 876 | addLine(meshOBB[1], meshOBB[2]); 877 | addLine(meshOBB[2], meshOBB[3]); 878 | addLine(meshOBB[3], meshOBB[0]); 879 | 880 | addLine(meshOBB[4], meshOBB[5]); 881 | addLine(meshOBB[5], meshOBB[6]); 882 | addLine(meshOBB[6], meshOBB[7]); 883 | addLine(meshOBB[7], meshOBB[4]); 884 | 885 | addLine(meshOBB[0], meshOBB[4]); 886 | addLine(meshOBB[1], meshOBB[5]); 887 | addLine(meshOBB[2], meshOBB[6]); 888 | addLine(meshOBB[3], meshOBB[7]); 889 | } 890 | } 891 | } 892 | 893 | #if (ENABLE_PHYSICS == 1) 894 | // UPDATE 895 | const float solver_dt = 0.016f; 896 | if (physicsTime > solver_dt || callbackData.isAnimStep) 897 | { 898 | // The updateSim function includes calls to all the default high-level functions of the 899 | // physics simulation code, such as collision detection, cntact cache matching, dynamics 900 | // simulation, etc. They all operate on concepts defined in the Core physics framework, 901 | // and could easily be modified to e.g. inject custom contacts, or broadphase candidates, 902 | // or change the MLCP solve scheme. 903 | physics::updateSim(&FEMTestSolver, callbackData.isPaused ? 0.0f : solver_dt); 904 | // Do not accumulate time 905 | physicsTime = 0.0; 906 | } 907 | 908 | // DRAW 909 | // Current physics joint rendering code is weak - it uses lower level joint blocks, and hence 910 | // cannot properly anchor hinge axis and stuff like that. 911 | // TODO: introduce higher level joints that wrap several low level blocks. 912 | for (size_t iJoint = 0, iJointEnd = physics::g_joints.size(); iJoint < iJointEnd; ++iJoint) 913 | { 914 | physics::JointBase * curJoint = physics::g_joints[iJoint]; 915 | physics::JointBase::Type jointType = curJoint->getType(); 916 | 917 | if (jointType == physics::JointBase::Type::eBallSocket) 918 | { 919 | physics::BallSocket * curBallSocket = static_cast(curJoint); 920 | 921 | Mat34 rotMatrix; 922 | rotMatrix.identity(); 923 | 924 | Vec3 b0_AnchorBS, b1_AnchorBS; 925 | 926 | Vec3 b0_comPos, b1_comPos; 927 | Vec3 b0_originPos, b1_originPos; 928 | Vec3 b0_AnchorWS, b1_AnchorWS; 929 | 930 | curBallSocket->getAnchorPoints_BS(b0_AnchorBS, b1_AnchorBS); 931 | 932 | b0_comPos = curBallSocket->getBody0L()->m_pos; 933 | 934 | physics::NodeRotational * body0Rot = curBallSocket->getBody0R(); 935 | rotMatrix = math::Quat::toMatrix33(body0Rot->m_rot); 936 | 937 | b0_originPos = b0_comPos + rotMatrix * (-body0Rot->m_com); 938 | b0_AnchorWS = b0_comPos + rotMatrix * (b0_AnchorBS - body0Rot->m_com); 939 | 940 | drawLine(b0_originPos, b0_AnchorWS); 941 | drawPoint(b0_AnchorWS); 942 | 943 | physics::NodeTranslational * body1L = curBallSocket->getBody1L(); 944 | physics::NodeRotational * body1Rot = curBallSocket->getBody1R(); 945 | if (body1L) 946 | { 947 | b1_comPos = body1L->m_pos; 948 | b1_originPos = b1_comPos; 949 | } 950 | if (body1Rot) 951 | { 952 | rotMatrix = math::Quat::toMatrix33(body1Rot->m_rot); 953 | 954 | b1_originPos = b1_comPos + rotMatrix * (-body1Rot->m_com); 955 | b1_AnchorWS = b1_comPos + rotMatrix * (b1_AnchorBS - body1Rot->m_com); 956 | 957 | drawLine(b1_originPos, b1_AnchorWS); 958 | drawPoint(b1_AnchorWS); 959 | } 960 | } 961 | if (jointType == physics::JointBase::Type::eSlider) 962 | { 963 | physics::Slider * curSlider = static_cast(curJoint); 964 | 965 | const float axisHalfLen = 1.0f; 966 | 967 | Vec3 wAxis0 = curSlider->getWorldAxis0(); 968 | drawLine(curSlider->getBody0L()->m_pos - axisHalfLen*wAxis0, curSlider->getBody0L()->m_pos + axisHalfLen*wAxis0, Vec4C(0.0f, 1.0f, 1.0f, 1.0f)); 969 | 970 | physics::NodeTranslational * body1L = curSlider->getBody1L(); 971 | physics::NodeRotational * body1Rot = curSlider->getBody1R(); 972 | if (body1L) 973 | { 974 | Vec3 wAxis1 = curSlider->getWorldAxis1(); 975 | drawLine(body1L->m_pos - axisHalfLen*wAxis1, body1L->m_pos + axisHalfLen*wAxis1, Vec4C(0.0f, 1.0f, 1.0f, 1.0f)); 976 | } 977 | } 978 | else if (jointType == physics::JointBase::Type::ePlane) 979 | { 980 | physics::PlaneConstraint * curPlaneConstraint = static_cast(curJoint); 981 | 982 | if (!curPlaneConstraint->m_bActive) continue; 983 | 984 | Vec3 NodePos = curPlaneConstraint->m_bodyL->m_pos; 985 | Vec3 plLambda = curPlaneConstraint->m_PlaneNormal * curPlaneConstraint->getLambda(0); 986 | 987 | //float color = fabsf(itPlaneJ->m_Violation); 988 | float color = fabsf(FEMTestSolver.m_resid[curPlaneConstraint->m_startIdx]) * 1000.0f; 989 | 990 | drawLine(NodePos, NodePos+plLambda, Vec4C(0.7f, color * 0.25f, color * 0.5f, 1.0f)); 991 | } 992 | else if (jointType == physics::JointBase::Type::eFEM) 993 | { 994 | physics::FEMJoint * curFEMJoint = static_cast(curJoint); 995 | #if 0 996 | drawLine(curFEMJoint->getNode0()->m_pos, curFEMJoint->getNode1()->m_pos, Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 997 | drawLine(curFEMJoint->getNode0()->m_pos, curFEMJoint->getNode2()->m_pos, Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 998 | drawLine(curFEMJoint->getNode0()->m_pos, curFEMJoint->getNode3()->m_pos, Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 999 | //drawLine(curFEMJoint->getNode0()->m_pos, curFEMJoint->getNode1()->m_pos, Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 1000 | #else 1001 | vulkan::Vertex faceVtx; 1002 | 1003 | float FEstrain = curFEMJoint->m_strainNorm * 10.0f; 1004 | faceVtx.col = Vec4C( 1005 | clamp(1.0f + FEstrain, 0.0f, 1.0f), 1006 | clamp(1.0f - FEstrain * 0.5f, 0.0f, 1.0f), 1007 | clamp(1.0f - FEstrain * 0.5f, 0.0f, 1.0f), 1008 | 1.0f 1009 | ); 1010 | 1011 | physics::NodeTranslational * n0 = curFEMJoint->getNode0(); 1012 | physics::NodeTranslational * n1 = curFEMJoint->getNode1(); 1013 | physics::NodeTranslational * n2 = curFEMJoint->getNode2(); 1014 | physics::NodeTranslational * n3 = curFEMJoint->getNode3(); 1015 | 1016 | auto addTetraFace = [&renderManager]( 1017 | vulkan::Vertex & faceVtx, 1018 | const physics::NodeTranslational * n0, 1019 | const physics::NodeTranslational * n1, 1020 | const physics::NodeTranslational * n2 1021 | ) 1022 | { 1023 | Vec3 normal = (n1->m_pos - n0->m_pos).cross(n2->m_pos - n0->m_pos).getNormalized(); 1024 | 1025 | faceVtx.tc = Vec2C(0.0f, 0.0f); 1026 | faceVtx.pos = n0->m_pos; 1027 | faceVtx.nrm = normal; 1028 | renderManager.m_debugTris.push_back(faceVtx); 1029 | faceVtx.tc = Vec2C(1.0f, 0.0f); 1030 | faceVtx.pos = n1->m_pos; 1031 | faceVtx.nrm = normal; 1032 | renderManager.m_debugTris.push_back(faceVtx); 1033 | faceVtx.tc = Vec2C(0.0f, 1.0f); 1034 | faceVtx.pos = n2->m_pos; 1035 | faceVtx.nrm = normal; 1036 | renderManager.m_debugTris.push_back(faceVtx); 1037 | }; 1038 | 1039 | addTetraFace(faceVtx, n0, n2, n1); 1040 | addTetraFace(faceVtx, n0, n1, n3); 1041 | addTetraFace(faceVtx, n0, n3, n2); 1042 | addTetraFace(faceVtx, n1, n2, n3); 1043 | #endif 1044 | } 1045 | else if (jointType == physics::JointBase::Type::eFEM_BallSocket) 1046 | { 1047 | physics::BallSocket_FEM * curBSFEMJoint = static_cast(curJoint); 1048 | 1049 | Vec3 FEMAnchor = curBSFEMJoint->getFEMAnchor(); 1050 | drawLine(curBSFEMJoint->getNode0()->m_pos, FEMAnchor, Vec4C(1.0f, 0.0f, 0.0f, 1.0f)); 1051 | drawLine(curBSFEMJoint->getNode1()->m_pos, FEMAnchor, Vec4C(0.0f, 1.0f, 0.0f, 1.0f)); 1052 | drawLine(curBSFEMJoint->getNode2()->m_pos, FEMAnchor, Vec4C(0.0f, 0.0f, 1.0f, 1.0f)); 1053 | 1054 | Vec3 bodyAnchor = physics::transformOriginToWorld(curBSFEMJoint->getBodyL(), curBSFEMJoint->getBodyR(), curBSFEMJoint->getBodyAnchor()); 1055 | drawLine(curBSFEMJoint->getBodyL()->m_pos, bodyAnchor, Vec4C(1.0f, 1.0f, 0.0f, 1.0f)); 1056 | } 1057 | else if (jointType == physics::JointBase::Type::eFEM_BallSocketSimple) 1058 | { 1059 | physics::BallSocket_FEM_Simple * curBSFEMJoint = static_cast(curJoint); 1060 | 1061 | Vec3 FEMAnchor = curBSFEMJoint->getFEMAnchor(); 1062 | drawLine(curBSFEMJoint->getNode0()->m_pos, FEMAnchor, Vec4C(1.0f, 0.0f, 0.0f, 1.0f)); 1063 | drawLine(curBSFEMJoint->getNode1()->m_pos, FEMAnchor, Vec4C(0.0f, 1.0f, 0.0f, 1.0f)); 1064 | drawLine(curBSFEMJoint->getNode2()->m_pos, FEMAnchor, Vec4C(0.0f, 0.0f, 1.0f, 1.0f)); 1065 | 1066 | Vec3 bodyAnchor = physics::transformOriginToWorld(curBSFEMJoint->getBodyL(), curBSFEMJoint->getBodyR(), curBSFEMJoint->getBodyAnchor()); 1067 | if (curBSFEMJoint->getBodyL()) 1068 | drawLine(curBSFEMJoint->getBodyL()->m_pos, bodyAnchor, Vec4C(1.0f, 1.0f, 0.0f, 1.0f)); 1069 | } 1070 | } 1071 | 1072 | // Draw bodies - just a simple RGB basis at the CoM of the body (linear node position) 1073 | // Note: the CoM position may be different from the point where user originally placed 1074 | // rigid body, to transform between the world and original design spaces, use 1075 | // physics::transformWorldToOrigin/transformOriginToWorld 1076 | Vec3 wsX, wsY, wsZ; 1077 | for (size_t iNode = 0, iNodeEnd = physics::g_nodes.size() - 1; iNode < iNodeEnd; ++iNode) 1078 | { 1079 | // We need linear nodes, sequenced by rotational ones [full rigid body] 1080 | if (physics::g_nodes[iNode]->getType() != physics::Node::Type::eTranslational || physics::g_nodes[iNode+1]->getType() != physics::Node::Type::eRotational) 1081 | continue; 1082 | 1083 | physics::NodeTranslational * curNodeTrn = static_cast(physics::g_nodes[iNode]); 1084 | physics::NodeRotational * curNodeRot = static_cast(physics::g_nodes[iNode+1]); 1085 | 1086 | Mat34 Rotation; 1087 | // NOTE: x y z wF 1088 | Rotation = math::Quat::toMatrix33(curNodeRot->m_rot); 1089 | 1090 | // Get Basis 1091 | wsX = Rotation.getBasis0(); 1092 | wsY = Rotation.getBasis1(); 1093 | wsZ = Rotation.getBasis2(); 1094 | 1095 | drawLine(curNodeTrn->m_pos, curNodeTrn->m_pos + wsX, Vec4C(1.0f, 0.0f, 0.0f, 1.0f)); 1096 | drawLine(curNodeTrn->m_pos, curNodeTrn->m_pos + wsY, Vec4C(0.0f, 1.0f, 0.0f, 1.0f)); 1097 | drawLine(curNodeTrn->m_pos, curNodeTrn->m_pos + wsZ, Vec4C(0.0f, 0.0f, 1.0f, 1.0f)); 1098 | } 1099 | 1100 | // Draw geometries, geometries are included in the higher level rigid body concept 1101 | // (nodes do not have info about geometries) 1102 | for (size_t irb = 0, irbEnd = physics::g_rigidBodies.size(); irb < irbEnd; ++irb) 1103 | { 1104 | physics::RigidBody * curBody = physics::g_rigidBodies[irb]; 1105 | 1106 | Mat34 shapeTransform; 1107 | Mat34 bodyTransform; 1108 | Mat34 totalTransform; 1109 | 1110 | bodyTransform = Quat::toMatrix33(curBody->m_bodyR->m_rot); 1111 | bodyTransform.fillTranslation(curBody->m_bodyL->m_pos); 1112 | 1113 | for (size_t gi = 0, giEnd = curBody->m_geometryShapes.size(); gi < giEnd; ++gi) 1114 | { 1115 | physics::GeometryShape * curShape = curBody->m_geometryShapes[gi]; 1116 | 1117 | shapeTransform = curShape->m_rotation; 1118 | shapeTransform.fillTranslation(curShape->m_origin - curBody->m_bodyR->m_com); 1119 | 1120 | totalTransform = bodyTransform * shapeTransform; 1121 | 1122 | if (curShape->getType() == physics::GeometryShape::Type::eGenericConvex) 1123 | { 1124 | physics::GeometryConvex * curConvex = static_cast(curShape); 1125 | if (curConvex->m_convexHullShape->getType() == ConvexHullShape::Type::eBox) 1126 | { 1127 | // Get box extents 1128 | Vec3 extX = curConvex->m_convexHullShape->getSupportVertexLocal(Vec3C(1.0f, 0.0f, 0.0f)); 1129 | Vec3 extY = curConvex->m_convexHullShape->getSupportVertexLocal(Vec3C(0.0f, 1.0f, 0.0f)); 1130 | Vec3 extZ = curConvex->m_convexHullShape->getSupportVertexLocal(Vec3C(0.0f, 0.0f, 1.0f)); 1131 | 1132 | Vec3 halfExt = Vec3C(extX.x, extY.y, extZ.z); 1133 | drawVerticesScaled(unitBoxVertices, totalTransform, halfExt); 1134 | } 1135 | else if (curConvex->m_convexHullShape->getType() == ConvexHullShape::Type::eSphere) 1136 | { 1137 | // Get sphere radius 1138 | Vec3 radius = curConvex->m_convexHullShape->getSupportVertexLocal(Vec3C(1.0f, 0.0f, 0.0f)); 1139 | drawVerticesScaled(unitSphereVertices, totalTransform, Vec3C(radius.x, radius.x, radius.x)); 1140 | } 1141 | else if (curConvex->m_convexHullShape->getType() == ConvexHullShape::Type::eCapsule) 1142 | { 1143 | // Capsule is oriented vertically 1144 | Vec3 radius = curConvex->m_convexHullShape->getSupportVertexLocal(Vec3C(1.0f, 0.0f, 0.0f)); 1145 | Vec3 height = curConvex->m_convexHullShape->getSupportVertexLocal(Vec3C(0.0f, 1.0f, 0.0f)); 1146 | 1147 | height.y -= radius.x; 1148 | 1149 | drawVerticesScaled(unitCylinderVertices, totalTransform, Vec3C(radius.x, height.y, radius.x)); 1150 | 1151 | Mat34 translation; 1152 | translation.identity(); 1153 | 1154 | translation.fillTranslation(height); 1155 | drawVerticesScaled(unitHemiSphereVertices, totalTransform * translation, Vec3C(radius.x, radius.x, radius.x)); 1156 | 1157 | translation.fillTranslation(-height); 1158 | translation.fillRotation(Vec3C(1.0f, 0.0f, 0.0f), PI); 1159 | drawVerticesScaled(unitHemiSphereVertices, totalTransform * translation, Vec3C(radius.x, radius.x, radius.x)); 1160 | } 1161 | else if (curConvex->m_convexHullShape->getType() == ConvexHullShape::Type::eCylinder) 1162 | { 1163 | // Get cylinder extents 1164 | Vec3 radius = curConvex->m_convexHullShape->getSupportVertexLocal(Vec3C(1.0f, 0.0f, 0.0f)); 1165 | Vec3 height = curConvex->m_convexHullShape->getSupportVertexLocal(Vec3C(0.0f, 1.0f, 0.0f)); 1166 | drawVerticesScaled(unitCylinderVertices, totalTransform, Vec3C(radius.x, height.y, radius.x)); 1167 | 1168 | Mat34 translation; 1169 | translation.identity(); 1170 | 1171 | translation.fillTranslation(height); 1172 | drawVerticesScaled(unitDiskVertices, totalTransform * translation, Vec3C(radius.x, 1.0f, radius.x)); 1173 | 1174 | translation.fillTranslation(-height); 1175 | translation.fillRotation(Vec3C(1.0f, 0.0f, 0.0f), PI); 1176 | drawVerticesScaled(unitDiskVertices, totalTransform * translation, Vec3C(radius.x, 1.0f, radius.x)); 1177 | } 1178 | else if (curConvex->m_convexHullShape->getType() == ConvexHullShape::Type::eCone) 1179 | { 1180 | // Get cone extents 1181 | Vec3 radius = curConvex->m_convexHullShape->getSupportVertexLocal(Vec3C(1.0f, 0.0f, 0.0f)); 1182 | Vec3 height = curConvex->m_convexHullShape->getSupportVertexLocal(Vec3C(0.0f, 1.0f, 0.0f)); 1183 | // Normals will be slightly off, as cylinder is scaled 1184 | // TODO: introduce additional function that also scales normal 1185 | drawVerticesScaled(unitConeVertices, totalTransform, Vec3C(radius.x, height.y, radius.x)); 1186 | 1187 | Mat34 translation; 1188 | translation.identity(); 1189 | 1190 | translation.fillTranslation(-height); 1191 | translation.fillRotation(Vec3C(1.0f, 0.0f, 0.0f), PI); 1192 | drawVerticesScaled(unitDiskVertices, totalTransform * translation, Vec3C(radius.x, 1.0f, radius.x)); 1193 | } 1194 | else if (curConvex->m_convexHullShape->getType() == ConvexHullShape::Type::eCustom) 1195 | { 1196 | ConvexCustom * curCustomConvex = static_cast(curConvex->m_convexHullShape); 1197 | const size_t numTris = curCustomConvex->m_hullTriangles.size() / 3; 1198 | for (size_t tri = 0; tri < numTris; ++tri) 1199 | { 1200 | const Vec3 renderOffset = Vec3C(0.0f, 0.0f, 0.0f); 1201 | const Vec2 renderTCs = Vec2C(0.0f, 0.0f); 1202 | const Vec4 renderColor = Vec4C(1.0f, 1.0f, 1.0f, 1.0f); 1203 | 1204 | const Vec3 & p0 = curCustomConvex->m_hullTriangles[tri*3+0]; 1205 | const Vec3 & p1 = curCustomConvex->m_hullTriangles[tri*3+1]; 1206 | const Vec3 & p2 = curCustomConvex->m_hullTriangles[tri*3+2]; 1207 | 1208 | Vec3 p0w = totalTransform * p0; 1209 | Vec3 p1w = totalTransform * p1; 1210 | Vec3 p2w = totalTransform * p2; 1211 | 1212 | auto posToTexCoords = [](const Vec3 & pos) -> Vec2 1213 | { 1214 | float r = pos.len(); 1215 | float theta = atan2f(pos.x, pos.y); 1216 | float phi = atan2f(pos.z, sqrtf(pos.x*pos.x + pos.y*pos.y)); 1217 | return Vec2C(theta, phi); 1218 | }; 1219 | 1220 | vulkan::Vertex renderV0, renderV1, renderV2; 1221 | renderV0.pos = renderOffset + p0w; 1222 | renderV0.col = renderColor; 1223 | renderV0.tc = posToTexCoords(p0); 1224 | renderV0.nrm = (p1w - p0w).cross(p2w - p0w).normalize(); 1225 | renderV1.pos = renderOffset + p1w; 1226 | renderV1.col = renderColor; 1227 | renderV1.tc = posToTexCoords(p1); 1228 | renderV1.nrm = (p2w - p1w).cross(p0w - p1w).normalize(); 1229 | renderV2.pos = renderOffset + p2w; 1230 | renderV2.col = renderColor; 1231 | renderV2.tc = posToTexCoords(p2); 1232 | renderV2.nrm = (p0w - p2w).cross(p1w - p2w).normalize(); 1233 | 1234 | // Change winding for backface culling 1235 | renderManager.m_debugTris.push_back(renderV0); 1236 | renderManager.m_debugTris.push_back(renderV2); 1237 | renderManager.m_debugTris.push_back(renderV1); 1238 | } 1239 | } 1240 | } 1241 | } 1242 | } 1243 | #endif 1244 | 1245 | #if 1 1246 | Vec3 mouseWorldCoord = Vec3C(); 1247 | if (callbackData.mouseMode == CallbackData::MouseMode::ePicking) 1248 | { 1249 | // If mouse mode is picking - calculate mouse pointer coordinates in the world space 1250 | float perspFOV; 1251 | float perspAsp; 1252 | float perspNear; 1253 | float perspFar; 1254 | float perspWidth; 1255 | float perspHeight; 1256 | renderManager.getViewPerspProjParams(&perspFOV, &perspAsp, &perspNear, &perspFar, &perspWidth, &perspHeight); 1257 | 1258 | Mat44 perspMatrix; 1259 | projPerspective(perspFOV, perspAsp, perspNear, perspFar, perspWidth, perspHeight, &perspMatrix); 1260 | 1261 | float nrmX = internalMouseX / (float)window.getWidth() * 2.0f - 1.0f; 1262 | float nrmY = internalMouseY / (float)window.getHeight() * 2.0f - 1.0f; 1263 | 1264 | Vec3 mouseCoord = Vec3C(nrmX, nrmY, 0.5f); 1265 | Mat34 viewMat; 1266 | mainCamera.fillMatrix(&viewMat); 1267 | Mat44 mvp = perspMatrix * viewMat; 1268 | Mat44 imvp = mvp; 1269 | imvp.invert(); 1270 | mouseWorldCoord = imvp * mouseCoord; 1271 | float ow = mouseCoord.x * imvp._30 + mouseCoord.y * imvp._31 + mouseCoord.z * imvp._32 + imvp._33; 1272 | mouseWorldCoord /= ow; 1273 | 1274 | drawPoint(mouseWorldCoord, Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 1275 | } 1276 | #endif 1277 | 1278 | #if (ENABLE_PHYSICS == 1) 1279 | if (callbackData.mouseMode == CallbackData::MouseMode::ePicking) 1280 | { 1281 | // Raycast and create joint on closest hit (if registered) 1282 | static int lmbStatePrev = 0; 1283 | if (callbackData.lmbState && !lmbStatePrev) 1284 | { 1285 | Vec3 rayO = mainCamera.getPosition(); 1286 | Vec3 rayD = mouseWorldCoord - mainCamera.getPosition(); 1287 | rayD.normalize(); 1288 | 1289 | float minHitTime = FLT_MAX; 1290 | physics::RigidBody * hitRigidBody = nullptr; 1291 | 1292 | for (size_t irb = 0, irbEnd = physics::g_rigidBodies.size(); irb < irbEnd; ++irb) 1293 | { 1294 | physics::RigidBody * curBody = physics::g_rigidBodies[irb]; 1295 | for (size_t gi = 0, giEnd = curBody->m_geometryShapes.size(); gi < giEnd; ++gi) 1296 | { 1297 | physics::GeometryShape * curShape = curBody->m_geometryShapes[gi]; 1298 | 1299 | if (curShape->getType() != physics::GeometryShape::Type::eGenericConvex) 1300 | continue; 1301 | 1302 | Mat34 shapeTransform; 1303 | Mat34 bodyTransform; 1304 | Mat34 totalTransform; 1305 | 1306 | shapeTransform = curShape->m_rotation; 1307 | shapeTransform.fillTranslation(curShape->m_origin - curBody->m_bodyR->m_com); 1308 | 1309 | bodyTransform = Quat::toMatrix33(curBody->m_bodyR->m_rot); 1310 | bodyTransform.fillTranslation(curBody->m_bodyL->m_pos); 1311 | 1312 | totalTransform = bodyTransform * shapeTransform; 1313 | 1314 | Vec3 hullPos = totalTransform.getBasis3(); 1315 | 1316 | // Get closest point on a line 1317 | float projTime = (hullPos - rayO).dot(rayD); 1318 | Vec3 closestPointOnLine = rayO + projTime * rayD; 1319 | 1320 | Vec3 diffVec = closestPointOnLine - hullPos; 1321 | 1322 | Quat hullRot = Quat::fromMatrix33(totalTransform.getRotation33()); 1323 | hullRot.normalize(); 1324 | 1325 | physics::GeometryConvex * curConvexShape = static_cast(curShape); 1326 | Vec3 supportToRay = curConvexShape->m_convexHullShape->getSupportVertex(diffVec, hullPos, hullRot); 1327 | if (supportToRay.sqLen() < diffVec.sqLen()) 1328 | { 1329 | continue; 1330 | } 1331 | 1332 | float rayScalar = 0.0f; 1333 | bool rayHit = raycastVsConvex(curConvexShape->m_convexHullShape, hullPos, hullRot, rayO, rayD, &rayScalar, 100.0f); 1334 | if (rayHit) 1335 | { 1336 | if (minHitTime > rayScalar) 1337 | { 1338 | minHitTime = rayScalar; 1339 | hitRigidBody = curBody; 1340 | } 1341 | } 1342 | } 1343 | } 1344 | if (hitRigidBody) 1345 | { 1346 | Vec3 hitPoint = rayO + minHitTime * rayD; 1347 | 1348 | // Picking joint - should be relatively weak to avoid system instabilities due to 1349 | // sharp and high-amplitude user interactions 1350 | physics::BallSocket * pickingBallsocket = new physics::BallSocket; 1351 | pickingBallsocket->init( 1352 | 0.1f, 0.1f, hitPoint, 1353 | hitRigidBody->m_bodyL, 1354 | hitRigidBody->m_bodyR, 1355 | nullptr, 1356 | nullptr 1357 | ); 1358 | 1359 | physics::addTrackJoint(pickingBallsocket); 1360 | pickingJoint = pickingBallsocket; 1361 | pickingDistance = minHitTime; 1362 | } 1363 | } 1364 | else if (!callbackData.lmbState && pickingJoint) 1365 | { 1366 | // Probably should go in reverse direction as picking joint most likely near to the end 1367 | for (size_t ij = 0, ijEnd = physics::g_joints.size(); ij < ijEnd; ++ij) 1368 | { 1369 | physics::JointBase * curJoint = physics::g_joints[ij]; 1370 | if (curJoint == pickingJoint) 1371 | { 1372 | physics::g_joints.erase(physics::g_joints.begin() + ij); 1373 | break; 1374 | } 1375 | } 1376 | if (pickingJoint) 1377 | delete pickingJoint; 1378 | pickingJoint = nullptr; 1379 | } 1380 | else if (pickingJoint) 1381 | { 1382 | // Attachment to regular rigid body 1383 | if (pickingJoint->getType() == physics::JointBase::Type::eBallSocket) 1384 | { 1385 | physics::BallSocket * pickingBallsocket = static_cast(pickingJoint); 1386 | Vec3 rayO = mainCamera.getPosition(); 1387 | Vec3 rayD = mouseWorldCoord - mainCamera.getPosition(); 1388 | rayD.normalize(); 1389 | Vec3 newPoint = rayO + pickingDistance * rayD; 1390 | pickingBallsocket->setAnchorPoint1(newPoint); 1391 | } 1392 | } 1393 | 1394 | lmbStatePrev = callbackData.lmbState; 1395 | } 1396 | 1397 | if (callbackData.reqDropBox) 1398 | { 1399 | callbackData.reqDropBox = false; 1400 | 1401 | const float skinWidth = 0.015f; 1402 | 1403 | physics::NodeTranslational * bodyL; 1404 | const float boxMass = 1.0f; 1405 | static int DBGnumBoxes = 0; 1406 | 1407 | Vec3 camPos = mainCamera.getPosition(); 1408 | Vec3 camView = mainCamera.getView().getNormalized(); 1409 | 1410 | Vec3 camRight = mainCamera.getUp().cross(camView); 1411 | camRight.normalize(); 1412 | 1413 | Vec3 camUp = camView.cross(camRight); 1414 | camUp.normalize(); 1415 | 1416 | Mat33 boxOrient; 1417 | boxOrient.setBasis0(camRight); 1418 | boxOrient.setBasis1(camUp); 1419 | boxOrient.setBasis2(camView); 1420 | 1421 | bodyL = physics::addTranslationalNode(1.0f / boxMass, camPos - camView, Vec3C()); 1422 | Quat identityQuat(1.0f, 0.0f, 0.0f, 0.0f); 1423 | physics::NodeRotational * bodyR = physics::addRotationalNode(Mat33().identity(), identityQuat, Vec3C()); 1424 | bodyR->m_rot = Quat::fromMatrix33(boxOrient); 1425 | bodyR->m_rot.normalize(); 1426 | Mat33 DBGmat = Quat::toMatrix33(bodyR->m_rot); 1427 | 1428 | bodyL->m_vel = -20.0f*camView; 1429 | 1430 | DBGnumBoxes++; 1431 | 1432 | bodyL->m_skinWidth = skinWidth; 1433 | 1434 | physics::RigidBody * body = physics::createRigidBody(); 1435 | body->m_bodyL = bodyL; 1436 | body->m_bodyR = bodyR; 1437 | 1438 | ConvexBox * convexBox= new ConvexBox; 1439 | convexBox->m_halfExtents = Vec3C(0.5f, 0.5f, 0.5f); 1440 | convexBox->m_origin = Vec3C(); 1441 | convexBox->m_rotation.identity(); 1442 | 1443 | physics::GeometryConvex * convex = new physics::GeometryConvex; 1444 | convex->m_density = 1.0f; 1445 | convex->m_origin = Vec3C(0.0f, 0.0f, 0.0f); 1446 | convex->m_rotation.identity(); 1447 | convex->m_convexHullShape = convexBox; 1448 | 1449 | trackGeometryShape(convex); 1450 | body->m_geometryShapes.push_back(convex); 1451 | 1452 | body->prepareGeometry(); 1453 | } 1454 | #endif 1455 | 1456 | for (const ExtDrawLine & simLine : g_simLines) 1457 | { 1458 | drawLine(simLine.p0, simLine.p1, simLine.c0); 1459 | } 1460 | for (const ExtDrawPoint & simPoint : g_simPoints) 1461 | { 1462 | drawPoint(simPoint.p, simPoint.c); 1463 | } 1464 | 1465 | #if 0 1466 | { 1467 | Vec3 cubeOffset = Vec3C(0.0f, 3.0f, 0.0f); 1468 | Vec3 cubeSize = Vec3C(1.0f, 1.0f, 1.0f); 1469 | Vec3 cubeNodes[8] = 1470 | { 1471 | Vec3C(-cubeSize.x, -cubeSize.y, -cubeSize.z),//0 1472 | Vec3C( cubeSize.x, -cubeSize.y, -cubeSize.z),//1 1473 | Vec3C(-cubeSize.x, cubeSize.y, -cubeSize.z),//2 1474 | Vec3C( cubeSize.x, cubeSize.y, -cubeSize.z),//3 1475 | Vec3C(-cubeSize.x, -cubeSize.y, cubeSize.z),//4 1476 | Vec3C( cubeSize.x, -cubeSize.y, cubeSize.z),//5 1477 | Vec3C(-cubeSize.x, cubeSize.y, cubeSize.z),//6 1478 | Vec3C( cubeSize.x, cubeSize.y, cubeSize.z),//7 1479 | }; 1480 | for (int i = 0; i < 8; ++i) 1481 | { 1482 | cubeNodes[i] += cubeOffset; 1483 | } 1484 | 1485 | Vec3 tetraOffsets[5]; 1486 | for (int i = 0; i < 5; ++i) 1487 | { 1488 | tetraOffsets[i] = Vec3C(); 1489 | } 1490 | 1491 | auto drawWireTetra = [&drawLine](const Vec3 & v0, const Vec3 & v1, const Vec3 & v2, const Vec3 & v3, const Vec4C & color) 1492 | { 1493 | drawLine(v0, v1, color); 1494 | drawLine(v0, v2, color); 1495 | drawLine(v1, v2, color); 1496 | drawLine(v1, v3, color); 1497 | drawLine(v2, v3, color); 1498 | drawLine(v3, v0, color); 1499 | }; 1500 | 1501 | auto drawTetra = [&renderManager](const Vec3 & v0, const Vec3 & v1, const Vec3 & v2, const Vec3 & v3, const Vec4C & color) 1502 | { 1503 | vulkan::Vertex faceVtx; 1504 | faceVtx.col = color; 1505 | 1506 | auto addTetraFace = [&renderManager]( 1507 | vulkan::Vertex & faceVtx, 1508 | const Vec3 & n0, 1509 | const Vec3 & n1, 1510 | const Vec3 & n2 1511 | ) 1512 | { 1513 | Vec3 normal = (n1 - n0).cross(n2 - n0).getNormalized(); 1514 | 1515 | faceVtx.tc = Vec2C(0.0f, 0.0f); 1516 | faceVtx.pos = n0; 1517 | faceVtx.nrm = normal; 1518 | renderManager.m_debugTris.push_back(faceVtx); 1519 | faceVtx.tc = Vec2C(1.0f, 0.0f); 1520 | faceVtx.pos = n1; 1521 | faceVtx.nrm = normal; 1522 | renderManager.m_debugTris.push_back(faceVtx); 1523 | faceVtx.tc = Vec2C(0.0f, 1.0f); 1524 | faceVtx.pos = n2; 1525 | faceVtx.nrm = normal; 1526 | renderManager.m_debugTris.push_back(faceVtx); 1527 | }; 1528 | 1529 | addTetraFace(faceVtx, v0, v2, v1); 1530 | addTetraFace(faceVtx, v0, v1, v3); 1531 | addTetraFace(faceVtx, v0, v3, v2); 1532 | addTetraFace(faceVtx, v1, v2, v3); 1533 | }; 1534 | 1535 | const float translationMul = 0.4f * (sinf((float)sampleApp.getElapsedTime() * 0.001f) * 0.5f + 0.5f); 1536 | const bool cornerTetraWire = true; 1537 | const bool centerTetraWire = false; 1538 | 1539 | // Render Corner tetra 0 1540 | tetraOffsets[0] = translationMul*Vec3C(-1.0f, -1.0f, -1.0f); 1541 | int t0idx0 = 1, t0idx1 = 0, t0idx2 = 2, t0idx3 = 4; 1542 | if (cornerTetraWire) 1543 | drawWireTetra(tetraOffsets[0]+cubeNodes[t0idx0], tetraOffsets[0]+cubeNodes[t0idx1], tetraOffsets[0]+cubeNodes[t0idx2], tetraOffsets[0]+cubeNodes[t0idx3], Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 1544 | else 1545 | drawTetra(tetraOffsets[0]+cubeNodes[t0idx0], tetraOffsets[0]+cubeNodes[t0idx1], tetraOffsets[0]+cubeNodes[t0idx2], tetraOffsets[0]+cubeNodes[t0idx3], Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 1546 | 1547 | // Render Corner tetra 1 1548 | tetraOffsets[1] = translationMul*Vec3C( 1.0f, -1.0f, 1.0f); 1549 | int t1idx0 = 5, t1idx1 = 4, t1idx2 = 1, t1idx3 = 7; 1550 | if (cornerTetraWire) 1551 | drawWireTetra(tetraOffsets[1]+cubeNodes[t1idx0], tetraOffsets[1]+cubeNodes[t1idx1], tetraOffsets[1]+cubeNodes[t1idx2], tetraOffsets[1]+cubeNodes[t1idx3], Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 1552 | else 1553 | drawTetra(tetraOffsets[1]+cubeNodes[t1idx0], tetraOffsets[1]+cubeNodes[t1idx1], tetraOffsets[1]+cubeNodes[t1idx2], tetraOffsets[1]+cubeNodes[t1idx3], Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 1554 | 1555 | // Render Corner tetra 2 1556 | tetraOffsets[2] = translationMul*Vec3C( 1.0f, 1.0f, -1.0f); 1557 | int t2idx0 = 2, t2idx1 = 3, t2idx2 = 1, t2idx3 = 7; 1558 | if (cornerTetraWire) 1559 | drawWireTetra(tetraOffsets[2]+cubeNodes[t2idx0], tetraOffsets[2]+cubeNodes[t2idx1], tetraOffsets[2]+cubeNodes[t2idx2], tetraOffsets[2]+cubeNodes[t2idx3], Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 1560 | else 1561 | drawTetra(tetraOffsets[2]+cubeNodes[t2idx0], tetraOffsets[2]+cubeNodes[t2idx1], tetraOffsets[2]+cubeNodes[t2idx2], tetraOffsets[2]+cubeNodes[t2idx3], Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 1562 | 1563 | // Render Corner tetra 3 1564 | tetraOffsets[3] = translationMul*Vec3C(-1.0f, 1.0f, 1.0f); 1565 | int t3idx0 = 6, t3idx1 = 7, t3idx2 = 2, t3idx3 = 4; 1566 | if (cornerTetraWire) 1567 | drawWireTetra(tetraOffsets[3]+cubeNodes[t3idx0], tetraOffsets[3]+cubeNodes[t3idx1], tetraOffsets[3]+cubeNodes[t3idx2], tetraOffsets[3]+cubeNodes[t3idx3], Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 1568 | else 1569 | drawTetra(tetraOffsets[3]+cubeNodes[t3idx0], tetraOffsets[3]+cubeNodes[t3idx1], tetraOffsets[3]+cubeNodes[t3idx2], tetraOffsets[3]+cubeNodes[t3idx3], Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 1570 | 1571 | // Render Center tetra 1572 | tetraOffsets[4] = translationMul*Vec3C( 0.0f, 0.0f, 0.0f); 1573 | int t4idx0 = 2, t4idx1 = 7, t4idx2 = 1, t4idx3 = 4; 1574 | if (centerTetraWire) 1575 | drawWireTetra(tetraOffsets[4]+cubeNodes[t4idx0], tetraOffsets[4]+cubeNodes[t4idx1], tetraOffsets[4]+cubeNodes[t4idx2], tetraOffsets[4]+cubeNodes[t4idx3], Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 1576 | else 1577 | drawTetra(tetraOffsets[4]+cubeNodes[t4idx0], tetraOffsets[4]+cubeNodes[t4idx1], tetraOffsets[4]+cubeNodes[t4idx2], tetraOffsets[4]+cubeNodes[t4idx3], Vec4C(1.0f, 1.0f, 1.0f, 1.0f)); 1578 | } 1579 | #endif 1580 | 1581 | sampleApp.update(callbackData.isPaused ? 0.0 : dtMS); 1582 | 1583 | renderManager.beginFrame(); 1584 | renderManager.update(); 1585 | renderManager.render(); 1586 | 1587 | dtMS = perfTimer.time(); 1588 | accumTimeMS += dtMS; 1589 | physicsTime += dtMS * 0.001; 1590 | ++accumFrames; 1591 | if (accumTimeMS > 500.0) 1592 | { 1593 | sampleApp.setDTime(accumTimeMS / (float)accumFrames); 1594 | accumTimeMS = 0.0; 1595 | accumFrames = 0; 1596 | } 1597 | perfTimer.start(); 1598 | 1599 | if (callbackData.isAnimStep) 1600 | { 1601 | callbackData.isPaused = true; 1602 | callbackData.isAnimStep = false; 1603 | } 1604 | } 1605 | 1606 | #if (ENABLE_PHYSICS == 1) 1607 | physics::cleanupPhysics(); 1608 | #endif 1609 | 1610 | sampleApp.deinit(); 1611 | window.deinit(); 1612 | 1613 | return 0; 1614 | } -------------------------------------------------------------------------------- /vkEngine/source/vulkan/definitions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "math\Vec2.h" 4 | #include "math\Vec3.h" 5 | #include "math\Vec4.h" 6 | 7 | #include "math\Mat44.h" 8 | 9 | namespace vulkan 10 | { 11 | struct Vertex 12 | { 13 | math::Vec3 pos; 14 | math::Vec3 nrm; 15 | math::Vec4 col; 16 | math::Vec2 tc; 17 | }; 18 | 19 | struct LinePoint 20 | { 21 | math::Vec3 pos; 22 | math::Vec4 col; 23 | }; 24 | 25 | enum class BufferUsage 26 | { 27 | eStatic, 28 | eDynamic, 29 | 30 | eNUM_ENTRIES 31 | }; 32 | 33 | } -------------------------------------------------------------------------------- /vkEngine/source/vulkan/helpers.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avoroshilov/physics_playground/06208f51d1b1a6a62a0c6cd5f54270b6ec0e42fe/vkEngine/source/vulkan/helpers.cpp -------------------------------------------------------------------------------- /vkEngine/source/vulkan/helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace vulkan 6 | { 7 | 8 | void getGenericSupportedDeviceExtensionsList(const VkPhysicalDevice & physDev, std::vector * supportedExtensionsProps); 9 | 10 | uint32_t findMemoryType(const VkPhysicalDevice & physDev, uint32_t typeFilter, VkMemoryPropertyFlags properties); 11 | 12 | bool hasStencilComponent(VkFormat format); 13 | 14 | VkFormat findSupportedFormat( 15 | const VkPhysicalDevice & physDev, 16 | const std::vector & formatCandidates, 17 | VkImageTiling imageTiling, 18 | VkFormatFeatureFlags formatFeatures 19 | ); 20 | 21 | void createBuffer( 22 | const VkPhysicalDevice & physDev, 23 | const VkDevice & logicDev, 24 | VkDeviceSize size, 25 | VkBufferUsageFlags usage, 26 | VkMemoryPropertyFlags memoryProperties, 27 | VkBuffer * buffer, 28 | VkDeviceMemory * bufferDeviceMemory, 29 | VkAllocationCallbacks * pAllocator 30 | ); 31 | 32 | void createImage( 33 | const VkPhysicalDevice & physDev, 34 | const VkDevice & logicDev, 35 | uint32_t width, 36 | uint32_t height, 37 | VkFormat format, 38 | VkImageTiling tiling, 39 | VkImageUsageFlags usage, 40 | VkMemoryPropertyFlags memoryProperties, 41 | VkImage * image, 42 | VkDeviceMemory * imageDeviceMemory, 43 | VkAllocationCallbacks * pAllocator 44 | ); 45 | 46 | VkImageView createImageView2D( 47 | const VkDevice & logicDev, 48 | VkImage image, 49 | VkFormat format, 50 | VkImageAspectFlags imageAspectFlags, 51 | VkAllocationCallbacks * pAllocator 52 | ); 53 | 54 | /*** Graphics pipeline stage creation helpers ***/ 55 | 56 | VkPipelineViewportStateCreateInfo getDefaultViewportStateCreateInfo(VkExtent2D bufferSize); 57 | 58 | // No DepthClamp, no RasterizerDiscard, PolygonMode=Fill, CullMode=Back, FrontFace=CW, no DepthBias, LineWidth=1.0 59 | VkPipelineRasterizationStateCreateInfo getDefaultRasterizationStateCreateInfo(); 60 | 61 | // Per-fragment shading, 1 sample per fragment, no Alpha-To-Coverage 62 | VkPipelineMultisampleStateCreateInfo getDefaultMultisampleStateCreateInfo(); 63 | 64 | // WriteMask=RGBA, no Blend, Color/Alpha Blend: Src=1 Dst=0 Op=add 65 | VkPipelineColorBlendAttachmentState getDefaultColorBlendAttachmentState(); 66 | 67 | // no LogicOp, LogicOp=Copy, BlendConst=(0,0,0,0), !no attachments! 68 | VkPipelineColorBlendStateCreateInfo getDefaultColorBlendStateCreateInfo(); 69 | 70 | // DepthTest=1, DepthWrite=1, DepthCompare=Less, no DepthBoundsTest, Min/MaxDepthBounds=0.0/1.0, no StencilTest 71 | VkPipelineDepthStencilStateCreateInfo getDefaultDepthStencilStateCreateInfo(); 72 | 73 | } -------------------------------------------------------------------------------- /vkEngine/source/vulkan/manager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define NOMINMAX 8 | #include // GetModuleHandle 9 | 10 | #define VK_USE_PLATFORM_WIN32_KHR 11 | #include 12 | 13 | #include "math\Vec2.h" 14 | #include "math\Vec3.h" 15 | #include "math\Vec4.h" 16 | 17 | #include "math\Mat44.h" 18 | 19 | #include "definitions.h" 20 | #include "mesh.h" 21 | 22 | namespace vulkan 23 | { 24 | struct GlobalConstantsUBO 25 | { 26 | float time; 27 | }; 28 | 29 | struct TransformUBO 30 | { 31 | math::Mat44 view; 32 | math::Mat44 proj; 33 | }; 34 | 35 | struct ModelPushConstant 36 | { 37 | math::Mat44 model; 38 | }; 39 | 40 | class Wrapper 41 | { 42 | public: 43 | 44 | int m_windowWidth = -1, m_windowHeight = -1; 45 | 46 | void setWindowSize(int width, int height) 47 | { 48 | m_windowWidth = width; 49 | m_windowHeight = height; 50 | } 51 | 52 | VkInstance m_vkInstance = VK_NULL_HANDLE; 53 | 54 | VkSurfaceKHR m_vkPresentableSurface = VK_NULL_HANDLE; 55 | 56 | struct VulkanPhysicalDeviceData 57 | { 58 | VkPhysicalDevice vkHandle = VK_NULL_HANDLE; 59 | VkPhysicalDeviceFeatures deviceFeatures; 60 | VkPhysicalDeviceProperties deviceProperties; 61 | 62 | std::vector requiredExtensionNamesList; 63 | std::vector supportedExtensionsProps; 64 | 65 | struct SurfaceInfo 66 | { 67 | VkSurfaceCapabilitiesKHR capabilities; 68 | std::vector formats; 69 | std::vector presentModes; 70 | }; 71 | 72 | SurfaceInfo surfaceInfo; 73 | }; 74 | VulkanPhysicalDeviceData m_vkPhysicalDeviceData; 75 | 76 | struct VulkanLogicalDeviceData 77 | { 78 | VkDevice vkHandle = VK_NULL_HANDLE; 79 | 80 | VkQueue graphicsQueue = VK_NULL_HANDLE; 81 | VkQueue presentingQueue = VK_NULL_HANDLE; 82 | 83 | uint32_t graphicsQueueFamilyIndex = 0xFFffFFff; 84 | uint32_t presentingQueueFamilyIndex = 0xFFffFFff; 85 | }; 86 | VulkanLogicalDeviceData m_vkLogicalDeviceData; 87 | 88 | VkPhysicalDevice getPhysicalDeviceHandle() const { return m_vkPhysicalDeviceData.vkHandle; } 89 | VkDevice getLogicalDeviceHandle() const { return m_vkLogicalDeviceData.vkHandle; } 90 | 91 | VkQueue getGraphicsQueue() const { return m_vkLogicalDeviceData.graphicsQueue; } 92 | VkQueue getPresentingQueue() const { return m_vkLogicalDeviceData.presentingQueue; } 93 | 94 | VkAllocationCallbacks * getVkAllocator() { return nullptr; } 95 | 96 | // Vulkan-specific projection matrix 97 | void projPerspective(float fovRad, float aspect, float zNear, float zFar, float width, float height, math::Mat44 * projection); 98 | 99 | struct VulkanSwapchainData 100 | { 101 | VkSwapchainKHR vkHandle = VK_NULL_HANDLE; 102 | VkFormat format; 103 | VkFormatProperties formatProps; 104 | 105 | // Screenshots 106 | VkFormat captureFormat; 107 | VkFormatProperties captureFormatProps; 108 | 109 | VkExtent2D extent; 110 | VkColorSpaceKHR colorSpace; 111 | uint32_t imageIndexInSwapchain; 112 | std::vector images; 113 | std::vector imageViews; 114 | std::vector framebuffers; 115 | bool supportsCapture; 116 | }; 117 | VulkanSwapchainData m_vkSwapchainData; 118 | 119 | // Default scene depth-buffer (used in z-prepass and final shading) 120 | VkFormat m_vkDepthFormat; 121 | VkImage m_vkDepthImage = VK_NULL_HANDLE; 122 | VkDeviceMemory m_vkDepthDeviceMemory = VK_NULL_HANDLE; 123 | VkImageView m_vkDepthImageView = VK_NULL_HANDLE; 124 | 125 | /* Shadowmap generation and z-prepass */ 126 | 127 | // Descriptor set layout defines set of resources for a *shader*; 128 | // i.e. how much uniforms it has, how much storage buffers, samplers, push constants, etc. 129 | // This one is for the depth-only passes 130 | VkDescriptorSetLayout m_vkDepthOnlyShaderDescriptorSetLayout = VK_NULL_HANDLE; 131 | 132 | // Pipeline: Depth-only passes (e.g. shadowmap, z-prepass) 133 | VkPipelineLayout m_vkDepthOnlyPipelineLayout = VK_NULL_HANDLE; 134 | VkPipeline m_vkDepthOnlyGraphicsPipeline = VK_NULL_HANDLE; 135 | 136 | // Render pass: Shadowmap generation 137 | VkRenderPass m_vkShadowMapGenRenderPass = VK_NULL_HANDLE; 138 | 139 | // Descriptor sets 140 | VkDescriptorSet m_vkShadowMapGenDescriptorSet = VK_NULL_HANDLE; 141 | 142 | // Attachment: Shadowmap depth-buffer, used as attachment in shadowmap generation, and as shader resource in final shading 143 | VkFormat m_vkShadowMapDepthFormat; 144 | VkImage m_vkShadowMapDepthImage = VK_NULL_HANDLE; 145 | VkDeviceMemory m_vkShadowMapDepthDeviceMemory = VK_NULL_HANDLE; 146 | VkImageView m_vkShadowMapDepthImageView = VK_NULL_HANDLE; 147 | 148 | VkFramebuffer m_vkShadowMapGenFramebuffer = VK_NULL_HANDLE; 149 | 150 | // ZPrePass 151 | VkRenderPass m_vkZPrePassRenderPass = VK_NULL_HANDLE; 152 | 153 | VkDescriptorSet m_vkZPrePassDescriptorSet = VK_NULL_HANDLE; 154 | 155 | VkFramebuffer m_vkZPrePassFramebuffer = VK_NULL_HANDLE; 156 | 157 | /* Forward rendering (mesh & debug) */ 158 | 159 | VkDescriptorSetLayout m_vkFwdShadingDescriptorSetLayout = VK_NULL_HANDLE; 160 | 161 | // General mesh rendering 162 | VkPipelineLayout m_vkFwdShadingPipelineLayout = VK_NULL_HANDLE; 163 | VkPipeline m_vkFwdShadingGraphicsPipeline = VK_NULL_HANDLE; 164 | 165 | // Debug lines rendering 166 | VkPipelineLayout m_vkDebugVisPipelineLayout = VK_NULL_HANDLE; 167 | VkPipeline m_vkDebugVisGraphicsPipeline = VK_NULL_HANDLE; 168 | 169 | VkRenderPass m_vkRenderPass = VK_NULL_HANDLE; 170 | 171 | VkDescriptorSet m_vkDescriptorSet = VK_NULL_HANDLE; 172 | 173 | // We don't have post-processing, so final shading uses VkFramebuffer of the swapchain, created for each swapchain image, 174 | // and all are stored inside the VulkanSwapchainData structure 175 | 176 | /* Others */ 177 | 178 | // Samplers 179 | // General texture sampler 180 | VkSampler m_vkTextureSampler = VK_NULL_HANDLE; 181 | // Sampler for HW PCF 182 | VkSampler m_vkDepthTextureSampler = VK_NULL_HANDLE; 183 | 184 | // Hardcoded triangle mesh (fullscreen quad) 185 | int m_vkTriangleVerticesCount = -1; 186 | VkBuffer m_vkTriangleVertexBuffer; 187 | VkDeviceMemory m_vkTriangleVertexBufferDeviceMemory; 188 | 189 | int m_vkTriangleIndicesCount = -1; 190 | VkIndexType m_vkTriangleIndexBufferType; 191 | VkBuffer m_vkTriangleIndexBuffer = VK_NULL_HANDLE; 192 | VkDeviceMemory m_vkTriangleIndexBufferDeviceMemory = VK_NULL_HANDLE; 193 | 194 | // Semaphores 195 | VkSemaphore m_vkSemaphoreImageAvailable = VK_NULL_HANDLE; 196 | VkSemaphore m_vkSemaphoreZPrePassFinished = VK_NULL_HANDLE; 197 | VkSemaphore m_vkSemaphoreShadowMapGenFinished = VK_NULL_HANDLE; 198 | VkSemaphore m_vkSemaphoreRenderFinished = VK_NULL_HANDLE; 199 | 200 | 201 | std::vector m_requiredExtensionNamesList; 202 | std::vector m_supportedExtensionsProps; 203 | 204 | bool m_debugCallbackInitialized = false; 205 | VkDebugReportCallbackEXT m_debugCallbackDesc = VK_NULL_HANDLE; 206 | std::vector m_requiredInstanceValidationLayerNamesList; 207 | std::vector m_requiredLogDevValidationLayerNamesList; 208 | 209 | void buildSupportedInstanceExtensionsList(bool printList = false); 210 | void buildRequiredInstanceExtensionsList(bool printList = false); 211 | 212 | bool m_enableValidationLayers = false; 213 | bool initValidationLayers(bool areValidationLayersEnabled = false); 214 | 215 | void initDebugCallback(PFN_vkDebugReportCallbackEXT debugCallback); 216 | void deinitDebugCallback(); 217 | 218 | void initInstance(); 219 | void deinitInstance(); 220 | 221 | // TODO: implement through getQueueFamilyIndex (request idx if required and check if it's valid) 222 | static bool checkQueuesPresence(const VkPhysicalDevice & physDev, const VkSurfaceKHR & surface, bool needsGraphics, bool needsPresent, bool needsMemoryTransfer, bool needsCompute); 223 | 224 | static VulkanPhysicalDeviceData::SurfaceInfo queryDeviceSurfaceInfo(const VkPhysicalDevice & physDev, const VkSurfaceKHR & surface); 225 | 226 | static bool checkPhysicalDevice(const VkPhysicalDevice & physDev, const std::vector & requiredExtensionNamesList, const VkSurfaceKHR & surface); 227 | 228 | void selectPhysicalDevice(); 229 | 230 | void initLogicalDevice(); 231 | void deinitLogicalDevice(); 232 | 233 | void initWindowSurface(HWND hWnd); 234 | void deinitWindowSurface(); 235 | 236 | void buildSupportedDeviceExtensionsList(bool printList = false); 237 | 238 | void buildRequiredDeviceExtensionsList(bool printList = false); 239 | 240 | static VkExtent2D selectPresentableSurfaceExtents(const VkSurfaceCapabilitiesKHR & capabilities, uint32_t w, uint32_t h); 241 | 242 | static VkSurfaceFormatKHR selectPresentableSurfaceFormat(const std::vector & availableFormats); 243 | 244 | static VkPresentModeKHR selectPresentMode(const std::vector & availablePresentModes); 245 | 246 | void initSwapchain(); 247 | void deinitSwapchain(); 248 | 249 | void reinitSwapchain(); 250 | 251 | void storeSwapchainImage(const wchar_t * filename); 252 | 253 | void onWindowResize(int width, int height) 254 | { 255 | if (width == 0 || height == 0) 256 | return; 257 | 258 | setWindowSize(width, height); 259 | reinitSwapchain(); 260 | } 261 | 262 | PFN_vkDebugReportCallbackEXT m_vkDebugCallback = nullptr; 263 | void setDebugCallback(PFN_vkDebugReportCallbackEXT debugCallback) 264 | { 265 | m_vkDebugCallback = debugCallback; 266 | } 267 | PFN_vkDebugReportCallbackEXT getDebugCallback() const 268 | { 269 | return m_vkDebugCallback; 270 | } 271 | 272 | std::vector m_vkShaderModules; 273 | VkShaderModule initShaderModule(const std::vector & shaderByteCode); 274 | void deinitShaderModules(); 275 | 276 | void initShadowMapGenRenderPass(); 277 | void deinitShadowMapGenRenderPass(); 278 | 279 | void initZPrePassRenderPass(); 280 | void deinitZPrePassRenderPass(); 281 | 282 | void initRenderPass(); 283 | void deinitRenderPass(); 284 | 285 | static void getVertexInputDescriptions(VkVertexInputBindingDescription * bindingDescr, VkVertexInputAttributeDescription attribsDescr[], int numAttribs = 3); 286 | static void getLinePointInputDescriptions(VkVertexInputBindingDescription * bindingDescr, VkVertexInputAttributeDescription attribsDescr[], int numAttribs = 3); 287 | 288 | // Depth-only (z-prepass, shadowmap) pipeline state 289 | void initDepthOnlyPipelineState(); 290 | void deinitDepthOnlyPipelineState(); 291 | 292 | // Forward (mesh & debug) 293 | void initPipelineState(); 294 | void deinitPipelineState(); 295 | 296 | void initDebugPipelineState(); 297 | void deinitDebugPipelineState(); 298 | 299 | // TODO: probably enhance/reuse TextureResource init/deinit 300 | void initShadowMapDepthBuffer(); 301 | void deinitShadowMapDepthBuffer(); 302 | 303 | void initShadowMapGenFramebuffers(); 304 | void deinitShadowMapGenFramebuffers(); 305 | 306 | void initZPrePassFramebuffers(); 307 | void deinitZPrePassFramebuffers(); 308 | 309 | void initSwapchainFramebuffers(); 310 | void deinitSwapchainFramebuffers(); 311 | 312 | // Command pool is per-thread, in case of multi-threaded scene generation - create as many command pools as there are threads 313 | VkCommandPool m_vkMainThreadCommandPool = VK_NULL_HANDLE; 314 | 315 | VkCommandBuffer m_vkShadowMapGenCommandBuffer = VK_NULL_HANDLE; 316 | VkCommandBuffer m_vkZPrePassCommandBuffer = VK_NULL_HANDLE; 317 | 318 | std::vector m_vkMainThreadCommandBuffers; 319 | std::vector m_vkMainThreadSwapchainCommandBuffers; 320 | 321 | void initCommandPool(); 322 | void deinitCommandPool(); 323 | 324 | void initDepthBuffer(); 325 | void deinitDepthBuffer(); 326 | 327 | VkCommandPool getTransientCommandPool(); 328 | VkCommandBuffer beginTransientCommandBuffer(); 329 | void endTransientCommandBuffer(const VkCommandBuffer & transientCommandBuffer); 330 | 331 | void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); 332 | 333 | void insertImageMemoryBarrierBuf( 334 | const VkCommandBuffer & commandBuffer, 335 | VkImage image, 336 | VkAccessFlags srcAccessMask, 337 | VkAccessFlags dstAccessMask, 338 | VkPipelineStageFlags srcSyncStageMask, 339 | VkPipelineStageFlags dstSyncStageMask, 340 | VkDependencyFlags dependencyFlags, 341 | VkImageLayout oldImageLayout, 342 | VkImageLayout newImageLayout, 343 | const VkImageSubresourceRange & subresourceRange 344 | ); 345 | // This function effectively creates transient cmd buf, inserts image barrier to it, and submits it 346 | void transitionImageLayout( 347 | VkImage image, 348 | VkFormat format, 349 | VkImageLayout oldImageLayout, 350 | VkImageLayout newImageLayout 351 | ); 352 | // Image layout should be transitioned to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL 353 | void copyBufferToImage(uint32_t width, uint32_t height, VkBuffer buffer, VkImage image); 354 | 355 | struct TextureResource 356 | { 357 | uint32_t width, height; 358 | VkFormat imageFormat; 359 | VkImage image = VK_NULL_HANDLE; 360 | VkDeviceMemory imageDeviceMemory = VK_NULL_HANDLE; 361 | VkImageView imageView = VK_NULL_HANDLE; 362 | }; 363 | 364 | std::vector m_textureResources; 365 | TextureResource * createTextureResource(uint32_t width, uint32_t height, void * data) 366 | { 367 | // TODO: could be replaced with pool 368 | TextureResource * newTextureResource = new TextureResource; 369 | 370 | initTextureResource(newTextureResource, width, height, data); 371 | 372 | m_textureResources.push_back(newTextureResource); 373 | return newTextureResource; 374 | } 375 | void destroyTextureResource(TextureResource * textureResource) 376 | { 377 | delete textureResource; 378 | } 379 | 380 | void initTextureResource(TextureResource * textureResource, uint32_t width, uint32_t height, void * data); 381 | void deinitTextureResource(TextureResource * textureResource); 382 | 383 | TextureResource m_albedoTex; 384 | void initAlbedoTexResource(); 385 | void deinitAlbedoTexResource(); 386 | 387 | TextureResource m_lightProjTex; 388 | void initLightProjTexResource(); 389 | void deinitLightProjTexResource(); 390 | 391 | void initTextureSampler(); 392 | void deinitTextureSampler(); 393 | 394 | void initDepthTextureSampler(); 395 | void deinitDepthTextureSampler(); 396 | 397 | void initFSQuadBuffers(); 398 | void deinitFSQuadBuffers(); 399 | 400 | // Shadowmap parameters 401 | uint32_t m_smWidth = 1024, m_smHeight = 1024; 402 | // Debug (immediate-mode-like) triangles 403 | std::vector m_debugTris; 404 | Mesh m_debugTrisMesh; 405 | 406 | // Debug (immediate-mode-like) lines 407 | std::vector m_debugLines; 408 | Mesh m_debugLinesMesh; 409 | 410 | std::vector m_meshes; 411 | Mesh * createMesh() 412 | { 413 | // TODO: could be replaced with pool 414 | Mesh * newMesh = new Mesh; 415 | newMesh->init(this); 416 | m_meshes.push_back(newMesh); 417 | return newMesh; 418 | } 419 | void destroyMesh(Mesh * mesh) 420 | { 421 | delete mesh; 422 | } 423 | 424 | void initDepthOnlyDescriptorSetLayout(); 425 | void deinitDepthOnlyDescriptorSetLayout(); 426 | 427 | void initDescriptorSetLayout(); 428 | void deinitDescriptorSetLayout(); 429 | 430 | VkBuffer m_vkShadowMapGenTransformUBOBuffer = VK_NULL_HANDLE; 431 | VkDeviceMemory m_vkShadowMapGenTransformUBOBufferDeviceMemory = VK_NULL_HANDLE; 432 | void initShadowMapGenTransformUBO(); 433 | void deinitShadowMapGenTransformUBO(); 434 | 435 | VkBuffer m_vkGlobalConstantsUBOBuffer = VK_NULL_HANDLE; 436 | VkDeviceMemory m_vkGlobalConstantsUBOBufferDeviceMemory = VK_NULL_HANDLE; 437 | void initGlobalConstantsUBO(); 438 | void deinitGlobalConstantsUBO(); 439 | 440 | VkBuffer m_vkTransformUBOBuffer = VK_NULL_HANDLE; 441 | VkDeviceMemory m_vkTransformUBOBufferDeviceMemory = VK_NULL_HANDLE; 442 | void initTransformUBO(); 443 | void deinitTransformUBO(); 444 | 445 | VkDescriptorPool m_vkDescriptorPool = VK_NULL_HANDLE; 446 | void initDescriptorPool(); 447 | void deinitDescriptorPool(); 448 | 449 | void initShadowMapGenDescriptorSet(); 450 | void updateShadowMapGenDescriptorSetBindings(); 451 | void deinitShadowMapGenDescriptorSet(); 452 | 453 | void initZPrePassDescriptorSet(); 454 | void updateZPrePassDescriptorSetBindings(); 455 | void deinitZPrePassDescriptorSet(); 456 | 457 | void initDescriptorSet(); 458 | void updateDescriptorSetBindings(); 459 | void deinitDescriptorSet(); 460 | 461 | void buildShadowMapGenCommandBuffer(); 462 | void updateShadowMapGenCommandBuffers(); 463 | void destroyShadowMapGenCommandBuffer(); 464 | 465 | void buildZPrePassCommandBuffer(); 466 | void updateZPrePassCommandBuffers(); 467 | void destroyZPrePassCommandBuffer(); 468 | 469 | void buildSecondaryCommandBuffers(); 470 | void updateSecondaryCommandBuffers(const VkCommandBufferInheritanceInfo & commandBufferInheritanceInfo); 471 | void destroySecondaryCommandBuffers(); 472 | 473 | void buildSwapchainCommandBuffers(); 474 | void updateSwapchainCommandBuffers(const VkFramebuffer & framebuffer); 475 | void destroySwapchainCommandBuffers(); 476 | 477 | void initSemaphores(); 478 | void deinitSemaphores(); 479 | 480 | HWND m_hWnd = nullptr; 481 | void init(HWND hWnd, int width, int height); 482 | void deinit(); 483 | 484 | bool m_captureRequested = false; 485 | void requestCapture(bool captureRequested) { m_captureRequested = captureRequested; } 486 | 487 | math::Mat34 m_viewMatrix; 488 | math::Mat34 & getViewMatrix() { return m_viewMatrix; } 489 | const math::Mat34 & getViewMatrix() const { return m_viewMatrix; } 490 | 491 | double m_elapsedTimeMS = 0.0, m_dtMS = 0.0; 492 | double getElapsedTime() const { return m_elapsedTimeMS; } 493 | void increaseDTime(double dtMS) { m_dtMS += dtMS; } 494 | 495 | struct PerspProjParams 496 | { 497 | float fovRad; 498 | float zNear; 499 | float zFar; 500 | float width, height; 501 | float aspect; 502 | }; 503 | void setPerspectiveProjectionParameters(float fovRad, float aspect, float zNear, float zFar, float width, float height, PerspProjParams * params) 504 | { 505 | params->fovRad = fovRad; 506 | params->width = width; 507 | params->height = height; 508 | params->aspect = aspect; 509 | params->zNear = zNear; 510 | params->zFar = zFar; 511 | } 512 | 513 | PerspProjParams m_viewPerspParameters; 514 | void setViewPerspProjParams(float fovRad, float aspect, float zNear, float zFar, float width, float height) 515 | { 516 | setPerspectiveProjectionParameters(fovRad, aspect, zNear, zFar, width, height, &m_viewPerspParameters); 517 | } 518 | void getViewPerspProjParams(float * fovRad, float * aspect, float * zNear, float * zFar, float * width, float * height) const 519 | { 520 | *fovRad = m_viewPerspParameters.fovRad; 521 | *aspect = m_viewPerspParameters.aspect; 522 | *zNear = m_viewPerspParameters.zNear; 523 | *zFar = m_viewPerspParameters.zFar; 524 | *width = m_viewPerspParameters.width; 525 | *height = m_viewPerspParameters.height; 526 | } 527 | 528 | float getViewFOV() const 529 | { 530 | return m_viewPerspParameters.fovRad; 531 | } 532 | void setViewFOV(float fovRad) 533 | { 534 | m_viewPerspParameters.fovRad = fovRad; 535 | } 536 | 537 | PerspProjParams m_lightPerspParameters; 538 | void setLightPerspProjParams(float fovRad, float aspect, float zNear, float zFar, float width, float height) 539 | { 540 | if (aspect != 1.0f) 541 | { 542 | // TODO: warning 543 | printf("Non-unit aspect for light projection matrix is not supprted!\n"); 544 | aspect = 1.0f; 545 | } 546 | 547 | setPerspectiveProjectionParameters(fovRad, aspect, zNear, zFar, width, height, &m_lightPerspParameters); 548 | } 549 | void getLightPerspProjParams(float * fovRad, float * aspect, float * zNear, float * zFar, float * width, float * height) const 550 | { 551 | *fovRad = m_lightPerspParameters.fovRad; 552 | *aspect = m_lightPerspParameters.aspect; 553 | *zNear = m_lightPerspParameters.zNear; 554 | *zFar = m_lightPerspParameters.zFar; 555 | *width = m_lightPerspParameters.width; 556 | *height = m_lightPerspParameters.height; 557 | } 558 | 559 | math::Mat44 m_lightViewMatrix; 560 | void setLightViewMatrix(const math::Mat44 & lightViewMatrix) { m_lightViewMatrix = lightViewMatrix; } 561 | const math::Mat44 & getLightViewMatrix() const { return m_lightViewMatrix; } 562 | 563 | // All rendering-related updates should go strickly after this function 564 | void beginFrame(); 565 | 566 | void update(); 567 | void render(); 568 | }; 569 | 570 | } -------------------------------------------------------------------------------- /vkEngine/source/vulkan/mesh.cpp: -------------------------------------------------------------------------------- 1 | #include "manager.h" 2 | #include "mesh.h" 3 | #include "helpers.h" 4 | 5 | namespace vulkan 6 | { 7 | 8 | void Mesh::createVertexBuffer(uint32_t numVertices, size_t vertexSize) 9 | { 10 | m_meshData.vertexSize = vertexSize; 11 | m_meshData.verticesCount = numVertices; 12 | m_meshData.verticesCapacity = numVertices; 13 | m_meshData.vertexBufferDeviceMemorySize = numVertices * vertexSize; 14 | 15 | VkBufferUsageFlags vertexBufUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; 16 | if (m_vertexBufUsage == BufferUsage::eStatic) 17 | { 18 | vertexBufUsage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; 19 | } 20 | 21 | VkMemoryPropertyFlags vertexBufMemoryProps; 22 | if (m_vertexBufUsage == BufferUsage::eStatic) 23 | { 24 | vertexBufMemoryProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 25 | } 26 | else if (m_vertexBufUsage == BufferUsage::eDynamic) 27 | { 28 | vertexBufMemoryProps = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 29 | } 30 | 31 | if (numVertices > 0) 32 | { 33 | createBuffer( 34 | m_parentWrapper->getPhysicalDeviceHandle(), 35 | m_parentWrapper->getLogicalDeviceHandle(), 36 | (VkDeviceSize)m_meshData.vertexBufferDeviceMemorySize, 37 | vertexBufUsage, 38 | vertexBufMemoryProps, 39 | &m_meshData.vertexBuffer, 40 | &m_meshData.vertexBufferDeviceMemory, 41 | m_parentWrapper->getVkAllocator() 42 | ); 43 | } 44 | } 45 | 46 | void Mesh::createIndexBuffer(uint32_t numIndices, size_t indexSize) 47 | { 48 | if (indexSize == sizeof(uint16_t)) 49 | m_meshData.indexBufferType = VK_INDEX_TYPE_UINT16; 50 | else if (indexSize == sizeof(uint32_t)) 51 | m_meshData.indexBufferType = VK_INDEX_TYPE_UINT32; 52 | else 53 | { 54 | // TOOD: error 55 | printf("Unsupported index size!\n"); 56 | } 57 | 58 | m_meshData.indicesCount = numIndices; 59 | m_meshData.indexBufferDeviceMemorySize = indexSize * numIndices; 60 | 61 | VkBufferUsageFlags indexBufUsage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; 62 | if (m_indexBufUsage == BufferUsage::eStatic) 63 | { 64 | indexBufUsage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; 65 | } 66 | 67 | VkMemoryPropertyFlags indexBufMemoryProps; 68 | if (m_indexBufUsage == BufferUsage::eStatic) 69 | { 70 | indexBufMemoryProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 71 | } 72 | else if (m_indexBufUsage == BufferUsage::eDynamic) 73 | { 74 | indexBufMemoryProps = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 75 | } 76 | 77 | if (numIndices > 0) 78 | { 79 | createBuffer( 80 | m_parentWrapper->getPhysicalDeviceHandle(), 81 | m_parentWrapper->getLogicalDeviceHandle(), 82 | (VkDeviceSize)m_meshData.indexBufferDeviceMemorySize, 83 | indexBufUsage, 84 | indexBufMemoryProps, 85 | &m_meshData.indexBuffer, 86 | &m_meshData.indexBufferDeviceMemory, 87 | m_parentWrapper->getVkAllocator() 88 | ); 89 | } 90 | } 91 | 92 | void Mesh::deleteVertexBuffer() 93 | { 94 | const VkDevice & logicalDev = m_parentWrapper->getLogicalDeviceHandle(); 95 | 96 | if (m_meshData.vertexBuffer != VK_NULL_HANDLE) 97 | { 98 | vkDestroyBuffer(logicalDev, m_meshData.vertexBuffer, m_parentWrapper->getVkAllocator()); 99 | m_meshData.vertexBuffer = VK_NULL_HANDLE; 100 | } 101 | if (m_meshData.vertexBufferDeviceMemory != VK_NULL_HANDLE) 102 | { 103 | vkFreeMemory(logicalDev, m_meshData.vertexBufferDeviceMemory, m_parentWrapper->getVkAllocator()); 104 | m_meshData.vertexBufferDeviceMemory = VK_NULL_HANDLE; 105 | } 106 | m_meshData.verticesCount = -1; 107 | m_meshData.verticesCapacity = 0; 108 | } 109 | 110 | void Mesh::deleteIndexBuffer() 111 | { 112 | const VkDevice & logicalDev = m_parentWrapper->getLogicalDeviceHandle(); 113 | 114 | if (m_meshData.indexBuffer != VK_NULL_HANDLE) 115 | { 116 | vkDestroyBuffer(logicalDev, m_meshData.indexBuffer, m_parentWrapper->getVkAllocator()); 117 | m_meshData.indexBuffer = VK_NULL_HANDLE; 118 | } 119 | if (m_meshData.indexBufferDeviceMemory != VK_NULL_HANDLE) 120 | { 121 | vkFreeMemory(logicalDev, m_meshData.indexBufferDeviceMemory, m_parentWrapper->getVkAllocator()); 122 | m_meshData.indexBufferDeviceMemory = VK_NULL_HANDLE; 123 | } 124 | m_meshData.indicesCount = -1; 125 | m_meshData.indicesCapacity = 0; 126 | } 127 | 128 | void Mesh::updateBufferStaging(const VkBuffer & targetBuffer, const void * bufferData, size_t bufferSize) 129 | { 130 | if (bufferSize == 0) 131 | return; 132 | 133 | VkBuffer stagingBuffer; 134 | VkDeviceMemory stagingBufferDeviceMemory; 135 | createBuffer( 136 | m_parentWrapper->getPhysicalDeviceHandle(), 137 | m_parentWrapper->getLogicalDeviceHandle(), 138 | (VkDeviceSize)bufferSize, 139 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 140 | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 141 | &stagingBuffer, 142 | &stagingBufferDeviceMemory, 143 | m_parentWrapper->getVkAllocator() 144 | ); 145 | 146 | const VkDevice & logicalDev = m_parentWrapper->getLogicalDeviceHandle(); 147 | 148 | void * data = nullptr; 149 | vkMapMemory(logicalDev, stagingBufferDeviceMemory, 0, (VkDeviceSize)bufferSize, 0, &data); 150 | memcpy(data, bufferData, bufferSize); 151 | vkUnmapMemory(logicalDev, stagingBufferDeviceMemory); 152 | 153 | m_parentWrapper->copyBuffer(stagingBuffer, targetBuffer, (VkDeviceSize)bufferSize); 154 | 155 | vkDestroyBuffer(logicalDev, stagingBuffer, m_parentWrapper->getVkAllocator()); 156 | vkFreeMemory(logicalDev, stagingBufferDeviceMemory, m_parentWrapper->getVkAllocator()); 157 | } 158 | 159 | void Mesh::updateBufferDirect(const VkDeviceMemory & bufferDeviceMemory, const void * bufferData, size_t bufferSize) 160 | { 161 | const VkDevice & logicalDev = m_parentWrapper->getLogicalDeviceHandle(); 162 | 163 | void * data; 164 | vkMapMemory(logicalDev, bufferDeviceMemory, 0, (VkDeviceSize)bufferSize, 0, &data); 165 | memcpy(data, bufferData, bufferSize); 166 | vkUnmapMemory(logicalDev, bufferDeviceMemory); 167 | } 168 | 169 | void Mesh::initBuffers(BufferUsage vertexBufferUsage, uint32_t numVertices, size_t vertexSize, BufferUsage indexBufferUsage, uint32_t numIndices) 170 | { 171 | m_vertexBufUsage = vertexBufferUsage; 172 | m_indexBufUsage = indexBufferUsage; 173 | 174 | createVertexBuffer(numVertices, vertexSize); 175 | createIndexBuffer(numIndices); 176 | } 177 | 178 | void Mesh::deinitBuffers() 179 | { 180 | const VkDevice & logicalDev = m_parentWrapper->getLogicalDeviceHandle(); 181 | 182 | deleteIndexBuffer(); 183 | deleteVertexBuffer(); 184 | } 185 | 186 | void Mesh::updateVertexBuffer(const void * bufferData) 187 | { 188 | size_t vertexBufferSize = m_meshData.verticesCount * m_meshData.vertexSize; 189 | if (m_vertexBufUsage == BufferUsage::eStatic) 190 | { 191 | updateBufferStaging(m_meshData.vertexBuffer, bufferData, vertexBufferSize); 192 | } 193 | else if (m_vertexBufUsage == BufferUsage::eDynamic) 194 | { 195 | updateBufferDirect(m_meshData.vertexBufferDeviceMemory, bufferData, vertexBufferSize); 196 | } 197 | } 198 | 199 | void Mesh::updateResizeVertexBuffer(const void * bufferData, uint32_t numVertices) 200 | { 201 | if ((int)numVertices > m_meshData.verticesCapacity) 202 | { 203 | size_t vertexSize = m_meshData.vertexSize; 204 | 205 | if (m_meshData.verticesCount > 0) 206 | { 207 | vkQueueWaitIdle(m_parentWrapper->getGraphicsQueue()); 208 | deleteVertexBuffer(); 209 | } 210 | 211 | createVertexBuffer(numVertices, vertexSize); 212 | } 213 | 214 | m_meshData.verticesCount = numVertices; 215 | updateVertexBuffer(bufferData); 216 | } 217 | 218 | void Mesh::updateIndexBuffer(const void * bufferData) 219 | { 220 | size_t indexBufferSize = m_meshData.indicesCount * m_meshData.indexSize; 221 | if (m_indexBufUsage == BufferUsage::eStatic) 222 | { 223 | updateBufferStaging(m_meshData.indexBuffer, bufferData, indexBufferSize); 224 | } 225 | else if (m_indexBufUsage == BufferUsage::eDynamic) 226 | { 227 | updateBufferDirect(m_meshData.indexBufferDeviceMemory, bufferData, indexBufferSize); 228 | } 229 | } 230 | 231 | void Mesh::updateResizeIndexBuffer(const void * bufferData, uint32_t numIndices) 232 | { 233 | const VkDevice & logicalDev = m_parentWrapper->getLogicalDeviceHandle(); 234 | 235 | if ((int)numIndices > m_meshData.indicesCapacity) 236 | { 237 | size_t indexSize = m_meshData.indexSize; 238 | 239 | if (m_meshData.indicesCount > 0) 240 | { 241 | vkDeviceWaitIdle(logicalDev); 242 | deleteIndexBuffer(); 243 | } 244 | 245 | createIndexBuffer(numIndices, indexSize); 246 | } 247 | 248 | m_meshData.indicesCount = numIndices; 249 | updateIndexBuffer(bufferData); 250 | } 251 | 252 | } -------------------------------------------------------------------------------- /vkEngine/source/vulkan/mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "definitions.h" 6 | 7 | namespace vulkan 8 | { 9 | class Wrapper; 10 | 11 | class Mesh 12 | { 13 | protected: 14 | 15 | BufferUsage m_vertexBufUsage; 16 | BufferUsage m_indexBufUsage; 17 | 18 | struct VulkanMeshData 19 | { 20 | int verticesCount = -1; 21 | size_t vertexSize = 0; 22 | size_t verticesCapacity = 0; 23 | VkBuffer vertexBuffer = VK_NULL_HANDLE; 24 | size_t vertexBufferDeviceMemorySize = 0; 25 | VkDeviceMemory vertexBufferDeviceMemory = VK_NULL_HANDLE; 26 | 27 | int indicesCount = -1; 28 | size_t indexSize = sizeof(uint16_t); 29 | size_t indicesCapacity = 0; 30 | VkIndexType indexBufferType = VK_INDEX_TYPE_UINT16; 31 | VkBuffer indexBuffer = VK_NULL_HANDLE; 32 | size_t indexBufferDeviceMemorySize = 0; 33 | VkDeviceMemory indexBufferDeviceMemory = VK_NULL_HANDLE; 34 | }; 35 | VulkanMeshData m_meshData; 36 | 37 | math::Mat44 m_viewMatrix; 38 | 39 | Wrapper * m_parentWrapper = nullptr; 40 | 41 | void createVertexBuffer(uint32_t numVertices, size_t vertexSize); 42 | void createIndexBuffer(uint32_t numIndices, size_t indexSize = sizeof(uint16_t)); 43 | 44 | void deleteVertexBuffer(); 45 | void deleteIndexBuffer(); 46 | 47 | void updateBufferStaging(const VkBuffer & targetBuffer, const void * bufferData, size_t bufferSize); 48 | void updateBufferDirect(const VkDeviceMemory & bufferDeviceMemory, const void * bufferData, size_t bufferSize); 49 | 50 | public: 51 | 52 | void init(Wrapper * vulkanWrapper) 53 | { 54 | m_parentWrapper = vulkanWrapper; 55 | m_viewMatrix.identity(); 56 | } 57 | void deinit() 58 | { 59 | deinitBuffers(); 60 | } 61 | 62 | void initBuffers(BufferUsage vertexBufferUsage, uint32_t numVertices, size_t vertexSize, BufferUsage indexBufferUsage, uint32_t numIndices); 63 | void deinitBuffers(); 64 | 65 | VkBuffer getVertexBuffer() const { return m_meshData.vertexBuffer; } 66 | int getVerticesCount() const { return m_meshData.verticesCount; } 67 | VkBuffer getIndexBuffer() const { return m_meshData.indexBuffer; } 68 | VkIndexType getIndexBufferType() const { return m_meshData.indexBufferType; } 69 | int getIndicesCount() const { return m_meshData.indicesCount; } 70 | 71 | void setModelMatrix(const math::Mat44 & mat44) { m_viewMatrix = mat44; } 72 | math::Mat44 & getModelMatrix() { return m_viewMatrix; } 73 | const math::Mat44 & getModelMatrix() const { return m_viewMatrix; } 74 | 75 | void updateVertexBuffer(const void * bufferData); 76 | void updateResizeVertexBuffer(const void * bufferData, uint32_t numVertices); 77 | void updateIndexBuffer(const void * bufferData); 78 | void updateResizeIndexBuffer(const void * bufferData, uint32_t numIndices); 79 | }; 80 | 81 | } -------------------------------------------------------------------------------- /vkEngine/vkEngine.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {35C0E3E4-4770-4581-98DC-8A7D4178BDEC} 24 | Win32Proj 25 | vkEngine 26 | 10.0.10586.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v140 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v140 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v140 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v140 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | true 79 | $(SolutionDir)_out\$(ProjectName)\$(Platform)\$(Configuration)\ 80 | $(SolutionDir)_interm\$(ProjectName)\$(Platform)\$(Configuration)\ 81 | 82 | 83 | true 84 | $(SolutionDir)_out\$(ProjectName)\$(Platform)\$(Configuration)\ 85 | $(SolutionDir)_interm\$(ProjectName)\$(Platform)\$(Configuration)\ 86 | 87 | 88 | false 89 | $(SolutionDir)_out\$(ProjectName)\$(Platform)\$(Configuration)\ 90 | $(SolutionDir)_interm\$(ProjectName)\$(Platform)\$(Configuration)\ 91 | 92 | 93 | false 94 | $(SolutionDir)_out\$(ProjectName)\$(Platform)\$(Configuration)\ 95 | $(SolutionDir)_interm\$(ProjectName)\$(Platform)\$(Configuration)\ 96 | 97 | 98 | 99 | 100 | 101 | Level3 102 | Disabled 103 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | shaders;..\core\include;source;$(VulkanSDKRoot)\include; 105 | 106 | 107 | Console 108 | $(VulkanSDKRoot)\Lib32 109 | vulkan-1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 110 | 111 | 112 | 113 | 114 | 115 | 116 | Level3 117 | Disabled 118 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 119 | shaders;..\core\include;source;$(VulkanSDKRoot)\include; 120 | 121 | 122 | Console 123 | $(VulkanSDKRoot)\Lib 124 | vulkan-1.lib;%(AdditionalDependencies) 125 | 126 | 127 | 128 | 129 | Level3 130 | 131 | 132 | MaxSpeed 133 | true 134 | true 135 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | shaders;..\core\include;source;$(VulkanSDKRoot)\include; 137 | 138 | 139 | Console 140 | true 141 | true 142 | $(VulkanSDKRoot)\Lib32 143 | vulkan-1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 144 | 145 | 146 | 147 | 148 | Level3 149 | 150 | 151 | MaxSpeed 152 | true 153 | true 154 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 155 | shaders;..\core\include;source;$(VulkanSDKRoot)\include; 156 | 157 | 158 | Console 159 | true 160 | true 161 | $(VulkanSDKRoot)\Lib 162 | vulkan-1.lib;%(AdditionalDependencies) 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | Document 176 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\pathtracer.fs.spv shaders\pathtracer.fs 177 | shaders\bin\pathtracer.fs.spv 178 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\pathtracer.fs.spv shaders\pathtracer.fs 179 | shaders\bin\pathtracer.fs.spv 180 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\pathtracer.fs.spv shaders\pathtracer.fs 181 | shaders\bin\pathtracer.fs.spv 182 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\pathtracer.fs.spv shaders\pathtracer.fs 183 | shaders\bin\pathtracer.fs.spv 184 | shaders\shader_bindings.h 185 | shaders\shader_bindings.h 186 | shaders\shader_bindings.h 187 | shaders\shader_bindings.h 188 | 189 | 190 | Document 191 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\test.vs.spv shaders\test.vs 192 | shaders\bin\test.vs.spv 193 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\test.vs.spv shaders\test.vs 194 | shaders\bin\test.vs.spv 195 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\test.vs.spv shaders\test.vs 196 | shaders\bin\test.vs.spv 197 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\test.vs.spv shaders\test.vs 198 | shaders\bin\test.vs.spv 199 | shaders\shader_bindings.h 200 | shaders\shader_bindings.h 201 | shaders\shader_bindings.h 202 | shaders\shader_bindings.h 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | {4504335c-7145-485f-ae40-6824da670a3e} 218 | 219 | 220 | 221 | 222 | Document 223 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\fs_blobs.fs.spv shaders\fs_blobs.fs 224 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\fs_blobs.fs.spv shaders\fs_blobs.fs 225 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\fs_blobs.fs.spv shaders\fs_blobs.fs 226 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\fs_blobs.fs.spv shaders\fs_blobs.fs 227 | shaders\bin\fs_blobs.fs.spv 228 | shaders\bin\fs_blobs.fs.spv 229 | shaders\bin\fs_blobs.fs.spv 230 | shaders\bin\fs_blobs.fs.spv 231 | shaders\shader_bindings.h 232 | shaders\shader_bindings.h 233 | shaders\shader_bindings.h 234 | shaders\shader_bindings.h 235 | 236 | 237 | Document 238 | shaders\bin\fs_blobs.vs.spv 239 | shaders\bin\fs_blobs.vs.spv 240 | shaders\bin\fs_blobs.vs.spv 241 | shaders\bin\fs_blobs.vs.spv 242 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\fs_blobs.vs.spv shaders\fs_blobs.vs 243 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\fs_blobs.vs.spv shaders\fs_blobs.vs 244 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\fs_blobs.vs.spv shaders\fs_blobs.vs 245 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\fs_blobs.vs.spv shaders\fs_blobs.vs 246 | shaders\shader_bindings.h 247 | shaders\shader_bindings.h 248 | shaders\shader_bindings.h 249 | shaders\shader_bindings.h 250 | 251 | 252 | 253 | 254 | Document 255 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\mesh.fs.spv shaders\mesh.fs 256 | shaders\bin\mesh.fs.spv 257 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\mesh.fs.spv shaders\mesh.fs 258 | shaders\bin\mesh.fs.spv 259 | shaders\bin\mesh.fs.spv 260 | shaders\bin\mesh.fs.spv 261 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\mesh.fs.spv shaders\mesh.fs 262 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\mesh.fs.spv shaders\mesh.fs 263 | shaders\shader_bindings.h 264 | shaders\shader_bindings.h 265 | shaders\shader_bindings.h 266 | shaders\shader_bindings.h 267 | 268 | 269 | Document 270 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\mesh.vs.spv shaders\mesh.vs 271 | shaders\bin\mesh.vs.spv 272 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\mesh.vs.spv shaders\mesh.vs 273 | shaders\bin\mesh.vs.spv 274 | shaders\shader_bindings.h 275 | shaders\shader_bindings.h 276 | shaders\shader_bindings.h 277 | shaders\shader_bindings.h 278 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\mesh.vs.spv shaders\mesh.vs 279 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\mesh.vs.spv shaders\mesh.vs 280 | shaders\bin\mesh.vs.spv 281 | shaders\bin\mesh.vs.spv 282 | 283 | 284 | 285 | 286 | Document 287 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\debug_vis.fs.spv shaders\debug_vis.fs 288 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\debug_vis.fs.spv shaders\debug_vis.fs 289 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\debug_vis.fs.spv shaders\debug_vis.fs 290 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\debug_vis.fs.spv shaders\debug_vis.fs 291 | shaders\bin\debug_vis.fs.spv 292 | shaders\bin\debug_vis.fs.spv 293 | shaders\bin\debug_vis.fs.spv 294 | shaders\bin\debug_vis.fs.spv 295 | shaders\shader_bindings.h 296 | shaders\shader_bindings.h 297 | shaders\shader_bindings.h 298 | shaders\shader_bindings.h 299 | 300 | 301 | Document 302 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\debug_vis.vs.spv shaders\debug_vis.vs 303 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\debug_vis.vs.spv shaders\debug_vis.vs 304 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\debug_vis.vs.spv shaders\debug_vis.vs 305 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\debug_vis.vs.spv shaders\debug_vis.vs 306 | shaders\bin\debug_vis.vs.spv 307 | shaders\bin\debug_vis.vs.spv 308 | shaders\bin\debug_vis.vs.spv 309 | shaders\bin\debug_vis.vs.spv 310 | shaders\shader_bindings.h 311 | shaders\shader_bindings.h 312 | shaders\shader_bindings.h 313 | shaders\shader_bindings.h 314 | 315 | 316 | 317 | 318 | Document 319 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\shadowmap.fs.spv shaders\shadowmap.fs 320 | shaders\bin\shadowmap.fs.spv 321 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\shadowmap.fs.spv shaders\shadowmap.fs 322 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\shadowmap.fs.spv shaders\shadowmap.fs 323 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S frag -o shaders\bin\shadowmap.fs.spv shaders\shadowmap.fs 324 | shaders\bin\shadowmap.fs.spv 325 | shaders\bin\shadowmap.fs.spv 326 | shaders\bin\shadowmap.fs.spv 327 | shaders\shader_bindings.h 328 | shaders\shader_bindings.h 329 | shaders\shader_bindings.h 330 | shaders\shader_bindings.h 331 | 332 | 333 | Document 334 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\shadowmap.vs.spv shaders\shadowmap.vs 335 | shaders\bin\shadowmap.vs.spv 336 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\shadowmap.vs.spv shaders\shadowmap.vs 337 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\shadowmap.vs.spv shaders\shadowmap.vs 338 | "$(VulkanSDKRoot)\Bin32\glslangValidator.exe" -V -S vert -o shaders\bin\shadowmap.vs.spv shaders\shadowmap.vs 339 | shaders\bin\shadowmap.vs.spv 340 | shaders\bin\shadowmap.vs.spv 341 | shaders\bin\shadowmap.vs.spv 342 | shaders\shader_bindings.h 343 | shaders\shader_bindings.h 344 | shaders\shader_bindings.h 345 | shaders\shader_bindings.h 346 | 347 | 348 | 349 | 350 | 351 | -------------------------------------------------------------------------------- /vkEngine/vkEngine.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {87b9cb7a-5d3a-4d27-85a3-219d29b1894f} 18 | 19 | 20 | {a526831f-376c-4902-b461-de91b61b9ebb} 21 | 22 | 23 | {fd65e2b9-7679-4ce9-a0d0-d949dbb4c123} 24 | 25 | 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files\vulkan 32 | 33 | 34 | Source Files\vulkan 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files\vulkan 41 | 42 | 43 | Source Files 44 | 45 | 46 | 47 | 48 | Shaders 49 | 50 | 51 | Shaders 52 | 53 | 54 | Shaders 55 | 56 | 57 | Shaders 58 | 59 | 60 | Shaders 61 | 62 | 63 | Shaders 64 | 65 | 66 | Shaders 67 | 68 | 69 | Shaders 70 | 71 | 72 | Shaders 73 | 74 | 75 | Shaders 76 | 77 | 78 | 79 | 80 | Header Files\vulkan 81 | 82 | 83 | Header Files\vulkan 84 | 85 | 86 | Header Files\vulkan 87 | 88 | 89 | Header Files 90 | 91 | 92 | Header Files\vulkan 93 | 94 | 95 | Header Files 96 | 97 | 98 | Source Files 99 | 100 | 101 | Source Files 102 | 103 | 104 | --------------------------------------------------------------------------------