Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 110 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,116 @@
Vulkan Grass Rendering
==================================

**University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 5**
**University of Pennsylvania, CIS 5650: GPU Programming and Architecture, Project 5**

* (TODO) YOUR NAME HERE
* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab)
* Michael Rabbitz
* [LinkedIn](https://www.linkedin.com/in/mike-rabbitz)
* Tested on: Windows 10, i7-9750H @ 2.60GHz 32GB, RTX 2060 6GB (Personal)

### (TODO: Your README)
![](img/grass.gif)

*DO NOT* leave the README to the last minute! It is a crucial part of the
project, and we will not be able to grade you without a good README.
## Part 1: Introduction

This project is an implementation of techniques described in [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), using Vulkan to build an efficient grass simulator and renderer. Grass blades are represented as Bezier curves, with a compute shader handling physics and culling processes, while graphics shaders manage rendering. The goal is to achieve realistic, performance-efficient grass rendering suitable for real-time applications.

The base code includes a basic Vulkan setup with a compute pipeline and two graphics pipelines. This implementation focuses on developing shaders for the grass compute and graphics pipelines, along with custom descriptor bindings necessary to manage data between these pipelines.

## Part 2: Simulating Forces
To create realistic movement, we simulate environmental forces on each grass blade using a compute shader.

Before we get into the simulated forces, here is an image showing the static, initial setup of the grass blades with no forces applied.
![](img/no_forces.PNG)

### Gravity
The first simulated force is gravity, which is an application of the Earth's downward gravitational force at 9.81 m/s<sup>2</sup>. As we can see, without a counter force, the blades are flattened to the ground plane.

|Gravity|
|:--:|
|![](img/gravity.PNG) <tr></tr>|

### Recovery
Next, we add the second simulated force, recovery, which counteracts gravity and returns the blades to equilibrium, following Hooke's law as derived in the paper.

|Gravity + Recovery|
|:--:|
|![](img/gravity_recovery.PNG) <tr></tr>|

### Wind
Finally, we add the third simulated force, wind, by implementing a custom wind function to influence the grass, considering the alignment of the blades with the wind direction.

The arbitrary wind function we use is: WIND_INTENSITY * vec3(cos(totalTime), 0.0, sin(totalTime)) * directional_alignment * height_ratio

|Gravity + Recovery + Wind|
|:--:|
|![](img/grass.gif) <tr></tr>|

## Part 3: Culling Tests
To optimize performance, various culling methods are implemented to avoid rendering blades that don’t contribute to the final image:

### Orientation Culling
In this technique, blades near-perpendicular or perpendicular to the camera are culled to prevent rendering artifacts.

![](img/orientation_culling.gif)

### View-Frustum Culling
In this technique, blades outside the view-frustum are excluded based on visibility tests for each Bezier curve.

![](img/frustrum_culling.gif)

### Distance Culling
In this technique, blades beyond a certain distance are culled in buckets, with more distant blades culled more aggressively.

![](img/distance_culling.gif)

## Part 4: Performance Analysis
- Frames Per Second (FPS) is the measurment of performance in this section. FPS is measured using a GLFW timer within the main loop.
- The Test Scene is positioned to render many grass blades as we increase the count, and to apply all three culling options.


|Test Scene|
|:--:|
|![](img/test_scene.PNG) <tr></tr>|

### Runtime vs Blade Count
- Culling ON refers to when all three culling options are enabled.
- Culling OFF refers to when all three culling options are disabled.


![](img/runtime_blade_count.png)

| Blade Count | Culling OFF (FPS) | Culling ON (FPS) |
| ------------- | ----------------- | ----------------- |
|2<sup>10</sup> |1235 |1245 |
|2<sup>12</sup> |1145 |1230 |
|2<sup>14</sup> |565 |1130 |
|2<sup>16</sup> |195 |545 |
|2<sup>18</sup> |62 |180 |
|2<sup>20</sup> |17 |60 |
|2<sup>22</sup> |4 |16 |
|2<sup>24</sup> |1 |4 |

**Observations**
- **Trend:** As the blade count increases, FPS decreases significantly in both cases, but with culling enabled, FPS remains higher.
- **Culling Efficiency:** At higher blade counts, culling's impact on performance becomes much more noticeable, maintaining playable FPS even as the blade count reaches 2<sup>20</sup>.
- **Culling Overhead:** There’s minimal overhead for culling at lower blade counts, as FPS differences between Culling ON and OFF remain small.

### Runtime vs Culling Options
- Blade Count is 2<sup>16</sup> for the following tests.


![](img/runtime_culling.png)

| Culling Option(s) | FPS |
| -------------------------- | --- |
|Culling OFF |195 |
|Orientation |225 |
|View Frustrum |200 |
|Distance |500 |
|Orientation + View Frustrum |215 |
|Orientation + Distance |530 |
|View Frustrum + Distance |505 |
|All Culling |545 |

**Observations**
- **Distance Culling Effectiveness:** Distance culling alone boosts FPS by over 2x, suggesting that rendering fewer distant blades is the most impactful optimization.
- **All Culling:** Using all three techniques provides a slight additional FPS boost over distance culling alone, though the improvement is minor, indicating diminishing returns with combined techniques.
Binary file modified bin/Release/vulkan_grass_rendering.exe
Binary file not shown.
Binary file added img/distance_culling.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/frustrum_culling.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified img/grass.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed img/grass2.gif
Binary file not shown.
Binary file removed img/grass_basic.gif
Binary file not shown.
Binary file added img/gravity.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/gravity_recovery.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/no_forces.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/orientation_culling.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/runtime_blade_count.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/runtime_culling.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/test_scene.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/Blades.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ Blades::Blades(Device* device, VkCommandPool commandPool, float planeDim) : Mode
indirectDraw.firstVertex = 0;
indirectDraw.firstInstance = 0;

BufferUtils::CreateBufferFromData(device, commandPool, blades.data(), NUM_BLADES * sizeof(Blade), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, bladesBuffer, bladesBufferMemory);
BufferUtils::CreateBuffer(device, NUM_BLADES * sizeof(Blade), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, culledBladesBuffer, culledBladesBufferMemory);
BufferUtils::CreateBufferFromData(device, commandPool, blades.data(), NUM_BLADES * sizeof(Blade), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, bladesBuffer, bladesBufferMemory);
BufferUtils::CreateBuffer(device, NUM_BLADES * sizeof(Blade), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, culledBladesBuffer, culledBladesBufferMemory);
BufferUtils::CreateBufferFromData(device, commandPool, &indirectDraw, sizeof(BladeDrawIndirect), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, numBladesBuffer, numBladesBufferMemory);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Blades.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
#include <array>
#include "Model.h"

constexpr static unsigned int NUM_BLADES = 1 << 13;
constexpr static unsigned int NUM_BLADES = 1 << 16;
constexpr static float MIN_HEIGHT = 1.3f;
constexpr static float MAX_HEIGHT = 2.5f;
constexpr static float MIN_WIDTH = 0.1f;
constexpr static float MAX_WIDTH = 0.14f;
constexpr static float MIN_BEND = 7.0f;
constexpr static float MIN_BEND = 9.0f;
constexpr static float MAX_BEND = 13.0f;

struct Blade {
Expand Down
Loading