Updated displacement example

This commit is contained in:
saschawillems 2016-06-06 14:28:13 +02:00
parent 0ecff76c40
commit 2ec1a60535
16 changed files with 77 additions and 177 deletions

View file

@ -12,12 +12,10 @@ if %ERRORLEVEL% EQU 0 (
xcopy "..\..\data\shaders\displacement\*.spv" "assets\shaders\displacement" /Y
mkdir "assets\textures"
xcopy "..\..\data\textures\stonewall_colormap_bc3.dds" "assets\textures" /Y
xcopy "..\..\data\textures\stonewall_heightmap_rgba.dds" "assets\textures" /Y
xcopy "..\..\data\textures\pattern_36_bc3.ktx" "assets\textures" /Y
mkdir "assets\models"
xcopy "..\..\data\models\torus.obj" "assets\models" /Y
xcopy "..\..\data\models\plane.obj" "assets\models" /Y
mkdir "res\drawable"
xcopy "..\..\android\images\icon.png" "res\drawable" /Y

View file

@ -3,7 +3,7 @@
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (binding = 3) uniform sampler2D colorMap;
layout (binding = 2) uniform sampler2D colorMap;
layout (location = 0) in vec3 inNormal;
layout (location = 1) in vec2 inUV;
@ -25,5 +25,5 @@ void main()
vec4 IAmbient = vec4(0.0, 0.0, 0.0, 1.0);
vec4 IDiffuse = vec4(1.0) * max(dot(inNormal, inLightVec), 0.0);
outFragColor = vec4((IAmbient + IDiffuse) * texture(colorMap, inUV));
outFragColor = vec4((IAmbient + IDiffuse) * vec4(texture(colorMap, inUV).rgb, 1.0));
}

View file

@ -26,12 +26,11 @@ layout (location = 3) out vec3 outLightVec;
void main()
{
gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) + (gl_TessCoord.y * gl_in[1].gl_Position) + (gl_TessCoord.z * gl_in[2].gl_Position);
outUV = gl_TessCoord.x * inUV[0] + gl_TessCoord.y * inUV[1] + gl_TessCoord.z * inUV[2];
outNormal = gl_TessCoord.x * inNormal[0] + gl_TessCoord.y * inNormal[1] + gl_TessCoord.z * inNormal[2];
gl_Position.xyz += normalize(outNormal) * (max(textureLod(displacementMap, outUV.st, 0.0).r, 0.45) * ubo.tessStrength);
gl_Position.xyz += normalize(outNormal) * (max(textureLod(displacementMap, outUV.st, 0.0).a, 0.0) * ubo.tessStrength);
outEyesPos = (gl_Position).xyz;
outLightVec = normalize(ubo.lightPos.xyz - outEyesPos);

View file

@ -1,7 +1,5 @@
glslangvalidator -V base.vert -o base.vert.spv
glslangvalidator -V base.frag -o base.frag.spv
glslangvalidator -V passthrough.tesc -o passthrough.tesc.spv
glslangvalidator -V passthrough.tese -o passthrough.tese.spv
glslangvalidator -V displacement.tesc -o displacement.tesc.spv
glslangvalidator -V displacement.tese -o displacement.tese.spv

View file

@ -1,26 +0,0 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (vertices = 3) out;
layout (location = 0) in vec3 inNormal[];
layout (location = 1) in vec2 inTexCoord[];
layout (location = 0) out vec3 outNormal[3];
layout (location = 3) out vec2 oTexCoord[3];
void main(void)
{
if (gl_InvocationID == 0)
{
gl_TessLevelInner[0] = 1.0;
gl_TessLevelOuter[0] = 1.0;
gl_TessLevelOuter[1] = 1.0;
gl_TessLevelOuter[2] = 1.0;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
outNormal[gl_InvocationID] = inNormal[gl_InvocationID];
oTexCoord[gl_InvocationID] = inTexCoord[gl_InvocationID];
}

View file

@ -1,34 +0,0 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (triangles) in;
layout (binding = 1) uniform UBO
{
mat4 projection;
mat4 model;
vec3 lightPos;
float tessAlpha;
float tessStrength;
} ubo;
layout (location = 0) in vec3 inNormal[];
layout (location = 3) in vec2 inTexCoord[];
layout (location = 0) out vec3 outNormal;
layout (location = 1) out vec2 outTexCoord;
layout (location = 2) out vec3 outEyesPos;
layout (location = 3) out vec3 outLightVec;
void main(void)
{
gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) + (gl_TessCoord.y * gl_in[1].gl_Position) + (gl_TessCoord.z * gl_in[2].gl_Position);
outNormal = gl_TessCoord.x * inNormal[0] + gl_TessCoord.y * inNormal[1] + gl_TessCoord.z * inNormal[2];
outTexCoord = gl_TessCoord.x * inTexCoord[0] + gl_TessCoord.y * inTexCoord[1] + gl_TessCoord.z * inTexCoord[2];
gl_Position.xyz += normalize(outNormal);
outEyesPos = (gl_Position).xyz;
outLightVec = normalize(ubo.lightPos - outEyesPos);
gl_Position = ubo.projection * ubo.model * gl_Position;
}

Binary file not shown.

View file

@ -36,11 +36,11 @@ class VulkanExample : public VulkanExampleBase
{
private:
struct {
vkTools::VulkanTexture colorMap;
vkTools::VulkanTexture heightMap;
vkTools::VulkanTexture colorHeightMap;
} textures;
public:
bool splitScreen = true;
bool displacement = true;
struct {
VkPipelineVertexInputStateCreateInfo inputState;
@ -55,25 +55,21 @@ public:
vkTools::UniformData uniformDataTC, uniformDataTE;
struct {
float tessLevel = 8.0;
float tessLevel = 64.0f;
} uboTC;
struct {
glm::mat4 projection;
glm::mat4 model;
glm::vec4 lightPos = glm::vec4(0.0, -25.0, 0.0, 0.0);
float tessAlpha = 1.0;
float tessStrength = 1.0;
glm::vec4 lightPos = glm::vec4(0.0f, -1.0f, 0.0f, 0.0f);
float tessAlpha = 1.0f;
float tessStrength = 0.1f;
} uboTE;
struct {
VkPipeline solid;
VkPipeline wire;
VkPipeline solidPassThrough;
VkPipeline wirePassThrough;
VkPipeline wireframe;
} pipelines;
VkPipeline *pipelineLeft = &pipelines.solidPassThrough;
VkPipeline *pipelineRight = &pipelines.solid;
VkPipelineLayout pipelineLayout;
VkDescriptorSet descriptorSet;
@ -81,8 +77,8 @@ public:
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
{
zoom = -35;
rotation = glm::vec3(-35.0, 0.0, 0);
zoom = -1.25f;
rotation = glm::vec3(-20.0f, 45.0f, 0.0f);
enableTextOverlay = true;
title = "Vulkan Example - Tessellation shader displacement mapping";
// Support for tessellation shaders is optional, so check first
@ -97,9 +93,7 @@ public:
// Clean up used Vulkan resources
// Note : Inherited destructor cleans up resources stored in base class
vkDestroyPipeline(device, pipelines.solid, nullptr);
vkDestroyPipeline(device, pipelines.wire, nullptr);
vkDestroyPipeline(device, pipelines.solidPassThrough, nullptr);
vkDestroyPipeline(device, pipelines.wirePassThrough, nullptr);
vkDestroyPipeline(device, pipelines.wireframe, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
@ -112,20 +106,15 @@ public:
vkDestroyBuffer(device, uniformDataTE.buffer, nullptr);
vkFreeMemory(device, uniformDataTE.memory, nullptr);
textureLoader->destroyTexture(textures.colorMap);
textureLoader->destroyTexture(textures.heightMap);
textureLoader->destroyTexture(textures.colorHeightMap);
}
void loadTextures()
{
textureLoader->loadTexture(
getAssetPath() + "textures/stonewall_colormap_bc3.dds",
getAssetPath() + "textures/pattern_36_bc3.ktx",
VK_FORMAT_BC3_UNORM_BLOCK,
&textures.colorMap);
textureLoader->loadTexture(
getAssetPath() + "textures/stonewall_heightmap_rgba.dds",
VK_FORMAT_R8G8B8A8_UNORM,
&textures.heightMap);
&textures.colorHeightMap);
}
void reBuildCommandBuffers()
@ -164,10 +153,10 @@ public:
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport = vkTools::initializers::viewport(splitScreen ? (float)width / 2.0f : (float)width, (float)height, 0.0f, 1.0f);
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);
VkRect2D scissor = vkTools::initializers::rect2D(splitScreen ? width / 2 : width, height, 0, 0);
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
vkCmdSetLineWidth(drawCmdBuffers[i], 1.0f);
@ -180,14 +169,13 @@ public:
if (splitScreen)
{
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLeft);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.wireframe);
vkCmdDrawIndexed(drawCmdBuffers[i], meshes.object.indexCount, 1, 0, 0, 0);
viewport.x = float(width) / 2;
scissor.offset.x = width / 2;
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
}
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineRight);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.solid);
vkCmdDrawIndexed(drawCmdBuffers[i], meshes.object.indexCount, 1, 0, 0, 0);
vkCmdEndRenderPass(drawCmdBuffers[i]);
@ -198,7 +186,7 @@ public:
void loadMeshes()
{
loadMesh(getAssetPath() + "models/torus.obj", &meshes.object, vertexLayout, 0.25f);
loadMesh(getAssetPath() + "models/plane.obj", &meshes.object, vertexLayout, 0.25f);
}
void setupVertexDescriptions()
@ -252,7 +240,7 @@ public:
std::vector<VkDescriptorPoolSize> poolSizes =
{
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2),
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2)
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1)
};
VkDescriptorPoolCreateInfo descriptorPoolInfo =
@ -278,16 +266,11 @@ public:
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
1),
// Binding 2 : Tessellation evaluation shader displacement map image sampler
// Binding 2 : Combined color (rgb) and height (alpha) map
vkTools::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
2),
// Binding 3 : Fragment shader color map image sampler
vkTools::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_SHADER_STAGE_FRAGMENT_BIT,
3),
};
VkDescriptorSetLayoutCreateInfo descriptorLayout =
@ -315,18 +298,11 @@ public:
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
// Displacement map image descriptor
VkDescriptorImageInfo texDescriptorDisplacementMap =
// Color and height map image descriptor
VkDescriptorImageInfo texDescriptor =
vkTools::initializers::descriptorImageInfo(
textures.heightMap.sampler,
textures.heightMap.view,
VK_IMAGE_LAYOUT_GENERAL);
// Color map image descriptor
VkDescriptorImageInfo texDescriptorColorMap =
vkTools::initializers::descriptorImageInfo(
textures.colorMap.sampler,
textures.colorMap.view,
textures.colorHeightMap.sampler,
textures.colorHeightMap.view,
VK_IMAGE_LAYOUT_GENERAL);
std::vector<VkWriteDescriptorSet> writeDescriptorSets =
@ -343,18 +319,12 @@ public:
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
1,
&uniformDataTE.descriptor),
// Binding 2 : Displacement map
// Binding 2 : Color and displacement map (alpha channel)
vkTools::initializers::writeDescriptorSet(
descriptorSet,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
2,
&texDescriptorDisplacementMap),
// Binding 3 : Color map
vkTools::initializers::writeDescriptorSet(
descriptorSet,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
3,
&texDescriptorColorMap),
&texDescriptor),
};
vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL);
@ -446,20 +416,7 @@ public:
// Wireframe pipeline
rasterizationState.polygonMode = VK_POLYGON_MODE_LINE;
rasterizationState.cullMode = VK_CULL_MODE_NONE;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.wire));
// Pass through pipelines
// Load pass through tessellation shaders (Vert and frag are reused)
shaderStages[2] = loadShader(getAssetPath() + "shaders/displacement/passthrough.tesc.spv", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
shaderStages[3] = loadShader(getAssetPath() + "shaders/displacement/passthrough.tese.spv", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
// Solid
rasterizationState.polygonMode = VK_POLYGON_MODE_FILL;
rasterizationState.cullMode = VK_CULL_MODE_BACK_BIT;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.solidPassThrough));
// Wireframe
rasterizationState.polygonMode = VK_POLYGON_MODE_LINE;
rasterizationState.cullMode = VK_CULL_MODE_NONE;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.wirePassThrough));
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.wireframe));
}
// Prepare and initialize uniform buffer containing shader uniforms
@ -492,7 +449,7 @@ public:
{
// Tessellation eval
glm::mat4 viewMatrix = glm::mat4();
uboTE.projection = glm::perspective(glm::radians(45.0f), (float)(width* ((splitScreen) ? 0.5f : 1.0f)) / (float)height, 0.1f, 256.0f);
uboTE.projection = glm::perspective(glm::radians(45.0f), (float)(width) / (float)height, 0.1f, 256.0f);
viewMatrix = glm::translate(viewMatrix, glm::vec3(0.0f, 0.0f, zoom));
float offset = 0.5f;
@ -503,15 +460,27 @@ public:
uboTE.model = glm::rotate(uboTE.model, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
uboTE.model = glm::rotate(uboTE.model, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
uboTE.lightPos.y = -0.5f - uboTE.tessStrength;
uint8_t *pData;
VK_CHECK_RESULT(vkMapMemory(device, uniformDataTE.memory, 0, sizeof(uboTE), 0, (void **)&pData));
memcpy(pData, &uboTE, sizeof(uboTE));
vkUnmapMemory(device, uniformDataTE.memory);
// Tessellation control
float savedLevel = uboTC.tessLevel;
if (!displacement)
{
uboTC.tessLevel = 1.0f;
}
VK_CHECK_RESULT(vkMapMemory(device, uniformDataTC.memory, 0, sizeof(uboTC), 0, (void **)&pData));
memcpy(pData, &uboTC, sizeof(uboTC));
vkUnmapMemory(device, uniformDataTC.memory);
if (!displacement)
{
uboTC.tessLevel = savedLevel;
}
}
void draw()
@ -547,9 +516,7 @@ public:
{
if (!prepared)
return;
vkDeviceWaitIdle(device);
draw();
vkDeviceWaitIdle(device);
}
virtual void viewChanged()
@ -560,25 +527,17 @@ public:
void changeTessellationLevel(float delta)
{
uboTC.tessLevel += delta;
// Clamp
uboTC.tessLevel = fmax(1.0, fmin(uboTC.tessLevel, 32.0));
updateUniformBuffers();
updateTextOverlay();
}
void togglePipelines()
void changeTessellationStrength(float delta)
{
if (pipelineRight == &pipelines.solid)
{
pipelineRight = &pipelines.wire;
pipelineLeft = &pipelines.wirePassThrough;
}
else
{
pipelineRight = &pipelines.solid;
pipelineLeft = &pipelines.solidPassThrough;
}
reBuildCommandBuffers();
uboTE.tessStrength += delta;
uboTE.tessStrength = fmax(0.0f, fmin(uboTE.tessStrength, 1.0f));
updateUniformBuffers();
updateTextOverlay();
}
void toggleSplitScreen()
@ -588,21 +547,27 @@ public:
updateUniformBuffers();
}
void toggleDisplacement()
{
displacement = !displacement;
updateUniformBuffers();
}
virtual void keyPressed(uint32_t keyCode)
{
switch (keyCode)
{
case 0x6B:
case GAMEPAD_BUTTON_R1:
changeTessellationLevel(0.25);
changeTessellationStrength(0.025);
break;
case 0x6D:
case GAMEPAD_BUTTON_L1:
changeTessellationLevel(-0.25);
changeTessellationStrength(-0.025);
break;
case 0x57:
case 0x44:
case GAMEPAD_BUTTON_A:
togglePipelines();
toggleDisplacement();
break;
case 0x53:
case GAMEPAD_BUTTON_X:
@ -614,14 +579,14 @@ public:
virtual void getOverlayText(VulkanTextOverlay *textOverlay)
{
std::stringstream ss;
ss << std::setprecision(2) << std::fixed << uboTC.tessLevel;
ss << std::setprecision(2) << std::fixed << uboTE.tessStrength;
#if defined(__ANDROID__)
textOverlay->addText("Tessellation level: " + ss.str() + " (Buttons L1/R1 to change)", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
textOverlay->addText("Press \"Button A\" to toggle wireframe", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
textOverlay->addText("Press \"Button X\" to toggle splitscreen", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
textOverlay->addText("Tessellation height: " + ss.str() + " (Buttons L1/R1)", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
textOverlay->addText("Press \"Button A\" to toggle displacement", 5.0f, 100.0f, VulkanTextOverlay::alignLeft);
textOverlay->addText("Press \"Button X\" to toggle splitscreen", 5.0f, 115.0f, VulkanTextOverlay::alignLeft);
#else
textOverlay->addText("Tessellation level: " + ss.str() + " (NUMPAD +/- to change)", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
textOverlay->addText("Press \"w\" to toggle wireframe", 5.0f, 100.0f, VulkanTextOverlay::alignLeft);
textOverlay->addText("Tessellation height: " + ss.str() + " (numpad +/-)", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
textOverlay->addText("Press \"d\" to toggle displacement", 5.0f, 100.0f, VulkanTextOverlay::alignLeft);
textOverlay->addText("Press \"s\" to toggle splitscreen", 5.0f, 115.0f, VulkanTextOverlay::alignLeft);
#endif
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 118 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 KiB

After

Width:  |  Height:  |  Size: 283 KiB

Before After
Before After