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
278 changes: 47 additions & 231 deletions README.md

Large diffs are not rendered by default.

Binary file added distance_per.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 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 everything.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 grass_per.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 main.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 not-moving.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 orientation_per.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 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.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <array>
#include "Model.h"

constexpr static unsigned int NUM_BLADES = 1 << 13;
constexpr static unsigned int NUM_BLADES = 1 << 14;
constexpr static float MIN_HEIGHT = 1.3f;
constexpr static float MAX_HEIGHT = 2.5f;
constexpr static float MIN_WIDTH = 0.1f;
Expand Down
155 changes: 152 additions & 3 deletions src/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,39 @@ 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

VkDescriptorSetLayoutBinding blades_layout_binding = {};
blades_layout_binding.binding = 0;
blades_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
blades_layout_binding.descriptorCount = 1;
blades_layout_binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
blades_layout_binding.pImmutableSamplers = nullptr;

VkDescriptorSetLayoutBinding culled_layout_binding = {};
culled_layout_binding.binding = 1;
culled_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
culled_layout_binding.descriptorCount = 1;
culled_layout_binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
culled_layout_binding.pImmutableSamplers = nullptr;

VkDescriptorSetLayoutBinding blades_num_layout_binding = {};
blades_num_layout_binding.binding = 2;
blades_num_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
blades_num_layout_binding.descriptorCount = 1;
blades_num_layout_binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
blades_num_layout_binding.pImmutableSamplers = nullptr;

std::vector<VkDescriptorSetLayoutBinding> bindings{ blades_layout_binding, culled_layout_binding, blades_num_layout_binding };

// Create the descriptor set layout
VkDescriptorSetLayoutCreateInfo layoutInfo = {};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
layoutInfo.pBindings = bindings.data();

if (vkCreateDescriptorSetLayout(logicalDevice, &layoutInfo, nullptr, &compute_descriptor_set_layout) != VK_SUCCESS) {
throw std::runtime_error("Failed to create descriptor set layout");
}
}

void Renderer::CreateDescriptorPool() {
Expand All @@ -216,8 +249,10 @@ void Renderer::CreateDescriptorPool() {
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 },

// TODO: Add any additional types and counts of descriptors you will need to allocate
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER , static_cast<uint32_t>(compute_descriptor_set_layout_size * scene->GetBlades().size()) }
};


VkDescriptorPoolCreateInfo poolInfo = {};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
Expand Down Expand Up @@ -320,6 +355,42 @@ void Renderer::CreateModelDescriptorSets() {
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
grass_descriptor_sets.resize(scene->GetBlades().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<uint32_t>(grass_descriptor_sets.size());
allocInfo.pSetLayouts = layouts;

// Allocate descriptor sets
if (vkAllocateDescriptorSets(logicalDevice, &allocInfo, grass_descriptor_sets.data()) != VK_SUCCESS) {
throw std::runtime_error("Failed to allocate descriptor set");
}

std::vector<VkWriteDescriptorSet> descriptorWrites(grass_descriptor_sets.size());

for (uint32_t i = 0; i < scene->GetBlades().size(); ++i) {
VkDescriptorBufferInfo modelBufferInfo = {};
modelBufferInfo.buffer = scene->GetBlades()[i]->GetBladesBuffer();
modelBufferInfo.offset = 0;
modelBufferInfo.range = sizeof(ModelBufferObject);

descriptorWrites[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[i].dstSet = grass_descriptor_sets[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<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
}

void Renderer::CreateTimeDescriptorSet() {
Expand Down Expand Up @@ -360,6 +431,77 @@ void Renderer::CreateTimeDescriptorSet() {
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
compute_descriptor_sets.resize(scene->GetBlades().size());

// Describe the desciptor set
VkDescriptorSetLayout layouts[] = { compute_descriptor_set_layout };
VkDescriptorSetAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = descriptorPool;
allocInfo.descriptorSetCount = static_cast<uint32_t>(compute_descriptor_sets.size());
allocInfo.pSetLayouts = layouts;

// Allocate descriptor sets
if (vkAllocateDescriptorSets(logicalDevice, &allocInfo, compute_descriptor_sets.data()) != VK_SUCCESS) {
throw std::runtime_error("Failed to allocate descriptor set");
}

std::vector<VkWriteDescriptorSet> descriptorWrites(compute_descriptor_set_layout_size * compute_descriptor_sets.size());

for (uint32_t i = 0; i < scene->GetBlades().size(); ++i) {
VkDescriptorBufferInfo blades_buffer_info = {};
blades_buffer_info.buffer = scene->GetBlades()[i]->GetBladesBuffer();
blades_buffer_info.offset = 0;
blades_buffer_info.range = NUM_BLADES * sizeof(Blade);

// Bind image and sampler resources to the descriptor
VkDescriptorBufferInfo cull_buffer_info = {};
cull_buffer_info.buffer = scene->GetBlades()[i]->GetCulledBladesBuffer();
cull_buffer_info.offset = 0;
cull_buffer_info.range = NUM_BLADES * sizeof(Blade);

VkDescriptorBufferInfo blades_num_buffer_info = {};
blades_num_buffer_info.buffer = scene->GetBlades()[i]->GetNumBladesBuffer();
blades_num_buffer_info.offset = 0;
blades_num_buffer_info.range = sizeof(BladeDrawIndirect);

int blades_index = compute_descriptor_set_layout_size * i;
int cull_index = compute_descriptor_set_layout_size * i + 1;
int blades_num_index = compute_descriptor_set_layout_size * i + 2;

descriptorWrites[blades_index].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[blades_index].dstSet = compute_descriptor_sets[i];
descriptorWrites[blades_index].dstBinding = 0;
descriptorWrites[blades_index].dstArrayElement = 0;
descriptorWrites[blades_index].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptorWrites[blades_index].descriptorCount = 1;
descriptorWrites[blades_index].pBufferInfo = &blades_buffer_info;
descriptorWrites[blades_index].pImageInfo = nullptr;
descriptorWrites[blades_index].pTexelBufferView = nullptr;

descriptorWrites[cull_index].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[cull_index].dstSet = compute_descriptor_sets[i];
descriptorWrites[cull_index].dstBinding = 1;
descriptorWrites[cull_index].dstArrayElement = 0;
descriptorWrites[cull_index].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptorWrites[cull_index].descriptorCount = 1;
descriptorWrites[cull_index].pBufferInfo = &cull_buffer_info;
descriptorWrites[cull_index].pImageInfo = nullptr;
descriptorWrites[cull_index].pTexelBufferView = nullptr;

descriptorWrites[blades_num_index].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[blades_num_index].dstSet = compute_descriptor_sets[i];
descriptorWrites[blades_num_index].dstBinding = 2;
descriptorWrites[blades_num_index].dstArrayElement = 0;
descriptorWrites[blades_num_index].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptorWrites[blades_num_index].descriptorCount = 1;
descriptorWrites[blades_num_index].pBufferInfo = &blades_num_buffer_info;
descriptorWrites[blades_num_index].pImageInfo = nullptr;
descriptorWrites[blades_num_index].pTexelBufferView = nullptr;
}

// Update descriptor sets
vkUpdateDescriptorSets(logicalDevice, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
}

void Renderer::CreateGraphicsPipeline() {
Expand Down Expand Up @@ -717,7 +859,7 @@ void Renderer::CreateComputePipeline() {
computeShaderStageInfo.pName = "main";

// TODO: Add the compute dsecriptor set layout you create to this list
std::vector<VkDescriptorSetLayout> descriptorSetLayouts = { cameraDescriptorSetLayout, timeDescriptorSetLayout };
std::vector<VkDescriptorSetLayout> descriptorSetLayouts = { cameraDescriptorSetLayout, timeDescriptorSetLayout, compute_descriptor_set_layout };

// Create pipeline layout
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
Expand Down Expand Up @@ -884,6 +1026,10 @@ void Renderer::RecordComputeCommandBuffer() {
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(const auto& compute_descriptor_set : compute_descriptor_sets) {
vkCmdBindDescriptorSets(computeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout, 2, 1, &compute_descriptor_set, 0, nullptr);
vkCmdDispatch(computeCommandBuffer, (NUM_BLADES + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE, 1, 1);
}

// ~ End recording ~
if (vkEndCommandBuffer(computeCommandBuffer) != VK_SUCCESS) {
Expand Down Expand Up @@ -976,13 +1122,14 @@ void Renderer::RecordCommandBuffers() {
VkBuffer vertexBuffers[] = { scene->GetBlades()[j]->GetCulledBladesBuffer() };
VkDeviceSize offsets[] = { 0 };
// TODO: Uncomment this when the buffers are populated
// vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
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, graphicsPipelineLayout, 1, 1, &grass_descriptor_sets[j], 0, nullptr);

// Draw
// TODO: Uncomment this when the buffers are populated
// vkCmdDrawIndirect(commandBuffers[i], scene->GetBlades()[j]->GetNumBladesBuffer(), 0, 1, sizeof(BladeDrawIndirect));
vkCmdDrawIndirect(commandBuffers[i], scene->GetBlades()[j]->GetNumBladesBuffer(), 0, 1, sizeof(BladeDrawIndirect));
}

// End render pass
Expand Down Expand Up @@ -1042,6 +1189,8 @@ Renderer::~Renderer() {
vkDeviceWaitIdle(logicalDevice);

// TODO: destroy any resources you created
vkDestroyDescriptorSetLayout(logicalDevice, compute_descriptor_set_layout, nullptr);


vkFreeCommandBuffers(logicalDevice, graphicsCommandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
vkFreeCommandBuffers(logicalDevice, computeCommandPool, 1, &computeCommandBuffer);
Expand Down
5 changes: 5 additions & 0 deletions src/Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ class Renderer {
std::vector<VkDescriptorSet> modelDescriptorSets;
VkDescriptorSet timeDescriptorSet;

VkDescriptorSetLayout compute_descriptor_set_layout;
static constexpr int compute_descriptor_set_layout_size = 3;
std::vector<VkDescriptorSet> compute_descriptor_sets;
std::vector<VkDescriptorSet> grass_descriptor_sets;

VkPipelineLayout graphicsPipelineLayout;
VkPipelineLayout grassPipelineLayout;
VkPipelineLayout computePipelineLayout;
Expand Down
139 changes: 133 additions & 6 deletions src/shaders/compute.comp
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,148 @@ struct Blade {
// uint firstInstance; // = 0
// } numBlades;

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

layout(set = 2, binding = 1) buffer CullBlades {
Blade cullBlades[];
};

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() {
// 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 i = gl_GlobalInvocationID.x;
Blade cur_blade = blades_[i];

// Position and direction
vec3 v0 = cur_blade.v0.xyz;
float direction = cur_blade.v0.w;

// Bezier point and height
vec3 v1 = cur_blade.v1.xyz;
float height = cur_blade.v1.w;

// Physical model guide and width
vec3 v2 = cur_blade.v2.xyz;
float width = cur_blade.v2.w;

// Up vector and stiffness coefficient
vec3 up = cur_blade.up.xyz;
float stiffness = cur_blade.up.w;

//r = (Iv2 - v2) * s
//basically a direction upwards towards v1
vec3 total_height = v0 + up * height;
vec3 recovery_force = (total_height - v2) * stiffness;

// environmental gravity (GE)
// It can be a global gravity direction that is the same for the whole scene
vec3 GE = vec3(0.0, -9.81, 0.0);

// front gravity (GF)
// gf = 1/4 |GE| * front direction (perpendicular to width of blade)
float x_direction = cos(direction);
float y_direction = sin(direction);
vec3 right = vec3(x_direction, 0.0, y_direction);
vec3 front = normalize(cross(right, up));
vec3 GF = 1.0 / 4.0 * abs(-9.81) * front;

//total gravitational force
vec3 gravity = GE + GF;

//wind calculations from the paper
vec3 wind_direction = vec3(1.0);
float FD = 1.0 - abs(dot(normalize(wind_direction), normalize(v2 - v0)));
float FR = dot(v2 - v0, up) / height;

// TODO: Apply forces on every blade and update the vertices in the buffer
//calculate total wind based on time
float wind_multiple = 3.0;
vec3 wind = wind_multiple * wind_direction * FD * FR * cos(totalTime);

//add all forces together and multiply by delta time
vec3 trans_dt = (recovery_force + wind + gravity) * deltaTime;

//state validation
//calculating new v2
v2 = v2 + trans_dt;
v2 = v2 - up * min(dot(up, (v2 - v0)), 0.0);

//calculating new v1
vec3 l_projection = abs(v2 - v0 - up * dot((v2 - v0), up));
v1 = v0 + height * up * max((1.0 - l_projection) / height, 0.05 * max((l_projection/height), 1.0));

//approximate bezier curve
//lengths of points
//L0 indicates the distance between the first and the last control
//point and L1 is the sum of all distances between a control point and
//its subsequent one
float L0 = distance(v0, v2);
float L1 = distance(v0, v1) + distance(v1, v2);

//length of beizer
float n = 1.5;
float L = (n * L0 + (n - 1.0) * L1) / (n + 1.0);
float r = height / L;

vec3 v1_c = v0 + r * (v1 - v0);
vec3 v2_c = v1_c + r * (v2 - v1);

blades_[i].v1.xyz = v1_c;
blades_[i].v2.xyz = v2_c;

//culling


//orientation test
vec3 dir_b = front;
vec4 eye_world = inverse(camera.view) * vec4(0.0, 0.0, 0.0, 1.0);
vec3 dir_c = eye_world.xyz - v0;

if(0.6 < dot(dir_c, dir_b))
{
return;
}

//view frustrum cull
vec4 v0_cull = camera.proj * camera.view * vec4(v0, 1.0);
vec4 v2_cull = camera.proj * camera.view * vec4(v2, 1.0);
vec4 m_cull = camera.proj * camera.view * vec4(v0 * 0.25 + v1 * 0.5 + v2 * 0.25, 1.0);
float t_ = 0.5;
if(!inBounds(v0_cull.x, v0_cull.w + t_) || !inBounds(v0_cull.y, v0_cull.w + t_) ||
!inBounds(v2_cull.x, v2_cull.w + t_) || !inBounds(v2_cull.y, v2_cull.w + t_) ||
!inBounds(m_cull.x, m_cull.w + t_) || !inBounds(m_cull.y, m_cull.w + t_)
)
{
return;
}

//distance cull
float n_ = 5.0;
float d_proj = length(v0 - eye_world.xyz - dot((v0 - eye_world.xyz), up) * up);
float d_max = 30.0;
if(floor(n_ * (1.0 - d_proj/d_max)) < mod(i, n_))
{
return;
}


// 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
//update the vertex cound and index the cull blades
uint new_v = atomicAdd(numBlades.vertexCount, 1);
cullBlades[new_v] = blades_[i];
}
Loading