diff --git a/README.md b/README.md index 20ee451..a34c48b 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,9 @@ Vulkan Grass Rendering **University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 5** -* (TODO) YOUR NAME HERE -* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab) +* Logan Cho + * [LinkedIn](https://www.linkedin.com/in/logan-cho/) + * [Personal Website](https://www.logancho.com/) +* Tested on: Windows 11, 13th Gen Intel(R) Core(TM) i7-13700H, 2.40 GHz, RTX 4060 Laptop GPU -### (TODO: Your README) - -*DO NOT* leave the README to the last minute! It is a crucial part of the -project, and we will not be able to grade you without a good README. +![](img/1.png) diff --git a/img/1.png b/img/1.png new file mode 100644 index 0000000..e2a5cbd Binary files /dev/null and b/img/1.png differ diff --git a/src/Blades.cpp b/src/Blades.cpp index 80e3d76..3eb583c 100644 --- a/src/Blades.cpp +++ b/src/Blades.cpp @@ -45,7 +45,7 @@ Blades::Blades(Device* device, VkCommandPool commandPool, float planeDim) : Mode indirectDraw.firstInstance = 0; BufferUtils::CreateBufferFromData(device, commandPool, blades.data(), NUM_BLADES * sizeof(Blade), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, bladesBuffer, bladesBufferMemory); - BufferUtils::CreateBuffer(device, NUM_BLADES * sizeof(Blade), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, culledBladesBuffer, culledBladesBufferMemory); + BufferUtils::CreateBuffer(device, NUM_BLADES * sizeof(Blade), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, culledBladesBuffer, culledBladesBufferMemory); //Need to add vertex_buffer_bit to prevent Validation error... BufferUtils::CreateBufferFromData(device, commandPool, &indirectDraw, sizeof(BladeDrawIndirect), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, numBladesBuffer, numBladesBufferMemory); } diff --git a/src/Blades.h b/src/Blades.h index 9bd1eed..2fb679d 100644 --- a/src/Blades.h +++ b/src/Blades.h @@ -4,7 +4,7 @@ #include #include "Model.h" -constexpr static unsigned int NUM_BLADES = 1 << 13; +constexpr static unsigned int NUM_BLADES = 1 << 10; constexpr static float MIN_HEIGHT = 1.3f; constexpr static float MAX_HEIGHT = 2.5f; constexpr static float MIN_WIDTH = 0.1f; diff --git a/src/Renderer.cpp b/src/Renderer.cpp index b445d04..2a8c90b 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -198,6 +198,41 @@ 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 inputBladesLayoutBinding = {}; + inputBladesLayoutBinding.binding = 0; //0 + inputBladesLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + inputBladesLayoutBinding.descriptorCount = 1; + inputBladesLayoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + inputBladesLayoutBinding.pImmutableSamplers = nullptr; + + VkDescriptorSetLayoutBinding culledBladesLayoutBinding = {}; + culledBladesLayoutBinding.binding = 1; //1 + culledBladesLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + culledBladesLayoutBinding.descriptorCount = 1; + culledBladesLayoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + culledBladesLayoutBinding.pImmutableSamplers = nullptr; + + VkDescriptorSetLayoutBinding numBladesLayoutBinding = {}; + numBladesLayoutBinding.binding = 2; //2 + numBladesLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + numBladesLayoutBinding.descriptorCount = 1; + numBladesLayoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + numBladesLayoutBinding.pImmutableSamplers = nullptr; + + std::vector bindings = { inputBladesLayoutBinding, + culledBladesLayoutBinding, + numBladesLayoutBinding }; + + // Create the descriptor set layout + VkDescriptorSetLayoutCreateInfo layoutInfo = {}; + layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutInfo.bindingCount = static_cast(bindings.size()); + layoutInfo.pBindings = bindings.data(); + + if (vkCreateDescriptorSetLayout(logicalDevice, &layoutInfo, nullptr, &computeDescriptorSetLayout) != VK_SUCCESS) { + throw std::runtime_error("Failed to create compute descriptor set layout"); + } } void Renderer::CreateDescriptorPool() { @@ -216,6 +251,8 @@ void Renderer::CreateDescriptorPool() { { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 }, // TODO: Add any additional types and counts of descriptors you will need to allocate + // Add Compute Buffer Descriptor (grass blades already accounted for above) + { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER , static_cast(3 * scene->GetBlades().size()) }, }; VkDescriptorPoolCreateInfo poolInfo = {}; @@ -320,6 +357,43 @@ 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 + + // copy CreateModelDescriptorSets - very similar (in fact, Blade is a child class of Model) + grassDescriptorSets.resize(scene->GetBlades().size()); + + VkDescriptorSetLayout layouts[] = { modelDescriptorSetLayout }; + VkDescriptorSetAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocInfo.descriptorPool = descriptorPool; + allocInfo.descriptorSetCount = static_cast(grassDescriptorSets.size()); + allocInfo.pSetLayouts = layouts; + + // Allocate descriptor sets + if (vkAllocateDescriptorSets(logicalDevice, &allocInfo, grassDescriptorSets.data()) != VK_SUCCESS) { + throw std::runtime_error("Failed to allocate grass descriptor sets"); + } + + std::vector descriptorWrites(grassDescriptorSets.size()); + + for (uint32_t i = 0; i < scene->GetBlades().size(); ++i) { + VkDescriptorBufferInfo modelBufferInfo = {}; + modelBufferInfo.buffer = scene->GetBlades()[i]->GetModelBuffer(); + modelBufferInfo.offset = 0; + modelBufferInfo.range = sizeof(ModelBufferObject); + + descriptorWrites[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[i].dstSet = grassDescriptorSets[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(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr); } void Renderer::CreateTimeDescriptorSet() { @@ -360,6 +434,72 @@ 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 + computeDescriptorSets.resize(scene->GetBlades().size()); + + VkDescriptorSetLayout layouts[] = { computeDescriptorSetLayout }; + VkDescriptorSetAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocInfo.descriptorPool = descriptorPool; + allocInfo.descriptorSetCount = static_cast(computeDescriptorSets.size()); + allocInfo.pSetLayouts = layouts; + + if (vkAllocateDescriptorSets(logicalDevice, &allocInfo, computeDescriptorSets.data()) != VK_SUCCESS) { + throw std::runtime_error("Failed to allocate compute descriptor sets"); + } + + std::vector descriptorWrites(3 * computeDescriptorSets.size()); // 3 x for all 3 buffers in each stride + + for (uint32_t i = 0; i < scene->GetBlades().size(); ++i) { + VkDescriptorBufferInfo inputBladesBufferInfo = {}; + inputBladesBufferInfo.buffer = scene->GetBlades()[i]->GetBladesBuffer(); + inputBladesBufferInfo.offset = 0; + inputBladesBufferInfo.range = NUM_BLADES * sizeof(Blade); + + VkDescriptorBufferInfo culledBladesBufferInfo = {}; + culledBladesBufferInfo.buffer = scene->GetBlades()[i]->GetCulledBladesBuffer(); + culledBladesBufferInfo.offset = 0; + culledBladesBufferInfo.range = NUM_BLADES * sizeof(Blade); + + + VkDescriptorBufferInfo numBladesBufferInfo = {}; + numBladesBufferInfo.buffer = scene->GetBlades()[i]->GetNumBladesBuffer(); + numBladesBufferInfo.offset = 0; + numBladesBufferInfo.range = sizeof(BladeDrawIndirect); + + + descriptorWrites[3 * i + 0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[3 * i + 0].dstSet = computeDescriptorSets[i]; + descriptorWrites[3 * i + 0].dstBinding = 0; + descriptorWrites[3 * i + 0].dstArrayElement = 0; + descriptorWrites[3 * i + 0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorWrites[3 * i + 0].descriptorCount = 1; + descriptorWrites[3 * i + 0].pBufferInfo = &inputBladesBufferInfo; + descriptorWrites[3 * i + 0].pImageInfo = nullptr; + descriptorWrites[3 * i + 0].pTexelBufferView = nullptr; + + descriptorWrites[3 * i + 1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[3 * i + 1].dstSet = computeDescriptorSets[i]; + descriptorWrites[3 * i + 1].dstBinding = 1; + descriptorWrites[3 * i + 1].dstArrayElement = 0; + descriptorWrites[3 * i + 1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorWrites[3 * i + 1].descriptorCount = 1; + descriptorWrites[3 * i + 1].pBufferInfo = &culledBladesBufferInfo; + descriptorWrites[3 * i + 1].pImageInfo = nullptr; + descriptorWrites[3 * i + 1].pTexelBufferView = nullptr; + + descriptorWrites[3 * i + 2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[3 * i + 2].dstSet = computeDescriptorSets[i]; + descriptorWrites[3 * i + 2].dstBinding = 2; + descriptorWrites[3 * i + 2].dstArrayElement = 0; + descriptorWrites[3 * i + 2].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorWrites[3 * i + 2].descriptorCount = 1; + descriptorWrites[3 * i + 2].pBufferInfo = &numBladesBufferInfo; + descriptorWrites[3 * i + 2].pImageInfo = nullptr; + descriptorWrites[3 * i + 2].pTexelBufferView = nullptr; + } + + // Update descriptor sets + vkUpdateDescriptorSets(logicalDevice, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr); } void Renderer::CreateGraphicsPipeline() { @@ -717,7 +857,7 @@ void Renderer::CreateComputePipeline() { computeShaderStageInfo.pName = "main"; // TODO: Add the compute dsecriptor set layout you create to this list - std::vector descriptorSetLayouts = { cameraDescriptorSetLayout, timeDescriptorSetLayout }; + std::vector descriptorSetLayouts = { cameraDescriptorSetLayout, timeDescriptorSetLayout, computeDescriptorSetLayout }; // Add Compute here // Create pipeline layout VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; @@ -884,7 +1024,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 (int i = 0; i < scene->GetBlades().size(); i++) { + vkCmdBindDescriptorSets(computeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout, 2, 1, &computeDescriptorSets[i], 0, nullptr); + vkCmdDispatch(computeCommandBuffer, (int)(NUM_BLADES / WORKGROUP_SIZE + 0.5f), 1, 1); + } // ~ End recording ~ if (vkEndCommandBuffer(computeCommandBuffer) != VK_SUCCESS) { throw std::runtime_error("Failed to record compute command buffer"); @@ -976,13 +1119,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, grassPipelineLayout, 1, 1, &grassDescriptorSets[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 @@ -1057,6 +1201,7 @@ Renderer::~Renderer() { vkDestroyDescriptorSetLayout(logicalDevice, cameraDescriptorSetLayout, nullptr); vkDestroyDescriptorSetLayout(logicalDevice, modelDescriptorSetLayout, nullptr); vkDestroyDescriptorSetLayout(logicalDevice, timeDescriptorSetLayout, nullptr); + vkDestroyDescriptorSetLayout(logicalDevice, computeDescriptorSetLayout, nullptr); vkDestroyDescriptorPool(logicalDevice, descriptorPool, nullptr); diff --git a/src/Renderer.h b/src/Renderer.h index 95e025f..728ab34 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -56,12 +56,15 @@ class Renderer { VkDescriptorSetLayout cameraDescriptorSetLayout; VkDescriptorSetLayout modelDescriptorSetLayout; VkDescriptorSetLayout timeDescriptorSetLayout; + VkDescriptorSetLayout computeDescriptorSetLayout; VkDescriptorPool descriptorPool; VkDescriptorSet cameraDescriptorSet; std::vector modelDescriptorSets; VkDescriptorSet timeDescriptorSet; + std::vector computeDescriptorSets; + std::vector grassDescriptorSets; VkPipelineLayout graphicsPipelineLayout; VkPipelineLayout grassPipelineLayout; diff --git a/src/SwapChain.cpp b/src/SwapChain.cpp index 711fec0..5946691 100644 --- a/src/SwapChain.cpp +++ b/src/SwapChain.cpp @@ -74,14 +74,17 @@ SwapChain::SwapChain(Device* device, VkSurfaceKHR vkSurface, unsigned int numBuf } } -void SwapChain::Create() { +void SwapChain::Create(int w, int h) { auto* instance = device->GetInstance(); const auto& surfaceCapabilities = instance->GetSurfaceCapabilities(); VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(instance->GetSurfaceFormats()); VkPresentModeKHR presentMode = chooseSwapPresentMode(instance->GetPresentModes()); - VkExtent2D extent = chooseSwapExtent(surfaceCapabilities, GetGLFWWindow()); + VkExtent2D extent = { w, h }; + if (w == 0 || h == 0) { + extent = chooseSwapExtent(surfaceCapabilities, GetGLFWWindow()); + } uint32_t imageCount = surfaceCapabilities.minImageCount + 1; imageCount = numBuffers > imageCount ? numBuffers : imageCount; @@ -188,9 +191,9 @@ VkSemaphore SwapChain::GetRenderFinishedVkSemaphore() const { return renderFinishedSemaphore; } -void SwapChain::Recreate() { +void SwapChain::Recreate(int w, int h) { Destroy(); - Create(); + Create(w, h); } bool SwapChain::Acquire() { diff --git a/src/SwapChain.h b/src/SwapChain.h index dbafcf0..9486e60 100644 --- a/src/SwapChain.h +++ b/src/SwapChain.h @@ -17,14 +17,15 @@ class SwapChain { VkSemaphore GetImageAvailableVkSemaphore() const; VkSemaphore GetRenderFinishedVkSemaphore() const; - void Recreate(); + //test + void Recreate(int w = 0, int h = 0); bool Acquire(); bool Present(); ~SwapChain(); private: SwapChain(Device* device, VkSurfaceKHR vkSurface, unsigned int numBuffers); - void Create(); + void Create(int w = 0, int h = 0); void Destroy(); Device* device; diff --git a/src/main.cpp b/src/main.cpp index 8bf822b..2783046 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,7 +16,7 @@ namespace { if (width == 0 || height == 0) return; vkDeviceWaitIdle(device->GetVkDevice()); - swapChain->Recreate(); + swapChain->Recreate(width, height); renderer->RecreateFrameResources(); } diff --git a/src/shaders/compute.comp b/src/shaders/compute.comp index 0fd0224..2edf8e4 100644 --- a/src/shaders/compute.comp +++ b/src/shaders/compute.comp @@ -36,14 +36,32 @@ struct Blade { // uint firstInstance; // = 0 // } numBlades; + +layout(set = 2, binding = 0) buffer InputBlades { //real name + Blade blades[]; +} inputBlades; //instance name + +layout(set = 2, binding = 1) buffer CulledBlades { + Blade blades[]; +} 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 @@ -53,4 +71,11 @@ void main() { // 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 + +//No culling + uint blade_idx = gl_GlobalInvocationID.x; + Blade curBlade = inputBlades.blades[blade_idx]; + + uint culled_idx = atomicAdd(numBlades.vertexCount, 1); + culledBlades.blades[culled_idx] = curBlade; } diff --git a/src/shaders/grass.frag b/src/shaders/grass.frag index c7df157..f141fcb 100644 --- a/src/shaders/grass.frag +++ b/src/shaders/grass.frag @@ -7,11 +7,13 @@ layout(set = 0, binding = 0) uniform CameraBufferObject { } camera; // TODO: Declare fragment shader inputs +layout(location = 0) in vec2 fs_uv; + layout(location = 0) out vec4 outColor; -void main() { - // TODO: Compute fragment color - outColor = vec4(1.0); +void main() { + float v = fs_uv.y; + outColor = vec4(0.2 + v * 0.3,0.2 + v * 0.8,0.3 + v * 0.3, 1.0); } diff --git a/src/shaders/grass.tesc b/src/shaders/grass.tesc index f9ffd07..d799375 100644 --- a/src/shaders/grass.tesc +++ b/src/shaders/grass.tesc @@ -10,17 +10,32 @@ layout(set = 0, binding = 0) uniform CameraBufferObject { // TODO: Declare tessellation control shader inputs and outputs +layout(location = 0) in vec4 tesc_v0[]; +layout(location = 1) in vec4 tesc_v1[]; +layout(location = 2) in vec4 tesc_v2[]; + +layout(location = 0) out vec4 tese_v0[]; +layout(location = 1) out vec4 tese_v1[]; +layout(location = 2) out vec4 tese_v2[]; + +in gl_PerVertex { + vec4 gl_Position; +} gl_in[gl_MaxPatchVertices]; + 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 + tese_v0[gl_InvocationID] = tesc_v0[gl_InvocationID]; + tese_v1[gl_InvocationID] = tesc_v1[gl_InvocationID]; + tese_v2[gl_InvocationID] = tesc_v2[gl_InvocationID]; // 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] = 2; + gl_TessLevelInner[1] = 2; + gl_TessLevelOuter[0] = 2; + gl_TessLevelOuter[1] = 2; + gl_TessLevelOuter[2] = 2; + gl_TessLevelOuter[3] = 2; } diff --git a/src/shaders/grass.tese b/src/shaders/grass.tese index 751fff6..89fa687 100644 --- a/src/shaders/grass.tese +++ b/src/shaders/grass.tese @@ -10,9 +10,45 @@ layout(set = 0, binding = 0) uniform CameraBufferObject { // TODO: Declare tessellation evaluation shader inputs and outputs +layout(location = 0) in vec4 tese_v0[]; +layout(location = 1) in vec4 tese_v1[]; +layout(location = 2) in vec4 tese_v2[]; + +layout(location = 0) out vec2 fs_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 +// TODO: Use u and v to parameterize along the grass blade and output positions for each vertex of the grass blade +// Extract Parameters + float direction = tese_v0[0].w; + float height = tese_v1[0].w; + float width = tese_v2[0].w; + +// De casteljau's for Bezier Curve point interpolation, copied from the paper: + + vec3 v0 = tese_v0[0].xyz; + vec3 v1 = tese_v1[0].xyz; + vec3 v2 = tese_v2[0].xyz; + + vec3 a = v0 + v * (v1 - v0); + vec3 b = v1 + v * (v2 - v1); + vec3 c = a + v * (b - a); + + vec3 t0 = normalize(b - a); + +// bitangent, perpendicular to plane tangent along the width of the + vec3 t1 = normalize(vec3(-cos(direction), 0, sin(direction))); + + vec3 c0 = c - width * t1; + vec3 c1 = c + width * t1; + + float t = u + 0.5 * u * v; // basic t from the paper + vec3 pos = mix(c0, c1, t); //lerp + + gl_Position = camera.proj * camera.view * vec4(pos, 1.0); + + fs_uv = vec2(u, v); } diff --git a/src/shaders/grass.vert b/src/shaders/grass.vert index db9dfe9..09e48b9 100644 --- a/src/shaders/grass.vert +++ b/src/shaders/grass.vert @@ -8,10 +8,32 @@ layout(set = 1, binding = 0) uniform ModelBufferObject { // TODO: Declare vertex shader inputs and outputs +//Passing vertices to the tesselation stage (control first) + +layout(location = 0) in vec4 in_v0; +layout(location = 1) in vec4 in_v1; +layout(location = 2) in vec4 in_v2; + +layout(location = 0) out vec4 tesc_v0; +layout(location = 1) out vec4 tesc_v1; +layout(location = 2) out vec4 tesc_v2; + out gl_PerVertex { vec4 gl_Position; }; +vec4 multAndPreserveW(mat4 modelMat, vec4 inputVec) { + vec4 outputVec = modelMat * inputVec; + outputVec.w = inputVec.w; + return outputVec; +} + void main() { + // TODO: Write gl_Position and any other shader outputs + tesc_v0 = multAndPreserveW(model, in_v0); + tesc_v1 = multAndPreserveW(model, in_v1); + tesc_v2 = multAndPreserveW(model, in_v2); + + gl_Position = tesc_v0; }