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

Large diffs are not rendered by default.

311 changes: 26 additions & 285 deletions README.md

Large diffs are not rendered by default.

Binary file modified bin/Release/vulkan_grass_rendering.exe
Binary file not shown.
Binary file added img/1.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/1.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/2.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/2.png
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 << 15;
constexpr static float MIN_HEIGHT = 1.3f;
constexpr static float MAX_HEIGHT = 2.5f;
constexpr static float MIN_WIDTH = 0.1f;
Expand Down
2,086 changes: 1,121 additions & 965 deletions src/Renderer.cpp

Large diffs are not rendered by default.

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

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

VkDescriptorPool descriptorPool;

VkDescriptorSet cameraDescriptorSet;
std::vector<VkDescriptorSet> modelDescriptorSets;
std::vector<VkDescriptorSet> computeDescriptorSets;
std::vector<VkDescriptorSet> grassDescriptorSets;
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;
};
21 changes: 21 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "Camera.h"
#include "Scene.h"
#include "Image.h"
#include <sstream>

Device* device;
SwapChain* swapChain;
Expand Down Expand Up @@ -143,10 +144,30 @@ int main() {
glfwSetMouseButtonCallback(GetGLFWWindow(), mouseDownCallback);
glfwSetCursorPosCallback(GetGLFWWindow(), mouseMoveCallback);



double start = 0;
double fps = 0;
int count = 0;

while (!ShouldQuit()) {

glfwPollEvents();

count++;
double end = glfwGetTime();
if (end - start > 0.99) {
fps = count / (end - start);
start = end;
count = 0;
}
scene->UpdateTime();
renderer->Frame();
std::ostringstream ss;

ss.precision(1);
ss << "[" << std::fixed << fps << " fps] ";
glfwSetWindowTitle(GetGLFWWindow(), ss.str().c_str());
}

vkDeviceWaitIdle(device->GetVkDevice());
Expand Down
132 changes: 124 additions & 8 deletions src/shaders/compute.comp
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,153 @@ struct Blade {
vec4 v2;
vec4 up;
};
#define orientCull 1
#define frustumCull 1
#define distCull 1


// 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 = 2) buffer numBlades {
uint vertexCount; // Write the number of blades remaining here
uint instanceCount; // = 1
uint firstVertex; // = 0
uint firstInstance; // = 0
} num_Blades;


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

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


bool inBounds(float value, float bounds) {
return (value >= -bounds) && (value <= bounds);
}

bool validatePos(vec3 vector, float thresh) {
return inBounds(vector.x, thresh) && inBounds(vector.y, thresh) && inBounds(vector.z, thresh);
}


void main() {
// Reset the number of blades to 0
if (gl_GlobalInvocationID.x == 0) {
// numBlades.vertexCount = 0;
num_Blades.vertexCount = 0;
}
barrier(); // Wait till all threads reach this point

Blade blade = input_blades[gl_GlobalInvocationID.x];

// grass
float orientation = blade.v0.w;
float height = blade.v1.w;
float width = blade.v2.w;
float stiff = blade.up.w;

vec3 up = vec3(blade.up.xyz);
vec3 frontDir = vec3(sin(orientation), 0.0, cos(orientation));
vec3 f = normalize(cross(up, frontDir));


// grass position
vec3 v0 = vec3(blade.v0.xyz);
vec3 v1 = vec3(blade.v1.xyz);
vec3 v2 = vec3(blade.v2.xyz);
vec3 iv2 = up * height + v0;

// TODO: Apply forces on every blade and update the vertices in the buffer
vec4 D = vec4(0.f, -1.f, 0.f, 9.8);
vec3 gE = normalize(D.xyz) * D.w;
vec3 gF = length(gE) * f * 0.25;
vec3 totalG= gE + gF;

vec3 recover = (iv2 - v2) * stiff;

// wind function
vec3 wi = vec3(cos(v0.x + totalTime), 0.f, sin(v0.z + totalTime));
float fd = 1 - abs(dot(normalize(wi), normalize(v2-v0)));
float fr = dot(v2-v0, up) / height;
vec3 wind = wi * fd * fr;

// update v2
v2 += (totalG + recover + wind) * deltaTime;


// correction to prevent v1 and v2 getting out of bounds
v2-= up * min(dot(up, v2-v0), 0.f);
float lProj = length(v2 - v0 - up * dot(v2-v0, up));
v1 = v0 + height * up * max(1 - lProj / height, 0.05 * max(lProj / height, 1));
float n = 2;
float L0 = distance(v0, v2);
float L1 = distance(v0, v1) + distance(v1, v2);
float L = (2.f * L0 + (n - 1.f) * L1) / (n + 1.f);
float r = height / L;
vec3 oldV1 = v1;
v1 = v0 + r * (v1 - v0);
v2 = v1 + r * (v2 - oldV1);

// update
blade.v1.xyz = v1;
blade.v2.xyz = v2;
input_blades[gl_GlobalInvocationID.x] = blade;

// 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

#if orientCull
vec4 dirCamera = normalize(inverse(camera.view) * vec4(0.f, 0.f, -1.f, 0.f));
if (abs(dot(normalize(dirCamera.xyz), f)) > 0.9) {
return;
}
#endif

mat4 VP= camera.proj * camera.view;
vec4 v0Prime = VP * vec4(v0.xyz, 1.0);

#if frustumCull
// frustum test
vec3 m = v0/4.f + v1/2.f + v2/4.f;
vec4 mPrime = VP * vec4(m.xyz, 1.0);
vec4 v2Prime = VP * vec4(v2.xyz, 1.0);

float h_v0 = v0Prime.w + 0.1;
float h_m = mPrime.w + 0.1;
float h_v2 = v2Prime.w + 0.1;

if (!validatePos(v0Prime.xyz, h_v0) && !validatePos(mPrime.xyz, h_m) && !validatePos(v2Prime.xyz, h_v2)) {
return;
}
#endif

#if distCull
//distance test
vec4 cameraPos = VP * vec4(0.f, 0.f, 0.f, 1.f);
cameraPos /= cameraPos.w;
vec4 upTrans = VP * vec4(up.xyz, 1.f);
upTrans /= upTrans.w;
float dProj = length(v0Prime.xyz - cameraPos.xyz - upTrans.xyz * dot(v0Prime.xyz-cameraPos.xyz, upTrans.xyz));
float dmax = 100.f;
uint level = 3;
if (gl_GlobalInvocationID.x % level < uint(floor(level * (1-dProj/dmax)))) {
return;
}
#endif
culled_blades[atomicAdd(num_Blades.vertexCount, 1)] = input_blades[gl_GlobalInvocationID.x];

}
14 changes: 13 additions & 1 deletion src/shaders/grass.frag
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,22 @@ layout(set = 0, binding = 0) uniform CameraBufferObject {

// TODO: Declare fragment shader inputs

layout(location = 0) in vec4 inPos;
layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec2 inUV;

layout(location = 0) out vec4 outColor;

void main() {
// TODO: Compute fragment color
// interpolate color from bottom to top
vec4 top = vec4(125, 193, 21, 255) / 255;
vec4 bot = vec4(65, 121, 37, 255) / 255;

vec4 color = mix(bot, top, inUV.y);

outColor = vec4(1.0);
vec3 light = normalize(vec3(-1.f, 0.f, -1.0));
vec4 ambient_term = vec4(0.1, 0.15, 0.1, 1.0);
float lambert = clamp(dot(light, inNormal), 0.1, 1.0);
outColor = clamp(color * lambert + ambient_term, 0.2, 1.0);
}
Loading