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
297 changes: 297 additions & 0 deletions INSTRUCTIONS.md

Large diffs are not rendered by default.

292 changes: 20 additions & 272 deletions README.md

Large diffs are not rendered by default.

Binary file added bin/Debug/vulkan_grass_rendering.exe
Binary file not shown.
Binary file added bin/Debug/vulkan_grass_rendering.ilk
Binary file not shown.
Binary file added bin/Debug/vulkan_grass_rendering.pdb
Binary file not shown.
Binary file added bin/Release/vulkan_grass_rendering.exe
Binary file not shown.
Binary file added img/blooper1.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/crabgrass.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/culling-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/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/orientation-frustum-distance-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/orientation-frustum-distance.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/result.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/result2.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/result3.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.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ constexpr static unsigned int NUM_BLADES = 1 << 13;
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 MAX_WIDTH = 0.1f;
constexpr static float MIN_BEND = 7.0f;
constexpr static float MAX_BEND = 13.0f;

Expand Down
2,100 changes: 1,134 additions & 966 deletions src/Renderer.cpp

Large diffs are not rendered by default.

129 changes: 67 additions & 62 deletions src/Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,76 +7,81 @@

class Renderer {
public:
Renderer() = delete;
Renderer(Device* device, SwapChain* swapChain, Scene* scene, Camera* camera);
~Renderer();
Renderer() = delete;
Renderer(Device* device, SwapChain* swapChain, Scene* scene, Camera* camera);
~Renderer();

void CreateCommandPools();
void CreateCommandPools();

void CreateRenderPass();
void CreateRenderPass();

void CreateCameraDescriptorSetLayout();
void CreateModelDescriptorSetLayout();
void CreateTimeDescriptorSetLayout();
void CreateComputeDescriptorSetLayout();
void CreateCameraDescriptorSetLayout();
void CreateModelDescriptorSetLayout();
void CreateTimeDescriptorSetLayout();
void CreateGrassDescriptorSetLayout();
void CreateComputeDescriptorSetLayout();

void CreateDescriptorPool();
void CreateDescriptorPool();

void CreateCameraDescriptorSet();
void CreateModelDescriptorSets();
void CreateGrassDescriptorSets();
void CreateTimeDescriptorSet();
void CreateComputeDescriptorSets();
void CreateCameraDescriptorSet();
void CreateModelDescriptorSets();
void CreateGrassDescriptorSets();
void CreateTimeDescriptorSet();
void CreateComputeDescriptorSets();

void CreateGraphicsPipeline();
void CreateGrassPipeline();
void CreateComputePipeline();
void CreateGraphicsPipeline();
void CreateGrassPipeline();
void CreateComputePipeline();

void CreateFrameResources();
void DestroyFrameResources();
void RecreateFrameResources();
void CreateFrameResources();
void DestroyFrameResources();
void RecreateFrameResources();

void RecordCommandBuffers();
void RecordComputeCommandBuffer();
void RecordCommandBuffers();
void RecordComputeCommandBuffer();

void Frame();
void Frame();

private:
Device* device;
VkDevice logicalDevice;
SwapChain* swapChain;
Scene* scene;
Camera* camera;

VkCommandPool graphicsCommandPool;
VkCommandPool computeCommandPool;

VkRenderPass renderPass;

VkDescriptorSetLayout cameraDescriptorSetLayout;
VkDescriptorSetLayout modelDescriptorSetLayout;
VkDescriptorSetLayout timeDescriptorSetLayout;

VkDescriptorPool descriptorPool;

VkDescriptorSet cameraDescriptorSet;
std::vector<VkDescriptorSet> modelDescriptorSets;
VkDescriptorSet timeDescriptorSet;

VkPipelineLayout graphicsPipelineLayout;
VkPipelineLayout grassPipelineLayout;
VkPipelineLayout computePipelineLayout;

VkPipeline graphicsPipeline;
VkPipeline grassPipeline;
VkPipeline computePipeline;

std::vector<VkImageView> imageViews;
VkImage depthImage;
VkDeviceMemory depthImageMemory;
VkImageView depthImageView;
std::vector<VkFramebuffer> framebuffers;

std::vector<VkCommandBuffer> commandBuffers;
VkCommandBuffer computeCommandBuffer;
};
Device* device;
VkDevice logicalDevice;
SwapChain* swapChain;
Scene* scene;
Camera* camera;

VkCommandPool graphicsCommandPool;
VkCommandPool computeCommandPool;

VkRenderPass renderPass;

VkDescriptorSetLayout computeDescriptorSetLayout;
VkDescriptorSetLayout cameraDescriptorSetLayout;
VkDescriptorSetLayout modelDescriptorSetLayout;
VkDescriptorSetLayout timeDescriptorSetLayout;
VkDescriptorSetLayout grassDescriptorSetLayout;

VkDescriptorPool descriptorPool;

VkDescriptorSet cameraDescriptorSet;
std::vector<VkDescriptorSet> modelDescriptorSets;
std::vector<VkDescriptorSet> grassDescriptorSets;
std::vector<VkDescriptorSet> computeDescriptorSets;
VkDescriptorSet timeDescriptorSet;

VkPipelineLayout graphicsPipelineLayout;
VkPipelineLayout grassPipelineLayout;
VkPipelineLayout computePipelineLayout;

VkPipeline graphicsPipeline;
VkPipeline grassPipeline;
VkPipeline computePipeline;

std::vector<VkImageView> imageViews;
VkImage depthImage;
VkDeviceMemory depthImageMemory;
VkImageView depthImageView;
std::vector<VkFramebuffer> framebuffers;

std::vector<VkCommandBuffer> commandBuffers;
VkCommandBuffer computeCommandBuffer;
};
162 changes: 150 additions & 12 deletions src/shaders/compute.comp
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@
#define WORKGROUP_SIZE 32
layout(local_size_x = WORKGROUP_SIZE, local_size_y = 1, local_size_z = 1) in;

layout(set = 0, binding = 0) uniform CameraBufferObject {
layout(set = 0, binding = 0) uniform CameraBufferObject
{
mat4 view;
mat4 proj;
} camera;

layout(set = 1, binding = 0) uniform Time {
layout(set = 1, binding = 0) uniform Time
{
float deltaTime;
float totalTime;
};

struct Blade {
struct Blade
{
vec4 v0;
vec4 v1;
vec4 v2;
Expand All @@ -28,29 +31,164 @@ struct Blade {

// The project is using vkCmdDrawIndirect to use a buffer as the arguments for a draw call
// This is sort of an advanced feature so we've showed you what this buffer should look like
//
// layout(set = ???, binding = ???) buffer NumBlades {
// uint vertexCount; // Write the number of blades remaining here
// uint instanceCount; // = 1
// uint firstVertex; // = 0
// uint firstInstance; // = 0
// } numBlades;

layout(set = 2, binding = 0) buffer InputBlades
{
Blade inputBlades[];
};

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);
}

void main() {
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

uint index = gl_GlobalInvocationID.x;

// Get the current blade
Blade blade = inputBlades[index];
vec3 v0 = blade.v0.xyz; // Random point
vec3 v1 = blade.v1.xyz; // Bezier point
vec3 v2 = blade.v2.xyz; // Physical model guide
vec3 up = blade.up.xyz; // Up vector

float theta = blade.v0.w;
float height = blade.v1.w;
float width = blade.v2.w;
float stiffness = blade.up.w;

// TODO: Apply forces on every blade and update the vertices in the buffer

// Recovery ----------------------------------
// Initial pose of v2
vec3 Iv2 = v0 + (up * height);

// TODO?
// Not sure what c and a are supposed to be...
// r = (Iv2 - v2) * s * max(1 - n, 0.1)
// n = max(c - a * dt, 0)
vec3 recovery = (Iv2 - v2) * stiffness;

// Gravity ----------------------------------
// Environmental gravity
vec3 gE = vec3(0.0, -9.8, 0.0);

// Front gravity
vec3 f = normalize(cross(up, vec3(cos(theta), 0.0, sin(theta)))); // Front direction thats perp. to the blade width
vec3 gF = .25 * 9.8 * f;

vec3 gravity = gE + gF;

// Wind ----------------------------------
vec3 wi = vec3(1, 0, 1) * cos(totalTime) * 5.0;
float fd = 1 - abs(dot(normalize(wi), normalize(v2 - v0))); // Directional alignment
float fr = dot((v2 - v0), up) / height;
float alignment = fd * fr;

vec3 wind = wi * alignment;

// Final displacement
vec3 displacement = (recovery + gravity + wind) * deltaTime;
v2 += displacement;

// State Validation ----------------------------------
// v2 = (v2 - up) * min(dot(up, (v2 - v0)), 0.0);
v2 = v2 - up * min(dot(up, (v2-v0)), 0.0);

// Calculate v1
float lProj = length(v2 - v0 - up * (dot((v2 - v0), up)));
v1 = v0 + height * up * max(1 - (lProj / height), 0.05 * max((lProj / height), 1.0));

// Ensure that the length of the Bezier curve is less than the blade height
float L0 = distance(v0, v2); // Distance between the first and last cps
float L1 = distance(v0, v1) + distance(v1, v2); // Sum of the distances between a cp and its subsequent cp
float n = 2.0;
float L = ((2.0 * L0) + (n - 1.0) * L1) / (n + 1.0);
float r = height / L;

// Correct v1 and v2
vec3 v1Corr = v0 + r * (v1 - v0);
vec3 v2Corr = v1Corr + r * (v2 - v1);

// Update the blade with changed v1 and v2 control points
inputBlades[index].v1.xyz = v1Corr;
inputBlades[index].v2.xyz = v2Corr;



// 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 ----------------------------------
// Calculate the absolute value of the cosine between the viewing direction and
// the vector along the width of the blade.

mat4 invView = inverse(camera.view);
vec4 eyePos = invView * vec4(0.0, 0.0, 0.0, 1.0);
vec3 dirC = eyePos.xyz - v0; // viewing direction
vec3 dirB = f; // direction along blade

// Culled blade
if(dot(dirC, dirB) > 0.9) {
return;
}

// View-frustum test ----------------------------------
// Test the point against the view frustum
// Project the point to NDC using view projection and homogenous coords
// Compare x, y, z with the homogenous coordinates

vec4 v0_ndc = camera.proj * camera.view * vec4(v0, 1.0);

float t = 3.0; // Tolerance
float h = v0_ndc.w + t; // Homogenous coordinate
float px = v0_ndc.x;
float py = v0_ndc.y;
float pz = v0_ndc.z;

// Culled blade
if(!inBounds(px, h) || !inBounds(py, h) || !inBounds(pz, h)) {
return;
}

// Distance test ----------------------------------
// Culls blades based on their distance towards the camera

// Project the distance onto the local plane
// Blade gets classified into one of the nLevels
float dProj = length(v0 - eyePos.xyz - up * dot((v0 - eyePos.xyz), up));

float nLevels = 10.0; // Distance levels that get distributed over dMax
float dMax = 40.0; // Maximum distance

// Culled blade
if(mod(index, nLevels) < floor(nLevels * (1 - (dProj / dMax)))) {
return;
}

// Made it thus far so lets do some stuff to the blade
culledBlades[atomicAdd(numBlades.vertexCount, 1)] = inputBlades[index];
}
20 changes: 19 additions & 1 deletion src/shaders/grass.frag
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,28 @@ layout(set = 0, binding = 0) uniform CameraBufferObject {

// TODO: Declare fragment shader inputs

layout(location = 0) in vec4 inPos;
layout(location = 1) in vec4 inNor;

layout(location = 0) out vec4 outColor;

vec3 color(float r, float g, float b)
{
return vec3(r / 255.0, g / 255.0, b / 255.0);
}

void main() {
// TODO: Compute fragment color

outColor = vec4(1.0);
vec3 green1 = color(0.0, 92.0, 0.0);
vec3 green2 = color(0.0, 104.0, 10.0);

vec3 lightPos = vec3(5.0, 20.0, 0.0);
vec3 lightDir = (lightPos - inPos.xyz) / distance(lightPos, inPos.xyz);

float lambert = max(dot(inNor.xyz, lightDir), 0.0);
float lightIntensity = 1.5f;

vec3 col = lambert * lightIntensity * green2 + green1;
outColor = vec4(col, 1.0);
}
Loading