diff --git a/README.md b/README.md
index a744a2e..26bca5d 100644
--- a/README.md
+++ b/README.md
@@ -1,297 +1,55 @@
-Instructions - Vulkan Grass Rendering
+Vulkan Grass Rendering
========================
-This is due **Sunday 11/5, evening at midnight**.
+**University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 6**
-**Summary:**
-In this project, you will use Vulkan to implement a grass simulator and renderer. You will
-use compute shaders to perform physics calculations on Bezier curves that represent individual
-grass blades in your application. Since rendering every grass blade on every frame will is fairly
-inefficient, you will also use compute shaders to cull grass blades that don't contribute to a given frame.
-The remaining blades will be passed to a graphics pipeline, in which you will write several shaders.
-You will write a vertex shader to transform Bezier control points, tessellation shaders to dynamically create
-the grass geometry from the Bezier curves, and a fragment shader to shade the grass blades.
+* Yalun Hu
+* Tested on: Windows 10, i7-6700HQ CPU @ 2.60GHz 32GB, GTX 1070 8192MB (Personal computer)
-The base code provided includes all of the basic Vulkan setup, including a compute pipeline that will run your compute
-shaders and two graphics pipelines, one for rendering the geometry that grass will be placed on and the other for
-rendering the grass itself. Your job will be to write the shaders for the grass graphics pipeline and the compute pipeline,
-as well as binding any resources (descriptors) you may need to accomplish the tasks described in this assignment.
+
+
+
-
+# Features
-You are not required to use this base code if you don't want
-to. You may also change any part of the base code as you please.
-**This is YOUR project.** The above .gif is just a simple example that you
-can use as a reference to compare to.
+## 1. Compute Shader
-**Important:**
-- If you are not in CGGT/DMD, you may replace this project with a GPU compute
-project. You MUST get this pre-approved by Austin Eng before continuing!
+
+
+
-### Contents
+* Perform physics calculations on Bezier curves that represent individual grass blades.
+ * Apply gravity, wind force, recovery force to each blade.
+* Cull grass blades that don't contribute to a given frame.
+ * Orientation culling
+ * View-frustum culling
+ * Distance culling
-* `src/` C++/Vulkan source files.
- * `shaders/` glsl shader source files
- * `images/` images used as textures within graphics pipelines
-* `external/` Includes and static libraries for 3rd party libraries.
-* `img/` Screenshots and images to use in your READMEs
+## 2. Graphics pipeline
+* Vertex shader
+ * transform Bezier control points from model space to world space.
+* Tessellation control shader
+ * Decide tesselation level.
+* Tessellation evaluation shader
+ * place the vertices in world space, respecting the width, height, and orientation information of each blade. Here I used triangle as the basic shape.
+* Fragment shader
+ * Lambert shading with a simple point light.
-### Installing Vulkan
+# Performance Analysis
+
+
+
-In order to run a Vulkan project, you first need to download and install the [Vulkan SDK](https://vulkan.lunarg.com/).
-Make sure to run the downloaded installed as administrator so that the installer can set the appropriate environment
-variables for you.
+* Parameter:
+ * Distance culling: Max depth = 50, Culling level = 10
+ * View-frustum culling: tolerance = 1
-Once you have done this, you need to make sure your GPU driver supports Vulkan. Download and install a
-[Vulkan driver](https://developer.nvidia.com/vulkan-driver) from NVIDIA's website.
+It shows that culling really improves the performance, especially when the number of blades is big. For different three culling method, orientation culling has a bigger influence than other two methods, and view-frustum culling has less impact on the performance.
-Finally, to check that Vulkan is ready for use, go to your Vulkan SDK directory (`C:/VulkanSDK/` unless otherwise specified)
-and run the `cube.exe` example within the `Bin` directory. IF you see a rotating gray cube with the LunarG logo, then you
-are all set!
-
-### Running the code
-
-While developing your grass renderer, you will want to keep validation layers enabled so that error checking is turned on.
-The project is set up such that when you are in `debug` mode, validation layers are enabled, and when you are in `release` mode,
-validation layers are disabled. After building the code, you should be able to run the project without any errors. You will see
-a plane with a grass texture on it to begin with.
-
-
-
-## Requirements
-
-**Ask on the mailing list for any clarifications.**
-
-In this project, you are given the following code:
-
-* The basic setup for a Vulkan project, including the swapchain, physical device, logical device, and the pipelines described above.
-* Structs for some of the uniform buffers you will be using.
-* Some buffer creation utility functions.
-* A simple interactive camera using the mouse.
-
-You need to implement the following features/pipeline stages:
-
-* Compute shader (`shaders/compute.comp`)
-* Grass pipeline stages
- * Vertex shader (`shaders/grass.vert')
- * Tessellation control shader (`shaders/grass.tesc`)
- * Tessellation evaluation shader (`shaders/grass.tese`)
- * Fragment shader (`shaders/grass.frag`)
-* Binding of any extra descriptors you may need
-
-See below for more guidance.
-
-## Base Code Tour
-
-Areas that you need to complete are
-marked with a `TODO` comment. Functions that are useful
-for reference are marked with the comment `CHECKITOUT`.
-
-* `src/main.cpp` is the entry point of our application.
-* `src/Instance.cpp` sets up the application state, initializes the Vulkan library, and contains functions that will create our
-physical and logical device handles.
-* `src/Device.cpp` manages the logical device and sets up the queues that our command buffers will be submitted to.
-* `src/Renderer.cpp` contains most of the rendering implementation, including Vulkan setup and resource creation. You will
-likely have to make changes to this file in order to support changes to your pipelines.
-* `src/Camera.cpp` manages the camera state.
-* `src/Model.cpp` manages the state of the model that grass will be created on. Currently a plane is hardcoded, but feel free to
-update this with arbitrary model loading!
-* `src/Blades.cpp` creates the control points corresponding to the grass blades. There are many parameters that you can play with
-here that will change the behavior of your rendered grass blades.
-* `src/Scene.cpp` manages the scene state, including the model, blades, and simualtion time.
-* `src/BufferUtils.cpp` provides helper functions for creating buffers to be used as descriptors.
-
-We left out descriptions for a couple files that you likely won't have to modify. Feel free to investigate them to understand their
-importance within the scope of the project.
-
-## Grass Rendering
-
-This project is an implementation of the paper, [Responsive Real-Time Grass Rendering for General 3D Scenes](https://www.cg.tuwien.ac.at/research/publications/2017/JAHRMANN-2017-RRTG/JAHRMANN-2017-RRTG-draft.pdf).
-Please make sure to use this paper as a primary resource while implementing your grass renderers. It does a great job of explaining
-the key algorithms and math you will be using. Below is a brief description of the different components in chronological order of how your renderer will
-execute, but feel free to develop the components in whatever order you prefer.
-
-### Representing Grass as Bezier Curves
-
-In this project, grass blades will be represented as Bezier curves while performing physics calculations and culling operations.
-Each Bezier curve has three control points.
-* `v0`: the position of the grass blade on the geomtry
-* `v1`: a Bezier curve guide that is always "above" `v0` with respect to the grass blade's up vector (explained soon)
-* `v2`: a physical guide for which we simulate forces on
-
-We also need to store per-blade characteristics that will help us simulate and tessellate our grass blades correctly.
-* `up`: the blade's up vector, which corresponds to the normal of the geometry that the grass blade resides on at `v0`
-* Orientation: the orientation of the grass blade's face
-* Height: the height of the grass blade
-* Width: the width of the grass blade's face
-* Stiffness coefficient: the stiffness of our grass blade, which will affect the force computations on our blade
-
-We can pack all this data into four `vec4`s, such that `v0.w` holds orientation, `v1.w` holds height, `v2.w` holds width, and
-`up.w` holds the stiffness coefficient.
-
-
-
-### Simulating Forces
-
-In this project, you will be simulating forces on grass blades while they are still Bezier curves. This will be done in a compute
-shader using the compute pipeline that has been created for you. Remember that `v2` is our physical guide, so we will be
-applying transformations to `v2` initially, then correcting for potential errors. We will finally update `v1` to maintain the appropriate
-length of our grass blade.
-
-#### Binding Resources
-
-In order to update the state of your grass blades on every frame, you will need to create a storage buffer to maintain the grass data.
-You will also need to pass information about how much time has passed in the simulation and the time since the last frame. To do this,
-you can extend or create descriptor sets that will be bound to the compute pipeline.
-
-#### Gravity
-
-Given a gravity direction, `D.xyz`, and the magnitude of acceleration, `D.w`, we can compute the environmental gravity in
-our scene as `gE = normalize(D.xyz) * D.w`.
-
-We then determine the contribution of the gravity with respect to the front facing direction of the blade, `f`,
-as a term called the "front gravity". Front gravity is computed as `gF = (1/4) * ||gE|| * f`.
-
-We can then determine the total gravity on the grass blade as `g = gE + gF`.
-
-#### Recovery
-
-Recovery corresponds to the counter-force that brings our grass blade back into equilibrium. This is derived in the paper using Hooke's law.
-In order to determine the recovery force, we need to compare the current position of `v2` to its original position before
-simulation started, `iv2`. At the beginning of our simulation, `v1` and `v2` are initialized to be a distance of the blade height along the `up` vector.
-
-Once we have `iv2`, we can compute the recovery forces as `r = (iv2 - v2) * stiffness`.
-
-#### Wind
-
-In order to simulate wind, you are at liberty to create any wind function you want! In order to have something interesting,
-you can make the function depend on the position of `v0` and a function that changes with time. Consider using some combination
-of sine or cosine functions.
-
-Your wind function will determine a wind direction that is affecting the blade, but it is also worth noting that wind has a larger impact on
-grass blades whose forward directions are parallel to the wind direction. The paper describes this as a "wind alignment" term. We won't go
-over the exact math here, but use the paper as a reference when implementing this. It does a great job of explaining this!
-
-Once you have a wind direction and a wind alignment term, your total wind force (`w`) will be `windDirection * windAlignment`.
-
-#### Total force
-
-We can then determine a translation for `v2` based on the forces as `tv2 = (gravity + recovery + wind) * deltaTime`. However, we can't simply
-apply this translation and expect the simulation to be robust. Our forces might push `v2` under the ground! Similarly, moving `v2` but leaving
-`v1` in the same position will cause our grass blade to change length, which doesn't make sense.
-
-Read section 5.2 of the paper in order to learn how to determine the corrected final positions for `v1` and `v2`.
-
-### Culling tests
-
-Although we need to simulate forces on every grass blade at every frame, there are many blades that we won't need to render
-due to a variety of reasons. Here are some heuristics we can use to cull blades that won't contribute positively to a given frame.
-
-#### Orientation culling
-
-Consider the scenario in which the front face direction of the grass blade is perpendicular to the view vector. Since our grass blades
-won't have width, we will end up trying to render parts of the grass that are actually smaller than the size of a pixel. This could
-lead to aliasing artifacts.
-
-In order to remedy this, we can cull these blades! Simply do a dot product test to see if the view vector and front face direction of
-the blade are perpendicular. The paper uses a threshold value of `0.9` to cull, but feel free to use what you think looks best.
-
-#### View-frustum culling
-
-We also want to cull blades that are outside of the view-frustum, considering they won't show up in the frame anyway. To determine if
-a grass blade is in the view-frustum, we want to compare the visibility of three points: `v0, v2, and m`, where `m = (1/4)v0 * (1/2)v1 * (1/4)v2`.
-Notice that we aren't using `v1` for the visibility test. This is because the `v1` is a Bezier guide that doesn't represent a position on the grass blade.
-We instead use `m` to approximate the midpoint of our Bezier curve.
-
-If all three points are outside of the view-frustum, we will cull the grass blade. The paper uses a tolerance value for this test so that we are culling
-blades a little more conservatively. This can help with cases in which the Bezier curve is technically not visible, but we might be able to see the blade
-if we consider its width.
-
-#### Distance culling
-
-Similarly to orientation culling, we can end up with grass blades that at large distances are smaller than the size of a pixel. This could lead to additional
-artifacts in our renders. In this case, we can cull grass blades as a function of their distance from the camera.
-
-You are free to define two parameters here.
-* A max distance afterwhich all grass blades will be culled.
-* A number of buckets to place grass blades between the camera and max distance into.
-
-Define a function such that the grass blades in the bucket closest to the camera are kept while an increasing number of grass blades
-are culled with each farther bucket.
-
-#### Occlusion culling (extra credit)
-
-This type of culling only makes sense if our scene has additional objects aside from the plane and the grass blades. We want to cull grass blades that
-are occluded by other geometry. Think about how you can use a depth map to accomplish this!
-
-### Tessellating Bezier curves into grass blades
-
-In this project, you should pass in each Bezier curve as a single patch to be processed by your grass graphics pipeline. You will tessellate this patch into
-a quad with a shape of your choosing (as long as it looks sufficiently like grass of course). The paper has some examples of grass shapes you can use as inspiration.
-
-In the tessellation control shader, specify the amount of tessellation you want to occur. Remember that you need to provide enough detail to create the curvature of a grass blade.
-
-The generated vertices will be passed to the tessellation evaluation shader, where you will place the vertices in world space, respecting the width, height, and orientation information
-of each blade. Once you have determined the world space position of each vector, make sure to set the output `gl_Position` in clip space!
-
-** Extra Credit**: Tessellate to varying levels of detail as a function of how far the grass blade is from the camera. For example, if the blade is very far, only generate four vertices in the tessellation control shader.
-
-To build more intuition on how tessellation works, I highly recommend playing with the [helloTessellation sample](https://github.com/CIS565-Fall-2017/Vulkan-Samples/tree/master/samples/5_helloTessellation)
-and reading this [tutorial on tessellation](http://in2gpu.com/2014/07/12/tessellation-tutorial-opengl-4-3/).
-
-## Resources
-
-### Links
-
-The following resources may be useful for this project.
+# References
* [Responsive Real-Time Grass Grass Rendering for General 3D Scenes](https://www.cg.tuwien.ac.at/research/publications/2017/JAHRMANN-2017-RRTG/JAHRMANN-2017-RRTG-draft.pdf)
* [CIS565 Vulkan samples](https://github.com/CIS565-Fall-2017/Vulkan-Samples)
* [Official Vulkan documentation](https://www.khronos.org/registry/vulkan/)
* [Vulkan tutorial](https://vulkan-tutorial.com/)
-* [RenderDoc blog on Vulkan](https://renderdoc.org/vulkan-in-30-minutes.html)
-* [Tessellation tutorial](http://in2gpu.com/2014/07/12/tessellation-tutorial-opengl-4-3/)
-
-
-## Third-Party Code Policy
-
-* Use of any third-party code must be approved by asking on our Google Group.
-* If it is approved, all students are welcome to use it. Generally, we approve
- use of third-party code that is not a core part of the project. For example,
- for the path tracer, we would approve using a third-party library for loading
- models, but would not approve copying and pasting a CUDA function for doing
- refraction.
-* Third-party code **MUST** be credited in README.md.
-* Using third-party code without its approval, including using another
- student's code, is an academic integrity violation, and will, at minimum,
- result in you receiving an F for the semester.
-
-
-## README
-
-* A brief description of the project and the specific features you implemented.
-* At least one screenshot of your project running.
-* A performance analysis (described below).
-
-### Performance Analysis
-
-The performance analysis is where you will investigate how...
-* Your renderer handles varying numbers of grass blades
-* The improvement you get by culling using each of the three culling tests
-
-## Submit
-
-If you have modified any of the `CMakeLists.txt` files at all (aside from the
-list of `SOURCE_FILES`), mentions it explicity.
-Beware of any build issues discussed on the Google Group.
-
-Open a GitHub pull request so that we can see that you have finished.
-The title should be "Project 6: YOUR NAME".
-The template of the comment section of your pull request is attached below, you can do some copy and paste:
-
-* [Repo Link](https://link-to-your-repo)
-* (Briefly) Mentions features that you've completed. Especially those bells and whistles you want to highlight
- * Feature 0
- * Feature 1
- * ...
-* Feedback on the project itself, if any.
+* [Tessellation tutorial](http://in2gpu.com/2014/07/12/tessellation-tutorial-opengl-4-3/)
\ No newline at end of file
diff --git a/bin/Debug/vulkan_grass_rendering.exe b/bin/Debug/vulkan_grass_rendering.exe
new file mode 100644
index 0000000..db94648
Binary files /dev/null and b/bin/Debug/vulkan_grass_rendering.exe differ
diff --git a/bin/Debug/vulkan_grass_rendering.ilk b/bin/Debug/vulkan_grass_rendering.ilk
new file mode 100644
index 0000000..2e06513
Binary files /dev/null and b/bin/Debug/vulkan_grass_rendering.ilk differ
diff --git a/bin/Debug/vulkan_grass_rendering.pdb b/bin/Debug/vulkan_grass_rendering.pdb
new file mode 100644
index 0000000..44397a2
Binary files /dev/null and b/bin/Debug/vulkan_grass_rendering.pdb differ
diff --git a/bin/Release/vulkan_grass_rendering.exe b/bin/Release/vulkan_grass_rendering.exe
new file mode 100644
index 0000000..ac6c69c
Binary files /dev/null and b/bin/Release/vulkan_grass_rendering.exe differ
diff --git a/img/2.gif b/img/2.gif
new file mode 100644
index 0000000..a87ab27
Binary files /dev/null and b/img/2.gif differ
diff --git a/img/3.gif b/img/3.gif
new file mode 100644
index 0000000..1e14a2c
Binary files /dev/null and b/img/3.gif differ
diff --git a/img/chart.png b/img/chart.png
new file mode 100644
index 0000000..8dcb877
Binary files /dev/null and b/img/chart.png differ
diff --git a/src/Renderer.cpp b/src/Renderer.cpp
index b445d04..fb28d32 100644
--- a/src/Renderer.cpp
+++ b/src/Renderer.cpp
@@ -9,1059 +9,1241 @@
static constexpr unsigned int WORKGROUP_SIZE = 32;
Renderer::Renderer(Device* device, SwapChain* swapChain, Scene* scene, Camera* camera)
- : device(device),
- logicalDevice(device->GetVkDevice()),
- swapChain(swapChain),
- scene(scene),
- camera(camera) {
-
- CreateCommandPools();
- CreateRenderPass();
- CreateCameraDescriptorSetLayout();
- CreateModelDescriptorSetLayout();
- CreateTimeDescriptorSetLayout();
- CreateComputeDescriptorSetLayout();
- CreateDescriptorPool();
- CreateCameraDescriptorSet();
- CreateModelDescriptorSets();
- CreateGrassDescriptorSets();
- CreateTimeDescriptorSet();
- CreateComputeDescriptorSets();
- CreateFrameResources();
- CreateGraphicsPipeline();
- CreateGrassPipeline();
- CreateComputePipeline();
- RecordCommandBuffers();
- RecordComputeCommandBuffer();
+ : device(device),
+ logicalDevice(device->GetVkDevice()),
+ swapChain(swapChain),
+ scene(scene),
+ camera(camera) {
+
+ CreateCommandPools();
+ CreateRenderPass();
+ CreateCameraDescriptorSetLayout();
+ CreateModelDescriptorSetLayout();
+ CreateTimeDescriptorSetLayout();
+ CreateComputeDescriptorSetLayout();
+ CreateGrassDescriptorSetLayout();
+ CreateDescriptorPool();
+ CreateCameraDescriptorSet();
+ CreateModelDescriptorSets();
+ CreateGrassDescriptorSets();
+ CreateTimeDescriptorSet();
+ CreateComputeDescriptorSets();
+ CreateFrameResources();
+ CreateGraphicsPipeline();
+ CreateGrassPipeline();
+ CreateComputePipeline();
+ RecordCommandBuffers();
+ RecordComputeCommandBuffer();
}
void Renderer::CreateCommandPools() {
- VkCommandPoolCreateInfo graphicsPoolInfo = {};
- graphicsPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- graphicsPoolInfo.queueFamilyIndex = device->GetInstance()->GetQueueFamilyIndices()[QueueFlags::Graphics];
- graphicsPoolInfo.flags = 0;
-
- if (vkCreateCommandPool(logicalDevice, &graphicsPoolInfo, nullptr, &graphicsCommandPool) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create command pool");
- }
-
- VkCommandPoolCreateInfo computePoolInfo = {};
- computePoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- computePoolInfo.queueFamilyIndex = device->GetInstance()->GetQueueFamilyIndices()[QueueFlags::Compute];
- computePoolInfo.flags = 0;
-
- if (vkCreateCommandPool(logicalDevice, &computePoolInfo, nullptr, &computeCommandPool) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create command pool");
- }
+ VkCommandPoolCreateInfo graphicsPoolInfo = {};
+ graphicsPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+ graphicsPoolInfo.queueFamilyIndex = device->GetInstance()->GetQueueFamilyIndices()[QueueFlags::Graphics];
+ graphicsPoolInfo.flags = 0;
+
+ if (vkCreateCommandPool(logicalDevice, &graphicsPoolInfo, nullptr, &graphicsCommandPool) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create command pool");
+ }
+
+ VkCommandPoolCreateInfo computePoolInfo = {};
+ computePoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+ computePoolInfo.queueFamilyIndex = device->GetInstance()->GetQueueFamilyIndices()[QueueFlags::Compute];
+ computePoolInfo.flags = 0;
+
+ if (vkCreateCommandPool(logicalDevice, &computePoolInfo, nullptr, &computeCommandPool) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create command pool");
+ }
}
void Renderer::CreateRenderPass() {
- // Color buffer attachment represented by one of the images from the swap chain
- VkAttachmentDescription colorAttachment = {};
- colorAttachment.format = swapChain->GetVkImageFormat();
- colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
- colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
- colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
-
- // Create a color attachment reference to be used with subpass
- VkAttachmentReference colorAttachmentRef = {};
- colorAttachmentRef.attachment = 0;
- colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-
- // Depth buffer attachment
- VkFormat depthFormat = device->GetInstance()->GetSupportedFormat({ VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
- VkAttachmentDescription depthAttachment = {};
- depthAttachment.format = depthFormat;
- depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
- depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
-
- // Create a depth attachment reference
- VkAttachmentReference depthAttachmentRef = {};
- depthAttachmentRef.attachment = 1;
- depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
-
- // Create subpass description
- VkSubpassDescription subpass = {};
- subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpass.colorAttachmentCount = 1;
- subpass.pColorAttachments = &colorAttachmentRef;
- subpass.pDepthStencilAttachment = &depthAttachmentRef;
-
- std::array attachments = { colorAttachment, depthAttachment };
-
- // Specify subpass dependency
- VkSubpassDependency dependency = {};
- dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
- dependency.dstSubpass = 0;
- dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- dependency.srcAccessMask = 0;
- dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
-
- // Create render pass
- VkRenderPassCreateInfo renderPassInfo = {};
- renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- renderPassInfo.attachmentCount = static_cast(attachments.size());
- renderPassInfo.pAttachments = attachments.data();
- renderPassInfo.subpassCount = 1;
- renderPassInfo.pSubpasses = &subpass;
- renderPassInfo.dependencyCount = 1;
- renderPassInfo.pDependencies = &dependency;
-
- if (vkCreateRenderPass(logicalDevice, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create render pass");
- }
+ // Color buffer attachment represented by one of the images from the swap chain
+ VkAttachmentDescription colorAttachment = {};
+ colorAttachment.format = swapChain->GetVkImageFormat();
+ colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
+ colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+
+ // Create a color attachment reference to be used with subpass
+ VkAttachmentReference colorAttachmentRef = {};
+ colorAttachmentRef.attachment = 0;
+ colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ // Depth buffer attachment
+ VkFormat depthFormat = device->GetInstance()->GetSupportedFormat({ VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
+ VkAttachmentDescription depthAttachment = {};
+ depthAttachment.format = depthFormat;
+ depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
+ depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ // Create a depth attachment reference
+ VkAttachmentReference depthAttachmentRef = {};
+ depthAttachmentRef.attachment = 1;
+ depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ // Create subpass description
+ VkSubpassDescription subpass = {};
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.colorAttachmentCount = 1;
+ subpass.pColorAttachments = &colorAttachmentRef;
+ subpass.pDepthStencilAttachment = &depthAttachmentRef;
+
+ std::array attachments = { colorAttachment, depthAttachment };
+
+ // Specify subpass dependency
+ VkSubpassDependency dependency = {};
+ dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
+ dependency.dstSubpass = 0;
+ dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dependency.srcAccessMask = 0;
+ dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+
+ // Create render pass
+ VkRenderPassCreateInfo renderPassInfo = {};
+ renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ renderPassInfo.attachmentCount = static_cast(attachments.size());
+ renderPassInfo.pAttachments = attachments.data();
+ renderPassInfo.subpassCount = 1;
+ renderPassInfo.pSubpasses = &subpass;
+ renderPassInfo.dependencyCount = 1;
+ renderPassInfo.pDependencies = &dependency;
+
+ if (vkCreateRenderPass(logicalDevice, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create render pass");
+ }
}
void Renderer::CreateCameraDescriptorSetLayout() {
- // Describe the binding of the descriptor set layout
- VkDescriptorSetLayoutBinding uboLayoutBinding = {};
- uboLayoutBinding.binding = 0;
- uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- uboLayoutBinding.descriptorCount = 1;
- uboLayoutBinding.stageFlags = VK_SHADER_STAGE_ALL;
- uboLayoutBinding.pImmutableSamplers = nullptr;
-
- std::vector bindings = { uboLayoutBinding };
-
- // Create the descriptor set layout
- VkDescriptorSetLayoutCreateInfo layoutInfo = {};
- layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- layoutInfo.bindingCount = static_cast(bindings.size());
- layoutInfo.pBindings = bindings.data();
-
- if (vkCreateDescriptorSetLayout(logicalDevice, &layoutInfo, nullptr, &cameraDescriptorSetLayout) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create descriptor set layout");
- }
+ // Describe the binding of the descriptor set layout
+ VkDescriptorSetLayoutBinding uboLayoutBinding = {};
+ uboLayoutBinding.binding = 0;
+ uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ uboLayoutBinding.descriptorCount = 1;
+ uboLayoutBinding.stageFlags = VK_SHADER_STAGE_ALL;
+ uboLayoutBinding.pImmutableSamplers = nullptr;
+
+ std::vector bindings = { uboLayoutBinding };
+
+ // Create the descriptor set layout
+ VkDescriptorSetLayoutCreateInfo layoutInfo = {};
+ layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ layoutInfo.bindingCount = static_cast(bindings.size());
+ layoutInfo.pBindings = bindings.data();
+
+ if (vkCreateDescriptorSetLayout(logicalDevice, &layoutInfo, nullptr, &cameraDescriptorSetLayout) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create descriptor set layout");
+ }
+}
+
+void Renderer::CreateGrassDescriptorSetLayout() {
+ VkDescriptorSetLayoutBinding uboLayoutBinding = {};
+ uboLayoutBinding.binding = 0;
+ uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ uboLayoutBinding.descriptorCount = 1;
+ uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
+ uboLayoutBinding.pImmutableSamplers = nullptr;
+
+ VkDescriptorSetLayoutBinding depthLayoutBinding = {};
+ depthLayoutBinding.binding = 1;
+ depthLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ depthLayoutBinding.descriptorCount = 1;
+ depthLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+ depthLayoutBinding.pImmutableSamplers = nullptr;
+
+ std::vector bindings = { uboLayoutBinding, depthLayoutBinding };
+
+ // Create the descriptor set layout
+ VkDescriptorSetLayoutCreateInfo layoutInfo = {};
+ layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ layoutInfo.bindingCount = static_cast(bindings.size());
+ layoutInfo.pBindings = bindings.data();
+
+ if (vkCreateDescriptorSetLayout(logicalDevice, &layoutInfo, nullptr, &grassDescriptorSetLayout) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create descriptor set layout");
+ }
}
void Renderer::CreateModelDescriptorSetLayout() {
- VkDescriptorSetLayoutBinding uboLayoutBinding = {};
- uboLayoutBinding.binding = 0;
- uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- uboLayoutBinding.descriptorCount = 1;
- uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
- uboLayoutBinding.pImmutableSamplers = nullptr;
-
- VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
- samplerLayoutBinding.binding = 1;
- samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- samplerLayoutBinding.descriptorCount = 1;
- samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- samplerLayoutBinding.pImmutableSamplers = nullptr;
-
- std::vector bindings = { uboLayoutBinding, samplerLayoutBinding };
-
- // Create the descriptor set layout
- VkDescriptorSetLayoutCreateInfo layoutInfo = {};
- layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- layoutInfo.bindingCount = static_cast(bindings.size());
- layoutInfo.pBindings = bindings.data();
-
- if (vkCreateDescriptorSetLayout(logicalDevice, &layoutInfo, nullptr, &modelDescriptorSetLayout) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create descriptor set layout");
- }
+ VkDescriptorSetLayoutBinding uboLayoutBinding = {};
+ uboLayoutBinding.binding = 0;
+ uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ uboLayoutBinding.descriptorCount = 1;
+ uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
+ uboLayoutBinding.pImmutableSamplers = nullptr;
+
+ VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
+ samplerLayoutBinding.binding = 1;
+ samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ samplerLayoutBinding.descriptorCount = 1;
+ samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+ samplerLayoutBinding.pImmutableSamplers = nullptr;
+
+ std::vector bindings = { uboLayoutBinding, samplerLayoutBinding };
+
+ // Create the descriptor set layout
+ VkDescriptorSetLayoutCreateInfo layoutInfo = {};
+ layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ layoutInfo.bindingCount = static_cast(bindings.size());
+ layoutInfo.pBindings = bindings.data();
+
+ if (vkCreateDescriptorSetLayout(logicalDevice, &layoutInfo, nullptr, &modelDescriptorSetLayout) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create descriptor set layout");
+ }
}
void Renderer::CreateTimeDescriptorSetLayout() {
- // Describe the binding of the descriptor set layout
- VkDescriptorSetLayoutBinding uboLayoutBinding = {};
- uboLayoutBinding.binding = 0;
- uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- uboLayoutBinding.descriptorCount = 1;
- uboLayoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
- uboLayoutBinding.pImmutableSamplers = nullptr;
-
- std::vector bindings = { uboLayoutBinding };
-
- // Create the descriptor set layout
- VkDescriptorSetLayoutCreateInfo layoutInfo = {};
- layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- layoutInfo.bindingCount = static_cast(bindings.size());
- layoutInfo.pBindings = bindings.data();
-
- if (vkCreateDescriptorSetLayout(logicalDevice, &layoutInfo, nullptr, &timeDescriptorSetLayout) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create descriptor set layout");
- }
+ // Describe the binding of the descriptor set layout
+ VkDescriptorSetLayoutBinding uboLayoutBinding = {};
+ uboLayoutBinding.binding = 0;
+ uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ uboLayoutBinding.descriptorCount = 1;
+ uboLayoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+ uboLayoutBinding.pImmutableSamplers = nullptr;
+
+ std::vector bindings = { uboLayoutBinding };
+
+ // Create the descriptor set layout
+ VkDescriptorSetLayoutCreateInfo layoutInfo = {};
+ layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ layoutInfo.bindingCount = static_cast(bindings.size());
+ layoutInfo.pBindings = bindings.data();
+
+ if (vkCreateDescriptorSetLayout(logicalDevice, &layoutInfo, nullptr, &timeDescriptorSetLayout) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create descriptor set layout");
+ }
}
void Renderer::CreateComputeDescriptorSetLayout() {
- // TODO: Create the descriptor set layout for the compute pipeline
- // Remember this is like a class definition stating why types of information
- // will be stored at each binding
+ // TODO: Create the descriptor set layout for the compute pipeline
+ // Remember this is like a class definition stating why types of information
+ // will be stored at each binding
+ // Describe the binding of the descriptor set layout
+
+ VkDescriptorSetLayoutBinding bladesLayoutBinding = {};
+ bladesLayoutBinding.binding = 0;
+ bladesLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ bladesLayoutBinding.descriptorCount = 1;
+ bladesLayoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+ bladesLayoutBinding.pImmutableSamplers = nullptr;
+
+ VkDescriptorSetLayoutBinding CulledBladesLayoutBinding = {};
+ CulledBladesLayoutBinding.binding = 1;
+ CulledBladesLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ CulledBladesLayoutBinding.descriptorCount = 1;
+ CulledBladesLayoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+ CulledBladesLayoutBinding.pImmutableSamplers = nullptr;
+
+ VkDescriptorSetLayoutBinding NumBladesLayoutBinding = {};
+ NumBladesLayoutBinding.binding = 2;
+ NumBladesLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ NumBladesLayoutBinding.descriptorCount = 1;
+ NumBladesLayoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+ NumBladesLayoutBinding.pImmutableSamplers = nullptr;
+
+ std::vector bindings = { bladesLayoutBinding, CulledBladesLayoutBinding, NumBladesLayoutBinding };
+
+ // Create the descriptor set layout
+ VkDescriptorSetLayoutCreateInfo layoutInfo = {};
+ layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ layoutInfo.bindingCount = static_cast(bindings.size());
+ layoutInfo.pBindings = bindings.data();
+
+ if (vkCreateDescriptorSetLayout(logicalDevice, &layoutInfo, nullptr, &computeDescriptorSetLayout) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create descriptor set layout");
+ }
}
void Renderer::CreateDescriptorPool() {
- // Describe which descriptor types that the descriptor sets will contain
- std::vector poolSizes = {
- // Camera
- { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1},
+ // Describe which descriptor types that the descriptor sets will contain
+ std::vector poolSizes = {
+ // Camera
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 },
+
+ // Models + Blades
+ { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , static_cast(scene->GetModels().size() + scene->GetBlades().size()) },
- // Models + Blades
- { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , static_cast(scene->GetModels().size() + scene->GetBlades().size()) },
+ // Models + Blades
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , static_cast(scene->GetModels().size() + scene->GetBlades().size()) },
- // Models + Blades
- { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , static_cast(scene->GetModels().size() + scene->GetBlades().size()) },
+ // Time (compute)
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 },
- // Time (compute)
- { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 },
+ // TODO: Add any additional types and counts of descriptors you will need to allocate
- // TODO: Add any additional types and counts of descriptors you will need to allocate
- };
+ // Blades + CulledBlades + NumBlades(compute)
+ { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER , 3 * static_cast(scene->GetBlades().size()) },
- VkDescriptorPoolCreateInfo poolInfo = {};
- poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
- poolInfo.poolSizeCount = static_cast(poolSizes.size());
- poolInfo.pPoolSizes = poolSizes.data();
- poolInfo.maxSets = 5;
+ };
- if (vkCreateDescriptorPool(logicalDevice, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create descriptor pool");
- }
+ VkDescriptorPoolCreateInfo poolInfo = {};
+ poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ poolInfo.poolSizeCount = static_cast(poolSizes.size());
+ poolInfo.pPoolSizes = poolSizes.data();
+ poolInfo.maxSets = 5;
+
+ if (vkCreateDescriptorPool(logicalDevice, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create descriptor pool");
+ }
}
void Renderer::CreateCameraDescriptorSet() {
- // Describe the desciptor set
- VkDescriptorSetLayout layouts[] = { cameraDescriptorSetLayout };
- VkDescriptorSetAllocateInfo allocInfo = {};
- allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- allocInfo.descriptorPool = descriptorPool;
- allocInfo.descriptorSetCount = 1;
- allocInfo.pSetLayouts = layouts;
-
- // Allocate descriptor sets
- if (vkAllocateDescriptorSets(logicalDevice, &allocInfo, &cameraDescriptorSet) != VK_SUCCESS) {
- throw std::runtime_error("Failed to allocate descriptor set");
- }
-
- // Configure the descriptors to refer to buffers
- VkDescriptorBufferInfo cameraBufferInfo = {};
- cameraBufferInfo.buffer = camera->GetBuffer();
- cameraBufferInfo.offset = 0;
- cameraBufferInfo.range = sizeof(CameraBufferObject);
-
- std::array descriptorWrites = {};
- descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- descriptorWrites[0].dstSet = cameraDescriptorSet;
- descriptorWrites[0].dstBinding = 0;
- descriptorWrites[0].dstArrayElement = 0;
- descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- descriptorWrites[0].descriptorCount = 1;
- descriptorWrites[0].pBufferInfo = &cameraBufferInfo;
- descriptorWrites[0].pImageInfo = nullptr;
- descriptorWrites[0].pTexelBufferView = nullptr;
-
- // Update descriptor sets
- vkUpdateDescriptorSets(logicalDevice, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
+ // Describe the desciptor set
+ VkDescriptorSetLayout layouts[] = { cameraDescriptorSetLayout };
+ VkDescriptorSetAllocateInfo allocInfo = {};
+ allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ allocInfo.descriptorPool = descriptorPool;
+ allocInfo.descriptorSetCount = 1;
+ allocInfo.pSetLayouts = layouts;
+
+ // Allocate descriptor sets
+ if (vkAllocateDescriptorSets(logicalDevice, &allocInfo, &cameraDescriptorSet) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to allocate descriptor set");
+ }
+
+ // Configure the descriptors to refer to buffers
+ VkDescriptorBufferInfo cameraBufferInfo = {};
+ cameraBufferInfo.buffer = camera->GetBuffer();
+ cameraBufferInfo.offset = 0;
+ cameraBufferInfo.range = sizeof(CameraBufferObject);
+
+ std::array descriptorWrites = {};
+ descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrites[0].dstSet = cameraDescriptorSet;
+ descriptorWrites[0].dstBinding = 0;
+ descriptorWrites[0].dstArrayElement = 0;
+ descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ descriptorWrites[0].descriptorCount = 1;
+ descriptorWrites[0].pBufferInfo = &cameraBufferInfo;
+ descriptorWrites[0].pImageInfo = nullptr;
+ descriptorWrites[0].pTexelBufferView = nullptr;
+
+ // Update descriptor sets
+ vkUpdateDescriptorSets(logicalDevice, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
}
void Renderer::CreateModelDescriptorSets() {
- modelDescriptorSets.resize(scene->GetModels().size());
-
- // Describe the desciptor set
- VkDescriptorSetLayout layouts[] = { modelDescriptorSetLayout };
- VkDescriptorSetAllocateInfo allocInfo = {};
- allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- allocInfo.descriptorPool = descriptorPool;
- allocInfo.descriptorSetCount = static_cast(modelDescriptorSets.size());
- allocInfo.pSetLayouts = layouts;
-
- // Allocate descriptor sets
- if (vkAllocateDescriptorSets(logicalDevice, &allocInfo, modelDescriptorSets.data()) != VK_SUCCESS) {
- throw std::runtime_error("Failed to allocate descriptor set");
- }
-
- std::vector descriptorWrites(2 * modelDescriptorSets.size());
-
- for (uint32_t i = 0; i < scene->GetModels().size(); ++i) {
- VkDescriptorBufferInfo modelBufferInfo = {};
- modelBufferInfo.buffer = scene->GetModels()[i]->GetModelBuffer();
- modelBufferInfo.offset = 0;
- modelBufferInfo.range = sizeof(ModelBufferObject);
-
- // Bind image and sampler resources to the descriptor
- VkDescriptorImageInfo imageInfo = {};
- imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- imageInfo.imageView = scene->GetModels()[i]->GetTextureView();
- imageInfo.sampler = scene->GetModels()[i]->GetTextureSampler();
-
- descriptorWrites[2 * i + 0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- descriptorWrites[2 * i + 0].dstSet = modelDescriptorSets[i];
- descriptorWrites[2 * i + 0].dstBinding = 0;
- descriptorWrites[2 * i + 0].dstArrayElement = 0;
- descriptorWrites[2 * i + 0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- descriptorWrites[2 * i + 0].descriptorCount = 1;
- descriptorWrites[2 * i + 0].pBufferInfo = &modelBufferInfo;
- descriptorWrites[2 * i + 0].pImageInfo = nullptr;
- descriptorWrites[2 * i + 0].pTexelBufferView = nullptr;
-
- descriptorWrites[2 * i + 1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- descriptorWrites[2 * i + 1].dstSet = modelDescriptorSets[i];
- descriptorWrites[2 * i + 1].dstBinding = 1;
- descriptorWrites[2 * i + 1].dstArrayElement = 0;
- descriptorWrites[2 * i + 1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- descriptorWrites[2 * i + 1].descriptorCount = 1;
- descriptorWrites[2 * i + 1].pImageInfo = &imageInfo;
- }
-
- // Update descriptor sets
- vkUpdateDescriptorSets(logicalDevice, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
+ modelDescriptorSets.resize(scene->GetModels().size());
+
+ // Describe the desciptor set
+ VkDescriptorSetLayout layouts[] = { modelDescriptorSetLayout };
+ VkDescriptorSetAllocateInfo allocInfo = {};
+ allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ allocInfo.descriptorPool = descriptorPool;
+ allocInfo.descriptorSetCount = static_cast(modelDescriptorSets.size());
+ allocInfo.pSetLayouts = layouts;
+
+ // Allocate descriptor sets
+ if (vkAllocateDescriptorSets(logicalDevice, &allocInfo, modelDescriptorSets.data()) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to allocate descriptor set");
+ }
+
+ std::vector descriptorWrites(2 * modelDescriptorSets.size());
+
+ for (uint32_t i = 0; i < scene->GetModels().size(); ++i) {
+ VkDescriptorBufferInfo modelBufferInfo = {};
+ modelBufferInfo.buffer = scene->GetModels()[i]->GetModelBuffer();
+ modelBufferInfo.offset = 0;
+ modelBufferInfo.range = sizeof(ModelBufferObject);
+
+ // Bind image and sampler resources to the descriptor
+ VkDescriptorImageInfo imageInfo = {};
+ imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ imageInfo.imageView = scene->GetModels()[i]->GetTextureView();
+ imageInfo.sampler = scene->GetModels()[i]->GetTextureSampler();
+
+ descriptorWrites[2 * i + 0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrites[2 * i + 0].dstSet = modelDescriptorSets[i];
+ descriptorWrites[2 * i + 0].dstBinding = 0;
+ descriptorWrites[2 * i + 0].dstArrayElement = 0;
+ descriptorWrites[2 * i + 0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ descriptorWrites[2 * i + 0].descriptorCount = 1;
+ descriptorWrites[2 * i + 0].pBufferInfo = &modelBufferInfo;
+ descriptorWrites[2 * i + 0].pImageInfo = nullptr;
+ descriptorWrites[2 * i + 0].pTexelBufferView = nullptr;
+
+ descriptorWrites[2 * i + 1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrites[2 * i + 1].dstSet = modelDescriptorSets[i];
+ descriptorWrites[2 * i + 1].dstBinding = 1;
+ descriptorWrites[2 * i + 1].dstArrayElement = 0;
+ descriptorWrites[2 * i + 1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ descriptorWrites[2 * i + 1].descriptorCount = 1;
+ descriptorWrites[2 * i + 1].pImageInfo = &imageInfo;
+ }
+
+ // Update descriptor sets
+ vkUpdateDescriptorSets(logicalDevice, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
}
void Renderer::CreateGrassDescriptorSets() {
- // TODO: Create Descriptor sets for the grass.
- // This should involve creating descriptor sets which point to the model matrix of each group of grass blades
+ // TODO: Create Descriptor sets for the grass.
+ // This should involve creating descriptor sets which point to the model matrix of each group of grass blades
+
+ grassDescriptorSets.resize(scene->GetBlades().size());
+
+ // Describe the desciptor set
+ VkDescriptorSetLayout layouts[] = { grassDescriptorSetLayout };
+ VkDescriptorSetAllocateInfo allocInfo = {};
+ allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ allocInfo.descriptorPool = descriptorPool;
+ allocInfo.descriptorSetCount = static_cast(grassDescriptorSets.size());
+ allocInfo.pSetLayouts = layouts;
+
+ // Allocate descriptor sets
+ if (vkAllocateDescriptorSets(logicalDevice, &allocInfo, grassDescriptorSets.data()) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to allocate descriptor set");
+ }
+
+ std::vector descriptorWrites(/*2 * */grassDescriptorSets.size());
+
+ for (uint32_t i = 0; i < scene->GetBlades().size(); ++i) {
+ VkDescriptorBufferInfo modelBufferInfo = {};
+ modelBufferInfo.buffer = scene->GetBlades()[i]->GetModelBuffer();
+ modelBufferInfo.offset = 0;
+ modelBufferInfo.range = sizeof(ModelBufferObject);
+
+ descriptorWrites[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrites[i].dstSet = grassDescriptorSets[i];
+ descriptorWrites[i].dstBinding = 0;
+ descriptorWrites[i].dstArrayElement = 0;
+ descriptorWrites[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ descriptorWrites[i].descriptorCount = 1;
+ descriptorWrites[i].pBufferInfo = &modelBufferInfo;
+ descriptorWrites[i].pImageInfo = nullptr;
+ descriptorWrites[i].pTexelBufferView = nullptr;
+
+ }
+
+ // Update descriptor sets
+ vkUpdateDescriptorSets(logicalDevice, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
}
void Renderer::CreateTimeDescriptorSet() {
- // Describe the desciptor set
- VkDescriptorSetLayout layouts[] = { timeDescriptorSetLayout };
- VkDescriptorSetAllocateInfo allocInfo = {};
- allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- allocInfo.descriptorPool = descriptorPool;
- allocInfo.descriptorSetCount = 1;
- allocInfo.pSetLayouts = layouts;
-
- // Allocate descriptor sets
- if (vkAllocateDescriptorSets(logicalDevice, &allocInfo, &timeDescriptorSet) != VK_SUCCESS) {
- throw std::runtime_error("Failed to allocate descriptor set");
- }
-
- // Configure the descriptors to refer to buffers
- VkDescriptorBufferInfo timeBufferInfo = {};
- timeBufferInfo.buffer = scene->GetTimeBuffer();
- timeBufferInfo.offset = 0;
- timeBufferInfo.range = sizeof(Time);
-
- std::array descriptorWrites = {};
- descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- descriptorWrites[0].dstSet = timeDescriptorSet;
- descriptorWrites[0].dstBinding = 0;
- descriptorWrites[0].dstArrayElement = 0;
- descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- descriptorWrites[0].descriptorCount = 1;
- descriptorWrites[0].pBufferInfo = &timeBufferInfo;
- descriptorWrites[0].pImageInfo = nullptr;
- descriptorWrites[0].pTexelBufferView = nullptr;
-
- // Update descriptor sets
- vkUpdateDescriptorSets(logicalDevice, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
+ // Describe the desciptor set
+ VkDescriptorSetLayout layouts[] = { timeDescriptorSetLayout };
+ VkDescriptorSetAllocateInfo allocInfo = {};
+ allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ allocInfo.descriptorPool = descriptorPool;
+ allocInfo.descriptorSetCount = 1;
+ allocInfo.pSetLayouts = layouts;
+
+ // Allocate descriptor sets
+ if (vkAllocateDescriptorSets(logicalDevice, &allocInfo, &timeDescriptorSet) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to allocate descriptor set");
+ }
+
+ // Configure the descriptors to refer to buffers
+ VkDescriptorBufferInfo timeBufferInfo = {};
+ timeBufferInfo.buffer = scene->GetTimeBuffer();
+ timeBufferInfo.offset = 0;
+ timeBufferInfo.range = sizeof(Time);
+
+ std::array descriptorWrites = {};
+ descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrites[0].dstSet = timeDescriptorSet;
+ descriptorWrites[0].dstBinding = 0;
+ descriptorWrites[0].dstArrayElement = 0;
+ descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ descriptorWrites[0].descriptorCount = 1;
+ descriptorWrites[0].pBufferInfo = &timeBufferInfo;
+ descriptorWrites[0].pImageInfo = nullptr;
+ descriptorWrites[0].pTexelBufferView = nullptr;
+
+ // Update descriptor sets
+ vkUpdateDescriptorSets(logicalDevice, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
}
void Renderer::CreateComputeDescriptorSets() {
- // TODO: Create Descriptor sets for the compute pipeline
- // The descriptors should point to Storage buffers which will hold the grass blades, the culled grass blades, and the output number of grass blades
+ // TODO: Create Descriptor sets for the compute pipeline
+ // The descriptors should point to Storage buffers which will hold the grass blades, the culled grass blades, and the output number of grass blades
+ computeDescriptorSets.resize(scene->GetBlades().size());
+
+ // Describe the desciptor set
+ VkDescriptorSetLayout layouts[] = { computeDescriptorSetLayout };
+ VkDescriptorSetAllocateInfo allocInfo = {};
+ allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ allocInfo.descriptorPool = descriptorPool;
+ allocInfo.descriptorSetCount = static_cast(computeDescriptorSets.size());
+ allocInfo.pSetLayouts = layouts;
+
+ // Allocate descriptor sets
+ if (vkAllocateDescriptorSets(logicalDevice, &allocInfo, computeDescriptorSets.data()) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to allocate descriptor set");
+ }
+
+ std::vector descriptorWrites(3 * computeDescriptorSets.size());
+
+ for (uint32_t i = 0; i < scene->GetBlades().size(); ++i) {
+
+ // bladesBuffer
+ VkDescriptorBufferInfo bladesBufferInfo = {};
+ bladesBufferInfo.buffer = scene->GetBlades()[i]->GetBladesBuffer();
+ bladesBufferInfo.offset = 0;
+ bladesBufferInfo.range = NUM_BLADES * sizeof(Blade);
+
+ // culledBladesBuffer
+ VkDescriptorBufferInfo culledBladesBufferInfo = {};
+ culledBladesBufferInfo.buffer = scene->GetBlades()[i]->GetCulledBladesBuffer();
+ culledBladesBufferInfo.offset = 0;
+ culledBladesBufferInfo.range = NUM_BLADES * sizeof(Blade);
+
+ // numBladesBuffer
+ VkDescriptorBufferInfo numBladesBufferInfo = {};
+ numBladesBufferInfo.buffer = scene->GetBlades()[i]->GetNumBladesBuffer();
+ numBladesBufferInfo.offset = 0;
+ numBladesBufferInfo.range = sizeof(BladeDrawIndirect);
+
+ descriptorWrites[3 * i + 0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrites[3 * i + 0].dstSet = computeDescriptorSets[i];
+ descriptorWrites[3 * i + 0].dstBinding = 0;
+ descriptorWrites[3 * i + 0].dstArrayElement = 0;
+ descriptorWrites[3 * i + 0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ descriptorWrites[3 * i + 0].descriptorCount = 1;
+ descriptorWrites[3 * i + 0].pBufferInfo = &bladesBufferInfo;
+ descriptorWrites[3 * i + 0].pImageInfo = nullptr;
+ descriptorWrites[3 * i + 0].pTexelBufferView = nullptr;
+
+ descriptorWrites[3 * i + 1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrites[3 * i + 1].dstSet = computeDescriptorSets[i];
+ descriptorWrites[3 * i + 1].dstBinding = 1;
+ descriptorWrites[3 * i + 1].dstArrayElement = 0;
+ descriptorWrites[3 * i + 1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ descriptorWrites[3 * i + 1].descriptorCount = 1;
+ descriptorWrites[3 * i + 1].pBufferInfo = &culledBladesBufferInfo;
+ descriptorWrites[3 * i + 1].pImageInfo = nullptr;
+ descriptorWrites[3 * i + 1].pTexelBufferView = nullptr;
+
+ descriptorWrites[3 * i + 2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrites[3 * i + 2].dstSet = computeDescriptorSets[i];
+ descriptorWrites[3 * i + 2].dstBinding = 2;
+ descriptorWrites[3 * i + 2].dstArrayElement = 0;
+ descriptorWrites[3 * i + 2].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ descriptorWrites[3 * i + 2].descriptorCount = 1;
+ descriptorWrites[3 * i + 2].pBufferInfo = &numBladesBufferInfo;
+ descriptorWrites[3 * i + 2].pImageInfo = nullptr;
+ descriptorWrites[3 * i + 2].pTexelBufferView = nullptr;
+ }
+
+ // Update descriptor sets
+ vkUpdateDescriptorSets(logicalDevice, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
}
void Renderer::CreateGraphicsPipeline() {
- VkShaderModule vertShaderModule = ShaderModule::Create("shaders/graphics.vert.spv", logicalDevice);
- VkShaderModule fragShaderModule = ShaderModule::Create("shaders/graphics.frag.spv", logicalDevice);
-
- // Assign each shader module to the appropriate stage in the pipeline
- VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
- vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
- vertShaderStageInfo.module = vertShaderModule;
- vertShaderStageInfo.pName = "main";
-
- VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
- fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
- fragShaderStageInfo.module = fragShaderModule;
- fragShaderStageInfo.pName = "main";
-
- VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
-
- // --- Set up fixed-function stages ---
-
- // Vertex input
- VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
- vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
-
- auto bindingDescription = Vertex::getBindingDescription();
- auto attributeDescriptions = Vertex::getAttributeDescriptions();
-
- vertexInputInfo.vertexBindingDescriptionCount = 1;
- vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
- vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size());
- vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
-
- // Input assembly
- VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
- inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
- inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
- inputAssembly.primitiveRestartEnable = VK_FALSE;
-
- // Viewports and Scissors (rectangles that define in which regions pixels are stored)
- VkViewport viewport = {};
- viewport.x = 0.0f;
- viewport.y = 0.0f;
- viewport.width = static_cast(swapChain->GetVkExtent().width);
- viewport.height = static_cast(swapChain->GetVkExtent().height);
- viewport.minDepth = 0.0f;
- viewport.maxDepth = 1.0f;
-
- VkRect2D scissor = {};
- scissor.offset = { 0, 0 };
- scissor.extent = swapChain->GetVkExtent();
-
- VkPipelineViewportStateCreateInfo viewportState = {};
- viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
- viewportState.viewportCount = 1;
- viewportState.pViewports = &viewport;
- viewportState.scissorCount = 1;
- viewportState.pScissors = &scissor;
-
- // Rasterizer
- VkPipelineRasterizationStateCreateInfo rasterizer = {};
- rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
- rasterizer.depthClampEnable = VK_FALSE;
- rasterizer.rasterizerDiscardEnable = VK_FALSE;
- rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
- rasterizer.lineWidth = 1.0f;
- rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
- rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
- rasterizer.depthBiasEnable = VK_FALSE;
- rasterizer.depthBiasConstantFactor = 0.0f;
- rasterizer.depthBiasClamp = 0.0f;
- rasterizer.depthBiasSlopeFactor = 0.0f;
-
- // Multisampling (turned off here)
- VkPipelineMultisampleStateCreateInfo multisampling = {};
- multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
- multisampling.sampleShadingEnable = VK_FALSE;
- multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
- multisampling.minSampleShading = 1.0f;
- multisampling.pSampleMask = nullptr;
- multisampling.alphaToCoverageEnable = VK_FALSE;
- multisampling.alphaToOneEnable = VK_FALSE;
-
- // Depth testing
- VkPipelineDepthStencilStateCreateInfo depthStencil = {};
- depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
- depthStencil.depthTestEnable = VK_TRUE;
- depthStencil.depthWriteEnable = VK_TRUE;
- depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
- depthStencil.depthBoundsTestEnable = VK_FALSE;
- depthStencil.minDepthBounds = 0.0f;
- depthStencil.maxDepthBounds = 1.0f;
- depthStencil.stencilTestEnable = VK_FALSE;
-
- // Color blending (turned off here, but showing options for learning)
- // --> Configuration per attached framebuffer
- VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
- colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
- colorBlendAttachment.blendEnable = VK_FALSE;
- colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
- colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
- colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
- colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
- colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
- colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
-
- // --> Global color blending settings
- VkPipelineColorBlendStateCreateInfo colorBlending = {};
- colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
- colorBlending.logicOpEnable = VK_FALSE;
- colorBlending.logicOp = VK_LOGIC_OP_COPY;
- colorBlending.attachmentCount = 1;
- colorBlending.pAttachments = &colorBlendAttachment;
- colorBlending.blendConstants[0] = 0.0f;
- colorBlending.blendConstants[1] = 0.0f;
- colorBlending.blendConstants[2] = 0.0f;
- colorBlending.blendConstants[3] = 0.0f;
-
- std::vector descriptorSetLayouts = { cameraDescriptorSetLayout, modelDescriptorSetLayout };
-
- // Pipeline layout: used to specify uniform values
- VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
- pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- pipelineLayoutInfo.setLayoutCount = static_cast(descriptorSetLayouts.size());
- pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts.data();
- pipelineLayoutInfo.pushConstantRangeCount = 0;
- pipelineLayoutInfo.pPushConstantRanges = 0;
-
- if (vkCreatePipelineLayout(logicalDevice, &pipelineLayoutInfo, nullptr, &graphicsPipelineLayout) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create pipeline layout");
- }
-
- // --- Create graphics pipeline ---
- VkGraphicsPipelineCreateInfo pipelineInfo = {};
- pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
- pipelineInfo.stageCount = 2;
- pipelineInfo.pStages = shaderStages;
- pipelineInfo.pVertexInputState = &vertexInputInfo;
- pipelineInfo.pInputAssemblyState = &inputAssembly;
- pipelineInfo.pViewportState = &viewportState;
- pipelineInfo.pRasterizationState = &rasterizer;
- pipelineInfo.pMultisampleState = &multisampling;
- pipelineInfo.pDepthStencilState = &depthStencil;
- pipelineInfo.pColorBlendState = &colorBlending;
- pipelineInfo.pDynamicState = nullptr;
- pipelineInfo.layout = graphicsPipelineLayout;
- pipelineInfo.renderPass = renderPass;
- pipelineInfo.subpass = 0;
- pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
- pipelineInfo.basePipelineIndex = -1;
-
- if (vkCreateGraphicsPipelines(logicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create graphics pipeline");
- }
-
- vkDestroyShaderModule(logicalDevice, vertShaderModule, nullptr);
- vkDestroyShaderModule(logicalDevice, fragShaderModule, nullptr);
+ VkShaderModule vertShaderModule = ShaderModule::Create("shaders/graphics.vert.spv", logicalDevice);
+ VkShaderModule fragShaderModule = ShaderModule::Create("shaders/graphics.frag.spv", logicalDevice);
+
+ // Assign each shader module to the appropriate stage in the pipeline
+ VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
+ vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
+ vertShaderStageInfo.module = vertShaderModule;
+ vertShaderStageInfo.pName = "main";
+
+ VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
+ fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+ fragShaderStageInfo.module = fragShaderModule;
+ fragShaderStageInfo.pName = "main";
+
+ VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
+
+ // --- Set up fixed-function stages ---
+
+ // Vertex input
+ VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
+ vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+
+ auto bindingDescription = Vertex::getBindingDescription();
+ auto attributeDescriptions = Vertex::getAttributeDescriptions();
+
+ vertexInputInfo.vertexBindingDescriptionCount = 1;
+ vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
+ vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size());
+ vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
+
+ // Input assembly
+ VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
+ inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ inputAssembly.primitiveRestartEnable = VK_FALSE;
+
+ // Viewports and Scissors (rectangles that define in which regions pixels are stored)
+ VkViewport viewport = {};
+ viewport.x = 0.0f;
+ viewport.y = 0.0f;
+ viewport.width = static_cast(swapChain->GetVkExtent().width);
+ viewport.height = static_cast(swapChain->GetVkExtent().height);
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ VkRect2D scissor = {};
+ scissor.offset = { 0, 0 };
+ scissor.extent = swapChain->GetVkExtent();
+
+ VkPipelineViewportStateCreateInfo viewportState = {};
+ viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ viewportState.viewportCount = 1;
+ viewportState.pViewports = &viewport;
+ viewportState.scissorCount = 1;
+ viewportState.pScissors = &scissor;
+
+ // Rasterizer
+ VkPipelineRasterizationStateCreateInfo rasterizer = {};
+ rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rasterizer.depthClampEnable = VK_FALSE;
+ rasterizer.rasterizerDiscardEnable = VK_FALSE;
+ rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
+ rasterizer.lineWidth = 1.0f;
+ rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
+ rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+ rasterizer.depthBiasEnable = VK_FALSE;
+ rasterizer.depthBiasConstantFactor = 0.0f;
+ rasterizer.depthBiasClamp = 0.0f;
+ rasterizer.depthBiasSlopeFactor = 0.0f;
+
+ // Multisampling (turned off here)
+ VkPipelineMultisampleStateCreateInfo multisampling = {};
+ multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ multisampling.sampleShadingEnable = VK_FALSE;
+ multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+ multisampling.minSampleShading = 1.0f;
+ multisampling.pSampleMask = nullptr;
+ multisampling.alphaToCoverageEnable = VK_FALSE;
+ multisampling.alphaToOneEnable = VK_FALSE;
+
+ // Depth testing
+ VkPipelineDepthStencilStateCreateInfo depthStencil = {};
+ depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ depthStencil.depthTestEnable = VK_TRUE;
+ depthStencil.depthWriteEnable = VK_TRUE;
+ depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
+ depthStencil.depthBoundsTestEnable = VK_FALSE;
+ depthStencil.minDepthBounds = 0.0f;
+ depthStencil.maxDepthBounds = 1.0f;
+ depthStencil.stencilTestEnable = VK_FALSE;
+
+ // Color blending (turned off here, but showing options for learning)
+ // --> Configuration per attached framebuffer
+ VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
+ colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+ colorBlendAttachment.blendEnable = VK_FALSE;
+ colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
+ colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
+ colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
+ colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
+ colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
+ colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
+
+ // --> Global color blending settings
+ VkPipelineColorBlendStateCreateInfo colorBlending = {};
+ colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ colorBlending.logicOpEnable = VK_FALSE;
+ colorBlending.logicOp = VK_LOGIC_OP_COPY;
+ colorBlending.attachmentCount = 1;
+ colorBlending.pAttachments = &colorBlendAttachment;
+ colorBlending.blendConstants[0] = 0.0f;
+ colorBlending.blendConstants[1] = 0.0f;
+ colorBlending.blendConstants[2] = 0.0f;
+ colorBlending.blendConstants[3] = 0.0f;
+
+ std::vector descriptorSetLayouts = { cameraDescriptorSetLayout, modelDescriptorSetLayout };
+
+ // Pipeline layout: used to specify uniform values
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
+ pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutInfo.setLayoutCount = static_cast(descriptorSetLayouts.size());
+ pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts.data();
+ pipelineLayoutInfo.pushConstantRangeCount = 0;
+ pipelineLayoutInfo.pPushConstantRanges = 0;
+
+ if (vkCreatePipelineLayout(logicalDevice, &pipelineLayoutInfo, nullptr, &graphicsPipelineLayout) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create pipeline layout");
+ }
+
+ // --- Create graphics pipeline ---
+ VkGraphicsPipelineCreateInfo pipelineInfo = {};
+ pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ pipelineInfo.stageCount = 2;
+ pipelineInfo.pStages = shaderStages;
+ pipelineInfo.pVertexInputState = &vertexInputInfo;
+ pipelineInfo.pInputAssemblyState = &inputAssembly;
+ pipelineInfo.pViewportState = &viewportState;
+ pipelineInfo.pRasterizationState = &rasterizer;
+ pipelineInfo.pMultisampleState = &multisampling;
+ pipelineInfo.pDepthStencilState = &depthStencil;
+ pipelineInfo.pColorBlendState = &colorBlending;
+ pipelineInfo.pDynamicState = nullptr;
+ pipelineInfo.layout = graphicsPipelineLayout;
+ pipelineInfo.renderPass = renderPass;
+ pipelineInfo.subpass = 0;
+ pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
+ pipelineInfo.basePipelineIndex = -1;
+
+ if (vkCreateGraphicsPipelines(logicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create graphics pipeline");
+ }
+
+ vkDestroyShaderModule(logicalDevice, vertShaderModule, nullptr);
+ vkDestroyShaderModule(logicalDevice, fragShaderModule, nullptr);
}
void Renderer::CreateGrassPipeline() {
- // --- Set up programmable shaders ---
- VkShaderModule vertShaderModule = ShaderModule::Create("shaders/grass.vert.spv", logicalDevice);
- VkShaderModule tescShaderModule = ShaderModule::Create("shaders/grass.tesc.spv", logicalDevice);
- VkShaderModule teseShaderModule = ShaderModule::Create("shaders/grass.tese.spv", logicalDevice);
- VkShaderModule fragShaderModule = ShaderModule::Create("shaders/grass.frag.spv", logicalDevice);
-
- // Assign each shader module to the appropriate stage in the pipeline
- VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
- vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
- vertShaderStageInfo.module = vertShaderModule;
- vertShaderStageInfo.pName = "main";
-
- VkPipelineShaderStageCreateInfo tescShaderStageInfo = {};
- tescShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- tescShaderStageInfo.stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
- tescShaderStageInfo.module = tescShaderModule;
- tescShaderStageInfo.pName = "main";
-
- VkPipelineShaderStageCreateInfo teseShaderStageInfo = {};
- teseShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- teseShaderStageInfo.stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
- teseShaderStageInfo.module = teseShaderModule;
- teseShaderStageInfo.pName = "main";
-
- VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
- fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
- fragShaderStageInfo.module = fragShaderModule;
- fragShaderStageInfo.pName = "main";
-
- VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, tescShaderStageInfo, teseShaderStageInfo, fragShaderStageInfo };
-
- // --- Set up fixed-function stages ---
-
- // Vertex input
- VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
- vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
-
- auto bindingDescription = Blade::getBindingDescription();
- auto attributeDescriptions = Blade::getAttributeDescriptions();
-
- vertexInputInfo.vertexBindingDescriptionCount = 1;
- vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
- vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size());
- vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
-
- // Input Assembly
- VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
- inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
- inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
- inputAssembly.primitiveRestartEnable = VK_FALSE;
-
- // Viewports and Scissors (rectangles that define in which regions pixels are stored)
- VkViewport viewport = {};
- viewport.x = 0.0f;
- viewport.y = 0.0f;
- viewport.width = static_cast(swapChain->GetVkExtent().width);
- viewport.height = static_cast(swapChain->GetVkExtent().height);
- viewport.minDepth = 0.0f;
- viewport.maxDepth = 1.0f;
-
- VkRect2D scissor = {};
- scissor.offset = { 0, 0 };
- scissor.extent = swapChain->GetVkExtent();
-
- VkPipelineViewportStateCreateInfo viewportState = {};
- viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
- viewportState.viewportCount = 1;
- viewportState.pViewports = &viewport;
- viewportState.scissorCount = 1;
- viewportState.pScissors = &scissor;
-
- // Rasterizer
- VkPipelineRasterizationStateCreateInfo rasterizer = {};
- rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
- rasterizer.depthClampEnable = VK_FALSE;
- rasterizer.rasterizerDiscardEnable = VK_FALSE;
- rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
- rasterizer.lineWidth = 1.0f;
- rasterizer.cullMode = VK_CULL_MODE_NONE;
- rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
- rasterizer.depthBiasEnable = VK_FALSE;
- rasterizer.depthBiasConstantFactor = 0.0f;
- rasterizer.depthBiasClamp = 0.0f;
- rasterizer.depthBiasSlopeFactor = 0.0f;
-
- // Multisampling (turned off here)
- VkPipelineMultisampleStateCreateInfo multisampling = {};
- multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
- multisampling.sampleShadingEnable = VK_FALSE;
- multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
- multisampling.minSampleShading = 1.0f;
- multisampling.pSampleMask = nullptr;
- multisampling.alphaToCoverageEnable = VK_FALSE;
- multisampling.alphaToOneEnable = VK_FALSE;
-
- // Depth testing
- VkPipelineDepthStencilStateCreateInfo depthStencil = {};
- depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
- depthStencil.depthTestEnable = VK_TRUE;
- depthStencil.depthWriteEnable = VK_TRUE;
- depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
- depthStencil.depthBoundsTestEnable = VK_FALSE;
- depthStencil.minDepthBounds = 0.0f;
- depthStencil.maxDepthBounds = 1.0f;
- depthStencil.stencilTestEnable = VK_FALSE;
-
- // Color blending (turned off here, but showing options for learning)
- // --> Configuration per attached framebuffer
- VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
- colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
- colorBlendAttachment.blendEnable = VK_FALSE;
- colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
- colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
- colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
- colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
- colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
- colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
-
- // --> Global color blending settings
- VkPipelineColorBlendStateCreateInfo colorBlending = {};
- colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
- colorBlending.logicOpEnable = VK_FALSE;
- colorBlending.logicOp = VK_LOGIC_OP_COPY;
- colorBlending.attachmentCount = 1;
- colorBlending.pAttachments = &colorBlendAttachment;
- colorBlending.blendConstants[0] = 0.0f;
- colorBlending.blendConstants[1] = 0.0f;
- colorBlending.blendConstants[2] = 0.0f;
- colorBlending.blendConstants[3] = 0.0f;
-
- std::vector descriptorSetLayouts = { cameraDescriptorSetLayout, modelDescriptorSetLayout };
-
- // Pipeline layout: used to specify uniform values
- VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
- pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- pipelineLayoutInfo.setLayoutCount = static_cast(descriptorSetLayouts.size());
- pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts.data();
- pipelineLayoutInfo.pushConstantRangeCount = 0;
- pipelineLayoutInfo.pPushConstantRanges = 0;
-
- if (vkCreatePipelineLayout(logicalDevice, &pipelineLayoutInfo, nullptr, &grassPipelineLayout) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create pipeline layout");
- }
-
- // Tessellation state
- VkPipelineTessellationStateCreateInfo tessellationInfo = {};
- tessellationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
- tessellationInfo.pNext = NULL;
- tessellationInfo.flags = 0;
- tessellationInfo.patchControlPoints = 1;
-
- // --- Create graphics pipeline ---
- VkGraphicsPipelineCreateInfo pipelineInfo = {};
- pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
- pipelineInfo.stageCount = 4;
- pipelineInfo.pStages = shaderStages;
- pipelineInfo.pVertexInputState = &vertexInputInfo;
- pipelineInfo.pInputAssemblyState = &inputAssembly;
- pipelineInfo.pViewportState = &viewportState;
- pipelineInfo.pRasterizationState = &rasterizer;
- pipelineInfo.pMultisampleState = &multisampling;
- pipelineInfo.pDepthStencilState = &depthStencil;
- pipelineInfo.pColorBlendState = &colorBlending;
- pipelineInfo.pTessellationState = &tessellationInfo;
- pipelineInfo.pDynamicState = nullptr;
- pipelineInfo.layout = grassPipelineLayout;
- pipelineInfo.renderPass = renderPass;
- pipelineInfo.subpass = 0;
- pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
- pipelineInfo.basePipelineIndex = -1;
-
- if (vkCreateGraphicsPipelines(logicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &grassPipeline) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create graphics pipeline");
- }
-
- // No need for the shader modules anymore
- vkDestroyShaderModule(logicalDevice, vertShaderModule, nullptr);
- vkDestroyShaderModule(logicalDevice, tescShaderModule, nullptr);
- vkDestroyShaderModule(logicalDevice, teseShaderModule, nullptr);
- vkDestroyShaderModule(logicalDevice, fragShaderModule, nullptr);
+ // --- Set up programmable shaders ---
+ VkShaderModule vertShaderModule = ShaderModule::Create("shaders/grass.vert.spv", logicalDevice);
+ VkShaderModule tescShaderModule = ShaderModule::Create("shaders/grass.tesc.spv", logicalDevice);
+ VkShaderModule teseShaderModule = ShaderModule::Create("shaders/grass.tese.spv", logicalDevice);
+ VkShaderModule fragShaderModule = ShaderModule::Create("shaders/grass.frag.spv", logicalDevice);
+
+ // Assign each shader module to the appropriate stage in the pipeline
+ VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
+ vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
+ vertShaderStageInfo.module = vertShaderModule;
+ vertShaderStageInfo.pName = "main";
+
+ VkPipelineShaderStageCreateInfo tescShaderStageInfo = {};
+ tescShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ tescShaderStageInfo.stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
+ tescShaderStageInfo.module = tescShaderModule;
+ tescShaderStageInfo.pName = "main";
+
+ VkPipelineShaderStageCreateInfo teseShaderStageInfo = {};
+ teseShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ teseShaderStageInfo.stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
+ teseShaderStageInfo.module = teseShaderModule;
+ teseShaderStageInfo.pName = "main";
+
+ VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
+ fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+ fragShaderStageInfo.module = fragShaderModule;
+ fragShaderStageInfo.pName = "main";
+
+ VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, tescShaderStageInfo, teseShaderStageInfo, fragShaderStageInfo };
+
+ // --- Set up fixed-function stages ---
+
+ // Vertex input
+ VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
+ vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+
+ auto bindingDescription = Blade::getBindingDescription();
+ auto attributeDescriptions = Blade::getAttributeDescriptions();
+
+ vertexInputInfo.vertexBindingDescriptionCount = 1;
+ vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
+ vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size());
+ vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
+
+ // Input Assembly
+ VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
+ inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
+ inputAssembly.primitiveRestartEnable = VK_FALSE;
+
+ // Viewports and Scissors (rectangles that define in which regions pixels are stored)
+ VkViewport viewport = {};
+ viewport.x = 0.0f;
+ viewport.y = 0.0f;
+ viewport.width = static_cast(swapChain->GetVkExtent().width);
+ viewport.height = static_cast(swapChain->GetVkExtent().height);
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ VkRect2D scissor = {};
+ scissor.offset = { 0, 0 };
+ scissor.extent = swapChain->GetVkExtent();
+
+ VkPipelineViewportStateCreateInfo viewportState = {};
+ viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ viewportState.viewportCount = 1;
+ viewportState.pViewports = &viewport;
+ viewportState.scissorCount = 1;
+ viewportState.pScissors = &scissor;
+
+ // Rasterizer
+ VkPipelineRasterizationStateCreateInfo rasterizer = {};
+ rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rasterizer.depthClampEnable = VK_FALSE;
+ rasterizer.rasterizerDiscardEnable = VK_FALSE;
+ rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
+ rasterizer.lineWidth = 1.0f;
+ rasterizer.cullMode = VK_CULL_MODE_NONE;
+ rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+ rasterizer.depthBiasEnable = VK_FALSE;
+ rasterizer.depthBiasConstantFactor = 0.0f;
+ rasterizer.depthBiasClamp = 0.0f;
+ rasterizer.depthBiasSlopeFactor = 0.0f;
+
+ // Multisampling (turned off here)
+ VkPipelineMultisampleStateCreateInfo multisampling = {};
+ multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ multisampling.sampleShadingEnable = VK_FALSE;
+ multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+ multisampling.minSampleShading = 1.0f;
+ multisampling.pSampleMask = nullptr;
+ multisampling.alphaToCoverageEnable = VK_FALSE;
+ multisampling.alphaToOneEnable = VK_FALSE;
+
+ // Depth testing
+ VkPipelineDepthStencilStateCreateInfo depthStencil = {};
+ depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ depthStencil.depthTestEnable = VK_TRUE;
+ depthStencil.depthWriteEnable = VK_TRUE;
+ depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
+ depthStencil.depthBoundsTestEnable = VK_FALSE;
+ depthStencil.minDepthBounds = 0.0f;
+ depthStencil.maxDepthBounds = 1.0f;
+ depthStencil.stencilTestEnable = VK_FALSE;
+
+ // Color blending (turned off here, but showing options for learning)
+ // --> Configuration per attached framebuffer
+ VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
+ colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+ colorBlendAttachment.blendEnable = VK_FALSE;
+ colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
+ colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
+ colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
+ colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
+ colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
+ colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
+
+ // --> Global color blending settings
+ VkPipelineColorBlendStateCreateInfo colorBlending = {};
+ colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ colorBlending.logicOpEnable = VK_FALSE;
+ colorBlending.logicOp = VK_LOGIC_OP_COPY;
+ colorBlending.attachmentCount = 1;
+ colorBlending.pAttachments = &colorBlendAttachment;
+ colorBlending.blendConstants[0] = 0.0f;
+ colorBlending.blendConstants[1] = 0.0f;
+ colorBlending.blendConstants[2] = 0.0f;
+ colorBlending.blendConstants[3] = 0.0f;
+
+ std::vector descriptorSetLayouts = { cameraDescriptorSetLayout, modelDescriptorSetLayout, grassDescriptorSetLayout };
+
+ // Pipeline layout: used to specify uniform values
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
+ pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutInfo.setLayoutCount = static_cast(descriptorSetLayouts.size());
+ pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts.data();
+ pipelineLayoutInfo.pushConstantRangeCount = 0;
+ pipelineLayoutInfo.pPushConstantRanges = 0;
+
+ if (vkCreatePipelineLayout(logicalDevice, &pipelineLayoutInfo, nullptr, &grassPipelineLayout) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create pipeline layout");
+ }
+
+ // Tessellation state
+ VkPipelineTessellationStateCreateInfo tessellationInfo = {};
+ tessellationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
+ tessellationInfo.pNext = NULL;
+ tessellationInfo.flags = 0;
+ tessellationInfo.patchControlPoints = 1;
+
+ // --- Create graphics pipeline ---
+ VkGraphicsPipelineCreateInfo pipelineInfo = {};
+ pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ pipelineInfo.stageCount = 4;
+ pipelineInfo.pStages = shaderStages;
+ pipelineInfo.pVertexInputState = &vertexInputInfo;
+ pipelineInfo.pInputAssemblyState = &inputAssembly;
+ pipelineInfo.pViewportState = &viewportState;
+ pipelineInfo.pRasterizationState = &rasterizer;
+ pipelineInfo.pMultisampleState = &multisampling;
+ pipelineInfo.pDepthStencilState = &depthStencil;
+ pipelineInfo.pColorBlendState = &colorBlending;
+ pipelineInfo.pTessellationState = &tessellationInfo;
+ pipelineInfo.pDynamicState = nullptr;
+ pipelineInfo.layout = grassPipelineLayout;
+ pipelineInfo.renderPass = renderPass;
+ pipelineInfo.subpass = 0;
+ pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
+ pipelineInfo.basePipelineIndex = -1;
+
+ if (vkCreateGraphicsPipelines(logicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &grassPipeline) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create graphics pipeline");
+ }
+
+ // No need for the shader modules anymore
+ vkDestroyShaderModule(logicalDevice, vertShaderModule, nullptr);
+ vkDestroyShaderModule(logicalDevice, tescShaderModule, nullptr);
+ vkDestroyShaderModule(logicalDevice, teseShaderModule, nullptr);
+ vkDestroyShaderModule(logicalDevice, fragShaderModule, nullptr);
}
void Renderer::CreateComputePipeline() {
- // Set up programmable shaders
- VkShaderModule computeShaderModule = ShaderModule::Create("shaders/compute.comp.spv", logicalDevice);
-
- VkPipelineShaderStageCreateInfo computeShaderStageInfo = {};
- computeShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- computeShaderStageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
- computeShaderStageInfo.module = computeShaderModule;
- computeShaderStageInfo.pName = "main";
-
- // TODO: Add the compute dsecriptor set layout you create to this list
- std::vector descriptorSetLayouts = { cameraDescriptorSetLayout, timeDescriptorSetLayout };
-
- // Create pipeline layout
- VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
- pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- pipelineLayoutInfo.setLayoutCount = static_cast(descriptorSetLayouts.size());
- pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts.data();
- pipelineLayoutInfo.pushConstantRangeCount = 0;
- pipelineLayoutInfo.pPushConstantRanges = 0;
-
- if (vkCreatePipelineLayout(logicalDevice, &pipelineLayoutInfo, nullptr, &computePipelineLayout) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create pipeline layout");
- }
-
- // Create compute pipeline
- VkComputePipelineCreateInfo pipelineInfo = {};
- pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
- pipelineInfo.stage = computeShaderStageInfo;
- pipelineInfo.layout = computePipelineLayout;
- pipelineInfo.pNext = nullptr;
- pipelineInfo.flags = 0;
- pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
- pipelineInfo.basePipelineIndex = -1;
-
- if (vkCreateComputePipelines(logicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &computePipeline) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create compute pipeline");
- }
-
- // No need for shader modules anymore
- vkDestroyShaderModule(logicalDevice, computeShaderModule, nullptr);
+ // Set up programmable shaders
+ VkShaderModule computeShaderModule = ShaderModule::Create("shaders/compute.comp.spv", logicalDevice);
+
+ VkPipelineShaderStageCreateInfo computeShaderStageInfo = {};
+ computeShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ computeShaderStageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
+ computeShaderStageInfo.module = computeShaderModule;
+ computeShaderStageInfo.pName = "main";
+
+ // TODO: Add the compute dsecriptor set layout you create to this list
+ std::vector descriptorSetLayouts = { cameraDescriptorSetLayout, timeDescriptorSetLayout, computeDescriptorSetLayout };
+
+ // Create pipeline layout
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
+ pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutInfo.setLayoutCount = static_cast(descriptorSetLayouts.size());
+ pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts.data();
+ pipelineLayoutInfo.pushConstantRangeCount = 0;
+ pipelineLayoutInfo.pPushConstantRanges = 0;
+
+ if (vkCreatePipelineLayout(logicalDevice, &pipelineLayoutInfo, nullptr, &computePipelineLayout) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create pipeline layout");
+ }
+
+ // Create compute pipeline
+ VkComputePipelineCreateInfo pipelineInfo = {};
+ pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
+ pipelineInfo.stage = computeShaderStageInfo;
+ pipelineInfo.layout = computePipelineLayout;
+ pipelineInfo.pNext = nullptr;
+ pipelineInfo.flags = 0;
+ pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
+ pipelineInfo.basePipelineIndex = -1;
+
+ if (vkCreateComputePipelines(logicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &computePipeline) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create compute pipeline");
+ }
+
+ // No need for shader modules anymore
+ vkDestroyShaderModule(logicalDevice, computeShaderModule, nullptr);
}
void Renderer::CreateFrameResources() {
- imageViews.resize(swapChain->GetCount());
-
- for (uint32_t i = 0; i < swapChain->GetCount(); i++) {
- // --- Create an image view for each swap chain image ---
- VkImageViewCreateInfo createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- createInfo.image = swapChain->GetVkImage(i);
-
- // Specify how the image data should be interpreted
- createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
- createInfo.format = swapChain->GetVkImageFormat();
-
- // Specify color channel mappings (can be used for swizzling)
- createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
- createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
- createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
- createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
-
- // Describe the image's purpose and which part of the image should be accessed
- createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- createInfo.subresourceRange.baseMipLevel = 0;
- createInfo.subresourceRange.levelCount = 1;
- createInfo.subresourceRange.baseArrayLayer = 0;
- createInfo.subresourceRange.layerCount = 1;
-
- // Create the image view
- if (vkCreateImageView(logicalDevice, &createInfo, nullptr, &imageViews[i]) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create image views");
- }
- }
-
- VkFormat depthFormat = device->GetInstance()->GetSupportedFormat({ VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
- // CREATE DEPTH IMAGE
- Image::Create(device,
- swapChain->GetVkExtent().width,
- swapChain->GetVkExtent().height,
- depthFormat,
- VK_IMAGE_TILING_OPTIMAL,
- VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
- depthImage,
- depthImageMemory
- );
-
- depthImageView = Image::CreateView(device, depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
-
- // Transition the image for use as depth-stencil
- Image::TransitionLayout(device, graphicsCommandPool, depthImage, depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
-
-
- // CREATE FRAMEBUFFERS
- framebuffers.resize(swapChain->GetCount());
- for (size_t i = 0; i < swapChain->GetCount(); i++) {
- std::vector attachments = {
- imageViews[i],
- depthImageView
- };
-
- VkFramebufferCreateInfo framebufferInfo = {};
- framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
- framebufferInfo.renderPass = renderPass;
- framebufferInfo.attachmentCount = static_cast(attachments.size());
- framebufferInfo.pAttachments = attachments.data();
- framebufferInfo.width = swapChain->GetVkExtent().width;
- framebufferInfo.height = swapChain->GetVkExtent().height;
- framebufferInfo.layers = 1;
-
- if (vkCreateFramebuffer(logicalDevice, &framebufferInfo, nullptr, &framebuffers[i]) != VK_SUCCESS) {
- throw std::runtime_error("Failed to create framebuffer");
- }
-
- }
+ imageViews.resize(swapChain->GetCount());
+
+ for (uint32_t i = 0; i < swapChain->GetCount(); i++) {
+ // --- Create an image view for each swap chain image ---
+ VkImageViewCreateInfo createInfo = {};
+ createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ createInfo.image = swapChain->GetVkImage(i);
+
+ // Specify how the image data should be interpreted
+ createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ createInfo.format = swapChain->GetVkImageFormat();
+
+ // Specify color channel mappings (can be used for swizzling)
+ createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+ createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+ createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+ createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+
+ // Describe the image's purpose and which part of the image should be accessed
+ createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ createInfo.subresourceRange.baseMipLevel = 0;
+ createInfo.subresourceRange.levelCount = 1;
+ createInfo.subresourceRange.baseArrayLayer = 0;
+ createInfo.subresourceRange.layerCount = 1;
+
+ // Create the image view
+ if (vkCreateImageView(logicalDevice, &createInfo, nullptr, &imageViews[i]) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create image views");
+ }
+ }
+
+ VkFormat depthFormat = device->GetInstance()->GetSupportedFormat({ VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
+ // CREATE DEPTH IMAGE
+ Image::Create(device,
+ swapChain->GetVkExtent().width,
+ swapChain->GetVkExtent().height,
+ depthFormat,
+ VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
+ depthImage,
+ depthImageMemory
+ );
+
+ depthImageView = Image::CreateView(device, depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
+
+ // Transition the image for use as depth-stencil
+ Image::TransitionLayout(device, graphicsCommandPool, depthImage, depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+
+
+ // CREATE FRAMEBUFFERS
+ framebuffers.resize(swapChain->GetCount());
+ for (size_t i = 0; i < swapChain->GetCount(); i++) {
+ std::vector attachments = {
+ imageViews[i],
+ depthImageView
+ };
+
+ VkFramebufferCreateInfo framebufferInfo = {};
+ framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ framebufferInfo.renderPass = renderPass;
+ framebufferInfo.attachmentCount = static_cast(attachments.size());
+ framebufferInfo.pAttachments = attachments.data();
+ framebufferInfo.width = swapChain->GetVkExtent().width;
+ framebufferInfo.height = swapChain->GetVkExtent().height;
+ framebufferInfo.layers = 1;
+
+ if (vkCreateFramebuffer(logicalDevice, &framebufferInfo, nullptr, &framebuffers[i]) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to create framebuffer");
+ }
+
+ }
}
void Renderer::DestroyFrameResources() {
- for (size_t i = 0; i < imageViews.size(); i++) {
- vkDestroyImageView(logicalDevice, imageViews[i], nullptr);
- }
+ for (size_t i = 0; i < imageViews.size(); i++) {
+ vkDestroyImageView(logicalDevice, imageViews[i], nullptr);
+ }
- vkDestroyImageView(logicalDevice, depthImageView, nullptr);
- vkFreeMemory(logicalDevice, depthImageMemory, nullptr);
- vkDestroyImage(logicalDevice, depthImage, nullptr);
+ vkDestroyImageView(logicalDevice, depthImageView, nullptr);
+ vkFreeMemory(logicalDevice, depthImageMemory, nullptr);
+ vkDestroyImage(logicalDevice, depthImage, nullptr);
- for (size_t i = 0; i < framebuffers.size(); i++) {
- vkDestroyFramebuffer(logicalDevice, framebuffers[i], nullptr);
- }
+ for (size_t i = 0; i < framebuffers.size(); i++) {
+ vkDestroyFramebuffer(logicalDevice, framebuffers[i], nullptr);
+ }
}
void Renderer::RecreateFrameResources() {
- vkDestroyPipeline(logicalDevice, graphicsPipeline, nullptr);
- vkDestroyPipeline(logicalDevice, grassPipeline, nullptr);
- vkDestroyPipelineLayout(logicalDevice, graphicsPipelineLayout, nullptr);
- vkDestroyPipelineLayout(logicalDevice, grassPipelineLayout, nullptr);
- vkFreeCommandBuffers(logicalDevice, graphicsCommandPool, static_cast(commandBuffers.size()), commandBuffers.data());
-
- DestroyFrameResources();
- CreateFrameResources();
- CreateGraphicsPipeline();
- CreateGrassPipeline();
- RecordCommandBuffers();
+ vkDestroyPipeline(logicalDevice, graphicsPipeline, nullptr);
+ vkDestroyPipeline(logicalDevice, grassPipeline, nullptr);
+ vkDestroyPipelineLayout(logicalDevice, graphicsPipelineLayout, nullptr);
+ vkDestroyPipelineLayout(logicalDevice, grassPipelineLayout, nullptr);
+ vkFreeCommandBuffers(logicalDevice, graphicsCommandPool, static_cast(commandBuffers.size()), commandBuffers.data());
+
+ DestroyFrameResources();
+ CreateFrameResources();
+ CreateGraphicsPipeline();
+ CreateGrassPipeline();
+ RecordCommandBuffers();
}
void Renderer::RecordComputeCommandBuffer() {
- // Specify the command pool and number of buffers to allocate
- VkCommandBufferAllocateInfo allocInfo = {};
- allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- allocInfo.commandPool = computeCommandPool;
- allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- allocInfo.commandBufferCount = 1;
-
- if (vkAllocateCommandBuffers(logicalDevice, &allocInfo, &computeCommandBuffer) != VK_SUCCESS) {
- throw std::runtime_error("Failed to allocate command buffers");
- }
-
- VkCommandBufferBeginInfo beginInfo = {};
- beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
- beginInfo.pInheritanceInfo = nullptr;
-
- // ~ Start recording ~
- if (vkBeginCommandBuffer(computeCommandBuffer, &beginInfo) != VK_SUCCESS) {
- throw std::runtime_error("Failed to begin recording compute command buffer");
- }
-
- // Bind to the compute pipeline
- vkCmdBindPipeline(computeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline);
-
- // Bind camera descriptor set
- vkCmdBindDescriptorSets(computeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout, 0, 1, &cameraDescriptorSet, 0, nullptr);
-
- // Bind descriptor set for time uniforms
- vkCmdBindDescriptorSets(computeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout, 1, 1, &timeDescriptorSet, 0, nullptr);
-
- // TODO: For each group of blades bind its descriptor set and dispatch
-
- // ~ End recording ~
- if (vkEndCommandBuffer(computeCommandBuffer) != VK_SUCCESS) {
- throw std::runtime_error("Failed to record compute command buffer");
- }
+ // Specify the command pool and number of buffers to allocate
+ VkCommandBufferAllocateInfo allocInfo = {};
+ allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ allocInfo.commandPool = computeCommandPool;
+ allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ allocInfo.commandBufferCount = 1;
+
+ if (vkAllocateCommandBuffers(logicalDevice, &allocInfo, &computeCommandBuffer) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to allocate command buffers");
+ }
+
+ VkCommandBufferBeginInfo beginInfo = {};
+ beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
+ beginInfo.pInheritanceInfo = nullptr;
+
+ // ~ Start recording ~
+ if (vkBeginCommandBuffer(computeCommandBuffer, &beginInfo) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to begin recording compute command buffer");
+ }
+
+ // Bind to the compute pipeline
+ vkCmdBindPipeline(computeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline);
+
+ // Bind camera descriptor set
+ vkCmdBindDescriptorSets(computeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout, 0, 1, &cameraDescriptorSet, 0, nullptr);
+
+ // Bind descriptor set for time uniforms
+ vkCmdBindDescriptorSets(computeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout, 1, 1, &timeDescriptorSet, 0, nullptr);
+
+ // TODO: For each group of blades bind its descriptor set and dispatch
+ for (uint32_t i = 0; i < scene->GetBlades().size(); ++i) {
+ vkCmdBindDescriptorSets(computeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout, 2, 1, &computeDescriptorSets[i], 0, nullptr);
+ vkCmdDispatch(computeCommandBuffer, (int)ceil(NUM_BLADES / WORKGROUP_SIZE), 1, 1);
+ }
+
+ // ~ End recording ~
+ if (vkEndCommandBuffer(computeCommandBuffer) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to record compute command buffer");
+ }
}
void Renderer::RecordCommandBuffers() {
- commandBuffers.resize(swapChain->GetCount());
-
- // Specify the command pool and number of buffers to allocate
- VkCommandBufferAllocateInfo allocInfo = {};
- allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- allocInfo.commandPool = graphicsCommandPool;
- allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- allocInfo.commandBufferCount = static_cast(commandBuffers.size());
-
- if (vkAllocateCommandBuffers(logicalDevice, &allocInfo, commandBuffers.data()) != VK_SUCCESS) {
- throw std::runtime_error("Failed to allocate command buffers");
- }
-
- // Start command buffer recording
- for (size_t i = 0; i < commandBuffers.size(); i++) {
- VkCommandBufferBeginInfo beginInfo = {};
- beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
- beginInfo.pInheritanceInfo = nullptr;
-
- // ~ Start recording ~
- if (vkBeginCommandBuffer(commandBuffers[i], &beginInfo) != VK_SUCCESS) {
- throw std::runtime_error("Failed to begin recording command buffer");
- }
-
- // Begin the render pass
- VkRenderPassBeginInfo renderPassInfo = {};
- renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- renderPassInfo.renderPass = renderPass;
- renderPassInfo.framebuffer = framebuffers[i];
- renderPassInfo.renderArea.offset = { 0, 0 };
- renderPassInfo.renderArea.extent = swapChain->GetVkExtent();
-
- std::array clearValues = {};
- clearValues[0].color = { 0.0f, 0.0f, 0.0f, 1.0f };
- clearValues[1].depthStencil = { 1.0f, 0 };
- renderPassInfo.clearValueCount = static_cast(clearValues.size());
- renderPassInfo.pClearValues = clearValues.data();
-
- std::vector barriers(scene->GetBlades().size());
- for (uint32_t j = 0; j < barriers.size(); ++j) {
- barriers[j].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
- barriers[j].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
- barriers[j].dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
- barriers[j].srcQueueFamilyIndex = device->GetQueueIndex(QueueFlags::Compute);
- barriers[j].dstQueueFamilyIndex = device->GetQueueIndex(QueueFlags::Graphics);
- barriers[j].buffer = scene->GetBlades()[j]->GetNumBladesBuffer();
- barriers[j].offset = 0;
- barriers[j].size = sizeof(BladeDrawIndirect);
- }
-
- vkCmdPipelineBarrier(commandBuffers[i], VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0, 0, nullptr, barriers.size(), barriers.data(), 0, nullptr);
-
- // Bind the camera descriptor set. This is set 0 in all pipelines so it will be inherited
- vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout, 0, 1, &cameraDescriptorSet, 0, nullptr);
-
- vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
-
- // Bind the graphics pipeline
- vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
-
- for (uint32_t j = 0; j < scene->GetModels().size(); ++j) {
- // Bind the vertex and index buffers
- VkBuffer vertexBuffers[] = { scene->GetModels()[j]->getVertexBuffer() };
- VkDeviceSize offsets[] = { 0 };
- vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
-
- vkCmdBindIndexBuffer(commandBuffers[i], scene->GetModels()[j]->getIndexBuffer(), 0, VK_INDEX_TYPE_UINT32);
-
- // Bind the descriptor set for each model
- vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout, 1, 1, &modelDescriptorSets[j], 0, nullptr);
-
- // Draw
- std::vector indices = scene->GetModels()[j]->getIndices();
- vkCmdDrawIndexed(commandBuffers[i], static_cast(indices.size()), 1, 0, 0, 0);
- }
-
- // Bind the grass pipeline
- vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, grassPipeline);
-
- for (uint32_t j = 0; j < scene->GetBlades().size(); ++j) {
- VkBuffer vertexBuffers[] = { scene->GetBlades()[j]->GetCulledBladesBuffer() };
- VkDeviceSize offsets[] = { 0 };
- // TODO: Uncomment this when the buffers are populated
- // vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
-
- // TODO: Bind the descriptor set for each grass blades model
-
- // Draw
- // TODO: Uncomment this when the buffers are populated
- // vkCmdDrawIndirect(commandBuffers[i], scene->GetBlades()[j]->GetNumBladesBuffer(), 0, 1, sizeof(BladeDrawIndirect));
- }
-
- // End render pass
- vkCmdEndRenderPass(commandBuffers[i]);
-
- // ~ End recording ~
- if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) {
- throw std::runtime_error("Failed to record command buffer");
- }
- }
+ commandBuffers.resize(swapChain->GetCount());
+
+ // Specify the command pool and number of buffers to allocate
+ VkCommandBufferAllocateInfo allocInfo = {};
+ allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ allocInfo.commandPool = graphicsCommandPool;
+ allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ allocInfo.commandBufferCount = static_cast(commandBuffers.size());
+
+ if (vkAllocateCommandBuffers(logicalDevice, &allocInfo, commandBuffers.data()) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to allocate command buffers");
+ }
+
+ // Start command buffer recording
+ for (size_t i = 0; i < commandBuffers.size(); i++) {
+ VkCommandBufferBeginInfo beginInfo = {};
+ beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
+ beginInfo.pInheritanceInfo = nullptr;
+
+ // ~ Start recording ~
+ if (vkBeginCommandBuffer(commandBuffers[i], &beginInfo) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to begin recording command buffer");
+ }
+
+ // Begin the render pass
+ VkRenderPassBeginInfo renderPassInfo = {};
+ renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ renderPassInfo.renderPass = renderPass;
+ renderPassInfo.framebuffer = framebuffers[i];
+ renderPassInfo.renderArea.offset = { 0, 0 };
+ renderPassInfo.renderArea.extent = swapChain->GetVkExtent();
+
+ std::array clearValues = {};
+ clearValues[0].color = { 0.0f, 0.0f, 0.0f, 1.0f };
+ clearValues[1].depthStencil = { 1.0f, 0 };
+ renderPassInfo.clearValueCount = static_cast(clearValues.size());
+ renderPassInfo.pClearValues = clearValues.data();
+
+ std::vector barriers(scene->GetBlades().size());
+ for (uint32_t j = 0; j < barriers.size(); ++j) {
+ barriers[j].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
+ barriers[j].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
+ barriers[j].dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
+ barriers[j].srcQueueFamilyIndex = device->GetQueueIndex(QueueFlags::Compute);
+ barriers[j].dstQueueFamilyIndex = device->GetQueueIndex(QueueFlags::Graphics);
+ barriers[j].buffer = scene->GetBlades()[j]->GetNumBladesBuffer();
+ barriers[j].offset = 0;
+ barriers[j].size = sizeof(BladeDrawIndirect);
+ }
+
+ vkCmdPipelineBarrier(commandBuffers[i], VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0, 0, nullptr, barriers.size(), barriers.data(), 0, nullptr);
+
+ // Bind the camera descriptor set. This is set 0 in all pipelines so it will be inherited
+ vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout, 0, 1, &cameraDescriptorSet, 0, nullptr);
+
+ vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+ // Bind the graphics pipeline
+ vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
+
+ for (uint32_t j = 0; j < scene->GetModels().size(); ++j) {
+ // Bind the vertex and index buffers
+ VkBuffer vertexBuffers[] = { scene->GetModels()[j]->getVertexBuffer() };
+ VkDeviceSize offsets[] = { 0 };
+ vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
+
+ vkCmdBindIndexBuffer(commandBuffers[i], scene->GetModels()[j]->getIndexBuffer(), 0, VK_INDEX_TYPE_UINT32);
+
+ // Bind the descriptor set for each model
+ vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout, 1, 1, &modelDescriptorSets[j], 0, nullptr);
+
+ // Draw
+ std::vector indices = scene->GetModels()[j]->getIndices();
+ vkCmdDrawIndexed(commandBuffers[i], static_cast(indices.size()), 1, 0, 0, 0);
+ }
+
+ // Bind the grass pipeline
+ vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, grassPipeline);
+
+ for (uint32_t j = 0; j < scene->GetBlades().size(); ++j) {
+ VkBuffer vertexBuffers[] = { scene->GetBlades()[j]->GetCulledBladesBuffer() };
+ VkDeviceSize offsets[] = { 0 };
+ // TODO: Uncomment this when the buffers are populated
+ vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
+
+ // TODO: Bind the descriptor set for each grass blades model
+ vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, grassPipelineLayout, 1, 1, &grassDescriptorSets[j], 0, nullptr);
+
+ // Draw
+ // TODO: Uncomment this when the buffers are populated
+ vkCmdDrawIndirect(commandBuffers[i], scene->GetBlades()[j]->GetNumBladesBuffer(), 0, 1, sizeof(BladeDrawIndirect));
+ }
+
+ // End render pass
+ vkCmdEndRenderPass(commandBuffers[i]);
+
+ // ~ End recording ~
+ if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to record command buffer");
+ }
+ }
}
void Renderer::Frame() {
- VkSubmitInfo computeSubmitInfo = {};
- computeSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ VkSubmitInfo computeSubmitInfo = {};
+ computeSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- computeSubmitInfo.commandBufferCount = 1;
- computeSubmitInfo.pCommandBuffers = &computeCommandBuffer;
+ computeSubmitInfo.commandBufferCount = 1;
+ computeSubmitInfo.pCommandBuffers = &computeCommandBuffer;
- if (vkQueueSubmit(device->GetQueue(QueueFlags::Compute), 1, &computeSubmitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
- throw std::runtime_error("Failed to submit draw command buffer");
- }
+ if (vkQueueSubmit(device->GetQueue(QueueFlags::Compute), 1, &computeSubmitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to submit draw command buffer");
+ }
- if (!swapChain->Acquire()) {
- RecreateFrameResources();
- return;
- }
+ if (!swapChain->Acquire()) {
+ RecreateFrameResources();
+ return;
+ }
- // Submit the command buffer
- VkSubmitInfo submitInfo = {};
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ // Submit the command buffer
+ VkSubmitInfo submitInfo = {};
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- VkSemaphore waitSemaphores[] = { swapChain->GetImageAvailableVkSemaphore() };
- VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
- submitInfo.waitSemaphoreCount = 1;
- submitInfo.pWaitSemaphores = waitSemaphores;
- submitInfo.pWaitDstStageMask = waitStages;
+ VkSemaphore waitSemaphores[] = { swapChain->GetImageAvailableVkSemaphore() };
+ VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
+ submitInfo.waitSemaphoreCount = 1;
+ submitInfo.pWaitSemaphores = waitSemaphores;
+ submitInfo.pWaitDstStageMask = waitStages;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &commandBuffers[swapChain->GetIndex()];
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &commandBuffers[swapChain->GetIndex()];
- VkSemaphore signalSemaphores[] = { swapChain->GetRenderFinishedVkSemaphore() };
- submitInfo.signalSemaphoreCount = 1;
- submitInfo.pSignalSemaphores = signalSemaphores;
+ VkSemaphore signalSemaphores[] = { swapChain->GetRenderFinishedVkSemaphore() };
+ submitInfo.signalSemaphoreCount = 1;
+ submitInfo.pSignalSemaphores = signalSemaphores;
- if (vkQueueSubmit(device->GetQueue(QueueFlags::Graphics), 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
- throw std::runtime_error("Failed to submit draw command buffer");
- }
+ if (vkQueueSubmit(device->GetQueue(QueueFlags::Graphics), 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
+ throw std::runtime_error("Failed to submit draw command buffer");
+ }
- if (!swapChain->Present()) {
- RecreateFrameResources();
- }
+ if (!swapChain->Present()) {
+ RecreateFrameResources();
+ }
}
Renderer::~Renderer() {
- vkDeviceWaitIdle(logicalDevice);
+ vkDeviceWaitIdle(logicalDevice);
- // TODO: destroy any resources you created
+ // TODO: destroy any resources you created
- vkFreeCommandBuffers(logicalDevice, graphicsCommandPool, static_cast(commandBuffers.size()), commandBuffers.data());
- vkFreeCommandBuffers(logicalDevice, computeCommandPool, 1, &computeCommandBuffer);
-
- vkDestroyPipeline(logicalDevice, graphicsPipeline, nullptr);
- vkDestroyPipeline(logicalDevice, grassPipeline, nullptr);
- vkDestroyPipeline(logicalDevice, computePipeline, nullptr);
+ vkFreeCommandBuffers(logicalDevice, graphicsCommandPool, static_cast(commandBuffers.size()), commandBuffers.data());
+ vkFreeCommandBuffers(logicalDevice, computeCommandPool, 1, &computeCommandBuffer);
- vkDestroyPipelineLayout(logicalDevice, graphicsPipelineLayout, nullptr);
- vkDestroyPipelineLayout(logicalDevice, grassPipelineLayout, nullptr);
- vkDestroyPipelineLayout(logicalDevice, computePipelineLayout, nullptr);
+ vkDestroyPipeline(logicalDevice, graphicsPipeline, nullptr);
+ vkDestroyPipeline(logicalDevice, grassPipeline, nullptr);
+ vkDestroyPipeline(logicalDevice, computePipeline, nullptr);
- vkDestroyDescriptorSetLayout(logicalDevice, cameraDescriptorSetLayout, nullptr);
- vkDestroyDescriptorSetLayout(logicalDevice, modelDescriptorSetLayout, nullptr);
- vkDestroyDescriptorSetLayout(logicalDevice, timeDescriptorSetLayout, nullptr);
+ vkDestroyPipelineLayout(logicalDevice, graphicsPipelineLayout, nullptr);
+ vkDestroyPipelineLayout(logicalDevice, grassPipelineLayout, nullptr);
+ vkDestroyPipelineLayout(logicalDevice, computePipelineLayout, nullptr);
- vkDestroyDescriptorPool(logicalDevice, descriptorPool, nullptr);
+ vkDestroyDescriptorSetLayout(logicalDevice, cameraDescriptorSetLayout, nullptr);
+ vkDestroyDescriptorSetLayout(logicalDevice, modelDescriptorSetLayout, nullptr);
+ vkDestroyDescriptorSetLayout(logicalDevice, timeDescriptorSetLayout, nullptr);
+ vkDestroyDescriptorSetLayout(logicalDevice, computeDescriptorSetLayout, nullptr);
+ vkDestroyDescriptorSetLayout(logicalDevice, grassDescriptorSetLayout, nullptr);
- vkDestroyRenderPass(logicalDevice, renderPass, nullptr);
- DestroyFrameResources();
- vkDestroyCommandPool(logicalDevice, computeCommandPool, nullptr);
- vkDestroyCommandPool(logicalDevice, graphicsCommandPool, nullptr);
-}
+ vkDestroyDescriptorPool(logicalDevice, descriptorPool, nullptr);
+
+ vkDestroyRenderPass(logicalDevice, renderPass, nullptr);
+ DestroyFrameResources();
+ vkDestroyCommandPool(logicalDevice, computeCommandPool, nullptr);
+ vkDestroyCommandPool(logicalDevice, graphicsCommandPool, nullptr);
+}
\ No newline at end of file
diff --git a/src/Renderer.h b/src/Renderer.h
index 95e025f..79f01e6 100644
--- a/src/Renderer.h
+++ b/src/Renderer.h
@@ -19,6 +19,7 @@ class Renderer {
void CreateModelDescriptorSetLayout();
void CreateTimeDescriptorSetLayout();
void CreateComputeDescriptorSetLayout();
+ void CreateGrassDescriptorSetLayout();
void CreateDescriptorPool();
@@ -56,12 +57,16 @@ class Renderer {
VkDescriptorSetLayout cameraDescriptorSetLayout;
VkDescriptorSetLayout modelDescriptorSetLayout;
VkDescriptorSetLayout timeDescriptorSetLayout;
+ VkDescriptorSetLayout computeDescriptorSetLayout;
+ VkDescriptorSetLayout grassDescriptorSetLayout;
VkDescriptorPool descriptorPool;
VkDescriptorSet cameraDescriptorSet;
std::vector modelDescriptorSets;
VkDescriptorSet timeDescriptorSet;
+ std::vector grassDescriptorSets;
+ std::vector computeDescriptorSets;
VkPipelineLayout graphicsPipelineLayout;
VkPipelineLayout grassPipelineLayout;
diff --git a/src/main.cpp b/src/main.cpp
index 8bf822b..c8133c0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -5,6 +5,8 @@
#include "Camera.h"
#include "Scene.h"
#include "Image.h"
+#include
+#pragma comment( lib,"winmm.lib" )
Device* device;
SwapChain* swapChain;
@@ -142,11 +144,21 @@ int main() {
glfwSetWindowSizeCallback(GetGLFWWindow(), resizeCallback);
glfwSetMouseButtonCallback(GetGLFWWindow(), mouseDownCallback);
glfwSetCursorPosCallback(GetGLFWWindow(), mouseMoveCallback);
+
+ //clock_t start, end;
+
+ while (!ShouldQuit()) {
+ glfwPollEvents();
- while (!ShouldQuit()) {
- glfwPollEvents();
+ //record time
scene->UpdateTime();
- renderer->Frame();
+ //start = clock();
+
+ renderer->Frame();
+
+ //end = clock();
+ //double dur = (double)(end - start);
+ //std::cout << dur * 1000.0 / CLOCKS_PER_SEC << std::endl;
}
vkDeviceWaitIdle(device->GetVkDevice());
diff --git a/src/shaders/compute.comp b/src/shaders/compute.comp
index 0fd0224..f4606aa 100644
--- a/src/shaders/compute.comp
+++ b/src/shaders/compute.comp
@@ -2,6 +2,11 @@
#extension GL_ARB_separate_shader_objects : enable
#define WORKGROUP_SIZE 32
+#define GRAV_ACCELERATION 9.8
+#define TOLERANCE 1.0
+#define CULLLEVEL 10.0
+#define DMAX 50.0
+
layout(local_size_x = WORKGROUP_SIZE, local_size_y = 1, local_size_z = 1) in;
layout(set = 0, binding = 0) uniform CameraBufferObject {
@@ -36,6 +41,25 @@ struct Blade {
// uint firstInstance; // = 0
// } numBlades;
+//===========================================================================
+
+layout(set = 2, binding = 0) buffer Blades {
+ Blade blades[];
+};
+
+layout(set = 2, binding = 1) buffer CulledBlades {
+ Blade culledBlades[];
+};
+
+layout(set = 2, binding = 2) buffer NumBlades {
+ uint vertexCount; // Write the number of blades remaining here
+ uint instanceCount; // = 1
+ uint firstVertex; // = 0
+ uint firstInstance; // = 0
+} numBlades;
+
+//===========================================================================
+
bool inBounds(float value, float bounds) {
return (value >= -bounds) && (value <= bounds);
}
@@ -43,14 +67,118 @@ bool inBounds(float value, float bounds) {
void main() {
// Reset the number of blades to 0
if (gl_GlobalInvocationID.x == 0) {
- // numBlades.vertexCount = 0;
+ numBlades.vertexCount = 0;
}
barrier(); // Wait till all threads reach this point
- // TODO: Apply forces on every blade and update the vertices in the buffer
+ //==========================================================================================================================
+ // TODO: Apply forces on every blade and update the vertices in the buffer
+
+ uint index = gl_GlobalInvocationID.x;
+
+ vec3 v0 = blades[index].v0.xyz;
+ vec3 v1 = blades[index].v1.xyz;
+ vec3 v2 = blades[index].v2.xyz;
+ vec3 up = blades[index].up.xyz;
+
+ float orientation = blades[index].v0.w;
+ float height = blades[index].v1.w;
+ float width = blades[index].v2.w;
+ float stiffness = blades[index].up.w;
+
+ //============ Calculate the direction of the blade ============
+ float sd = sin(orientation);
+ float cd = cos(orientation);
+ vec3 tmp = normalize(vec3(sd, sd + cd, cd)); //arbitrary vector for finding normal vector
+ vec3 bladeDir = normalize(cross(up, tmp));
+ vec3 bladeFront = normalize(cross(up, bladeDir));
+
+ //======================== Gravity ========================
+ vec4 D = vec4(0.0, -1.0, 0.0, GRAV_ACCELERATION);//--------------------------
+ vec3 g_e = normalize(D.xyz) * GRAV_ACCELERATION;
+ vec3 g_f = length(g_e) * 0.25f * bladeFront;
+ vec3 gravity = g_e + g_f;
+ //========================== Wind ==========================
+ vec4 windData = vec4(sin(totalTime)); //--------------------------
+ float windPos = 1.0f - max((cos((v0.x + v0.z) * 0.75f + windData.w) + sin((v0.x + v0.y) * 0.5f + windData.w) + sin((v0.y + v0.z) * 0.25f + windData.w)) / 3.0f, 0.0f);
+ vec3 windVec = windData.xyz * windPos;
+ float f_d = 1.0f - abs(dot(normalize(windVec), normalize(v2 - v0)));
+ float f_r = abs(dot(v2 - v0, up)) / height;
+ vec3 wind = windVec * f_d * f_r;
+
+ //======================== Recovery ========================
+ vec3 iv2 = v0 + up * height;
+ vec3 recovery = (iv2 - v2) * stiffness;
+
+ //==================== Apply new forces ====================
+ v2 += (gravity + wind + recovery) * deltaTime;
+
+ //==================== State Validation ====================
+ //=== Condition 1 : v2 must not be pushed beneath the ground.
+ v2 += up * -min(dot(up, v2 -v0), 0.0f);
+
+ //=== Condition 2 : v1 has to be set according to v2.
+ float l_proj = length(v2 - v0 - dot(v2- v0, up) * up);
+ v1 = v0 + height * max(1.0f - l_proj / height, 0.05f * max(l_proj / height, 1.0f)) * up;
+
+ //=== Condition 3 : the length of the curve must be equal to the height.
+ float L1 = length(v1 - v0) + length(v2 - v1);
+ float L0 = length(v2 - v0);
+ float L = (2.0f * L0 + L1) / 3.0f;
+ float r_hl = height / L;
+ v1 = v0 + (v1- v0) * r_hl;
+ v2 = v1 + (v2- v1) * r_hl;
+
+ //================== Update Blades buffer ==================
+ blades[index].v1.xyz = v1;
+ blades[index].v2.xyz = v2;
+
+
+ //======================================================================================================================================
// TODO: Cull blades that are too far away or not in the camera frustum and write them
// to the culled blades buffer
// Note: to do this, you will need to use an atomic operation to read and update numBlades.vertexCount
// You want to write the visible blades to the buffer without write conflicts between threads
+
+
+ //=================== Orientation Test ===================
+ vec4 camPos = inverse(camera.view) * vec4(0.0f, 0.0f, 0.0f, 1.0f);
+ vec3 camDir = v0 - camPos.xyz;
+ bool orienTest = abs(dot(normalize(camDir), bladeDir)) < 0.9f;
+ // true -> keep
+
+ //================== View-Frustum Test ==================
+ vec3 vmid = 0.25f * v0 + 0.5f * v1 + 0.25f * v2;
+ mat4 VPMatrix = camera.proj * camera.view;
+ vec4 v0_NDC = VPMatrix * vec4(v0, 1.0f);
+ vec4 vmid_NDC = VPMatrix * vec4(vmid, 1.0f);
+ vec4 v2_NDC = VPMatrix * vec4(v2,1.0f);
+ float tolerance = TOLERANCE;
+ float h_tol = v0_NDC.w + tolerance;
+ bool viewfTest = v0_NDC.x >= -h_tol && v0_NDC.x <= h_tol &&
+ v0_NDC.y >= -h_tol && v0_NDC.y <= h_tol &&
+ v0_NDC.z >= -h_tol && v0_NDC.z <= h_tol ||
+ vmid_NDC.x >= -h_tol && vmid_NDC.x <= h_tol &&
+ vmid_NDC.y >= -h_tol && vmid_NDC.y <= h_tol &&
+ vmid_NDC.z >= -h_tol && vmid_NDC.z <= h_tol ||
+ v2_NDC.x >= -h_tol && v2_NDC.x <= h_tol &&
+ v2_NDC.y >= -h_tol && v2_NDC.y <= h_tol &&
+ v2_NDC.z >= -h_tol && v2_NDC.z <= h_tol;
+ // true -> keep
+
+ //==================== Distance Test ====================
+ float d_proj = length(camDir - dot(camDir, up) * up);
+ uint value = uint(ceil(max((1.0f - d_proj / DMAX), 0.0f) * CULLLEVEL));
+ bool distTest = mod(index, uint(CULLLEVEL)) < value;
+ // true -> keep
+
+
+
+ //======================= Culling =======================
+ if(orienTest && viewfTest && distTest) {
+ culledBlades[atomicAdd(numBlades.vertexCount , 1)] = blades[index];
+ }
+
+ //culledBlades[index] = blades[index];
}
diff --git a/src/shaders/grass.frag b/src/shaders/grass.frag
index c7df157..657a868 100644
--- a/src/shaders/grass.frag
+++ b/src/shaders/grass.frag
@@ -8,10 +8,25 @@ layout(set = 0, binding = 0) uniform CameraBufferObject {
// TODO: Declare fragment shader inputs
+layout(location = 0) in vec4 tePosition;
+layout(location = 1) in vec3 teNormal;
+layout(location = 2) in vec3 teWindDir;
+layout(location = 3) in vec2 teUV;
+
layout(location = 0) out vec4 outColor;
void main() {
// TODO: Compute fragment color
- outColor = vec4(1.0);
+ vec3 color_green = vec3(0.1f, 0.9f, 0.1f);
+
+ //lambert
+ vec3 lightPos = vec3(-5.0f, 10.0f, -5.0f);
+ vec3 lightDir = normalize(tePosition.xyz - lightPos);
+ float lambert = clamp(dot(teNormal, lightDir), 0.1, 1.0);
+
+ outColor = vec4(0.1) + vec4(lambert * color_green ,1.0);
+
+ //outColor = vec4(1.0);
+
}
diff --git a/src/shaders/grass.tesc b/src/shaders/grass.tesc
index f9ffd07..138ad2c 100644
--- a/src/shaders/grass.tesc
+++ b/src/shaders/grass.tesc
@@ -10,17 +10,35 @@ layout(set = 0, binding = 0) uniform CameraBufferObject {
// TODO: Declare tessellation control shader inputs and outputs
+layout(location = 0) in vec4 tcV1[];
+layout(location = 1) in vec4 tcV2[];
+layout(location = 2) in vec3 tcBladeUp[];
+layout(location = 3) in vec3 tcBladeDir[];
+
+layout(location = 0) patch out vec4 teV1;
+layout(location = 1) patch out vec4 teV2;
+layout(location = 2) patch out vec3 teBladeUp;
+layout(location = 3) patch out vec3 teBladeDir;
+
void main() {
// Don't move the origin location of the patch
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
-
+
// TODO: Write any shader outputs
+ teV1 = tcV1[0];
+ teV2 = tcV2[0];
+ teBladeUp = tcBladeUp[0];
+ teBladeDir = tcBladeDir[0];
+
+ float level = 5.0f;
// TODO: Set level of tesselation
- // gl_TessLevelInner[0] = ???
- // gl_TessLevelInner[1] = ???
- // gl_TessLevelOuter[0] = ???
- // gl_TessLevelOuter[1] = ???
- // gl_TessLevelOuter[2] = ???
- // gl_TessLevelOuter[3] = ???
+ gl_TessLevelInner[0] = 1.0f;
+ gl_TessLevelInner[1] = level;
+ gl_TessLevelOuter[0] = level;
+ gl_TessLevelOuter[1] = 1.0f;
+ gl_TessLevelOuter[2] = level;
+ gl_TessLevelOuter[3] = 1.0f;
+
}
+
diff --git a/src/shaders/grass.tese b/src/shaders/grass.tese
index 751fff6..fe93168 100644
--- a/src/shaders/grass.tese
+++ b/src/shaders/grass.tese
@@ -10,9 +10,61 @@ layout(set = 0, binding = 0) uniform CameraBufferObject {
// TODO: Declare tessellation evaluation shader inputs and outputs
+layout(location = 0) patch in vec4 tcV1;
+layout(location = 1) patch in vec4 tcV2;
+layout(location = 2) patch in vec3 tcBladeUp;
+layout(location = 3) patch in vec3 tcBladeDir;
+
+layout(location = 0) out vec4 tePosition;
+layout(location = 1) out vec3 teNormal;
+layout(location = 2) out vec3 teWindDir;
+layout(location = 3) out vec2 teUV;
+
void main() {
float u = gl_TessCoord.x;
float v = gl_TessCoord.y;
// TODO: Use u and v to parameterize along the grass blade and output positions for each vertex of the grass blade
+
+ vec3 v0 = gl_in[0].gl_Position.xyz;
+ vec3 v1 = tcV1.xyz;
+ vec3 v2 = tcV2.xyz;
+ vec3 t1 = tcBladeDir; // bitangent
+ float width = tcV2.w;
+
+ vec3 a = v0 + v * (v1 - v0);
+ vec3 b = v1 + v * (v2 - v1);
+ vec3 c = a + v * (b - a);
+ vec3 c0 = c - width * t1;
+ vec3 c1 = c + width * t1;
+
+ vec3 t0; // tangent
+ if(dot(b - a, b - a) < 1e-3)
+ t0 = tcBladeUp;
+ else
+ t0 = normalize(b - a);
+
+ teNormal = normalize(cross(t0, t1));
+ teUV = vec2(u,v);
+
+ float t = u;
+
+ //quad
+ //t = u;
+
+ //triangle
+ t = u + 0.5f * v - u * v;
+
+ //quadratic
+ //t = u - u * v * v;
+
+ //triangle-tip
+ //float threshold = 0.5f; //----------------------
+ //t = 0.5f + (u - 0.5f) * (1 - max(v - threshold, 0.0f) / (1 - threshold));
+
+ vec3 position = mix(c0, c1, t);
+
+ gl_Position = camera.proj * camera.view * vec4(position, 1.0f);
+ tePosition = vec4(position, 1.0f);
+
}
diff --git a/src/shaders/grass.vert b/src/shaders/grass.vert
index db9dfe9..b9960ed 100644
--- a/src/shaders/grass.vert
+++ b/src/shaders/grass.vert
@@ -8,10 +8,40 @@ layout(set = 1, binding = 0) uniform ModelBufferObject {
// TODO: Declare vertex shader inputs and outputs
+layout(location = 0) in vec4 v0;
+layout(location = 1) in vec4 v1;
+layout(location = 2) in vec4 v2;
+layout(location = 3) in vec4 up;
+
+layout(location = 0) out vec4 tcV1;
+layout(location = 1) out vec4 tcV2;
+layout(location = 2) out vec3 tcBladeUp;
+layout(location = 3) out vec3 tcBladeDir;
+
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
// TODO: Write gl_Position and any other shader outputs
+
+ gl_Position = model * vec4(v0.xyz, 1.0);
+
+ float orientation = v0.w;
+ //float height = v1.w;
+ //float width = v2.w;
+ //float stiffness = up.w;
+
+ tcV1 = model * vec4(v1.xyz, 1.0);
+ tcV1.w = v1.w;
+ tcV2 = model * vec4(v2.xyz, 1.0);
+ tcV2.w = v2.w;
+ tcBladeUp = normalize(up.xyz);
+
+ //============ Calculate the direction of the blade ============
+ float sd = sin(orientation);
+ float cd = cos(orientation);
+ vec3 tmp = normalize(vec3(sd, sd + cd, cd)); //arbitrary vector for finding normal vector
+ tcBladeDir = normalize(cross(tcBladeUp, tmp));
+
}