├── vkEngine
├── source
│ ├── app.cpp
│ ├── vulkan
│ │ ├── helpers.cpp
│ │ ├── definitions.h
│ │ ├── helpers.h
│ │ ├── mesh.h
│ │ ├── mesh.cpp
│ │ └── manager.h
│ ├── camera.h
│ ├── camera.cpp
│ ├── app.h
│ ├── drawing_primitives.h
│ └── main.cpp
├── shaders
│ ├── shader_bindings.h
│ ├── shadowmap.fs
│ ├── debug_vis.fs
│ ├── debug_vis.vs
│ ├── test.vs
│ ├── shadowmap.vs
│ ├── fs_blobs.fs
│ ├── mesh.vs
│ ├── fs_blobs.vs
│ ├── mesh.fs
│ └── pathtracer.fs
├── PropertySheet.props
├── vkEngine.vcxproj.filters
└── vkEngine.vcxproj
├── .gitmodules
├── .gitignore
├── materials
├── PGS120_LCPCG60_NNCG85.png
├── PGS_105iters_vs_LCPCG_50iters.png
└── PGSvsLCPCGvsNNCG_convergence.png
├── vkEngine.sln
├── readme.md
└── LICENSE.md
/vkEngine/source/app.cpp:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "core"]
2 | path = core
3 | url = https://github.com/avoroshilov/core.git
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /_interm/*
2 | /_out/*
3 | /.vs/*
4 | /vkEngine.VC.db
5 | /vkEngine.VC.VC.opendb
6 | /vkEngine/shaders/bin/*
7 |
--------------------------------------------------------------------------------
/materials/PGS120_LCPCG60_NNCG85.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avoroshilov/physics_playground/HEAD/materials/PGS120_LCPCG60_NNCG85.png
--------------------------------------------------------------------------------
/vkEngine/source/vulkan/helpers.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avoroshilov/physics_playground/HEAD/vkEngine/source/vulkan/helpers.cpp
--------------------------------------------------------------------------------
/materials/PGS_105iters_vs_LCPCG_50iters.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avoroshilov/physics_playground/HEAD/materials/PGS_105iters_vs_LCPCG_50iters.png
--------------------------------------------------------------------------------
/materials/PGSvsLCPCGvsNNCG_convergence.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avoroshilov/physics_playground/HEAD/materials/PGSvsLCPCGvsNNCG_convergence.png
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/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/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/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/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/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/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.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/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/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/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/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 |
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 |
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/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/drawing_primitives.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include