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
245 changes: 30 additions & 215 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 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/chart1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
297 changes: 297 additions & 0 deletions instructions.md

Large diffs are not rendered by default.

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 << 23;
constexpr static float MIN_HEIGHT = 1.3f;
constexpr static float MAX_HEIGHT = 2.5f;
constexpr static float MIN_WIDTH = 0.1f;
Expand Down
2,142 changes: 1,177 additions & 965 deletions src/Renderer.cpp

Large diffs are not rendered by default.

12 changes: 10 additions & 2 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,19 @@ class Renderer {
VkDescriptorSetLayout cameraDescriptorSetLayout;
VkDescriptorSetLayout modelDescriptorSetLayout;
VkDescriptorSetLayout timeDescriptorSetLayout;

//added
VkDescriptorSetLayout grassDescriptorSetLayout;
VkDescriptorSetLayout computeDescriptorSetLayout;
//done
VkDescriptorPool descriptorPool;

VkDescriptorSet cameraDescriptorSet;
std::vector<VkDescriptorSet> modelDescriptorSets;
VkDescriptorSet timeDescriptorSet;
//added
std::vector <VkDescriptorSet> grassDescriptorSets;
std::vector<VkDescriptorSet> computeDescriptorSets;
//done.
VkDescriptorSet timeDescriptorSet;

VkPipelineLayout graphicsPipelineLayout;
VkPipelineLayout grassPipelineLayout;
Expand Down
9 changes: 8 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include "Camera.h"
#include "Scene.h"
#include "Image.h"
#include <WinBase.h>
#include <ctime>
using namespace std;

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

DWORD t1, t2;
t1 = GetTickCount();
while (!ShouldQuit()) {
glfwPollEvents();
scene->UpdateTime();
t1 = GetTickCount();
renderer->Frame();
t2 = GetTickCount();
printf("Use Time:%f\n", (t2 - t1)*1.0);
}

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

#define WORKGROUP_SIZE 32
#define GFORCE 9.8
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 +37,160 @@ 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);
}

vec3 Interpolation(vec3 posV0, vec3 V1_Position, vec3 posV2, float v)
{
vec3 a = posV0 + v*(V1_Position - posV0);
vec3 b = V1_Position + v*(posV2 - V1_Position);
return a + v*(b - a);
}

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
uint index = gl_GlobalInvocationID.x;
vec3 V0_Position = blades[index].v0.xyz;
vec3 V1_Position = blades[index].v1.xyz;
vec3 V2_Position = blades[index].v2.xyz;
vec3 Blades_UP = blades[index].up.xyz;
//Data de-compression
float theta = blades[index].v0.w;
float h = blades[index].v1.w;
float sinTheta = sin(theta);
float cosTheta = cos(theta);
vec3 faceDir = normalize(cross(Blades_UP, vec3(sinTheta, 0, cosTheta)));

//Gravity
vec4 gravityDirection = vec4(0, -1, 0, GFORCE);
vec3 g_overall = normalize(gravityDirection.xyz) * GFORCE;
vec3 g_blades = faceDir * 0.25 * length(g_overall);
vec3 G_TotalForce = g_overall + g_blades;

//Recovery
vec3 iv2 = V0_Position + Blades_UP * h;
float maxCap = 1.8;
vec3 recoveryForce = (iv2 - V2_Position) * blades[index].up.w * maxCap/ min(h, maxCap);

//Wind
vec3 windDirection = normalize(vec3(cos(totalTime * V0_Position.x), cos(totalTime), sin(totalTime * V0_Position.z))); // straight wave
float windSpeed = 10.0 * (float(int(totalTime) % 100) / 50.0);
float directionInfluence = 1.0 - abs(dot(windDirection ,normalize(V2_Position - V0_Position)));
float heightratio = dot(V2_Position - V0_Position, Blades_UP) / h;
float windStrength = 15.0;
vec3 windForce = windDirection * directionInfluence * heightratio * windStrength;


//Total force
vec3 tv2 = (G_TotalForce + recoveryForce + windForce) * deltaTime;
vec3 v2 = V2_Position + tv2;

//a position of v2 above the local plane can be ensured
v2 = v2 - Blades_UP*min(dot(Blades_UP, v2 - V0_Position), 0.0);


float lproj = length(v2 - V0_Position - Blades_UP * dot(v2 - V0_Position, Blades_UP));
float lprohOverh = lproj / h;
vec3 v1 = V0_Position + Blades_UP* h * max(1.0 - lprohOverh , 0.05*max(lprohOverh, 1.0));


float degree = 3.0;
float L0 = distance(v2,V0_Position);
float L1 = distance(v2,v1) + distance(v1,V0_Position);
float L = (2.0*L0 + (degree - 1.0)*L1) / (degree + 1.0);
float r = h / L;


blades[index].v1.xyz = V0_Position + r*(v1 - V0_Position);
blades[index].v2.xyz = blades[index].v1.xyz + r*(v2 - v1);
blades[index] = blades[index];


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


V0_Position = blades[index].v0.xyz;
V1_Position = blades[index].v1.xyz;
V2_Position = blades[index].v2.xyz;

mat4 invView = inverse(camera.view);
vec3 viewVectorWorld = (invView * vec4(0,0,1,0)).xyz;
//Reminder:
//If any flag is true, it means that he passes the test.
//Orientation culling
float tresholdOrientCull = 0.1;
bool culledByOrientation = abs(dot(faceDir, normalize(vec3(viewVectorWorld.x, 0.0, viewVectorWorld.z)))) >= tresholdOrientCull;

//View-frustum culling
bool culledByFrustum = true;
vec4 ScreenV0= camera.proj * camera.view * vec4(V0_Position, 1.0);
vec4 ScreenV2= camera.proj * camera.view * vec4(V2_Position, 1.0);
ScreenV0 /= ScreenV0.w;
ScreenV2 /= ScreenV2.w;
vec3 center025Pos = Interpolation(V0_Position, V1_Position, V2_Position, 0.25);
vec3 centerPos = 0.25*V0_Position * 0.5*V1_Position * 0.25*V2_Position;
vec3 center075Pos = Interpolation(V0_Position, V1_Position, V2_Position, 0.75);
vec4 projCenter025Pos= camera.proj * camera.view * vec4(center025Pos, 1.0);
projCenter025Pos /= projCenter025Pos.w;
vec4 projCenterPos= camera.proj * camera.view * vec4(centerPos, 1.0);
projCenterPos /= projCenterPos.w;
vec4 projCenter075Pos= camera.proj * camera.view * vec4(center075Pos, 1.0);
projCenter075Pos /= projCenter075Pos.w;

float clipVal = 1.3;

if( (ScreenV0.x >= -clipVal && ScreenV0.x <= clipVal) && (ScreenV0.y >= -clipVal && ScreenV0.y <= clipVal) && (ScreenV0.z >= 0.0 && ScreenV0.z <= 1.0) ||
(ScreenV2.x >= -clipVal && ScreenV2.x <= clipVal) && (ScreenV2.y >= -clipVal && ScreenV2.y <= clipVal) && (ScreenV2.z >= 0.0 && ScreenV2.z <= 1.0) ||
(projCenter025Pos.x >= -clipVal && projCenter025Pos.x <= clipVal) && (projCenter025Pos.y >= -clipVal && projCenter025Pos.y <= clipVal) && (projCenter025Pos.z >= 0.0 && projCenter025Pos.z <= 1.0) ||
(projCenterPos.x >= -clipVal && projCenterPos.x <= clipVal) && (projCenterPos.y >= -clipVal && projCenterPos.y <= clipVal) && (projCenterPos.z >= 0.0 && projCenterPos.z <= 1.0) ||
(projCenter075Pos.x >= -clipVal && projCenter075Pos.x <= clipVal) && (projCenter075Pos.y >= -clipVal && projCenter075Pos.y <= clipVal) && (projCenter075Pos.z >= 0.0 && projCenter075Pos.z <= 1.0)

)
culledByFrustum = true;
else
culledByFrustum = false;


//Distance culling
float near_clip = 0.1;
float far_clip = 100.0;

bool culledByDistance = false;
float linearDepth = (2.0 * near_clip) / (far_clip + near_clip - ScreenV0.z * (far_clip - near_clip));

float tresholdDistCull = 0.95;

if(linearDepth <= tresholdDistCull)
{
culledByDistance = true;
}
culledByDistance = true;
if((culledByOrientation && culledByFrustum && culledByDistance))
{
culledBlades[atomicAdd(numBlades.vertexCount , 1)] = blades[index];
}
}

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

// TODO: Declare fragment shader inputs

layout(location = 0) in vec4 Position;
layout(location = 1) in vec3 Normal;
layout(location = 2) in vec3 WindDirection;
layout(location = 3) in vec2 UV;
layout(location = 0) out vec4 outColor;

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

outColor = vec4(1.0);
vec3 Light = normalize(vec3(-1.0, 5.0, -3.0));
vec3 Green_UP = vec3(0.3,0.7,0.3);
vec3 Green_Down = vec3(0.1,0.2,0.1);
vec3 FinalColor = mix(Green_Down, Green_UP, UV.y);
outColor = vec4(FinalColor*clamp(dot(Normal, Light), 0.1, 1.0), 1.0);
}
49 changes: 41 additions & 8 deletions src/shaders/grass.tesc
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,51 @@ layout(set = 0, binding = 0) uniform CameraBufferObject {
} camera;

// TODO: Declare tessellation control shader inputs and outputs
layout(location = 0) in vec4 control_v1[];
layout(location = 1) in vec4 control_v2[];
layout(location = 2) in vec4 control_up[];
layout(location = 3) in vec4 control_width[];

layout(location = 0) patch out vec4 evaluation_v1;
layout(location = 1) patch out vec4 evaluation_v2;
layout(location = 2) patch out vec4 evaluation_up;
layout(location = 3) patch out vec4 evaluation_Width;


void main() {

// Don't move the origin location of the patch
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
vec4 WorldPosV0 = gl_in[gl_InvocationID].gl_Position;
gl_out[gl_InvocationID].gl_Position = WorldPosV0;



// TODO: Write any shader outputs
evaluation_v1 = control_v1[0];
evaluation_v2 = control_v2[0];
evaluation_up = control_up[0];
evaluation_Width = control_width[0];
float near = 0.1;
float far = 25.0;

float depth = -(camera.view * WorldPosV0).z / (far - near);
depth = clamp(depth, 0.0, 1.0);

float maxLevel = 5.0;
float minLevel = 1.0;

depth = depth*depth;

float level = mix(maxLevel, minLevel, depth);
evaluation_Width.w = depth;
// 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.0; //horizontal
gl_TessLevelInner[1] = level; //vertical

gl_TessLevelOuter[0] = level; //vertical
gl_TessLevelOuter[1] = 1.0; //horizontal
gl_TessLevelOuter[2] = level; //vertical
gl_TessLevelOuter[3] = 1.0; //horizontal


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

// TODO: Declare tessellation evaluation shader inputs and outputs
layout(location = 0) patch in vec4 tese_v1;
layout(location = 1) patch in vec4 tese_v2;
layout(location = 2) patch in vec4 tese_up;
layout(location = 3) patch in vec4 tese_widthDir;

layout(location = 0) out vec4 Position;
layout(location = 1) out vec3 Normal;
layout(location = 2) out vec3 WindDirection;
layout(location = 3) out vec2 UV;

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

mat4 viewProj = camera.proj * camera.view;

vec3 Current_V0 = gl_in[0].gl_Position.xyz + v*(tese_v1.xyz - gl_in[0].gl_Position.xyz);
vec3 Current_V1 = tese_v1.xyz + v*(tese_v2.xyz - tese_v1.xyz);
vec3 Current_V2 = Current_V0 + v*(Current_V1 - Current_V0);

vec3 Bi_tangent = tese_widthDir.xyz;
vec3 Width_Whole = Bi_tangent * tese_v2.w * 0.5;

Normal = normalize(cross(Bi_tangent, normalize(Current_V1 - Current_V0)));
UV = vec2(u, v);

float t = u + 0.5*v -u*v;
Position.xyz = (1.0 - t)*(Current_V2 - Width_Whole) + t*(Current_V2 + Width_Whole);
Position = viewProj * vec4(Position.xyz, 1.0);

gl_Position = Position;
WindDirection = tese_widthDir.xyz;

}
Loading