Skip to content
Snippets Groups Projects
Verified Commit ba77d9cc authored by Tobias Frisch's avatar Tobias Frisch
Browse files

Add normal mapping example

parent 05072a6a
No related branches found
No related tags found
No related merge requests found
Showing
with 692 additions and 1 deletion
......@@ -8,5 +8,8 @@ set(BUILD_CLANG_FORMAT OFF CACHE INTERNAL "")
set(BUILD_DOXYGEN_DOCS OFF CACHE INTERNAL "")
add_subdirectory(framework)
# Include add_project macro from framework
include(framework/config/ext/Project.cmake)
# Add demo projects
add_subdirectory(demos)
\ No newline at end of file
add_subdirectory(NormalMapping)
NormalMapping
\ No newline at end of file
cmake_minimum_required(VERSION 3.16)
project(NormalMapping)
# setting c++ standard for the project
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# adding source files to the project
add_project(NormalMapping src/main.cpp)
# including headers of dependencies and the VkCV framework
target_include_directories(NormalMapping SYSTEM BEFORE PRIVATE ${vkcv_includes})
# linking with libraries from all dependencies and the VkCV framework
target_link_libraries(NormalMapping ${vkcv_libraries})
#version 450
layout(set=0, binding=5) uniform texture2D colorTexture;
layout(set=0, binding=6) uniform sampler colorSampler;
layout(set=1, binding=0) uniform texture2D normalTexture;
struct Material {
vec3 diffuse;
float alpha;
vec3 specular;
float shininess;
};
layout(set=0, binding=1) uniform materialBuffer {
Material mat;
};
struct Light {
vec4 pos; // pos.w = 0 (dir light), pos.w = 1 (point light)
vec3 col;
float spot_exponent;
vec3 spot_direction;
float spot_cutoff; // no spotlight if cutoff = 0
};
layout(set=0, binding=2) uniform lightBuffer {
Light light;
vec3 lightAmbient;
};
layout(set=0, binding=4) uniform texturePropsBuffer {
int useColorTexture;
};
layout(location = 0) in vec3 passLightVector;
layout(location = 1) in vec3 passEyeVector;
layout(location = 2) in vec2 passUV;
layout(location = 0) out vec4 fragmentColor;
void main(){
/***************** Diffuse ******************************************************/
// local normal, in tangent space
vec3 normal = texture(sampler2D(normalTexture, colorSampler), passUV).rgb * 2.0 - 1.0;
// direction of the light (from the fragment to the light) in tangent space
vec3 lightVector = normalize(passLightVector);
//compute the diffuse lighting factor
float cos_phi = max(dot(normal, lightVector), 0);
/***************** Specular *****************************************************/
// compute the normalized reflection vector using GLSL's built-in reflect() function
vec3 reflection = normalize(reflect(-lightVector, normal));
// eye vector in tangent space
vec3 eyeVector = normalize(passEyeVector);
// compute the specular lighting factor
float cos_psi_n = pow(max(dot(reflection, eyeVector), 0.0f), mat.shininess);
/***************** Material properties ******************************************/
vec3 diffuse_color;
if (useColorTexture != 0)
diffuse_color = texture(sampler2D(colorTexture, colorSampler), passUV).rgb;
else
diffuse_color = mat.diffuse;
/***************** All together *************************************************/
fragmentColor.rgb = diffuse_color * lightAmbient;
fragmentColor.rgb += diffuse_color * cos_phi * light.col;
fragmentColor.rgb += mat.specular * cos_psi_n * light.col;
fragmentColor.a = 1.0;
}
#version 450
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 uv;
layout(location = 3) in vec3 tangent;
//vec3 tangent = vec3(0);
layout(set=0, binding=0) uniform matrixBuffer {
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projectionMatrix;
};
struct Light {
vec4 pos; // pos.w = 0 (dir light), pos.w = 1 (point light)
vec3 col;
float spot_exponent;
vec3 spot_direction;
float spot_cutoff; // no spotlight if cutoff = 0
};
layout(set=0, binding=2) uniform lightBuffer {
Light light;
vec3 lightAmbient;
};
layout(location = 0) out vec3 passLightVector;
layout(location = 1) out vec3 passEyeVector;
layout(location = 2) out vec2 passUV;
void main(){
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1);
/*********** Calculate matrix that goes from camera space to tangent space **********/
mat4 normalMatrix = transpose(inverse(viewMatrix * modelMatrix));
vec3 normal_cs = normalize((normalMatrix * vec4(normal,0)).xyz);
vec3 tangent_cs = normalize((normalMatrix * vec4(tangent,0)).xyz);
vec3 bitangent_cs = cross(tangent_cs, normal_cs);
mat3 tbn = transpose(mat3(
tangent_cs,
bitangent_cs,
normal_cs
));
/*********** Calculate position in camera space *************************************/
vec3 position_cs = (viewMatrix * modelMatrix * vec4(position, 1)).xyz;
/*********** Calculate light vector (tangent space) *********************************/
// light position in world coordinates
vec3 lightPosition_cs = (light.pos).xyz;
// calcluate vector that goes from the vertex to the light, in tangent space
passLightVector = tbn * normalize(lightPosition_cs - position_cs);
/*********** Calculate eye vector (tangent space) **********************************/
// calculate eye vector in camera space
vec3 eye_cs = normalize(-position_cs);
// calculate eye vector in tangent space
passEyeVector = tbn * eye_cs;
/*********** Pass uv of the vertex *************************************************/
// no special space for this one
passUV = uv;
}
#version 450
layout(location = 0) in vec3 passPosition;
layout(location = 1) in vec3 passNormal;
layout(location = 2) in vec2 passTcoord;
layout(set=0, binding=0) uniform matrixBuffer {
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projectionMatrix;
};
struct Material {
vec3 diffuse;
float alpha;
vec3 specular;
float shininess;
};
layout(set=0, binding=1) uniform materialBuffer {
Material mat;
};
struct Light {
vec4 pos; // pos.w = 0 (dir light), pos.w = 1 (point light)
vec3 col;
float spot_exponent;
vec3 spot_direction;
float spot_cutoff; // no spotlight if cutoff = 0
};
layout(set=0, binding=2) uniform lightBuffer {
Light light;
vec3 lightAmbient;
};
struct FogParams {
vec3 col; // Fog color
float density; // For exp and exp2 equation
float start; // This is only for linear fog
float end; // This is only for linear fog
int mode; // 1 = linear, 2 = exp, 3 = exp2
};
layout(set=0, binding=3) uniform fogBuffer {
FogParams fog;
};
layout(set=0, binding=4) uniform texturePropsBuffer {
int useColorTexture;
};
layout(set=0, binding=5) uniform texture2D colorTexture;
layout(set=0, binding=6) uniform sampler colorSampler;
layout(location = 0) out vec4 fragmentColor;
float getFogFactor(FogParams fog, float z) {
float f = 0.0;
if (fog.mode == 1) {
f = (fog.end-z)/(fog.end-fog.start);
} else if (fog.mode == 2) {
f = exp(-fog.density*z);
} else if(fog.mode == 3) {
f = exp(-pow(fog.density*z, 2.0));
}
f = clamp(f, 0.0, 1.0);
return f;
}
void main() {
vec3 lightVector;
float spot;
vec3 diffuse_color;
float diffuse_alpha;
// Diffuse
vec3 light_camcoord = (light.pos).xyz;
if (light.pos.w > 0.001f) {
lightVector = normalize(light_camcoord - passPosition);
} else {
lightVector = normalize(light_camcoord);
}
float cos_phi = max(dot(passNormal,lightVector), 0.0f);
// Specular
vec3 eye = normalize(-passPosition);
vec3 reflection = normalize(reflect(-lightVector, passNormal));
float cos_psi_n = pow(max(dot(reflection, eye), 0.0f), mat.shininess);
// Spotlight
if (light.spot_cutoff < 0.001f) {
spot = 1.0;
} else {
float cos_phi_spot = max(dot(-lightVector, mat3(viewMatrix) * light.spot_direction), 0.0f);
if (cos_phi_spot >= cos(light.spot_cutoff)) {
spot = pow(cos_phi_spot, light.spot_exponent);
} else {
spot = 0.0f;
}
}
// Textures
if (useColorTexture != 0) {
diffuse_color = texture(sampler2D(colorTexture, colorSampler), passTcoord).rgb;
diffuse_alpha = texture(sampler2D(colorTexture, colorSampler), passTcoord).a;
} else {
diffuse_color = mat.diffuse;
diffuse_alpha = mat.alpha;
}
// All together
fragmentColor.rgb = diffuse_color * lightAmbient;
fragmentColor.rgb += spot * diffuse_color * cos_phi * light.col;
fragmentColor.rgb += spot * mat.specular * cos_psi_n * light.col;
fragmentColor.a = diffuse_alpha;
//Add fog
if (fog.mode != 0) {
float f = getFogFactor(fog, length(passPosition));
fragmentColor.rgb = f * fragmentColor.rgb + (1-f) * fog.col;
}
}
#version 450
layout(location = 0) in vec3 Position;
layout(location = 1) in vec3 Normal;
layout(location = 2) in vec2 Tcoord;
layout(set=0, binding=0) uniform matrixBuffer {
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projectionMatrix;
};
layout(location = 0) out vec3 passPosition;
layout(location = 1) out vec3 passNormal;
layout(location = 2) out vec2 passTcoord;
void main() {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(Position, 1);
//transform the position correctly into view space
//and pass it to the fragment shader
passPosition = (viewMatrix * modelMatrix * vec4(Position, 1)).xyz;
//transform the normal correctly into view space
//and pass it to the fragment shader
mat3 normalMatrix = mat3(transpose(inverse(viewMatrix * modelMatrix)));
passNormal = normalize(normalMatrix * Normal);
passTcoord = Tcoord;
}
#include <iostream>
#include <vkcv/Buffer.hpp>
#include <vkcv/Core.hpp>
#include <vkcv/DescriptorWrites.hpp>
#include <vkcv/Image.hpp>
#include <vkcv/Sampler.hpp>
#include <vkcv/Window.hpp>
#include <vkcv/asset/asset_loader.hpp>
#include <vkcv/camera/CameraManager.hpp>
#include <vkcv/geometry/Cuboid.hpp>
#include <vkcv/gui/GUI.hpp>
#include <vkcv/shader/GLSLCompiler.hpp>
struct Material {
glm::vec3 diffuse;
float alpha;
glm::vec3 specular;
float shininess;
};
struct Light {
glm::vec4 pos; // pos.w = 0 (dir light), pos.w = 1 (point light)
glm::vec3 col;
float spot_exponent;
glm::vec3 spot_direction;
float spot_cutoff; // no spotlight if cutoff = 0
};
struct LightProps {
Light light;
glm::vec3 lightAmbient;
};
struct FogParams {
glm::vec3 col; // Fog color
float density; // For exp and exp2 equation
float start; // This is only for linear fog
float end; // This is only for linear fog
int mode; // 1 = linear, 2 = exp, 3 = exp2
};
struct TextureProps {
int useColorTexture;
};
int main(int argc, const char** argv) {
const std::string applicationName = "Normal Mapping";
vkcv::Core core = vkcv::Core::create(
applicationName,
VK_MAKE_VERSION(0, 0, 1),
{ vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eTransfer },
{ VK_KHR_SWAPCHAIN_EXTENSION_NAME }
);
vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 800, 800, true);
vkcv::Window& window = core.getWindow(windowHandle);
vkcv::camera::CameraManager cameraManager (window);
auto camHandle = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL);
vkcv::geometry::Cuboid cube (glm::vec3(0.0f), 1.0f);
vkcv::shader::GLSLCompiler compiler;
vkcv::ShaderProgram phongShaderProgram, normalMappingShaderProgram;
compiler.compileProgram(
phongShaderProgram,
{
{ vkcv::ShaderStage::VERTEX, "shaders/Phong.vert" },
{ vkcv::ShaderStage::FRAGMENT, "shaders/Phong.frag" }
},
nullptr
);
compiler.compileProgram(
normalMappingShaderProgram,
{
{ vkcv::ShaderStage::VERTEX, "shaders/NormalMapping.vert" },
{ vkcv::ShaderStage::FRAGMENT, "shaders/NormalMapping.frag" }
},
nullptr
);
vkcv::PassHandle renderPass = core.createPass(vkcv::PassConfig(
{
vkcv::AttachmentDescription(
core.getSwapchainFormat(window.getSwapchain()),
vkcv::AttachmentOperation::CLEAR,
vkcv::AttachmentOperation::STORE,
vk::ClearValue(vk::ClearColorValue(std::array<float, 4>{
1.0f, 1.0f, 1.0f, 1.0f
}))
),
vkcv::AttachmentDescription(
vk::Format::eD32Sfloat,
vkcv::AttachmentOperation::CLEAR,
vkcv::AttachmentOperation::STORE
)
}
));
const vkcv::VertexLayout vertexLayoutPhong {
vkcv::createVertexBindings(phongShaderProgram.getVertexAttachments())
};
const vkcv::VertexLayout vertexLayoutNormalMapping {
vkcv::createVertexBindings(normalMappingShaderProgram.getVertexAttachments())
};
vkcv::DescriptorBindings descriptorBindings0 = (
phongShaderProgram.getReflectedDescriptors().at(0)
);
descriptorBindings0.at(2).shaderStages |= vkcv::ShaderStage::VERTEX;
auto descriptorSetLayout0 = core.createDescriptorSetLayout(descriptorBindings0);
auto descriptorSet0 = core.createDescriptorSet(descriptorSetLayout0);
const vkcv::DescriptorBindings& descriptorBindings1 = (
normalMappingShaderProgram.getReflectedDescriptors().at(1)
);
auto descriptorSetLayout1 = core.createDescriptorSetLayout(descriptorBindings1);
auto descriptorSet1 = core.createDescriptorSet(descriptorSetLayout1);
vkcv::GraphicsPipelineHandle phongPipeline = core.createGraphicsPipeline(
vkcv::GraphicsPipelineConfig(
phongShaderProgram,
renderPass,
vertexLayoutPhong,
{ descriptorSetLayout0 }
)
);
vkcv::GraphicsPipelineHandle normalMappingPipeline = core.createGraphicsPipeline(
vkcv::GraphicsPipelineConfig(
normalMappingShaderProgram,
renderPass,
vertexLayoutNormalMapping,
{
descriptorSetLayout0,
descriptorSetLayout1
}
)
);
auto matrixBuffer = vkcv::buffer<glm::mat4>(
core,
vkcv::BufferType::UNIFORM,
3,
vkcv::BufferMemoryType::HOST_VISIBLE
);
auto materialBuffer = vkcv::buffer<Material>(
core,
vkcv::BufferType::UNIFORM,
1
);
Material material;
material.diffuse = glm::vec3(1.0f, 0.0f, 0.0f);
material.alpha = 1.0f;
material.specular = glm::vec3(1.0f);
material.shininess = 120.0f;
materialBuffer.fill(&material, 1);
auto lightBuffer = vkcv::buffer<LightProps>(
core,
vkcv::BufferType::UNIFORM,
1
);
LightProps lightProps;
lightProps.light.pos = glm::vec4(0.0f, 1.0f, -10.0f, 1.0f);
lightProps.light.col = glm::vec3(0.75f);
lightProps.light.spot_exponent = 1.0f;
lightProps.light.spot_direction = glm::vec3(0.0f);
lightProps.light.spot_cutoff = 0.0f;
lightProps.lightAmbient = glm::vec3(0.2f);
lightBuffer.fill(&lightProps, 1);
auto fogBuffer = vkcv::buffer<FogParams>(
core,
vkcv::BufferType::UNIFORM,
1
);
FogParams fogParams;
fogParams.col = glm::vec3(1.0f);
fogParams.density = 1.0f;
fogParams.start = 1.0f;
fogParams.end = 10.0f;
fogParams.mode = 0;
fogBuffer.fill(&fogParams, 1);
auto texturePropsBuffer = vkcv::buffer<TextureProps>(
core,
vkcv::BufferType::UNIFORM,
1,
vkcv::BufferMemoryType::HOST_VISIBLE
);
vkcv::asset::Texture diffusemap = vkcv::asset::loadTexture("../../resources/normalmapping/diffusemap.png");
vkcv::asset::Texture normalmap = vkcv::asset::loadTexture("../../resources/normalmapping/normalmap.png");
vkcv::Image diffusemapImage = vkcv::image(core, vk::Format::eR8G8B8A8Srgb, diffusemap.w, diffusemap.h);
diffusemapImage.fill(diffusemap.data.data());
vkcv::Image normalmapImage = vkcv::image(core, vk::Format::eR8G8B8A8Srgb, normalmap.w, normalmap.h);
normalmapImage.fill(normalmap.data.data());
vkcv::SamplerHandle sampler = vkcv::samplerLinear(core);
{
vkcv::DescriptorWrites writes;
writes.writeUniformBuffer(0, matrixBuffer.getHandle());
writes.writeUniformBuffer(1, materialBuffer.getHandle());
writes.writeUniformBuffer(2, lightBuffer.getHandle());
writes.writeUniformBuffer(3, fogBuffer.getHandle());
writes.writeUniformBuffer(4, texturePropsBuffer.getHandle());
writes.writeSampledImage(5, diffusemapImage.getHandle());
writes.writeSampler(6, sampler);
core.writeDescriptorSet(descriptorSet0, writes);
}
{
vkcv::DescriptorWrites writes;
writes.writeSampledImage(0, normalmapImage.getHandle());
core.writeDescriptorSet(descriptorSet1, writes);
}
vkcv::gui::GUI gui (core, windowHandle);
bool useColorTexture = false;
bool useNormalMappingShader = false;
const auto vertexData = cube.generateVertexData(core);
vkcv::InstanceDrawcall drawcallPhong (vertexData);
drawcallPhong.useDescriptorSet(0, descriptorSet0);
vkcv::InstanceDrawcall drawcallNormalMapping (vertexData);
drawcallNormalMapping.useDescriptorSet(0, descriptorSet0);
drawcallNormalMapping.useDescriptorSet(1, descriptorSet1);
const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
vkcv::ImageHandle depthBuffer;
glm::mat4* mvp = matrixBuffer.map();
TextureProps* textureProps = texturePropsBuffer.map();
core.run([&](const vkcv::WindowHandle &windowHandle,
double t,
double dt,
uint32_t swapchainWidth,
uint32_t swapchainHeight
) {
if ((!depthBuffer) ||
(swapchainWidth != core.getImageWidth(depthBuffer)) ||
(swapchainHeight != core.getImageHeight(depthBuffer))) {
depthBuffer = core.createImage(
vk::Format::eD32Sfloat,
swapchainWidth,
swapchainHeight
);
}
cameraManager.update(dt);
mvp[0] = glm::rotate(glm::identity<glm::mat4>(), glm::pi<float>() / 2, glm::vec3(1, 0, 0));
mvp[1] = cameraManager.getActiveCamera().getView();
mvp[2] = cameraManager.getActiveCamera().getProjection();
textureProps->useColorTexture = useColorTexture? 1 : 0;
if (useColorTexture) {
material.specular = glm::vec3(0.2f);
materialBuffer.fill(&material, 1);
lightProps.lightAmbient = glm::vec3(0.6f);
lightBuffer.fill(&lightProps, 1);
} else {
material.specular = glm::vec3(1.0f);
materialBuffer.fill(&material, 1);
lightProps.lightAmbient = glm::vec3(0.2f);
lightBuffer.fill(&lightProps, 1);
}
auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
core.prepareImageForSampling(cmdStream, diffusemapImage.getHandle());
if (useNormalMappingShader) {
core.prepareImageForSampling(cmdStream, normalmapImage.getHandle());
}
core.recordDrawcallsToCmdStream(
cmdStream,
useNormalMappingShader? normalMappingPipeline : phongPipeline,
vkcv::PushConstants(0),
{
useNormalMappingShader? drawcallNormalMapping : drawcallPhong
},
{
swapchainInput,
depthBuffer
},
windowHandle
);
core.prepareSwapchainImageForPresent(cmdStream);
core.submitCommandStream(cmdStream);
gui.beginGUI();
ImGui::Begin("Settings");
ImGui::Checkbox("Use color texture", &useColorTexture);
ImGui::Checkbox("Use normal mapping shader", &useNormalMappingShader);
ImGui::End();
gui.endGUI();
});
matrixBuffer.unmap();
texturePropsBuffer.unmap();
return 0;
}
\ No newline at end of file
Subproject commit a9250ba29e90881676696744403c9de2d84fde90
Subproject commit 21562cea94ff11677477431f8d958c0d6577a415
resources/brick.png

131 B

resources/cubeMap/negx.jpg

131 B

resources/cubeMap/negy.jpg

131 B

resources/cubeMap/negz.jpg

131 B

resources/cubeMap/posx.jpg

131 B

resources/cubeMap/posy.jpg

131 B

resources/cubeMap/posz.jpg

131 B

Author
======
This is the work of Emil Persson, aka Humus.
http://www.humus.name
License
=======
This work is licensed under a Creative Commons Attribution 3.0 Unported License.
http://creativecommons.org/licenses/by/3.0/
resources/cv_logo.png

129 B

resources/normalmapping/diffusemap.png

132 B

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment