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
316 changes: 37 additions & 279 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/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/3.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/chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2,114 changes: 1,148 additions & 966 deletions src/Renderer.cpp

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Renderer {
void CreateModelDescriptorSetLayout();
void CreateTimeDescriptorSetLayout();
void CreateComputeDescriptorSetLayout();
void CreateGrassDescriptorSetLayout();

void CreateDescriptorPool();

Expand Down Expand Up @@ -56,12 +57,16 @@ class Renderer {
VkDescriptorSetLayout cameraDescriptorSetLayout;
VkDescriptorSetLayout modelDescriptorSetLayout;
VkDescriptorSetLayout timeDescriptorSetLayout;
VkDescriptorSetLayout computeDescriptorSetLayout;
VkDescriptorSetLayout grassDescriptorSetLayout;

VkDescriptorPool descriptorPool;

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

VkPipelineLayout graphicsPipelineLayout;
VkPipelineLayout grassPipelineLayout;
Expand Down
18 changes: 15 additions & 3 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "Camera.h"
#include "Scene.h"
#include "Image.h"
#include <iostream>
#pragma comment( lib,"winmm.lib" )

Device* device;
SwapChain* swapChain;
Expand Down Expand Up @@ -142,11 +144,21 @@ int main() {
glfwSetWindowSizeCallback(GetGLFWWindow(), resizeCallback);
glfwSetMouseButtonCallback(GetGLFWWindow(), mouseDownCallback);
glfwSetCursorPosCallback(GetGLFWWindow(), mouseMoveCallback);

//clock_t start, end;

while (!ShouldQuit()) {
glfwPollEvents();

while (!ShouldQuit()) {
glfwPollEvents();
//record time
scene->UpdateTime();
renderer->Frame();
//start = clock();

renderer->Frame();

//end = clock();
//double dur = (double)(end - start);
//std::cout << dur * 1000.0 / CLOCKS_PER_SEC << std::endl;
}

vkDeviceWaitIdle(device->GetVkDevice());
Expand Down
132 changes: 130 additions & 2 deletions src/shaders/compute.comp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
#extension GL_ARB_separate_shader_objects : enable

#define WORKGROUP_SIZE 32
#define GRAV_ACCELERATION 9.8
#define TOLERANCE 1.0
#define CULLLEVEL 10.0
#define DMAX 50.0

layout(local_size_x = WORKGROUP_SIZE, local_size_y = 1, local_size_z = 1) in;

layout(set = 0, binding = 0) uniform CameraBufferObject {
Expand Down Expand Up @@ -36,21 +41,144 @@ struct Blade {
// uint firstInstance; // = 0
// } numBlades;

//===========================================================================

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

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() {
// 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

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

uint index = gl_GlobalInvocationID.x;

vec3 v0 = blades[index].v0.xyz;
vec3 v1 = blades[index].v1.xyz;
vec3 v2 = blades[index].v2.xyz;
vec3 up = blades[index].up.xyz;

float orientation = blades[index].v0.w;
float height = blades[index].v1.w;
float width = blades[index].v2.w;
float stiffness = blades[index].up.w;

//============ Calculate the direction of the blade ============
float sd = sin(orientation);
float cd = cos(orientation);
vec3 tmp = normalize(vec3(sd, sd + cd, cd)); //arbitrary vector for finding normal vector
vec3 bladeDir = normalize(cross(up, tmp));
vec3 bladeFront = normalize(cross(up, bladeDir));

//======================== Gravity ========================
vec4 D = vec4(0.0, -1.0, 0.0, GRAV_ACCELERATION);//--------------------------
vec3 g_e = normalize(D.xyz) * GRAV_ACCELERATION;
vec3 g_f = length(g_e) * 0.25f * bladeFront;
vec3 gravity = g_e + g_f;

//========================== Wind ==========================
vec4 windData = vec4(sin(totalTime)); //--------------------------
float windPos = 1.0f - max((cos((v0.x + v0.z) * 0.75f + windData.w) + sin((v0.x + v0.y) * 0.5f + windData.w) + sin((v0.y + v0.z) * 0.25f + windData.w)) / 3.0f, 0.0f);
vec3 windVec = windData.xyz * windPos;
float f_d = 1.0f - abs(dot(normalize(windVec), normalize(v2 - v0)));
float f_r = abs(dot(v2 - v0, up)) / height;
vec3 wind = windVec * f_d * f_r;

//======================== Recovery ========================
vec3 iv2 = v0 + up * height;
vec3 recovery = (iv2 - v2) * stiffness;

//==================== Apply new forces ====================
v2 += (gravity + wind + recovery) * deltaTime;

//==================== State Validation ====================
//=== Condition 1 : v2 must not be pushed beneath the ground.
v2 += up * -min(dot(up, v2 -v0), 0.0f);

//=== Condition 2 : v1 has to be set according to v2.
float l_proj = length(v2 - v0 - dot(v2- v0, up) * up);
v1 = v0 + height * max(1.0f - l_proj / height, 0.05f * max(l_proj / height, 1.0f)) * up;

//=== Condition 3 : the length of the curve must be equal to the height.
float L1 = length(v1 - v0) + length(v2 - v1);
float L0 = length(v2 - v0);
float L = (2.0f * L0 + L1) / 3.0f;
float r_hl = height / L;
v1 = v0 + (v1- v0) * r_hl;
v2 = v1 + (v2- v1) * r_hl;

//================== Update Blades buffer ==================
blades[index].v1.xyz = v1;
blades[index].v2.xyz = v2;


//======================================================================================================================================
// 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 ===================
vec4 camPos = inverse(camera.view) * vec4(0.0f, 0.0f, 0.0f, 1.0f);
vec3 camDir = v0 - camPos.xyz;
bool orienTest = abs(dot(normalize(camDir), bladeDir)) < 0.9f;
// true -> keep

//================== View-Frustum Test ==================
vec3 vmid = 0.25f * v0 + 0.5f * v1 + 0.25f * v2;
mat4 VPMatrix = camera.proj * camera.view;
vec4 v0_NDC = VPMatrix * vec4(v0, 1.0f);
vec4 vmid_NDC = VPMatrix * vec4(vmid, 1.0f);
vec4 v2_NDC = VPMatrix * vec4(v2,1.0f);
float tolerance = TOLERANCE;
float h_tol = v0_NDC.w + tolerance;
bool viewfTest = v0_NDC.x >= -h_tol && v0_NDC.x <= h_tol &&
v0_NDC.y >= -h_tol && v0_NDC.y <= h_tol &&
v0_NDC.z >= -h_tol && v0_NDC.z <= h_tol ||
vmid_NDC.x >= -h_tol && vmid_NDC.x <= h_tol &&
vmid_NDC.y >= -h_tol && vmid_NDC.y <= h_tol &&
vmid_NDC.z >= -h_tol && vmid_NDC.z <= h_tol ||
v2_NDC.x >= -h_tol && v2_NDC.x <= h_tol &&
v2_NDC.y >= -h_tol && v2_NDC.y <= h_tol &&
v2_NDC.z >= -h_tol && v2_NDC.z <= h_tol;
// true -> keep

//==================== Distance Test ====================
float d_proj = length(camDir - dot(camDir, up) * up);
uint value = uint(ceil(max((1.0f - d_proj / DMAX), 0.0f) * CULLLEVEL));
bool distTest = mod(index, uint(CULLLEVEL)) < value;
// true -> keep



//======================= Culling =======================
if(orienTest && viewfTest && distTest) {
culledBlades[atomicAdd(numBlades.vertexCount , 1)] = blades[index];
}

//culledBlades[index] = blades[index];
}
17 changes: 16 additions & 1 deletion src/shaders/grass.frag
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,25 @@ layout(set = 0, binding = 0) uniform CameraBufferObject {

// TODO: Declare fragment shader inputs

layout(location = 0) in vec4 tePosition;
layout(location = 1) in vec3 teNormal;
layout(location = 2) in vec3 teWindDir;
layout(location = 3) in vec2 teUV;

layout(location = 0) out vec4 outColor;

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

outColor = vec4(1.0);
vec3 color_green = vec3(0.1f, 0.9f, 0.1f);

//lambert
vec3 lightPos = vec3(-5.0f, 10.0f, -5.0f);
vec3 lightDir = normalize(tePosition.xyz - lightPos);
float lambert = clamp(dot(teNormal, lightDir), 0.1, 1.0);

outColor = vec4(0.1) + vec4(lambert * color_green ,1.0);

//outColor = vec4(1.0);

}
32 changes: 25 additions & 7 deletions src/shaders/grass.tesc
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,35 @@ layout(set = 0, binding = 0) uniform CameraBufferObject {

// TODO: Declare tessellation control shader inputs and outputs

layout(location = 0) in vec4 tcV1[];
layout(location = 1) in vec4 tcV2[];
layout(location = 2) in vec3 tcBladeUp[];
layout(location = 3) in vec3 tcBladeDir[];

layout(location = 0) patch out vec4 teV1;
layout(location = 1) patch out vec4 teV2;
layout(location = 2) patch out vec3 teBladeUp;
layout(location = 3) patch out vec3 teBladeDir;

void main() {
// Don't move the origin location of the patch
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;

// TODO: Write any shader outputs
teV1 = tcV1[0];
teV2 = tcV2[0];
teBladeUp = tcBladeUp[0];
teBladeDir = tcBladeDir[0];

float level = 5.0f;

// TODO: Set level of tesselation
// gl_TessLevelInner[0] = ???
// gl_TessLevelInner[1] = ???
// gl_TessLevelOuter[0] = ???
// gl_TessLevelOuter[1] = ???
// gl_TessLevelOuter[2] = ???
// gl_TessLevelOuter[3] = ???
gl_TessLevelInner[0] = 1.0f;
gl_TessLevelInner[1] = level;
gl_TessLevelOuter[0] = level;
gl_TessLevelOuter[1] = 1.0f;
gl_TessLevelOuter[2] = level;
gl_TessLevelOuter[3] = 1.0f;

}

52 changes: 52 additions & 0 deletions src/shaders/grass.tese
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,61 @@ layout(set = 0, binding = 0) uniform CameraBufferObject {

// TODO: Declare tessellation evaluation shader inputs and outputs

layout(location = 0) patch in vec4 tcV1;
layout(location = 1) patch in vec4 tcV2;
layout(location = 2) patch in vec3 tcBladeUp;
layout(location = 3) patch in vec3 tcBladeDir;

layout(location = 0) out vec4 tePosition;
layout(location = 1) out vec3 teNormal;
layout(location = 2) out vec3 teWindDir;
layout(location = 3) out vec2 teUV;

void main() {
float u = gl_TessCoord.x;
float v = gl_TessCoord.y;

// TODO: Use u and v to parameterize along the grass blade and output positions for each vertex of the grass blade

vec3 v0 = gl_in[0].gl_Position.xyz;
vec3 v1 = tcV1.xyz;
vec3 v2 = tcV2.xyz;
vec3 t1 = tcBladeDir; // bitangent
float width = tcV2.w;

vec3 a = v0 + v * (v1 - v0);
vec3 b = v1 + v * (v2 - v1);
vec3 c = a + v * (b - a);
vec3 c0 = c - width * t1;
vec3 c1 = c + width * t1;

vec3 t0; // tangent
if(dot(b - a, b - a) < 1e-3)
t0 = tcBladeUp;
else
t0 = normalize(b - a);

teNormal = normalize(cross(t0, t1));
teUV = vec2(u,v);

float t = u;

//quad
//t = u;

//triangle
t = u + 0.5f * v - u * v;

//quadratic
//t = u - u * v * v;

//triangle-tip
//float threshold = 0.5f; //----------------------
//t = 0.5f + (u - 0.5f) * (1 - max(v - threshold, 0.0f) / (1 - threshold));

vec3 position = mix(c0, c1, t);

gl_Position = camera.proj * camera.view * vec4(position, 1.0f);
tePosition = vec4(position, 1.0f);

}
30 changes: 30 additions & 0 deletions src/shaders/grass.vert
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,40 @@ layout(set = 1, binding = 0) uniform ModelBufferObject {

// TODO: Declare vertex shader inputs and outputs

layout(location = 0) in vec4 v0;
layout(location = 1) in vec4 v1;
layout(location = 2) in vec4 v2;
layout(location = 3) in vec4 up;

layout(location = 0) out vec4 tcV1;
layout(location = 1) out vec4 tcV2;
layout(location = 2) out vec3 tcBladeUp;
layout(location = 3) out vec3 tcBladeDir;

out gl_PerVertex {
vec4 gl_Position;
};

void main() {
// TODO: Write gl_Position and any other shader outputs

gl_Position = model * vec4(v0.xyz, 1.0);

float orientation = v0.w;
//float height = v1.w;
//float width = v2.w;
//float stiffness = up.w;

tcV1 = model * vec4(v1.xyz, 1.0);
tcV1.w = v1.w;
tcV2 = model * vec4(v2.xyz, 1.0);
tcV2.w = v2.w;
tcBladeUp = normalize(up.xyz);

//============ Calculate the direction of the blade ============
float sd = sin(orientation);
float cd = cos(orientation);
vec3 tmp = normalize(vec3(sd, sd + cd, cd)); //arbitrary vector for finding normal vector
tcBladeDir = normalize(cross(tcBladeUp, tmp));

}