Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project 5: Nicholas Liu #10

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -560,3 +560,5 @@ xcuserdata
*.xccheckout
*.moved-aside
*.xcuserstate

.vscode*
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
cmake_minimum_required(VERSION 2.8.12)
cmake_minimum_required(VERSION 3.5)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20")

project(cis565_project5_vulkan_grass_rendering)

OPTION(USE_D2D_WSI "Build the project using Direct to Display swapchain" OFF)
Expand Down
55 changes: 50 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,55 @@ Vulkan Grass Rendering

**University of Pennsylvania, CIS 565: 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)
* Nicholas Liu
* [Linkedin](https://www.linkedin.com/in/liunicholas6/)
* Tested on: Linux Mint 22 Wilma, AMD Ryzen 7 5800X @ 2.512GHz, 32GB RAM, GeForce GTX 1660 Ti

### (TODO: Your README)
| <img src="img/normals.gif"> |
|:--:|
| *I output the normals as colors for debug and it looked kinda good* |

## Project Overview

This Vulkan project implements grass rendering techniques outlined in 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)

Each blade of grass is represented as a cubic bezier: one at the base of the grass blade, that lies at some point above the grass blade, and one at the tip of the grass blade. The grass moves according to forces applied to the tip of the grass, namely gravity, a restorative force that tries to pull the grass to a vertical position, and a wind function. The grass control points are controlled using a compute shader.

The control points of each grass blade are transformed into quads with the tesselation pipeline. These quads are then distorted into a triangle shape that are bent along the bezier, thus producing the grass shape!

## Culling Methods

For maximum performance, several different criteria for culling blades were implemented

- Orientation culling: if a blade of grass is tangent to the camera's view vector, it has zero width and should not actually fill in any pixels, and can thus be discarded. Shown is an agressive cull that culls at `theta` where `cos(theta) < 10`

- Frustum culling: Any blades that are not within the view frustum should not be rendered and are culled at the compute stage. Shown is culling with a frustum that is just slightly too tight, hence blades of grass disappearing at the sides.

- Distance culling: In order to reduce the number of blades rendered, we don't render blades that are beyond a further distance. In order to lessen the effect of the aribtrary cutoff, we have each blade probabilistically have a higher change to disappear as they approach the maximum cutoff distance.


| <img src="img/orientationcull.gif" width=350> | <img src="img/frustumcull.gif" width=350> | <img src="img/distancecull.gif" width=350> |
|:--:|:--:|:--:|
| *Orientation Culling* | *View Frustum Culling* | *Distance Culling* |

## Performance

I tested performance in 3 different camera positions: the default (looking at all the grass, at ground level), a far away scene, and a close up in the middle of the scene. For each of these I let the program run for 2^16 frames and timed how long it took to render them.

| <img src="img/defaultcam.png" width=350> | <img src="img/closecam.png" width=350> | <img src="img/farcam.png" width=350> |
|:--:|:--:|:--:|
| *Default* | *Close* | *Far* |

In general, turning on all method of culling performed best, as expected. Distance culling made the greatest impact when the camera was far, and orientation culling had a significant impact where the camera was more or less parallel to the ground plane (as said scenarios are where the most blades of grass get culled, respectively).

Somewhat surprisingly, however, frustum culling seemed to have very little impact on performance generally -- its effect is explainable within the bounds of random variance; in fact the frustum-culling only run performed worse than no optimizations in the far camera setup. This is surprising, as I would expect frustum culling to have a very significant impact in the close up scene, where it should cull about 3/4 of the geometry. I hypothesize that the lack of performance benefit comes from the fact that the driver already performs frustum culling at the vertex stage with a computation that is about as cheap as what I perform manually in the compute stage.

| Optimizations | Default Scene | Close Scene | Far Scene |
|-------------------|---------------|-------------|-----------|
| No Optimizations | 118.695 | 118.259 | 92.6448 |
| Orientation Cull | 92.0582 | 91.6129 | 92.7531 |
| Frustum Cull | 114.687 | 115.402 | 93.2135 |
| Distance Cull | 115.637 | 114.76 | 35.1957 |
| All Optimizations | 87.186 | 88.1485 | 35.5031 |
<img src="img/chart.png">

*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.
Binary file removed bin/Release/vulkan_grass_rendering.exe
Binary file not shown.
Binary file added img/chart.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/closecam.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/defaultcam.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/distancecull.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/farcam.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/frustumcull.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/normals.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/orientationcull.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/Blades.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Blades::Blades(Device* device, VkCommandPool commandPool, float planeDim) : Mode
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::CreateBuffer(device, NUM_BLADES * sizeof(Blade), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_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
1 change: 1 addition & 0 deletions src/BufferUtils.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "BufferUtils.h"
#include "Instance.h"
#include <cstring>

void BufferUtils::CreateBuffer(Device* device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
// Create buffer
Expand Down
32 changes: 20 additions & 12 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20")

file(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/*.h)

file(GLOB IMAGES
Expand Down Expand Up @@ -30,21 +34,25 @@ else(WIN32)
target_link_libraries(vulkan_grass_rendering ${CMAKE_THREAD_LIBS_INIT})
endif(WIN32)

if(WIN32)
set(GLSLANGVALIDATOR "/Bin/glslangValidator.exe")
endif(WIN32)
if(UNIX)
set(GLSLANGVALIDATOR "/bin/glslangValidator")
endif(UNIX)

foreach(SHADER_SOURCE ${SHADER_SOURCES})
set(SHADER_DIR ${CMAKE_CURRENT_BINARY_DIR}/shaders)

if(WIN32)
get_filename_component(fname ${SHADER_SOURCE} NAME)
add_custom_target(${fname}.spv
COMMAND ${CMAKE_COMMAND} -E make_directory ${SHADER_DIR} &&
$ENV{VK_SDK_PATH}/Bin/glslangValidator.exe -V ${SHADER_SOURCE} -o ${SHADER_DIR}/${fname}.spv -g
SOURCES ${SHADER_SOURCE}
)
ExternalTarget("Shaders" ${fname}.spv)
add_dependencies(vulkan_grass_rendering ${fname}.spv)
endif(WIN32)

# TODO: Build shaders on not windows
get_filename_component(fname ${SHADER_SOURCE} NAME)
add_custom_target(${fname}.spv
COMMAND ${CMAKE_COMMAND} -E make_directory ${SHADER_DIR} &&
$ENV{VK_SDK_PATH}/${GLSLANGVALIDATOR} -V ${SHADER_SOURCE} -o ${SHADER_DIR}/${fname}.spv -g
SOURCES ${SHADER_SOURCE}
)
ExternalTarget("Shaders" ${fname}.spv)
add_dependencies(vulkan_grass_rendering ${fname}.spv)

endforeach()

target_link_libraries(vulkan_grass_rendering ${ASSIMP_LIBRARIES} Vulkan::Vulkan glfw)
Expand Down
6 changes: 2 additions & 4 deletions src/Camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@
#include "Camera.h"
#include "BufferUtils.h"

Camera::Camera(Device* device, float aspectRatio) : device(device) {
r = 10.0f;
theta = 0.0f;
phi = 0.0f;
Camera::Camera(Device* device, float aspectRatio, float r, float theta, float phi)
: device(device), r(r), theta(theta), phi(phi) {
cameraBufferObject.viewMatrix = glm::lookAt(glm::vec3(0.0f, 1.0f, 10.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
cameraBufferObject.projectionMatrix = glm::perspective(glm::radians(45.0f), aspectRatio, 0.1f, 100.0f);
cameraBufferObject.projectionMatrix[1][1] *= -1; // y-coordinate is flipped
Expand Down
2 changes: 1 addition & 1 deletion src/Camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Camera {
float r, theta, phi;

public:
Camera(Device* device, float aspectRatio);
Camera(Device* device, float aspectRatio, float r = 10, float theta = 0, float phi = 0);
~Camera();

VkBuffer GetBuffer() const;
Expand Down
2 changes: 2 additions & 0 deletions src/Device.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "QueueFlags.h"
#include "SwapChain.h"

class Instance;

class SwapChain;
class Device {
friend class Instance;
Expand Down
Loading