From 56e35390df5bb30922856cca79ab0d764b2369c6 Mon Sep 17 00:00:00 2001 From: saschawillems Date: Thu, 8 Sep 2016 22:27:45 +0200 Subject: [PATCH] Added 3D texture example (using perlin noise for runtime texture generation) --- data/shaders/texture3d/texture3d.frag | 28 + data/shaders/texture3d/texture3d.frag.spv | Bin 0 -> 2008 bytes data/shaders/texture3d/texture3d.vert | 43 ++ data/shaders/texture3d/texture3d.vert.spv | Bin 0 -> 3588 bytes texture3d/texture3d.cpp | 807 ++++++++++++++++++++++ texture3d/texture3d.vcxproj | 101 +++ texture3d/texture3d.vcxproj.filters | 53 ++ vulkanExamples.sln | 27 +- 8 files changed, 1058 insertions(+), 1 deletion(-) create mode 100644 data/shaders/texture3d/texture3d.frag create mode 100644 data/shaders/texture3d/texture3d.frag.spv create mode 100644 data/shaders/texture3d/texture3d.vert create mode 100644 data/shaders/texture3d/texture3d.vert.spv create mode 100644 texture3d/texture3d.cpp create mode 100644 texture3d/texture3d.vcxproj create mode 100644 texture3d/texture3d.vcxproj.filters diff --git a/data/shaders/texture3d/texture3d.frag b/data/shaders/texture3d/texture3d.frag new file mode 100644 index 00000000..9e6cf17e --- /dev/null +++ b/data/shaders/texture3d/texture3d.frag @@ -0,0 +1,28 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (binding = 1) uniform sampler3D samplerColor; + +layout (location = 0) in vec3 inUV; +layout (location = 1) in float inLodBias; +layout (location = 2) in vec3 inNormal; +layout (location = 3) in vec3 inViewVec; +layout (location = 4) in vec3 inLightVec; + +layout (location = 0) out vec4 outFragColor; + +void main() +{ + vec4 color = texture(samplerColor, inUV); + + vec3 N = normalize(inNormal); + vec3 L = normalize(inLightVec); + vec3 V = normalize(inViewVec); + vec3 R = reflect(-L, N); + vec3 diffuse = max(dot(N, L), 0.0) * vec3(1.0); + float specular = pow(max(dot(R, V), 0.0), 16.0) * color.r; + + outFragColor = vec4(diffuse * color.r + specular, 1.0); +} \ No newline at end of file diff --git a/data/shaders/texture3d/texture3d.frag.spv b/data/shaders/texture3d/texture3d.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..f8b405e11c7319372906df3f549278d38f3b0a45 GIT binary patch literal 2008 zcmZ9MNmCP15XYZ{un4kP@$xq~` z@?w?$-(8k0x}j4qsGt}Yjft*_Zi+TUZ$v}#!%hjsC6vXv-wM*{dR;b`&m8XL8-C5J zdrd#zIPr>pJzxFw*)KF3|Jz6vR7&}>S1Gl;lAm8*TC916FD|J_@j8%um7`ECSL?cy z>gST~hId*k`}N%j4*jS(sC+omB{|_nb?=9KGVCR&>{sijUfJ{$Vseq5K7&dwD4jHq z{6gFRhA@I9^*0yYA=W>5&-JiOjC7@7Lm~nflNp zvpcX=y)x#_PB{4d5t7u6Ej!{{ve?XsZzL}BO~hrsfw-JLC(p)Ydgt9^zoC5WazMl$ zk(t?L5qtWms<0aoVFSLYim4CG?8n8kxBh76SH;uoOA$JJ=mFe(CdIQ`^SLhGe9+-T zpWx;*C7%78PfEP`pu>k*fSb>>c;bAEdYcgsX8K#=sjXj~()(=@F|#6U(GxeV8=d*x z5s#nAcg2(ESNLDVxqITV0Vg(ZVNOJBF!a3LpRyKy| z@3DAnz%Adhc*}>Le5PBCbnF1T6;VdD@IIc3*fDROeANC-1pXuHZ(Tewz^Ruv1!nba zil+yQxh4L5%xz)dHiL|K{I*4wcSk(252ClVD;~_~do;fn!th7`E~=6D2hK5UPdpfN hF^pYTa4gu?@6IO;T2sYW)D>NAgqo zkLUP2Z|0Vv!?~S%fAgEW&YMHu=8-K$v59|Mi$9Cr+Er}EE{bi%V7X6BUY$JB>DG=M zKXFvXj-sz5%GrtK>PMEUji&k&$aZ8H@xle<2c(PKMb?l${%vOe2Pgg9n3$}LT^X-* z>dV!3wOg-r7OJ&+yV9DyQJ?E}9_Mh>XwFv_tIhe9>U_O&{Mgau>fFs@08e=y+UC+) z>0X~^*EX+4vox{$il?!!k6)tF!BWR8mfJ0(Hd<6O2uqH&F12d)MfSkV|5l@Zd#cr0 z$Lvh4zT914*Z(u@E3+;1f#OB<+pYFu%?ssuf7zo(vj+^|TY5R(q*x&SK7>(Oid0YzAzxF~88wa+(!ew+G6( z;cHUbbbYS8=N!SNDPO3>oU6Q6ZM;#X!im)X1K=)g`>$<3&tuzL*8p;!zhRG*=;Ig< zwLFh|`pEBTdv6p8Ut*8$_53?Gd81q2RZdzeJ|P|`w+4ZzV&N+K7_qB z>Efr8?RVn2{3qGv>r1|M7)xBfwsRDdzk^-A`R?cMPIfWv1DrThvA}z|^%uLqjN!R{ zwe7Xo9_-!hLx^z>CHq3-;;YD`OwIi2H=q~x@ z>bu#5941q_RYXom`1L*MCv4wS__fFP5c_DJ_mduZ{(&vmUU*-7Enz2l>)vzDE_wfg z_)W@n9{%PF`nLH9U4dUikJ!1N>lvQ=nNGNvEBt(gt{?H-&(|65 zS$yl?l)Cqe!kh#D7TsLU%Nzp#4&B(s(Wkh-$=@UT@}8V{%Ri#~d;F01wS~Qc$Q5^H z7ZRpEgI+~qesky>=T`$0k9zCqVzC1M2_W#i5AzwG_j4iPa$Vu4fvz9%+|P{+&;8s? zxR@*aETZd2JomGd;hsgGo9NbN9p)T(3*B7J%Nznw8GV_%-1X<2P(E#T7Av{{U +#include +#include +#include +#include +#include +#include +#include + +#define GLM_FORCE_RADIANS +#define GLM_FORCE_DEPTH_ZERO_TO_ONE +#include +#include + +#include +#include "vulkanexamplebase.h" +#include "vulkandevice.hpp" +#include "vulkanbuffer.hpp" + +#define VERTEX_BUFFER_BIND_ID 0 +#define ENABLE_VALIDATION false + +// Vertex layout for this example +struct Vertex { + float pos[3]; + float uv[2]; + float normal[3]; +}; + +// Translation of Ken Perlin's JAVA implementation (http://mrl.nyu.edu/~perlin/noise/) +template +class PerlinNoise +{ +private: + uint32_t permutations[512]; + T fade(T t) + { + return t * t * t * (t * (t * (T)6 - (T)15) + (T)10); + } + T lerp(T t, T a, T b) + { + return a + t * (b - a); + } + T grad(int hash, T x, T y, T z) + { + // Convert LO 4 bits of hash code into 12 gradient directions + int h = hash & 15; + T u = h < 8 ? x : y; + T v = h < 4 ? y : h == 12 || h == 14 ? x : z; + return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); + } +public: + PerlinNoise() + { + // Generate random lookup for permutations containing all numbers from 0..255 + std::vector plookup; + plookup.resize(256); + std::iota(plookup.begin(), plookup.end(), 0); + std::default_random_engine rndEngine(std::random_device{}()); + std::shuffle(plookup.begin(), plookup.end(), rndEngine); + + for (uint32_t i = 0; i < 256; i++) + { + permutations[i] = permutations[256 + i] = plookup[i]; + } + } + T noise(T x, T y, T z) + { + // Find unit cube that contains point + int32_t X = (int32_t)floor(x) & 255; + int32_t Y = (int32_t)floor(y) & 255; + int32_t Z = (int32_t)floor(z) & 255; + // Find relative x,y,z of point in cube + x -= floor(x); + y -= floor(y); + z -= floor(z); + + // Compute fade curves for each of x,y,z + T u = fade(x); + T v = fade(y); + T w = fade(z); + + // Hash coordinates of the 8 cube corners + uint32_t A = permutations[X] + Y; + uint32_t AA = permutations[A] + Z; + uint32_t AB = permutations[A + 1] + Z; + uint32_t B = permutations[X + 1] + Y; + uint32_t BA = permutations[B] + Z; + uint32_t BB = permutations[B + 1] + Z; + + // And add blended results for 8 corners of the cube; + T res = lerp(w, lerp(v, + lerp(u, grad(permutations[AA], x, y, z), grad(permutations[BA], x - 1, y, z)), lerp(u, grad(permutations[AB], x, y - 1, z), grad(permutations[BB], x - 1, y - 1, z))), + lerp(v, lerp(u, grad(permutations[AA + 1], x, y, z - 1), grad(permutations[BA + 1], x - 1, y, z - 1)), lerp(u, grad(permutations[AB + 1], x, y - 1, z - 1), grad(permutations[BB + 1], x - 1, y - 1, z - 1)))); + return res; + } +}; + +// Fractal noise generator based on perlin noise above +template +class FractalNoise +{ +private: + PerlinNoise perlinNoise; + uint32_t octaves; + T frequency; + T amplitude; + T persistence; +public: + + FractalNoise(const PerlinNoise &perlinNoise) + { + this->perlinNoise = perlinNoise; + octaves = 6; + persistence = (T)0.5; + } + + T noise(T x, T y, T z) + { + T sum = 0; + T frequency = (T)1; + T amplitude = (T)1; + T max = (T)0; + for (int32_t i = 0; i < octaves; i++) + { + sum += perlinNoise.noise(x * frequency, y * frequency, z * frequency) * amplitude; + max += amplitude; + amplitude *= persistence; + frequency *= (T)2; + } + + sum = sum / max; + return (sum + (T)1.0) / (T)2.0; + } +}; + +class VulkanExample : public VulkanExampleBase +{ +public: + // Contains all Vulkan objects that are required to store and use a 3D texture + struct Texture { + VkSampler sampler; + VkImage image; + VkImageLayout imageLayout; + VkDeviceMemory deviceMemory; + VkImageView view; + VkDescriptorImageInfo descriptor; + uint32_t width, height, depth; + uint32_t mipLevels; + } texture; + + struct { + VkPipelineVertexInputStateCreateInfo inputState; + std::vector inputBinding; + std::vector inputAttributes; + } vertices; + + vk::Buffer vertexBuffer; + vk::Buffer indexBuffer; + uint32_t indexCount; + + vk::Buffer uniformBufferVS; + + struct { + glm::mat4 projection; + glm::mat4 model; + glm::vec4 viewPos; + float depth = 0.0f; + } uboVS; + + struct { + VkPipeline solid; + } pipelines; + + VkPipelineLayout pipelineLayout; + VkDescriptorSet descriptorSet; + VkDescriptorSetLayout descriptorSetLayout; + + VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) + { + zoom = -2.5f; + rotation = { 0.0f, 15.0f, 0.0f }; + title = "Vulkan Example - 3D textures"; + enableTextOverlay = true; + } + + ~VulkanExample() + { + // Clean up used Vulkan resources + // Note : Inherited destructor cleans up resources stored in base class + + destroyTextureImage(texture); + + vkDestroyPipeline(device, pipelines.solid, nullptr); + + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + + vertexBuffer.destroy(); + indexBuffer.destroy(); + uniformBufferVS.destroy(); + } + + // Generate 3D fractal noise + void generateNoise3D(byte *data, uint32_t width, uint32_t height, uint32_t depth) + { + std::cout << "Generating " << width << " x " << height << " x " << depth << " noise texture..." << std::endl; + + auto tStart = std::chrono::high_resolution_clock::now(); + + PerlinNoise perlinNoise; + FractalNoise fractalNoise(perlinNoise); + +#pragma omp parallel for + for (int32_t z = 0; z < depth; z++) + { + for (int32_t y = 0; y < height; y++) + { + for (int32_t x = 0; x < width; x++) + { + float nx = (float)x / (float)width; + float ny = (float)y / (float)height; + float nz = (float)z / (float)depth; +#define FRACTAL +#ifdef FRACTAL + float n = fractalNoise.noise(nx * 10, ny * 10, nz * 10); +#else + float n = 20.0 * perlinNoise.noise(nx, ny, nz); +#endif + n = n - floor(n); + + data[x + y * width + z * width * height] = floor(n * 255); + } + } + } + + auto tEnd = std::chrono::high_resolution_clock::now(); + auto tDiff = std::chrono::duration(tEnd - tStart).count(); + + std::cout << "Done in " << tDiff << "ms" << std::endl; + } + + + void generateNoiseTexture(uint32_t width, uint32_t height, uint32_t depth) + { + const uint32_t texMemSize = width * height * depth; + const VkFormat texFormat = VK_FORMAT_R8_UNORM; + + byte *data = new byte[texMemSize]; + memset(data, 0, texMemSize); + + generateNoise3D(data, width, height, depth); + + VkFormatProperties formatProperties; + + // A 3D texture is described as width x height x depth + texture.width = width; + texture.height = height; + texture.depth = depth; + texture.mipLevels = 1; + + // Get device properites for the requested texture format + vkGetPhysicalDeviceFormatProperties(physicalDevice, texFormat, &formatProperties); + + VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); + VkMemoryRequirements memReqs = {}; + + // Create a host-visible staging buffer that contains the raw image data + VkBuffer stagingBuffer; + VkDeviceMemory stagingMemory; + + // Buffer + VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo(); + bufferCreateInfo.size = texMemSize; + bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCreateInfo, nullptr, &stagingBuffer)); + // Allocate host visible memory for data upload + vkGetBufferMemoryRequirements(device, stagingBuffer, &memReqs); + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &stagingMemory)); + VK_CHECK_RESULT(vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0)); + + // Copy texture data into staging buffer + uint8_t *mapped; + VK_CHECK_RESULT(vkMapMemory(device, stagingMemory, 0, memReqs.size, 0, (void **)&mapped)); + memcpy(mapped, data, texMemSize); + vkUnmapMemory(device, stagingMemory); + + // Create optimal tiled target image + VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); + imageCreateInfo.imageType = VK_IMAGE_TYPE_3D; + imageCreateInfo.format = texFormat; + imageCreateInfo.mipLevels = texture.mipLevels; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; + imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + // A 3D texture is described as width x height x depth + imageCreateInfo.extent.width = texture.width; + imageCreateInfo.extent.height = texture.width; + imageCreateInfo.extent.depth = texture.depth; + // Set initial layout of the image to undefined + imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + VK_CHECK_RESULT(vkCreateImage(device, &imageCreateInfo, nullptr, &texture.image)); + + vkGetImageMemoryRequirements(device, texture.image, &memReqs); + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &texture.deviceMemory)); + VK_CHECK_RESULT(vkBindImageMemory(device, texture.image, texture.deviceMemory, 0)); + + VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + + // Image barrier for optimal image + + // The sub resource range describes the regions of the image we will be transition + VkImageSubresourceRange subresourceRange = {}; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = 1; + subresourceRange.layerCount = 1; + + // Optimal image will be used as destination for the copy, so we must transfer from our + // initial undefined image layout to the transfer destination layout + vkTools::setImageLayout( + copyCmd, + texture.image, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + subresourceRange); + + // Copy 3D noise data to texture + + // Setup buffer copy regions + VkBufferImageCopy bufferCopyRegion{}; + bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + bufferCopyRegion.imageSubresource.mipLevel = 0; + bufferCopyRegion.imageSubresource.baseArrayLayer = 0; + bufferCopyRegion.imageSubresource.layerCount = 1; + bufferCopyRegion.imageExtent.width = texture.width; + bufferCopyRegion.imageExtent.height = texture.height; + bufferCopyRegion.imageExtent.depth = texture.depth; + + vkCmdCopyBufferToImage( + copyCmd, + stagingBuffer, + texture.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + &bufferCopyRegion); + + // Change texture image layout to shader read after all mip levels have been copied + texture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + vkTools::setImageLayout( + copyCmd, + texture.image, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + texture.imageLayout, + subresourceRange); + + VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true); + + // Clean up staging resources + delete[] data; + vkFreeMemory(device, stagingMemory, nullptr); + vkDestroyBuffer(device, stagingBuffer, nullptr); + + // Create sampler + VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo(); + sampler.magFilter = VK_FILTER_LINEAR; + sampler.minFilter = VK_FILTER_LINEAR; + sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + sampler.addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + sampler.addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + sampler.mipLodBias = 0.0f; + sampler.compareOp = VK_COMPARE_OP_NEVER; + sampler.minLod = 0.0f; + sampler.maxLod = 0.0f; + sampler.maxAnisotropy = 1.0; + sampler.anisotropyEnable = VK_FALSE; + sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + VK_CHECK_RESULT(vkCreateSampler(device, &sampler, nullptr, &texture.sampler)); + + // Create image view + VkImageViewCreateInfo view = vkTools::initializers::imageViewCreateInfo(); + view.image = VK_NULL_HANDLE; + view.viewType = VK_IMAGE_VIEW_TYPE_3D; + view.format = texFormat; + view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; + view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view.subresourceRange.baseMipLevel = 0; + view.subresourceRange.baseArrayLayer = 0; + view.subresourceRange.layerCount = 1; + view.subresourceRange.levelCount = 1; + view.image = texture.image; + VK_CHECK_RESULT(vkCreateImageView(device, &view, nullptr, &texture.view)); + + // Fill image descriptor image info that can be used during the descriptor set setup + texture.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + texture.descriptor.imageView = texture.view; + texture.descriptor.sampler = texture.sampler; + } + + // Free all Vulkan resources used a texture object + void destroyTextureImage(Texture texture) + { + vkDestroyImageView(device, texture.view, nullptr); + vkDestroyImage(device, texture.image, nullptr); + vkDestroySampler(device, texture.sampler, nullptr); + vkFreeMemory(device, texture.deviceMemory, nullptr); + } + + void buildCommandBuffers() + { + VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo(); + + VkClearValue clearValues[2]; + clearValues[0].color = defaultClearColor; + clearValues[1].depthStencil = { 1.0f, 0 }; + + VkRenderPassBeginInfo renderPassBeginInfo = vkTools::initializers::renderPassBeginInfo(); + renderPassBeginInfo.renderPass = renderPass; + renderPassBeginInfo.renderArea.offset.x = 0; + renderPassBeginInfo.renderArea.offset.y = 0; + renderPassBeginInfo.renderArea.extent.width = width; + renderPassBeginInfo.renderArea.extent.height = height; + renderPassBeginInfo.clearValueCount = 2; + renderPassBeginInfo.pClearValues = clearValues; + + for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) + { + // Set target frame buffer + renderPassBeginInfo.framebuffer = frameBuffers[i]; + + VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); + + vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); + vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); + + VkRect2D scissor = vkTools::initializers::rect2D(width, height, 0, 0); + vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); + + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.solid); + + VkDeviceSize offsets[1] = { 0 }; + vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &vertexBuffer.buffer, offsets); + vkCmdBindIndexBuffer(drawCmdBuffers[i], indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + + vkCmdDrawIndexed(drawCmdBuffers[i], indexCount, 1, 0, 0, 0); + + vkCmdEndRenderPass(drawCmdBuffers[i]); + + VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); + } + } + + void draw() + { + VulkanExampleBase::prepareFrame(); + + // Command buffer to be sumitted to the queue + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; + + // Submit to queue + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + + VulkanExampleBase::submitFrame(); + } + + void generateQuad() + { + // Setup vertices for a single uv-mapped quad made from two triangles + std::vector vertices = + { + { { 1.0f, 1.0f, 0.0f }, { 1.0f, 1.0f },{ 0.0f, 0.0f, 1.0f } }, + { { -1.0f, 1.0f, 0.0f }, { 0.0f, 1.0f },{ 0.0f, 0.0f, 1.0f } }, + { { -1.0f, -1.0f, 0.0f }, { 0.0f, 0.0f },{ 0.0f, 0.0f, 1.0f } }, + { { 1.0f, -1.0f, 0.0f }, { 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0f } } + }; + + // Setup indices + std::vector indices = { 0,1,2, 2,3,0 }; + indexCount = static_cast(indices.size()); + + // Create buffers + // For the sake of simplicity we won't stage the vertex data to the gpu memory + // Vertex buffer + VK_CHECK_RESULT(vulkanDevice->createBuffer( + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &vertexBuffer, + vertices.size() * sizeof(Vertex), + vertices.data())); + // Index buffer + VK_CHECK_RESULT(vulkanDevice->createBuffer( + VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &indexBuffer, + indices.size() * sizeof(uint32_t), + indices.data())); + } + + void setupVertexDescriptions() + { + // Binding description + vertices.inputBinding.resize(1); + vertices.inputBinding[0] = + vkTools::initializers::vertexInputBindingDescription( + VERTEX_BUFFER_BIND_ID, + sizeof(Vertex), + VK_VERTEX_INPUT_RATE_VERTEX); + + // Attribute descriptions + // Describes memory layout and shader positions + vertices.inputAttributes.resize(3); + // Location 0 : Position + vertices.inputAttributes[0] = + vkTools::initializers::vertexInputAttributeDescription( + VERTEX_BUFFER_BIND_ID, + 0, + VK_FORMAT_R32G32B32_SFLOAT, + offsetof(Vertex, pos)); + // Location 1 : Texture coordinates + vertices.inputAttributes[1] = + vkTools::initializers::vertexInputAttributeDescription( + VERTEX_BUFFER_BIND_ID, + 1, + VK_FORMAT_R32G32_SFLOAT, + offsetof(Vertex, uv)); + // Location 1 : Vertex normal + vertices.inputAttributes[2] = + vkTools::initializers::vertexInputAttributeDescription( + VERTEX_BUFFER_BIND_ID, + 2, + VK_FORMAT_R32G32B32_SFLOAT, + offsetof(Vertex, normal)); + + vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo(); + vertices.inputState.vertexBindingDescriptionCount = static_cast(vertices.inputBinding.size()); + vertices.inputState.pVertexBindingDescriptions = vertices.inputBinding.data(); + vertices.inputState.vertexAttributeDescriptionCount = static_cast(vertices.inputAttributes.size()); + vertices.inputState.pVertexAttributeDescriptions = vertices.inputAttributes.data(); + } + + void setupDescriptorPool() + { + // Example uses one ubo and one image sampler + std::vector poolSizes = + { + vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), + vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1) + }; + + VkDescriptorPoolCreateInfo descriptorPoolInfo = + vkTools::initializers::descriptorPoolCreateInfo( + static_cast(poolSizes.size()), + poolSizes.data(), + 2); + + VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); + } + + void setupDescriptorSetLayout() + { + std::vector setLayoutBindings = + { + // Binding 0 : Vertex shader uniform buffer + vkTools::initializers::descriptorSetLayoutBinding( + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + VK_SHADER_STAGE_VERTEX_BIT, + 0), + // Binding 1 : Fragment shader image sampler + vkTools::initializers::descriptorSetLayoutBinding( + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + VK_SHADER_STAGE_FRAGMENT_BIT, + 1) + }; + + VkDescriptorSetLayoutCreateInfo descriptorLayout = + vkTools::initializers::descriptorSetLayoutCreateInfo( + setLayoutBindings.data(), + static_cast(setLayoutBindings.size())); + + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); + + VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = + vkTools::initializers::pipelineLayoutCreateInfo( + &descriptorSetLayout, + 1); + + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + } + + void setupDescriptorSet() + { + VkDescriptorSetAllocateInfo allocInfo = + vkTools::initializers::descriptorSetAllocateInfo( + descriptorPool, + &descriptorSetLayout, + 1); + + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); + + std::vector writeDescriptorSets = + { + // Binding 0 : Vertex shader uniform buffer + vkTools::initializers::writeDescriptorSet( + descriptorSet, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 0, + &uniformBufferVS.descriptor), + // Binding 1 : Fragment shader texture sampler + vkTools::initializers::writeDescriptorSet( + descriptorSet, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 1, + &texture.descriptor) + }; + + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + } + + void preparePipelines() + { + VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = + vkTools::initializers::pipelineInputAssemblyStateCreateInfo( + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + 0, + VK_FALSE); + + VkPipelineRasterizationStateCreateInfo rasterizationState = + vkTools::initializers::pipelineRasterizationStateCreateInfo( + VK_POLYGON_MODE_FILL, + VK_CULL_MODE_NONE, + VK_FRONT_FACE_COUNTER_CLOCKWISE, + 0); + + VkPipelineColorBlendAttachmentState blendAttachmentState = + vkTools::initializers::pipelineColorBlendAttachmentState( + 0xf, + VK_FALSE); + + VkPipelineColorBlendStateCreateInfo colorBlendState = + vkTools::initializers::pipelineColorBlendStateCreateInfo( + 1, + &blendAttachmentState); + + VkPipelineDepthStencilStateCreateInfo depthStencilState = + vkTools::initializers::pipelineDepthStencilStateCreateInfo( + VK_TRUE, + VK_TRUE, + VK_COMPARE_OP_LESS_OR_EQUAL); + + VkPipelineViewportStateCreateInfo viewportState = + vkTools::initializers::pipelineViewportStateCreateInfo(1, 1, 0); + + VkPipelineMultisampleStateCreateInfo multisampleState = + vkTools::initializers::pipelineMultisampleStateCreateInfo( + VK_SAMPLE_COUNT_1_BIT, + 0); + + std::vector dynamicStateEnables = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + VkPipelineDynamicStateCreateInfo dynamicState = + vkTools::initializers::pipelineDynamicStateCreateInfo( + dynamicStateEnables.data(), + static_cast(dynamicStateEnables.size()), + 0); + + // Load shaders + std::array shaderStages; + + shaderStages[0] = loadShader(getAssetPath() + "shaders/texture3D/texture3D.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getAssetPath() + "shaders/texture3D/texture3D.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + + VkGraphicsPipelineCreateInfo pipelineCreateInfo = + vkTools::initializers::pipelineCreateInfo( + pipelineLayout, + renderPass, + 0); + + pipelineCreateInfo.pVertexInputState = &vertices.inputState; + pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; + pipelineCreateInfo.pRasterizationState = &rasterizationState; + pipelineCreateInfo.pColorBlendState = &colorBlendState; + pipelineCreateInfo.pMultisampleState = &multisampleState; + pipelineCreateInfo.pViewportState = &viewportState; + pipelineCreateInfo.pDepthStencilState = &depthStencilState; + pipelineCreateInfo.pDynamicState = &dynamicState; + pipelineCreateInfo.stageCount = static_cast(shaderStages.size()); + pipelineCreateInfo.pStages = shaderStages.data(); + + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.solid)); + } + + // Prepare and initialize uniform buffer containing shader uniforms + void prepareUniformBuffers() + { + // Vertex shader uniform buffer block + VK_CHECK_RESULT(vulkanDevice->createBuffer( + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &uniformBufferVS, + sizeof(uboVS), + &uboVS)); + + updateUniformBuffers(); + } + + void updateUniformBuffers(bool viewchanged = true) + { + if (viewchanged) + { + uboVS.projection = glm::perspective(glm::radians(60.0f), (float)width / (float)height, 0.001f, 256.0f); + glm::mat4 viewMatrix = glm::translate(glm::mat4(), glm::vec3(0.0f, 0.0f, zoom)); + + uboVS.model = viewMatrix * glm::translate(glm::mat4(), cameraPos); + uboVS.model = glm::rotate(uboVS.model, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); + uboVS.model = glm::rotate(uboVS.model, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); + uboVS.model = glm::rotate(uboVS.model, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); + + uboVS.viewPos = glm::vec4(0.0f, 0.0f, -zoom, 0.0f); + } + else + { + uboVS.depth += frameTimer * 0.15f; + if (uboVS.depth > 2.0f) + uboVS.depth = uboVS.depth - 2.0f; + } + + VK_CHECK_RESULT(uniformBufferVS.map()); + memcpy(uniformBufferVS.mapped, &uboVS, sizeof(uboVS)); + uniformBufferVS.unmap(); + } + + void prepare() + { + VulkanExampleBase::prepare(); + generateQuad(); + setupVertexDescriptions(); + prepareUniformBuffers(); + generateNoiseTexture(256, 256, 256); + setupDescriptorSetLayout(); + preparePipelines(); + setupDescriptorPool(); + setupDescriptorSet(); + buildCommandBuffers(); + prepared = true; + } + + virtual void render() + { + if (!prepared) + return; + draw(); + if (!paused) + updateUniformBuffers(false); + } + + virtual void viewChanged() + { + updateUniformBuffers(); + } + + virtual void keyPressed(uint32_t keyCode) + { + switch (keyCode) + { + case KEY_KPADD: + case GAMEPAD_BUTTON_R1: + break; + case KEY_KPSUB: + case GAMEPAD_BUTTON_L1: + break; + } + } + + virtual void getOverlayText(VulkanTextOverlay *textOverlay) + { +#if defined(__ANDROID__) +#else +#endif + } +}; + +VULKAN_EXAMPLE_MAIN() diff --git a/texture3d/texture3d.vcxproj b/texture3d/texture3d.vcxproj new file mode 100644 index 00000000..496020c4 --- /dev/null +++ b/texture3d/texture3d.vcxproj @@ -0,0 +1,101 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {D36B82DD-9114-44D2-A9C9-8DF0F8544BD5} + Win32Proj + 8.1 + + + + Application + true + v140 + + + Application + false + v140 + + + + + + + + + + + + + true + $(SolutionDir)\bin\ + $(SolutionDir)\bin\intermediate\$(ProjectName)\$(ConfigurationName) + + + true + $(SolutionDir)\bin\ + $(SolutionDir)\bin\intermediate\$(ProjectName)\$(ConfigurationName) + + + + WIN32;_DEBUG;_WINDOWS;VK_USE_PLATFORM_WIN32_KHR;_USE_MATH_DEFINES;NOMINMAX;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + ProgramDatabase + Disabled + ..\base;..\external\glm;..\external\gli;..\external\assimp;..\external;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + true + + + true + Windows + ..\libs\vulkan\vulkan-1.lib;..\libs\assimp\assimp.lib;%(AdditionalDependencies) + + + + + WIN32;NDEBUG;_WINDOWS;VK_USE_PLATFORM_WIN32_KHR;_USE_MATH_DEFINES;NOMINMAX;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + ..\base;..\external\glm;..\external\gli;..\external\assimp;..\external;%(AdditionalIncludeDirectories) + true + + + true + Windows + true + true + ..\libs\vulkan\vulkan-1.lib;..\libs\assimp\assimp.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/texture3d/texture3d.vcxproj.filters b/texture3d/texture3d.vcxproj.filters new file mode 100644 index 00000000..5259cc61 --- /dev/null +++ b/texture3d/texture3d.vcxproj.filters @@ -0,0 +1,53 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {f98305a8-a541-4aa2-9ee5-985eaa929027} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Shaders + + + Shaders + + + \ No newline at end of file diff --git a/vulkanExamples.sln b/vulkanExamples.sln index bca9e871..3840114b 100644 --- a/vulkanExamples.sln +++ b/vulkanExamples.sln @@ -73,7 +73,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "terraintessellation", "terr EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "deferredshadows", "deferredshadows\deferredshadows.vcxproj", "{BFEB15A3-D252-4AF7-8CA8-B9396F374DDB}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{09B9A54B-FC57-4A98-9671-5706FC3846C9}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Base", "Base", "{09B9A54B-FC57-4A98-9671-5706FC3846C9}" ProjectSection(SolutionItems) = preProject base\camera.hpp = base\camera.hpp base\frustum.hpp = base\frustum.hpp @@ -99,6 +99,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "indirectdraw", "indirectdra EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "texturemipmapgen", "texturemipmapgen\texturemipmapgen.vcxproj", "{24AD09B4-6ABE-4A82-83E7-6A7799A88762}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compute", "Compute", "{6B47BC47-0394-429E-9441-867EC23DFCD4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Textures", "Textures", "{A8492D6D-5243-456E-8173-39B99F1FEA9C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tessellation", "Tessellation", "{C93DE675-A816-4412-8E9F-1EFE9AC07750}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "texture3d", "texture3d\texture3d.vcxproj", "{D36B82DD-9114-44D2-A9C9-8DF0F8544BD5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -253,8 +261,25 @@ Global {24AD09B4-6ABE-4A82-83E7-6A7799A88762}.Debug|x64.Build.0 = Debug|x64 {24AD09B4-6ABE-4A82-83E7-6A7799A88762}.Release|x64.ActiveCfg = Release|x64 {24AD09B4-6ABE-4A82-83E7-6A7799A88762}.Release|x64.Build.0 = Release|x64 + {D36B82DD-9114-44D2-A9C9-8DF0F8544BD5}.Debug|x64.ActiveCfg = Debug|x64 + {D36B82DD-9114-44D2-A9C9-8DF0F8544BD5}.Debug|x64.Build.0 = Debug|x64 + {D36B82DD-9114-44D2-A9C9-8DF0F8544BD5}.Release|x64.ActiveCfg = Release|x64 + {D36B82DD-9114-44D2-A9C9-8DF0F8544BD5}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {015C3F70-FFCE-45DA-80E0-5DED015868D7} = {C93DE675-A816-4412-8E9F-1EFE9AC07750} + {44B86F78-3931-4198-B189-6DF4B32FA8AE} = {C93DE675-A816-4412-8E9F-1EFE9AC07750} + {57261E3A-6A05-4E33-B521-C4CB82D916B3} = {A8492D6D-5243-456E-8173-39B99F1FEA9C} + {553C9532-8989-4851-9D59-557C64FF62BE} = {6B47BC47-0394-429E-9441-867EC23DFCD4} + {5A049556-EA1E-4985-8D0B-3748E5D56F68} = {6B47BC47-0394-429E-9441-867EC23DFCD4} + {0D4DE16B-71FE-4B17-8310-3FFFB9E873B7} = {A8492D6D-5243-456E-8173-39B99F1FEA9C} + {5E512F97-14DB-4CEE-A495-BD8AED789521} = {A8492D6D-5243-456E-8173-39B99F1FEA9C} + {8B1C24E5-CC00-484C-9F6F-8FFCBDA3AA30} = {6B47BC47-0394-429E-9441-867EC23DFCD4} + {6C6E48B1-5946-4754-9E31-E1C989EC25FE} = {C93DE675-A816-4412-8E9F-1EFE9AC07750} + {24AD09B4-6ABE-4A82-83E7-6A7799A88762} = {A8492D6D-5243-456E-8173-39B99F1FEA9C} + {D36B82DD-9114-44D2-A9C9-8DF0F8544BD5} = {A8492D6D-5243-456E-8173-39B99F1FEA9C} + EndGlobalSection EndGlobal