diff --git a/aggregated-graphics-samples.sln b/aggregated-graphics-samples.sln
index f96bcb9..5e0314b 100644
--- a/aggregated-graphics-samples.sln
+++ b/aggregated-graphics-samples.sln
@@ -58,6 +58,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shadowmapping-poisson-stabl
{67B01ECD-2613-4FA0-84F7-87F5BCF40EB1} = {67B01ECD-2613-4FA0-84F7-87F5BCF40EB1}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "normalmapping", "normalmapping\normalmapping.vcxproj", "{0CC7CBF2-BFCD-477F-A639-5CAB35FCBA6C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {8D9D4A3E-439A-4210-8879-259B20D992CA} = {8D9D4A3E-439A-4210-8879-259B20D992CA}
+ {51CC36B3-921E-4853-ACD5-CB6CBC27FBA1} = {51CC36B3-921E-4853-ACD5-CB6CBC27FBA1}
+ {67B01ECD-2613-4FA0-84F7-87F5BCF40EB1} = {67B01ECD-2613-4FA0-84F7-87F5BCF40EB1}
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -138,6 +145,14 @@ Global
{DD90A343-7897-442B-9D19-7FF0676E80EB}.Release|x64.Build.0 = Release|x64
{DD90A343-7897-442B-9D19-7FF0676E80EB}.Release|x86.ActiveCfg = Release|Win32
{DD90A343-7897-442B-9D19-7FF0676E80EB}.Release|x86.Build.0 = Release|Win32
+ {0CC7CBF2-BFCD-477F-A639-5CAB35FCBA6C}.Debug|x64.ActiveCfg = Debug|x64
+ {0CC7CBF2-BFCD-477F-A639-5CAB35FCBA6C}.Debug|x64.Build.0 = Debug|x64
+ {0CC7CBF2-BFCD-477F-A639-5CAB35FCBA6C}.Debug|x86.ActiveCfg = Debug|Win32
+ {0CC7CBF2-BFCD-477F-A639-5CAB35FCBA6C}.Debug|x86.Build.0 = Debug|Win32
+ {0CC7CBF2-BFCD-477F-A639-5CAB35FCBA6C}.Release|x64.ActiveCfg = Release|x64
+ {0CC7CBF2-BFCD-477F-A639-5CAB35FCBA6C}.Release|x64.Build.0 = Release|x64
+ {0CC7CBF2-BFCD-477F-A639-5CAB35FCBA6C}.Release|x86.ActiveCfg = Release|Win32
+ {0CC7CBF2-BFCD-477F-A639-5CAB35FCBA6C}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/assets/textures/steelplate1_normal-dx.dds b/assets/textures/steelplate1_normal-dx.dds
new file mode 100644
index 0000000..52b9f97
Binary files /dev/null and b/assets/textures/steelplate1_normal-dx.dds differ
diff --git a/framework/arcball.h b/framework/arcball.h
index b0e7116..1acb038 100644
--- a/framework/arcball.h
+++ b/framework/arcball.h
@@ -1,5 +1,6 @@
#pragma once
#include "core/noncopyable.h"
+#include "core/aligned.h"
#include "rapid/rapid.h"
/*
@@ -11,7 +12,7 @@
https://www.talisman.org/~erlkonig/misc/shoemake92-arcball.pdf
*/
-class Arcball : public core::NonCopyable
+class Arcball : public core::Aligned<16>, public core::NonCopyable
{
public:
Arcball(const rapid::vector2& center, float radius,
diff --git a/framework/framework.vcxproj b/framework/framework.vcxproj
index 2aaa181..ea1d494 100644
--- a/framework/framework.vcxproj
+++ b/framework/framework.vcxproj
@@ -144,6 +144,7 @@
+
diff --git a/framework/framework.vcxproj.filters b/framework/framework.vcxproj.filters
index cc3fa78..a127b09 100644
--- a/framework/framework.vcxproj.filters
+++ b/framework/framework.vcxproj.filters
@@ -99,6 +99,9 @@
Resource Files
+
+ Resource Files
+
diff --git a/framework/graphicsApp.cpp b/framework/graphicsApp.cpp
index 5fc3fb2..5945b57 100644
--- a/framework/graphicsApp.cpp
+++ b/framework/graphicsApp.cpp
@@ -21,9 +21,23 @@ GraphicsApp::GraphicsApp(const AppEntry& entry, const core::tstring& caption, ui
magma::descriptors::CombinedImageSampler(8)
}));
+ arcball = std::shared_ptr(new Trackball(rapid::vector2(width/2.f, height/2.f), 300.f, false));
timer = std::make_unique();
}
+void GraphicsApp::onMouseMove(int x, int y)
+{
+ arcball->rotate(rapid::vector2((float)x, height - (float)y));
+}
+
+void GraphicsApp::onMouseLButton(bool down, int x, int y)
+{
+ if (down)
+ arcball->touch(rapid::vector2((float)x, height - (float)y));
+ else
+ arcball->release();
+}
+
void GraphicsApp::createMultisampleFramebuffer(VkFormat colorFormat)
{
const VkFormat depthFormat = utilities::getSupportedDepthFormat(physicalDevice, false, true);
@@ -216,6 +230,8 @@ std::shared_ptr GraphicsApp::createFullscreenPipeline(c
void GraphicsApp::updateViewProjTransforms()
{
+ viewProj->updateView();
+ viewProj->updateProjection();
magma::helpers::mapScoped(viewProjTransforms,
[this](auto *transforms)
{
@@ -252,6 +268,8 @@ void GraphicsApp::updateObjectTransforms(const std::vectorupdateView();
+ lightViewProj->updateProjection();
magma::helpers::mapScoped(lightSource,
[this](auto *light)
{
diff --git a/framework/graphicsApp.h b/framework/graphicsApp.h
index c5fe293..a4db565 100644
--- a/framework/graphicsApp.h
+++ b/framework/graphicsApp.h
@@ -3,6 +3,7 @@
#include "core/alignedAllocator.h"
#include "common.h"
#include "viewProjection.h"
+#include "arcball.h"
#include "timer.h"
class GraphicsApp : public VulkanApp
@@ -10,6 +11,8 @@ class GraphicsApp : public VulkanApp
public:
GraphicsApp(const AppEntry& entry, const core::tstring& caption,
uint32_t width, uint32_t height, bool sRGB);
+ virtual void onMouseMove(int x, int y) override;
+ virtual void onMouseLButton(bool down, int x, int y) override;
protected:
virtual void createMultisampleFramebuffer(VkFormat colorFormat);
@@ -71,5 +74,6 @@ class GraphicsApp : public VulkanApp
std::shared_ptr trilinearClampToEdge;
std::shared_ptr anisotropicClampToEdge;
+ std::shared_ptr arcball;
std::unique_ptr timer;
};
diff --git a/framework/shaders/common/reconstruct.h b/framework/shaders/common/reconstruct.h
new file mode 100644
index 0000000..ad2c5c7
--- /dev/null
+++ b/framework/shaders/common/reconstruct.h
@@ -0,0 +1,7 @@
+vec3 reconstructNormal(vec2 xy)
+{
+ vec3 n;
+ n.xy = xy;
+ n.z = sqrt(1. - dot(xy, xy));
+ return normalize(n);
+}
diff --git a/framework/textureLoader.cpp b/framework/textureLoader.cpp
index 2e3e3b5..29c08cf 100644
--- a/framework/textureLoader.cpp
+++ b/framework/textureLoader.cpp
@@ -19,38 +19,106 @@ static VkFormat blockCompressedFormat(const gliml::context& ctx)
}
}
+static void loadBC5SignedNorm(const gliml::dds_header *hdr, VkExtent2D& extent, magma::Image::MipmapLayout& mipOffsets, VkDeviceSize& baseMipOffset)
+{
+ const unsigned char* dataBytePtr = (const unsigned char *)hdr;
+ dataBytePtr += sizeof(gliml::dds_header);
+
+ constexpr int MaxNumMipmaps = 16;
+ struct Face {
+ int numMipmaps;
+ struct mipmap {
+ int width;
+ int height;
+ int depth;
+ int size;
+ const void* data;
+ } mipmaps[MaxNumMipmaps];
+ } face;
+
+ face.numMipmaps = (hdr->dwMipMapCount == 0) ? 1 : hdr->dwMipMapCount;
+ // For each mipmap
+ for (int mipIndex = 0; mipIndex < face.numMipmaps; mipIndex++)
+ {
+ Face::mipmap& curMip = face.mipmaps[mipIndex];
+ // mipmap dimensions
+ int w = hdr->dwWidth >> mipIndex;
+ if (w <= 0) w = 1;
+ int h = hdr->dwHeight >> mipIndex;
+ if (h <= 0) h = 1;
+ int d = hdr->dwDepth >> mipIndex;
+ if (d <= 0) d = 1;
+ curMip.width = w;
+ curMip.height = h;
+ curMip.depth = d;
+ // Mipmap byte size
+ constexpr int bytesPerElement = 16;
+ curMip.size = ((w + 3) / 4) * ((h + 3) / 4) * d * bytesPerElement;
+ // Set and advance surface data pointer
+ curMip.data = dataBytePtr;
+ dataBytePtr += curMip.size;
+ }
+
+ extent.width = static_cast(face.mipmaps[0].width);
+ extent.height = static_cast(face.mipmaps[0].height);
+ for (int level = 1; level < face.numMipmaps; ++level)
+ { // Compute relative offset
+ const intptr_t mipOffset = (const uint8_t *)face.mipmaps[level].data - (const uint8_t *)face.mipmaps[level - 1].data;
+ mipOffsets.push_back(mipOffset);
+ }
+ // Skip DDS header
+ baseMipOffset = (const uint8_t *)face.mipmaps[0].data - (const uint8_t *)hdr;
+}
+
std::shared_ptr loadDxtTexture(std::shared_ptr cmdCopy, const std::string& filename)
{
std::ifstream file("../assets/textures/" + filename, std::ios::in | std::ios::binary | std::ios::ate);
if (!file.is_open())
- throw std::runtime_error("failed to open file ../assets/textures/\"" + filename + "\"");
+ throw std::runtime_error("failed to open file \"../assets/textures/" + filename + "\"");
const std::streamoff size = file.tellg();
file.seekg(0, std::ios::beg);
gliml::context ctx;
+ VkFormat format;
+ VkExtent2D extent;
VkDeviceSize baseMipOffset = 0;
+ magma::Image::MipmapLayout mipOffsets(1, 0);
std::shared_ptr buffer = std::make_shared(cmdCopy->getDevice(), size);
magma::helpers::mapScoped(buffer, [&](uint8_t *data)
{ // Read data to buffer
file.read(reinterpret_cast(data), size);
file.close();
ctx.enable_dxt(true);
- if (!ctx.load(data, static_cast(size)))
+ if (ctx.load(data, static_cast(size)))
+ { // Setup texture data description
+ format = blockCompressedFormat(ctx);
+ extent.width = static_cast(ctx.image_width(0, 0));
+ extent.height = static_cast(ctx.image_height(0, 0));
+ for (int level = 1; level < ctx.num_mipmaps(0); ++level)
+ { // Compute relative offset
+ const intptr_t mipOffset = (const uint8_t *)ctx.image_data(0, level) - (const uint8_t *)ctx.image_data(0, level - 1);
+ mipOffsets.push_back(mipOffset);
+ }
+ // Skip DDS header
+ baseMipOffset = (const uint8_t *)ctx.image_data(0, 0) - data;
+ }
+ else if (ctx.error() == GLIML_ERROR_INVALID_COMPRESSED_FORMAT)
+ { // Not supported, proceed ourself
+ const gliml::dds_header *hdr = (const gliml::dds_header *)data;
+ switch (hdr->ddspf.dwFourCC)
+ {
+ case MAKEFOURCC('B', 'C', '5', 'S'): // ATI1
+ format = VK_FORMAT_BC5_SNORM_BLOCK;
+ loadBC5SignedNorm(hdr, extent, mipOffsets, baseMipOffset);
+ break;
+ default:
+ throw std::runtime_error("unknown compressed format");
+ }
+ }
+ else
+ {
throw std::runtime_error("failed to load DDS texture");
- // Skip DDS header
- baseMipOffset = reinterpret_cast(ctx.image_data(0, 0)) - data;
+ }
});
- // Setup texture data description
- const VkFormat format = blockCompressedFormat(ctx);
- const VkExtent2D extent = {
- static_cast(ctx.image_width(0, 0)),
- static_cast(ctx.image_height(0, 0))
- };
- magma::Image::MipmapLayout mipOffsets(1, 0);
- for (int level = 1; level < ctx.num_mipmaps(0); ++level)
- { // Compute relative offset
- const intptr_t mipOffset = (const uint8_t *)ctx.image_data(0, level) - (const uint8_t *)ctx.image_data(0, level - 1);
- mipOffsets.push_back(mipOffset);
- }
// Upload texture data from buffer
magma::Image::CopyLayout bufferLayout{baseMipOffset, 0, 0};
std::shared_ptr image = std::make_shared(cmdCopy,
diff --git a/framework/viewProjection.cpp b/framework/viewProjection.cpp
index 154b8db..a638b2d 100644
--- a/framework/viewProjection.cpp
+++ b/framework/viewProjection.cpp
@@ -2,7 +2,7 @@
ViewProjection::ViewProjection(bool lhs) noexcept:
lhs(lhs),
- eyePos(0.f, 0.f, 0.f),
+ eyePos(0.f, 0.f, -1.f),
focusPos(0.f, 0.f, 0.f)
{}
diff --git a/framework/viewProjection.h b/framework/viewProjection.h
index e59c424..5ed39c4 100644
--- a/framework/viewProjection.h
+++ b/framework/viewProjection.h
@@ -39,7 +39,7 @@ class ViewProjection : public core::Aligned<16>, public core::NonCopyable
bool lhs;
rapid::float3 eyePos;
rapid::float3 focusPos;
- float fieldOfView = 0.f;
+ float fieldOfView = 45.f;
float aspectRatio = 1.f;
float zNear = 0.1f;
float zFar = 100.f;
diff --git a/normalmapping/normalmapping.cpp b/normalmapping/normalmapping.cpp
new file mode 100644
index 0000000..6dc81a6
--- /dev/null
+++ b/normalmapping/normalmapping.cpp
@@ -0,0 +1,199 @@
+#include "graphicsApp.h"
+#include "textureLoader.h"
+
+#include "quadric/include/torus.h"
+#include "quadric/include/sphere.h"
+
+class NormalMapping : public GraphicsApp
+{
+ struct Constants
+ {
+ VkBool32 showNormals;
+ };
+
+ std::unique_ptr torus;
+ std::unique_ptr sphere;
+ std::shared_ptr normalMap;
+ std::shared_ptr bumpPipeline;
+ std::shared_ptr spherePipeline;
+ DescriptorSet bumpDescriptor;
+ DescriptorSet fillDescriptor;
+
+ Constants constants = {false};
+
+public:
+ explicit NormalMapping(const AppEntry& entry):
+ GraphicsApp(entry, TEXT("Normal mapping"), 1280, 720, true)
+ {
+ setupViewProjection();
+ createTransformBuffer(2);
+ createMeshObjects();
+ loadTexture();
+ setupDescriptorSets();
+ setupGraphicsPipelines();
+
+ renderScene(drawCmdBuffer);
+ blit(msaaFramebuffer->getColorView(), FrontBuffer);
+ blit(msaaFramebuffer->getColorView(), BackBuffer);
+ }
+
+ virtual void render(uint32_t bufferIndex) override
+ {
+ updateTransforms();
+ submitCommandBuffers(bufferIndex);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2)); // Cap fps
+ }
+
+ virtual void onKeyDown(char key, int repeat, uint32_t flags) override
+ {
+ constexpr float step = 0.1f;
+ switch (key)
+ {
+ case AppKey::Left:
+ lightViewProj->translate(-step, 0.f, 0.f);
+ break;
+ case AppKey::Right:
+ lightViewProj->translate(step, 0.f, 0.f);
+ break;
+ case AppKey::Up:
+ lightViewProj->translate(0.f, step, 0.f);
+ break;
+ case AppKey::Down:
+ lightViewProj->translate(0.f, -step, 0.f);
+ break;
+ case AppKey::PgUp:
+ lightViewProj->translate(0.f, 0.f, step);
+ break;
+ case AppKey::PgDn:
+ lightViewProj->translate(0.f, 0.f, -step);
+ break;
+ case AppKey::Space:
+ constants.showNormals = !constants.showNormals;
+ setupGraphicsPipelines();
+ renderScene(drawCmdBuffer);
+ break;
+ }
+ updateTransforms();
+ updateLightSource();
+ VulkanApp::onKeyDown(key, repeat, flags);
+ }
+
+ virtual void onMouseWheel(float distance) override
+ {
+ float step = distance * 0.2f;
+ float z = viewProj->getPosition().z;
+ if ((z + step < -2.5f) && (z + step > -15.f))
+ viewProj->translate(0.f, 0.f, step);
+ updateViewProjTransforms();
+ }
+
+ void setupViewProjection()
+ {
+ viewProj = std::make_unique();
+ viewProj->setPosition(0.f, 0.f, -4.f);
+ viewProj->setFocus(0.f, 0.f, 0.f);
+ viewProj->setFieldOfView(60.f);
+ viewProj->setNearZ(1.f);
+ viewProj->setFarZ(100.f);
+ viewProj->setAspectRatio(width / (float)height);
+ viewProj->updateView();
+ viewProj->updateProjection();
+
+ lightViewProj = std::make_unique();
+ lightViewProj->setPosition(-1., 1.f, -1.f);
+
+ updateViewProjTransforms();
+ }
+
+ void updateTransforms()
+ {
+ rapid::matrix lightTransform = rapid::translation(rapid::vector3(lightViewProj->getPosition()));
+ const std::vector> transforms = {
+ arcball->transform(),
+ lightTransform
+ };
+ updateObjectTransforms(transforms);
+ }
+
+ void createMeshObjects()
+ {
+ torus = std::make_unique(0.4f, 1.0f, 64, 128, true, cmdCopyBuf);
+ sphere = std::make_unique(0.02f, 8, 8, true, cmdCopyBuf);
+ }
+
+ void loadTexture()
+ { // https://freepbr.com/materials/steel-plate1/
+ normalMap = loadDxtTexture(cmdCopyImg, "steelplate1_normal-dx.dds");
+ }
+
+ void setupDescriptorSets()
+ {
+ bumpDescriptor.layout = std::shared_ptr(new magma::DescriptorSetLayout(device,
+ {
+ magma::bindings::VertexFragmentStageBinding(0, magma::descriptors::DynamicUniformBuffer(1)),
+ magma::bindings::FragmentStageBinding(1, magma::descriptors::UniformBuffer(1)),
+ magma::bindings::FragmentStageBinding(2, magma::descriptors::UniformBuffer(1)),
+ magma::bindings::FragmentStageBinding(3, magma::descriptors::CombinedImageSampler(1))
+ }));
+ bumpDescriptor.set = descriptorPool->allocateDescriptorSet(bumpDescriptor.layout);
+ bumpDescriptor.set->update(0, transforms);
+ bumpDescriptor.set->update(1, viewProjTransforms);
+ bumpDescriptor.set->update(2, lightSource);
+ bumpDescriptor.set->update(3, normalMap, anisotropicClampToEdge);
+
+ fillDescriptor.layout = std::shared_ptr(new magma::DescriptorSetLayout(device,
+ {
+ magma::bindings::VertexStageBinding(0, magma::descriptors::DynamicUniformBuffer(1))
+ }));
+ fillDescriptor.set = descriptorPool->allocateDescriptorSet(fillDescriptor.layout);
+ fillDescriptor.set->update(0, transforms);
+ }
+
+ void setupGraphicsPipelines()
+ {
+ std::shared_ptr specialization(new magma::Specialization(constants,
+ {
+ magma::SpecializationEntry(0, &Constants::showNormals)
+ }
+ ));
+ bumpPipeline = createCommonSpecializedPipeline(
+ "transform.o", "bump.o",
+ std::move(specialization),
+ torus->getVertexInput(),
+ bumpDescriptor.layout);
+ if (!spherePipeline)
+ {
+ spherePipeline = createCommonPipeline(
+ "transform.o", "fill.o",
+ sphere->getVertexInput(),
+ fillDescriptor.layout);
+ }
+ }
+
+ void renderScene(std::shared_ptr cmdBuffer)
+ {
+ cmdBuffer->begin();
+ {
+ cmdBuffer->beginRenderPass(msaaFramebuffer->getRenderPass(), msaaFramebuffer->getFramebuffer(),
+ {
+ magma::ClearColor(0.1f, 0.243f, 0.448f, 1.f),
+ magma::clears::depthOne
+ });
+ {
+ cmdBuffer->bindPipeline(bumpPipeline);
+ cmdBuffer->bindDescriptorSet(bumpPipeline, bumpDescriptor.set, transforms->getDynamicOffset(0));
+ torus->draw(cmdBuffer);
+ cmdBuffer->bindPipeline(spherePipeline);
+ cmdBuffer->bindDescriptorSet(spherePipeline, fillDescriptor.set, transforms->getDynamicOffset(1));
+ sphere->draw(cmdBuffer);
+ }
+ cmdBuffer->endRenderPass();
+ }
+ cmdBuffer->end();
+ }
+};
+
+std::unique_ptr appFactory(const AppEntry& entry)
+{
+ return std::unique_ptr(new NormalMapping(entry));
+}
diff --git a/normalmapping/normalmapping.vcxproj b/normalmapping/normalmapping.vcxproj
new file mode 100644
index 0000000..0fea745
--- /dev/null
+++ b/normalmapping/normalmapping.vcxproj
@@ -0,0 +1,186 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 15.0
+ {0CC7CBF2-BFCD-477F-A639-5CAB35FCBA6C}
+ normalmapping
+ 10.0.16299.0
+
+
+
+ Application
+ true
+ v141
+ Unicode
+
+
+ Application
+ false
+ v141
+ true
+ Unicode
+
+
+ Application
+ true
+ v141
+ Unicode
+
+
+ Application
+ false
+ v141
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ $(VK_SDK_PATH)\Include;..\third-party;..\framework
+ NDEBUG;VK_USE_PLATFORM_WIN32_KHR;%(PreprocessorDefinitions)
+ MultiThreaded
+
+
+ true
+ true
+ Windows
+ $(VK_SDK_PATH)\Lib;..\x64\Release
+ vulkan-1.lib;magma.lib;quadric.lib;framework.lib;Shcore.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ $(VK_SDK_PATH)\Include;..\third-party;..\framework
+ _DEBUG;VK_USE_PLATFORM_WIN32_KHR;%(PreprocessorDefinitions)
+
+
+ Windows
+ $(VK_SDK_PATH)\Lib32;..\Debug
+ vulkan-1.lib;magma.lib;quadric.lib;framework.lib;Shcore.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ $(VK_SDK_PATH)\Include;..\third-party;..\framework
+ _DEBUG;VK_USE_PLATFORM_WIN32_KHR;%(PreprocessorDefinitions)
+
+
+ Windows
+ $(VK_SDK_PATH)\Lib;..\x64\Debug
+ vulkan-1.lib;magma.lib;quadric.lib;framework.lib;Shcore.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ $(VK_SDK_PATH)\Include;..\third-party;..\framework
+ NDEBUG;VK_USE_PLATFORM_WIN32_KHR;%(PreprocessorDefinitions)
+ MultiThreaded
+
+
+ true
+ true
+ Windows
+ $(VK_SDK_PATH)\Lib32;..\Release
+ vulkan-1.lib;magma.lib;quadric.lib;framework.lib;Shcore.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+ Document
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ %(Filename).o
+ %(Filename).o
+ %(Filename).o
+ %(Filename).o
+
+
+ Document
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ %(Filename).o
+ %(Filename).o
+ %(Filename).o
+ %(Filename).o
+
+
+
+
+ Document
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ %(Filename).o
+ %(Filename).o
+ %(Filename).o
+ %(Filename).o
+
+
+
+
+
+
\ No newline at end of file
diff --git a/normalmapping/normalmapping.vcxproj.filters b/normalmapping/normalmapping.vcxproj.filters
new file mode 100644
index 0000000..98c952b
--- /dev/null
+++ b/normalmapping/normalmapping.vcxproj.filters
@@ -0,0 +1,33 @@
+
+
+
+
+ {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;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
+
+ Resource Files
+
+
+ Resource Files
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/normalmapping/shaders/bump.frag b/normalmapping/shaders/bump.frag
new file mode 100644
index 0000000..2271bd1
--- /dev/null
+++ b/normalmapping/shaders/bump.frag
@@ -0,0 +1,45 @@
+#version 450
+#extension GL_GOOGLE_include_directive : enable
+#include "common/transforms.h"
+#include "common/reconstruct.h"
+#include "common/cotangentFrame.h"
+#include "common/sRGB.h"
+
+layout(constant_id = 0) const bool c_showNormals = false;
+
+layout(binding = 2) uniform Light
+{
+ vec3 viewPos;
+} light;
+
+layout(binding = 3) uniform sampler2D normalMap;
+
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec3 viewPos;
+layout(location = 2) in vec3 normal;
+layout(location = 3) in vec2 texCoord;
+
+layout(location = 0) out vec3 oColor;
+
+void main()
+{
+ vec2 nxy = texture(normalMap, texCoord).xy;
+
+ // compute per-pixel cotangent frame
+ vec3 N = normalize(normal);
+ mat3 TBN = cotangentFrame(N, position, texCoord);
+
+ // transform from texture space to object space
+ vec3 normal = TBN * reconstructNormal(nxy);
+ // transform from object space to view space
+ vec3 viewNormal = mat3(normalMatrix) * normal;
+
+ vec3 n = normalize(viewNormal);
+ vec3 l = normalize(light.viewPos - viewPos);
+ float NdL = dot(n, l);
+
+ if (c_showNormals)
+ oColor = linear(normal * .5 + .5);
+ else
+ oColor = vec3(max(NdL, 0.));
+}
diff --git a/normalmapping/shaders/fill.frag b/normalmapping/shaders/fill.frag
new file mode 100644
index 0000000..dd3e227
--- /dev/null
+++ b/normalmapping/shaders/fill.frag
@@ -0,0 +1,8 @@
+#version 450
+
+layout(location = 0) out vec3 oColor;
+
+void main()
+{
+ oColor = vec3(1, 1, 0);
+}
diff --git a/normalmapping/shaders/transform.vert b/normalmapping/shaders/transform.vert
new file mode 100644
index 0000000..bee454a
--- /dev/null
+++ b/normalmapping/shaders/transform.vert
@@ -0,0 +1,25 @@
+#version 450
+#extension GL_GOOGLE_include_directive : enable
+#include "common/transforms.h"
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec3 normal;
+layout(location = 2) in vec2 texCoord;
+
+layout(location = 0) out vec3 oPos;
+layout(location = 1) out vec3 oViewPos;
+layout(location = 2) out vec3 oNormal;
+layout(location = 3) out vec2 oTexCoord;
+
+out gl_PerVertex {
+ vec4 gl_Position;
+};
+
+void main()
+{
+ oPos = position.xyz;
+ oViewPos = (worldView * position).xyz;
+ oNormal = normal;
+ oTexCoord = texCoord;
+ gl_Position = worldViewProj * position;
+}
diff --git a/screenshots/normalmapping.jpg b/screenshots/normalmapping.jpg
new file mode 100644
index 0000000..bc2a384
Binary files /dev/null and b/screenshots/normalmapping.jpg differ