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
289 changes: 33 additions & 256 deletions README.md

Large diffs are not rendered by default.

Binary file added img/dist_cull.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/graph.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/orient_cull.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/top.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2,123 changes: 1,152 additions & 971 deletions src/Renderer.cpp

Large diffs are not rendered by default.

130 changes: 69 additions & 61 deletions src/Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,76 +7,84 @@

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();
// Desc Set Layout
void CreateCameraDescriptorSetLayout();
void CreateModelDescriptorSetLayout();
void CreateTimeDescriptorSetLayout();
void CreateComputeDescriptorSetLayout();
void CreateGrassDescriptorSetLayout();

void CreateDescriptorPool();
// Desc Pool
void CreateDescriptorPool();

void CreateCameraDescriptorSet();
void CreateModelDescriptorSets();
void CreateGrassDescriptorSets();
void CreateTimeDescriptorSet();
void CreateComputeDescriptorSets();
// Desc Set
void CreateCameraDescriptorSet();
void CreateModelDescriptorSets();
void CreateTimeDescriptorSet();
void CreateComputeDescriptorSets();
void CreateGrassDescriptorSets();

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 cameraDescriptorSetLayout;
VkDescriptorSetLayout modelDescriptorSetLayout;
VkDescriptorSetLayout timeDescriptorSetLayout;
VkDescriptorSetLayout computeDescriptorSetLayout;
VkDescriptorSetLayout grassDescriptorSetLayout;

VkDescriptorPool descriptorPool;

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

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;
};
142 changes: 121 additions & 21 deletions src/shaders/compute.comp
Original file line number Diff line number Diff line change
Expand Up @@ -21,36 +21,136 @@ struct Blade {
vec4 up;
};

// TODO: Add bindings to:
// 1. Store the input blades
// 2. Write out the culled blades
// 3. Write the total number of blades remaining

// 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 NonCulledBlades {
Blade nonCulledBlades[];
};

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

bool inBoundsVec(vec3 v, float bounds) {
return inBounds(v.x, bounds) && inBounds(v.y, bounds) && inBounds(v.z, bounds);
}

void main() {
// Reset the number of blades to 0
if (gl_GlobalInvocationID.x == 0) {
// numBlades.vertexCount = 0;
uint idx = gl_GlobalInvocationID.x;
if (idx == 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
/** Unpack input information **/
Blade blade = inputBlades[idx];

// Grass properties
float orient = blade.v0.w;
float width = blade.v2.w;
float height = blade.v1.w;
float stiffness = blade.up.w;

// Direction
vec3 bladeUp = vec3(blade.up.xyz);
vec3 hypothenuseAlongOrient = vec3(sin(orient), 0.0, cos(orient)); // assume a right triangle with hypothenuse running along the base of the angle
vec3 f = normalize(cross(bladeUp, hypothenuseAlongOrient));

// Positions
vec3 v0 = vec3(blade.v0.xyz);
vec3 v1 = vec3(blade.v1.xyz);
vec3 v2 = vec3(blade.v2.xyz);
vec3 iv2 = v0 + height * bladeUp;

/** Apply forces on every blade and update the vertices in the buffer **/
// Gravity
vec4 D = vec4(0.0, -1.0, 0.0, 10);
vec3 gE = normalize(D.xyz) * D.w;
vec3 force_gravity = gE + (0.25 * length(gE) * f);

// Recovery
vec3 force_recovery = (iv2 - v2) * stiffness;

// Wind: circular
float xWind = v0.x;
float zWind = v0.z;
vec3 windDirCircular = normalize(vec3(xWind, 0.0, zWind));
float sinTime = sin(totalTime);
float windMagnitude = 10 * sin(sinTime * length(vec3(xWind, 0.0, zWind)));
vec3 windDirMag = windMagnitude * windDirCircular;

// Wind force
vec3 windDir = windDirMag;

// 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
float f_d = 1 - abs(dot(normalize(windDir), normalize(v2 - v0)));
float f_r = dot(v2 - v0, bladeUp) / height;
vec3 force_wind = windDir * f_d * f_r;

// Determine v2
v2 += (force_gravity + force_recovery + force_wind) * deltaTime;

// Make simulation robust
v2 = v2 - bladeUp * min(dot(bladeUp, (v2 - v0)), 0.0);
float l_proj = length(v2 - v0 - bladeUp * dot(v2 - v0, bladeUp));
v1 = v0 + height * bladeUp * max(1 - (l_proj / height), 0.05 * max((l_proj / height), 1));
float n = 2.0;
float L = (2.0 * distance(v0, v2) + (n - 1.0) * (distance(v0, v1) + distance(v1, v2))) / (n + 1.0);
float r = height / L;
vec3 v1Temp = v1;
v1 = v0 + r * (v1 - v0);
v2 = v1 + r * (v2 - v1Temp);

// Update simulation state
blade.v1.xyz = v1;
blade.v2.xyz = v2;
inputBlades[idx] = blade;

/** Culling optimizations **/
// Orientation culling
vec4 camView = normalize(inverse(camera.proj * camera.view) * vec4(0.0, 0.0, 1.0, 0.0));
float orientationFactor = dot(normalize(f.xyz), normalize(camView.xyz));
bool cull_orient = abs(orientationFactor) > 0.9;

// View-Frustum culling
vec3 m = 0.25 * v0 + 0.5 * v1 + 0.25 * v2;
mat4 vp = camera.proj * camera.view;

vec4 v0_prime = vp * vec4(v0.xyz, 1.0);
v0_prime /= v0_prime.w;

vec4 v2_prime = vp * vec4(v2.xyz, 1.0);
v2_prime /= v2_prime.w;

vec4 m_prime = vp * vec4(m.xyz, 1.0);
m_prime /= m_prime.w;

float threshold = 1.1; // since all w == 1
bool cull_view = !inBoundsVec(v0_prime.xyz, threshold) &&
!inBoundsVec(v2_prime.xyz, threshold) &&
!inBoundsVec(m_prime.xyz, threshold);

// Distance culling
float maxDist = 100.0;
uint nbSlices = 2;
vec4 camPos = vp * vec4(0.0, 0.0, 0.0, 1.0);
camPos /= camPos.w;
vec4 worldBladeUp = vp * vec4(bladeUp.xyz, 1.0);
worldBladeUp /= worldBladeUp.w;
float d_proj = length(v0_prime.xyz - camPos.xyz - worldBladeUp.xyz * dot(v0_prime.xyz - camPos.xyz, worldBladeUp.xyz));
bool cull_distance = idx % nbSlices < uint(floor(nbSlices * (1 - (d_proj / maxDist))));

// Final culling decision
if (!cull_distance && !cull_view && !cull_orient) {
nonCulledBlades[atomicAdd(numBlades.vertexCount, 1)] = inputBlades[idx];
}
}
26 changes: 20 additions & 6 deletions src/shaders/grass.frag
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,26 @@ layout(set = 0, binding = 0) uniform CameraBufferObject {
mat4 proj;
} camera;

// TODO: Declare fragment shader inputs
// Declare fragment shader inputs
layout(location = 0) in vec4 i_pos;
layout(location = 1) in vec3 i_normal;
layout(location = 2) in vec2 i_uv;

layout(location = 0) out vec4 outColor;
layout(location = 0) out vec4 o_col;

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

outColor = vec4(1.0);
}
// Lerp quad color
vec4 cUpL = vec4(0.2, 1.0, 0.0, 1.0); // reddish
vec4 cDownL = vec4(0.1, 0.7, 0.2, 1.0); // blueish
vec4 cUpR = vec4(0.2, 0.9, 0.1, 1.0); // reddish
vec4 cDownR = vec4(0.5, 0.9, 0.5, 1.0); // purple
vec4 colHori1 = mix(cUpL, cDownL, i_uv.x);
vec4 colHori2 = mix(cUpR, cDownR, i_uv.x);
vec4 col = mix(colHori1, colHori2, i_uv.y);

// Lambert shading
vec3 light = normalize(vec3(1.0, 1.0, -1.0));
vec4 ambient = vec4(0.1, 0.1, 0.1, 1.0);
float lambert = clamp(dot(i_normal, light), 0.2, 1.0);
o_col = clamp(ambient + col * lambert, 0.1, 1.0);
}
Loading