diff --git a/CREDITS.md b/CREDITS.md
index 9bbbc1ae..bc9002f4 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -1,16 +1,16 @@
## Credits
Thanks to the authors of these libraries :
- [OpenGL Mathematics (GLM)](https://github.com/g-truc/glm)
-- [OpenGL Image (GLI)](https://github.com/g-truc/gli)
- [Open Asset Import Library](https://github.com/assimp/assimp)
+Thanks to Ben Clayton from Google LLC for contributing the [HLSL shaders](data/hlsl).
+
And a huge thanks to the Vulkan Working Group, Vulkan Advisory Panel, the fine people at [LunarG](http://www.lunarg.com), Baldur Karlsson ([RenderDoc](https://github.com/baldurk/renderdoc)) and everyone from the different IHVs that helped me get the examples up and working on their hardware!
## Attributions / Licenses
Please note that (some) models and textures use separate licenses. Please comply to these when redistributing or using them in your own projects :
- Cubemap used in cubemap example by [Emil Persson(aka Humus)](http://www.humus.name/)
- Armored knight model used in deferred example by [Gabriel Piacenti](http://opengameart.org/users/piacenti)
-- Voyager model by [NASA](http://nasa3d.arc.nasa.gov/models)
- Old deer model used in tessellation example by [Čestmír Dammer](http://opengameart.org/users/cdmir)
- Hidden treasure scene used in pipeline and debug marker examples by [Laurynas Jurgila](http://www.blendswap.com/user/PigArt)
- Sibenik Cathedral model by Marko Dabrovic, using updated version by [Kenzie Lamar and Morgan McGuire](http://graphics.cs.williams.edu/data/meshes.xml)
diff --git a/README.md b/README.md
index da51b273..edf424af 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Vulkan C++ examples and demos
-A comprehensive collection of open source C++ examples for [Vulkan®](https://www.khronos.org/vulkan/), the new graphics and compute API from Khronos.
+A comprehensive collection of open source C++ examples for [Vulkan®](https://www.khronos.org/vulkan/), the new generation graphics and compute API from Khronos.
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=BHXPMV6ZKPH9E)
@@ -9,6 +9,7 @@ A comprehensive collection of open source C++ examples for [Vulkan®](https://ww
+ [Cloning](#Cloning)
+ [Assets](#Assets)
+ [Building](#Building)
++ [Shaders](#Shaders)
+ [Examples](#Examples)
+ [Basics](#Basics)
+ [Advanced](#Advanced)
@@ -60,6 +61,10 @@ The repository contains everything required to compile and build the examples on
See [BUILD.md](BUILD.md) for details on how to build for the different platforms.
+## Shaders
+
+Vulkan consumes shaders in an intermediate representation called SPIR-V. This makes it possible to use different shader languages by compiling them to that bytecode format. The primary shader language used here is [GLSL](data/shaders) but thanks to an external contribution you'll also find [HLSL](data/hlsl) shader sources.
+
## Examples
### Basics
diff --git a/data/hlsl/README.md b/data/hlsl/README.md
new file mode 100644
index 00000000..dfb2c79d
--- /dev/null
+++ b/data/hlsl/README.md
@@ -0,0 +1,18 @@
+## HLSL Shaders
+
+This directory contains a fork of the shaders found in [data/shaders](https://github.com/SaschaWillems/Vulkan/tree/master/data/shaders), re-written in HLSL.
+These can be compiled with [DXC](https://github.com/microsoft/DirectXShaderCompiler) using the `compile.py` script.
+
+### Known issues
+
+- specialization constants can't be used to specify array size.
+- `gl_PointCoord` not supported. HLSL has no equivalent. We changed the shaders to calulate the PointCoord manually in the shader. (`computenbody`, `computeparticles`, `particlefire` examples).
+- HLSL doesn't have inverse operation (`deferred`, `hdr`, `instancing`, `skeletalanimation` & `texturecubemap` examples).
+- `modf` causes compilation to fail without errors or warnings. (`modf` not used by any examples, easily confused with fmod)
+- In `specializationconstants` example, shader compilation fails with error:
+ ```
+ --- Error msg: fatal error: failed to optimize SPIR-V: Id 10 is defined more than once
+ ```
+ When multiple constant ids are defined and have different types. We work around this problem by making all constant ids the same type, then use `asfloat`, `asint` or `asuint` to get the original value in the shader.
+- `gl_RayTmaxNV` not supported. (`nv_ray_tracing_*` examples)
+- HLSL interface for sparse residency textures is different from GLSL interface. After translating from HLSL to GLSL the shaders behave slightly different. Most important parts do behave identically though.
\ No newline at end of file
diff --git a/data/hlsl/base/textoverlay.frag b/data/hlsl/base/textoverlay.frag
new file mode 100644
index 00000000..e9d9ba76
--- /dev/null
+++ b/data/hlsl/base/textoverlay.frag
@@ -0,0 +1,10 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureFont : register(t0);
+SamplerState samplerFont : register(s0);
+
+float4 main([[vk::location(0)]]float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ float color = textureFont.Sample(samplerFont, inUV).r;
+ return float4(color.xxx, 1.0);
+}
diff --git a/data/hlsl/base/textoverlay.vert b/data/hlsl/base/textoverlay.vert
new file mode 100644
index 00000000..a040eaaa
--- /dev/null
+++ b/data/hlsl/base/textoverlay.vert
@@ -0,0 +1,21 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+ [[vk::location(0)]]float2 Pos : POSITION0;
+ [[vk::location(1)]]float2 UV : TEXCOORD0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+ [[vk::location(0)]]float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = float4(input.Pos, 0.0, 1.0);
+ output.UV = input.UV;
+ return output;
+}
diff --git a/data/hlsl/base/uioverlay.frag b/data/hlsl/base/uioverlay.frag
new file mode 100644
index 00000000..9bec808d
--- /dev/null
+++ b/data/hlsl/base/uioverlay.frag
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+Texture2D fontTexture : register(t0);
+SamplerState fontSampler : register(s0);
+
+struct VSOutput
+{
+ [[vk::location(0)]]float2 UV : TEXCOORD0;
+ [[vk::location(1)]]float4 Color : COLOR0;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ return input.Color * fontTexture.Sample(fontSampler, input.UV);
+}
\ No newline at end of file
diff --git a/data/hlsl/base/uioverlay.vert b/data/hlsl/base/uioverlay.vert
new file mode 100644
index 00000000..be30fd74
--- /dev/null
+++ b/data/hlsl/base/uioverlay.vert
@@ -0,0 +1,33 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+ [[vk::location(0)]]float2 Pos : POSITION0;
+ [[vk::location(1)]]float2 UV : TEXCOORD0;
+ [[vk::location(2)]]float4 Color : COLOR0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+ [[vk::location(0)]]float2 UV : TEXCOORD0;
+ [[vk::location(1)]]float4 Color : COLOR0;
+};
+
+struct PushConstants
+{
+ float2 scale;
+ float2 translate;
+};
+
+[[vk::push_constant]]
+PushConstants pushConstants;
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = float4(input.Pos * pushConstants.scale + pushConstants.translate, 0.0, 1.0);
+ output.UV = input.UV;
+ output.Color = input.Color;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/bloom/colorpass.frag b/data/hlsl/bloom/colorpass.frag
new file mode 100644
index 00000000..9949fd3f
--- /dev/null
+++ b/data/hlsl/bloom/colorpass.frag
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+Texture2D colorMapTexture : register(t1);
+SamplerState colorMapSampler : register(s1);
+
+struct VSOutput
+{
+ [[vk::location(0)]]float3 Color : COLOR0;
+ [[vk::location(1)]]float2 UV : TEXCOORD0;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ return float4(input.Color, 1);
+}
\ No newline at end of file
diff --git a/data/hlsl/bloom/colorpass.vert b/data/hlsl/bloom/colorpass.vert
new file mode 100644
index 00000000..53dad1b2
--- /dev/null
+++ b/data/hlsl/bloom/colorpass.vert
@@ -0,0 +1,31 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+ [[vk::location(0)]]float4 Pos : POSITION0;
+ [[vk::location(1)]]float2 UV : TEXCOORD0;
+ [[vk::location(2)]]float3 Color : COLOR0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+ [[vk::location(0)]]float3 Color : COLOR0;
+ [[vk::location(1)]]float2 UV : TEXCOORD0;
+};
+
+cbuffer UBO : register(b0)
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV;
+ output.Color = input.Color;
+ output.Pos = mul(projection, mul(view, mul(model, input.Pos)));
+ return output;
+}
diff --git a/data/hlsl/bloom/gaussblur.frag b/data/hlsl/bloom/gaussblur.frag
new file mode 100644
index 00000000..5da50569
--- /dev/null
+++ b/data/hlsl/bloom/gaussblur.frag
@@ -0,0 +1,43 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+cbuffer UBO : register(b0)
+{
+ float blurScale;
+ float blurStrength;
+};
+
+[[vk::constant_id(0)]] const int blurdirection = 0;
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ float weight[5];
+ weight[0] = 0.227027;
+ weight[1] = 0.1945946;
+ weight[2] = 0.1216216;
+ weight[3] = 0.054054;
+ weight[4] = 0.016216;
+
+ float2 textureSize;
+ textureColor.GetDimensions(textureSize.x, textureSize.y);
+ float2 tex_offset = 1.0 / textureSize * blurScale; // gets size of single texel
+ float3 result = textureColor.Sample(samplerColor, inUV).rgb * weight[0]; // current fragment's contribution
+ for(int i = 1; i < 5; ++i)
+ {
+ if (blurdirection == 1)
+ {
+ // H
+ result += textureColor.Sample(samplerColor, inUV + float2(tex_offset.x * i, 0.0)).rgb * weight[i] * blurStrength;
+ result += textureColor.Sample(samplerColor, inUV - float2(tex_offset.x * i, 0.0)).rgb * weight[i] * blurStrength;
+ }
+ else
+ {
+ // V
+ result += textureColor.Sample(samplerColor, inUV + float2(0.0, tex_offset.y * i)).rgb * weight[i] * blurStrength;
+ result += textureColor.Sample(samplerColor, inUV - float2(0.0, tex_offset.y * i)).rgb * weight[i] * blurStrength;
+ }
+ }
+ return float4(result, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/bloom/gaussblur.vert b/data/hlsl/bloom/gaussblur.vert
new file mode 100644
index 00000000..a9c3d551
--- /dev/null
+++ b/data/hlsl/bloom/gaussblur.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+ [[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/bloom/phongpass.frag b/data/hlsl/bloom/phongpass.frag
new file mode 100644
index 00000000..3daed2c2
--- /dev/null
+++ b/data/hlsl/bloom/phongpass.frag
@@ -0,0 +1,32 @@
+// Copyright 2020 Google LLC
+
+Texture2D colorMapTexture : register(t1);
+SamplerState colorMapSampler : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 ambient = float3(0.0f, 0.0f, 0.0f);
+
+ // Adjust light calculations for glow color
+ if ((input.Color.r >= 0.9) || (input.Color.g >= 0.9) || (input.Color.b >= 0.9))
+ {
+ ambient = input.Color * 0.25;
+ }
+
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * input.Color;
+ float3 specular = pow(max(dot(R, V), 0.0), 8.0) * float3(0.75f, 0.75f, 0.75f);
+ return float4(ambient + diffuse + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/bloom/phongpass.vert b/data/hlsl/bloom/phongpass.vert
new file mode 100644
index 00000000..198c77c6
--- /dev/null
+++ b/data/hlsl/bloom/phongpass.vert
@@ -0,0 +1,42 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 Normal : NORMAL0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+cbuffer UBO : register(b0)
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.UV = input.UV;
+ output.Pos = mul(projection, mul(view, mul(model, input.Pos)));
+
+ float3 lightPos = float3(-5.0, -5.0, 0.0);
+ float4 pos = mul(view, mul(model, input.Pos));
+ output.Normal = mul((float4x3)mul(view, model), input.Normal).xyz;
+ output.LightVec = lightPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
diff --git a/data/hlsl/bloom/skybox.frag b/data/hlsl/bloom/skybox.frag
new file mode 100644
index 00000000..18460ed9
--- /dev/null
+++ b/data/hlsl/bloom/skybox.frag
@@ -0,0 +1,9 @@
+// Copyright 2020 Google LLC
+
+TextureCube textureCubeMap : register(t1);
+SamplerState samplerCubeMap : register(s1);
+
+float4 main([[vk::location(0)]] float3 inUVW : NORMAL0) : SV_TARGET
+{
+ return textureCubeMap.Sample(samplerCubeMap, inUVW);
+}
\ No newline at end of file
diff --git a/data/hlsl/bloom/skybox.vert b/data/hlsl/bloom/skybox.vert
new file mode 100644
index 00000000..212e404f
--- /dev/null
+++ b/data/hlsl/bloom/skybox.vert
@@ -0,0 +1,22 @@
+// Copyright 2020 Google LLC
+
+cbuffer UBO : register(b0)
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+ [[vk::location(0)]] float3 UVW : NORMAL0;
+};
+
+VSOutput main([[vk::location(0)]] float3 inPos : POSITION0)
+{
+ VSOutput output = (VSOutput)0;
+ output.UVW = inPos;
+ output.Pos = mul(projection, mul(view, mul(model, float4(inPos.xyz, 1.0))));
+ return output;
+}
diff --git a/data/hlsl/compile.py b/data/hlsl/compile.py
new file mode 100644
index 00000000..bad1f59b
--- /dev/null
+++ b/data/hlsl/compile.py
@@ -0,0 +1,73 @@
+# Copyright 2020 Google LLC
+
+import argparse
+import fileinput
+import os
+import subprocess
+import sys
+
+parser = argparse.ArgumentParser(description='Compile all .hlsl shaders')
+parser.add_argument('--dxc', type=str, help='path to DXC executable')
+args = parser.parse_args()
+
+def findDXC():
+ def isExe(path):
+ return os.path.isfile(path) and os.access(path, os.X_OK)
+
+ if args.dxc != None and isExe(args.dxc):
+ return args.dxc
+
+ exe_name = "dxc"
+ if os.name == "nt":
+ exe_name += ".exe"
+
+ for exe_dir in os.environ["PATH"].split(os.pathsep):
+ full_path = os.path.join(exe_dir, exe_name)
+ if isExe(full_path):
+ return full_path
+
+ sys.exit("Could not find DXC executable on PATH, and was not specified with --dxc")
+
+dxc_path = findDXC()
+dir_path = os.path.dirname(os.path.realpath(__file__))
+dir_path = dir_path.replace('\\', '/')
+for root, dirs, files in os.walk(dir_path):
+ for file in files:
+ if file.endswith(".vert") or file.endswith(".frag") or file.endswith(".comp") or file.endswith(".geom") or file.endswith(".tesc") or file.endswith(".tese") or file.endswith(".rgen") or file.endswith(".rchit") or file.endswith(".rmiss"):
+ hlsl_file = os.path.join(root, file)
+
+ spv_out = os.path.abspath(os.path.join(dir_path, "..", "shaders", os.path.relpath(hlsl_file, dir_path) + ".spv"))
+
+ # Make the spv directory if it does not already exist
+ spv_dir = os.path.dirname(spv_out)
+ if not os.path.exists(spv_dir):
+ os.makedirs(spv_dir)
+
+ profile = ''
+ if(hlsl_file.find('.vert') != -1):
+ profile = 'vs_6_1'
+ elif(hlsl_file.find('.frag') != -1):
+ profile = 'ps_6_1'
+ elif(hlsl_file.find('.comp') != -1):
+ profile = 'cs_6_1'
+ elif(hlsl_file.find('.geom') != -1):
+ profile = 'gs_6_1'
+ elif(hlsl_file.find('.tesc') != -1):
+ profile = 'hs_6_1'
+ elif(hlsl_file.find('.tese') != -1):
+ profile = 'ds_6_1'
+ elif(hlsl_file.find('.rgen') != -1 or
+ hlsl_file.find('.rchit') != -1 or
+ hlsl_file.find('.rmiss') != -1):
+ profile = 'lib_6_3'
+
+ print('Compiling %s' % (hlsl_file))
+ subprocess.check_output([
+ dxc_path,
+ '-spirv',
+ '-T', profile,
+ '-E', 'main',
+ '-fspv-extension=SPV_NV_ray_tracing',
+ '-fspv-extension=SPV_KHR_multiview',
+ hlsl_file,
+ '-Fo', spv_out])
diff --git a/data/hlsl/computecloth/cloth.comp b/data/hlsl/computecloth/cloth.comp
new file mode 100644
index 00000000..2ef2b880
--- /dev/null
+++ b/data/hlsl/computecloth/cloth.comp
@@ -0,0 +1,154 @@
+// Copyright 2020 Google LLC
+
+struct Particle {
+ float4 pos;
+ float4 vel;
+ float4 uv;
+ float4 normal;
+ float pinned;
+};
+
+[[vk::binding(0)]]
+StructuredBuffer particleIn;
+[[vk::binding(1)]]
+RWStructuredBuffer particleOut;
+
+struct UBO
+{
+ float deltaT;
+ float particleMass;
+ float springStiffness;
+ float damping;
+ float restDistH;
+ float restDistV;
+ float restDistD;
+ float sphereRadius;
+ float4 spherePos;
+ float4 gravity;
+ int2 particleCount;
+};
+
+cbuffer ubo : register(b2)
+{
+ UBO params;
+};
+
+struct PushConstants
+{
+ uint calculateNormals;
+};
+
+[[vk::push_constant]]
+PushConstants pushConstants;
+
+float3 springForce(float3 p0, float3 p1, float restDist)
+{
+ float3 dist = p0 - p1;
+ return normalize(dist) * params.springStiffness * (length(dist) - restDist);
+}
+
+[numthreads(10, 10, 1)]
+void main(uint3 id : SV_DispatchThreadID)
+{
+ uint index = id.y * params.particleCount.x + id.x;
+ if (index > params.particleCount.x * params.particleCount.y)
+ return;
+
+ // Pinned?
+ if (particleIn[index].pinned == 1.0) {
+ particleOut[index].pos = particleOut[index].pos;
+ particleOut[index].vel = float4(0, 0, 0, 0);
+ return;
+ }
+
+ // Initial force from gravity
+ float3 force = params.gravity.xyz * params.particleMass;
+
+ float3 pos = particleIn[index].pos.xyz;
+ float3 vel = particleIn[index].vel.xyz;
+
+ // Spring forces from neighboring particles
+ // left
+ if (id.x > 0) {
+ force += springForce(particleIn[index-1].pos.xyz, pos, params.restDistH);
+ }
+ // right
+ if (id.x < params.particleCount.x - 1) {
+ force += springForce(particleIn[index + 1].pos.xyz, pos, params.restDistH);
+ }
+ // upper
+ if (id.y < params.particleCount.y - 1) {
+ force += springForce(particleIn[index + params.particleCount.x].pos.xyz, pos, params.restDistV);
+ }
+ // lower
+ if (id.y > 0) {
+ force += springForce(particleIn[index - params.particleCount.x].pos.xyz, pos, params.restDistV);
+ }
+ // upper-left
+ if ((id.x > 0) && (id.y < params.particleCount.y - 1)) {
+ force += springForce(particleIn[index + params.particleCount.x - 1].pos.xyz, pos, params.restDistD);
+ }
+ // lower-left
+ if ((id.x > 0) && (id.y > 0)) {
+ force += springForce(particleIn[index - params.particleCount.x - 1].pos.xyz, pos, params.restDistD);
+ }
+ // upper-right
+ if ((id.x < params.particleCount.x - 1) && (id.y < params.particleCount.y - 1)) {
+ force += springForce(particleIn[index + params.particleCount.x + 1].pos.xyz, pos, params.restDistD);
+ }
+ // lower-right
+ if ((id.x < params.particleCount.x - 1) && (id.y > 0)) {
+ force += springForce(particleIn[index - params.particleCount.x + 1].pos.xyz, pos, params.restDistD);
+ }
+
+ force += (-params.damping * vel);
+
+ // Integrate
+ float3 f = force * (1.0 / params.particleMass);
+ particleOut[index].pos = float4(pos + vel * params.deltaT + 0.5 * f * params.deltaT * params.deltaT, 1.0);
+ particleOut[index].vel = float4(vel + f * params.deltaT, 0.0);
+
+ // Sphere collision
+ float3 sphereDist = particleOut[index].pos.xyz - params.spherePos.xyz;
+ if (length(sphereDist) < params.sphereRadius + 0.01) {
+ // If the particle is inside the sphere, push it to the outer radius
+ particleOut[index].pos.xyz = params.spherePos.xyz + normalize(sphereDist) * (params.sphereRadius + 0.01);
+ // Cancel out velocity
+ particleOut[index].vel = float4(0, 0, 0, 0);
+ }
+
+ // Normals
+ if (pushConstants.calculateNormals == 1) {
+ float3 normal = float3(0, 0, 0);
+ float3 a, b, c;
+ if (id.y > 0) {
+ if (id.x > 0) {
+ a = particleIn[index - 1].pos.xyz - pos;
+ b = particleIn[index - params.particleCount.x - 1].pos.xyz - pos;
+ c = particleIn[index - params.particleCount.x].pos.xyz - pos;
+ normal += cross(a,b) + cross(b,c);
+ }
+ if (id.x < params.particleCount.x - 1) {
+ a = particleIn[index - params.particleCount.x].pos.xyz - pos;
+ b = particleIn[index - params.particleCount.x + 1].pos.xyz - pos;
+ c = particleIn[index + 1].pos.xyz - pos;
+ normal += cross(a,b) + cross(b,c);
+ }
+ }
+ if (id.y < params.particleCount.y - 1) {
+ if (id.x > 0) {
+ a = particleIn[index + params.particleCount.x].pos.xyz - pos;
+ b = particleIn[index + params.particleCount.x - 1].pos.xyz - pos;
+ c = particleIn[index - 1].pos.xyz - pos;
+ normal += cross(a,b) + cross(b,c);
+ }
+ if (id.x < params.particleCount.x - 1) {
+ a = particleIn[index + 1].pos.xyz - pos;
+ b = particleIn[index + params.particleCount.x + 1].pos.xyz - pos;
+ c = particleIn[index + params.particleCount.x].pos.xyz - pos;
+ normal += cross(a,b) + cross(b,c);
+ }
+ }
+ particleOut[index].normal = float4(normalize(normal), 0.0f);
+ }
+}
\ No newline at end of file
diff --git a/data/hlsl/computecloth/cloth.frag b/data/hlsl/computecloth/cloth.frag
new file mode 100644
index 00000000..46612dc3
--- /dev/null
+++ b/data/hlsl/computecloth/cloth.frag
@@ -0,0 +1,24 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]]float2 UV : TEXCOORD0;
+[[vk::location(1)]]float3 Normal : NORMAL0;
+[[vk::location(2)]]float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]]float3 LightVec : TEXCOORD2;
+};
+
+float4 main (VSOutput input) : SV_TARGET
+{
+ float3 color = textureColor.Sample(samplerColor, input.UV).rgb;
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.15) * float3(1, 1, 1);
+ float3 specular = pow(max(dot(R, V), 0.0), 8.0) * float3(0.2, 0.2, 0.2);
+ return float4(diffuse * color.rgb + specular, 1.0);
+}
diff --git a/data/hlsl/computecloth/cloth.vert b/data/hlsl/computecloth/cloth.vert
new file mode 100644
index 00000000..00d46927
--- /dev/null
+++ b/data/hlsl/computecloth/cloth.vert
@@ -0,0 +1,43 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0)
+{
+ UBO ubo;
+};
+
+VSOutput main (VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV;
+ output.Normal = input.Normal.xyz;
+ float4 eyePos = mul(ubo.modelview, float4(input.Pos.x, input.Pos.y, input.Pos.z, 1.0));
+ output.Pos = mul(ubo.projection, eyePos);
+ float4 pos = float4(input.Pos, 1.0);
+ float3 lPos = ubo.lightPos.xyz;
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/computecloth/sphere.frag b/data/hlsl/computecloth/sphere.frag
new file mode 100644
index 00000000..207db7aa
--- /dev/null
+++ b/data/hlsl/computecloth/sphere.frag
@@ -0,0 +1,20 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 ViewVec : TEXCOORD0;
+[[vk::location(2)]] float3 LightVec : TEXCOORD1;
+};
+
+float4 main (VSOutput input) : SV_TARGET
+{
+ float3 color = float3(0.5, 0.5, 0.5);
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.15);
+ float3 specular = pow(max(dot(R, V), 0.0), 32.0);
+ return float4(diffuse * color.rgb + specular, 1.0);
+}
diff --git a/data/hlsl/computecloth/sphere.vert b/data/hlsl/computecloth/sphere.vert
new file mode 100644
index 00000000..8414cb58
--- /dev/null
+++ b/data/hlsl/computecloth/sphere.vert
@@ -0,0 +1,41 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]]float3 Pos : POSITION0;
+[[vk::location(2)]]float3 Normal : NORMAL0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 ViewVec : TEXCOORD0;
+[[vk::location(2)]] float3 LightVec : TEXCOORD1;
+};
+
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0)
+{
+ UBO ubo;
+};
+
+VSOutput main (VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ float4 eyePos = mul(ubo.modelview, float4(input.Pos.x, input.Pos.y, input.Pos.z, 1.0));
+ output.Pos = mul(ubo.projection, eyePos);
+ float4 pos = float4(input.Pos, 1.0);
+ float3 lPos = ubo.lightPos.xyz;
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ output.Normal = input.Normal;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/computecullandlod/cull.comp b/data/hlsl/computecullandlod/cull.comp
new file mode 100644
index 00000000..39d70c74
--- /dev/null
+++ b/data/hlsl/computecullandlod/cull.comp
@@ -0,0 +1,115 @@
+// Copyright 2020 Google LLC
+
+#define MAX_LOD_LEVEL_COUNT 6
+[[vk::constant_id(0)]] const int MAX_LOD_LEVEL = 5;
+
+struct InstanceData
+{
+ float3 pos;
+ float scale;
+};
+
+StructuredBuffer instances : register(t0);
+
+// Same layout as VkDrawIndexedIndirectCommand
+struct IndexedIndirectCommand
+{
+ uint indexCount;
+ uint instanceCount;
+ uint firstIndex;
+ uint vertexOffset;
+ uint firstInstance;
+};
+
+RWStructuredBuffer indirectDraws : register(u1);
+
+// Binding 2: Uniform block object with matrices
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+ float4 cameraPos;
+ float4 frustumPlanes[6];
+};
+
+cbuffer ubo : register(b2) { UBO ubo; }
+
+// Binding 3: Indirect draw stats
+struct UBOOut
+{
+ uint drawCount;
+ uint lodCount[MAX_LOD_LEVEL_COUNT];
+};
+RWStructuredBuffer uboOut : register(u3);
+
+// Binding 4: level-of-detail information
+struct LOD
+{
+ uint firstIndex;
+ uint indexCount;
+ float distance;
+ float _pad0;
+};
+
+StructuredBuffer lods : register(t4);
+
+[numthreads(16, 1, 1)]
+bool frustumCheck(float4 pos, float radius)
+{
+ // Check sphere against frustum planes
+ for (int i = 0; i < 6; i++)
+ {
+ if (dot(pos, ubo.frustumPlanes[i]) + radius < 0.0)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+[numthreads(16, 1, 1)]
+void main(uint3 GlobalInvocationID : SV_DispatchThreadID )
+{
+ uint idx = GlobalInvocationID.x;
+ uint temp;
+
+ // Clear stats on first invocation
+ if (idx == 0)
+ {
+ InterlockedExchange(uboOut[0].drawCount, 0, temp);
+ for (uint i = 0; i < MAX_LOD_LEVEL + 1; i++)
+ {
+ InterlockedExchange(uboOut[0].lodCount[i], 0, temp);
+ }
+ }
+
+ float4 pos = float4(instances[idx].pos.xyz, 1.0);
+
+ // Check if object is within current viewing frustum
+ if (frustumCheck(pos, 1.0))
+ {
+ indirectDraws[idx].instanceCount = 1;
+
+ // Increase number of indirect draw counts
+ InterlockedAdd(uboOut[0].drawCount, 1, temp);
+
+ // Select appropriate LOD level based on distance to camera
+ uint lodLevel = MAX_LOD_LEVEL;
+ for (uint i = 0; i < MAX_LOD_LEVEL; i++)
+ {
+ if (distance(instances[idx].pos.xyz, ubo.cameraPos.xyz) < lods[i].distance)
+ {
+ lodLevel = i;
+ break;
+ }
+ }
+ indirectDraws[idx].firstIndex = lods[lodLevel].firstIndex;
+ indirectDraws[idx].indexCount = lods[lodLevel].indexCount;
+ // Update stats
+ InterlockedAdd(uboOut[0].lodCount[lodLevel], 1, temp);
+ }
+ else
+ {
+ indirectDraws[idx].instanceCount = 0;
+ }
+}
\ No newline at end of file
diff --git a/data/hlsl/computecullandlod/indirectdraw.frag b/data/hlsl/computecullandlod/indirectdraw.frag
new file mode 100644
index 00000000..f4f49dab
--- /dev/null
+++ b/data/hlsl/computecullandlod/indirectdraw.frag
@@ -0,0 +1,18 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 ambient = float3(0.25, 0.25, 0.25);
+ float3 diffuse = max(dot(N, L), 0.0).xxx;
+ return float4((ambient + diffuse) * input.Color, 1.0);
+}
diff --git a/data/hlsl/computecullandlod/indirectdraw.vert b/data/hlsl/computecullandlod/indirectdraw.vert
new file mode 100644
index 00000000..9893ba84
--- /dev/null
+++ b/data/hlsl/computecullandlod/indirectdraw.vert
@@ -0,0 +1,46 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+// Instanced attributes
+[[vk::location(4)]] float3 instancePos : TEXCOORD0;
+[[vk::location(5)]] float instanceScale : TEXCOORD1;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+
+ output.Normal = input.Normal;
+
+ float4 pos = float4((input.Pos.xyz * input.instanceScale) + input.instancePos, 1.0);
+
+ output.Pos = mul(ubo.projection, mul(ubo.modelview, pos));
+
+ float4 wPos = mul(ubo.modelview, float4(pos.xyz, 1.0));
+ float4 lPos = float4(0.0, 10.0, 50.0, 1.0);
+ output.LightVec = lPos.xyz - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
diff --git a/data/hlsl/computeheadless/headless.comp b/data/hlsl/computeheadless/headless.comp
new file mode 100644
index 00000000..827f9159
--- /dev/null
+++ b/data/hlsl/computeheadless/headless.comp
@@ -0,0 +1,28 @@
+// Copyright 2020 Google LLC
+
+RWStructuredBuffer values : register(u0);
+[[vk::constant_id(0)]] const uint BUFFER_ELEMENTS = 32;
+
+uint fibonacci(uint n) {
+ if(n <= 1){
+ return n;
+ }
+ uint curr = 1;
+ uint prev = 1;
+ for(uint i = 2; i < n; ++i) {
+ uint temp = curr;
+ curr += prev;
+ prev = temp;
+ }
+ return curr;
+}
+
+[numthreads(1, 1, 1)]
+void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
+{
+ uint index = GlobalInvocationID.x;
+ if (index >= BUFFER_ELEMENTS)
+ return;
+ values[index] = fibonacci(values[index]);
+}
+
diff --git a/data/hlsl/computenbody/particle.frag b/data/hlsl/computenbody/particle.frag
new file mode 100644
index 00000000..dd7bd3b8
--- /dev/null
+++ b/data/hlsl/computenbody/particle.frag
@@ -0,0 +1,21 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t0);
+SamplerState samplerColorMap : register(s0);
+Texture2D textureGradientRamp : register(t1);
+SamplerState samplerGradientRamp : register(s1);
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float GradientPos : POSITION0;
+[[vk::location(1)]] float2 CenterPos : POSITION1;
+[[vk::location(2)]] float PointSize : TEXCOORD0;
+};
+
+float4 main (VSOutput input) : SV_TARGET
+{
+ float3 color = textureGradientRamp.Sample(samplerGradientRamp, float2(input.GradientPos, 0.0)).rgb;
+ float2 PointCoord = (input.Pos.xy - input.CenterPos.xy) / input.PointSize + 0.5;
+ return float4(textureColorMap.Sample(samplerColorMap, PointCoord).rgb * color, 1);
+}
diff --git a/data/hlsl/computenbody/particle.vert b/data/hlsl/computenbody/particle.vert
new file mode 100644
index 00000000..b2a76596
--- /dev/null
+++ b/data/hlsl/computenbody/particle.vert
@@ -0,0 +1,41 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float4 Vel : TEXCOORD0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float GradientPos : POSITION0;
+[[vk::location(1)]] float2 CenterPos : POSITION1;
+[[vk::builtin("PointSize")]] float PSize : PSIZE;
+[[vk::location(2)]] float PointSize : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+ float2 screendim;
+};
+
+cbuffer ubo : register(b2) { UBO ubo; }
+
+VSOutput main (VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ const float spriteSize = 0.005 * input.Pos.w; // Point size influenced by mass (stored in input.Pos.w);
+
+ float4 eyePos = mul(ubo.modelview, float4(input.Pos.x, input.Pos.y, input.Pos.z, 1.0));
+ float4 projectedCorner = mul(ubo.projection, float4(0.5 * spriteSize, 0.5 * spriteSize, eyePos.z, eyePos.w));
+ output.PSize = output.PointSize = clamp(ubo.screendim.x * projectedCorner.x / projectedCorner.w, 1.0, 128.0);
+
+ output.Pos = mul(ubo.projection, eyePos);
+ output.CenterPos = ((output.Pos.xy / output.Pos.w) + 1.0) * 0.5 * ubo.screendim;
+
+ output.GradientPos = input.Vel.w;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/computenbody/particle_calculate.comp b/data/hlsl/computenbody/particle_calculate.comp
new file mode 100644
index 00000000..3a4e8bbc
--- /dev/null
+++ b/data/hlsl/computenbody/particle_calculate.comp
@@ -0,0 +1,70 @@
+// Copyright 2020 Google LLC
+
+struct Particle
+{
+ float4 pos;
+ float4 vel;
+};
+
+// Binding 0 : Position storage buffer
+RWStructuredBuffer particles : register(u0);
+
+struct UBO
+{
+ float deltaT;
+ int particleCount;
+};
+
+cbuffer ubo : register(b1) { UBO ubo; }
+
+#define MAX_SHARED_DATA_SIZE 1024
+[[vk::constant_id(0)]] const int SHARED_DATA_SIZE = 512;
+[[vk::constant_id(1)]] const float GRAVITY = 0.002;
+[[vk::constant_id(2)]] const float POWER = 0.75;
+[[vk::constant_id(3)]] const float SOFTEN = 0.0075;
+
+// Share data between computer shader invocations to speed up caluclations
+groupshared float4 sharedData[MAX_SHARED_DATA_SIZE];
+
+[numthreads(256, 1, 1)]
+void main(uint3 GlobalInvocationID : SV_DispatchThreadID, uint3 LocalInvocationID : SV_GroupThreadID)
+{
+ // Current SSBO index
+ uint index = GlobalInvocationID.x;
+ if (index >= ubo.particleCount)
+ return;
+
+ float4 position = particles[index].pos;
+ float4 velocity = particles[index].vel;
+ float4 acceleration = float4(0, 0, 0, 0);
+
+ for (int i = 0; i < ubo.particleCount; i += SHARED_DATA_SIZE)
+ {
+ if (i + LocalInvocationID.x < ubo.particleCount)
+ {
+ sharedData[LocalInvocationID.x] = particles[i + LocalInvocationID.x].pos;
+ }
+ else
+ {
+ sharedData[LocalInvocationID.x] = float4(0, 0, 0, 0);
+ }
+
+ GroupMemoryBarrierWithGroupSync();
+
+ for (int j = 0; j < 256; j++)
+ {
+ float4 other = sharedData[j];
+ float3 len = other.xyz - position.xyz;
+ acceleration.xyz += GRAVITY * len * other.w / pow(dot(len, len) + SOFTEN, POWER);
+ }
+
+ GroupMemoryBarrierWithGroupSync();
+ }
+
+ particles[index].vel.xyz += ubo.deltaT * acceleration.xyz;
+
+ // Gradient texture position
+ particles[index].vel.w += 0.1 * ubo.deltaT;
+ if (particles[index].vel.w > 1.0)
+ particles[index].vel.w -= 1.0;
+}
\ No newline at end of file
diff --git a/data/hlsl/computenbody/particle_integrate.comp b/data/hlsl/computenbody/particle_integrate.comp
new file mode 100644
index 00000000..90065a5b
--- /dev/null
+++ b/data/hlsl/computenbody/particle_integrate.comp
@@ -0,0 +1,28 @@
+// Copyright 2020 Google LLC
+
+struct Particle
+{
+ float4 pos;
+ float4 vel;
+};
+
+// Binding 0 : Position storage buffer
+RWStructuredBuffer particles : register(u0);
+
+struct UBO
+{
+ float deltaT;
+ int particleCount;
+};
+
+cbuffer ubo : register(b1) { UBO ubo; }
+
+[numthreads(256, 1, 1)]
+void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
+{
+ int index = int(GlobalInvocationID.x);
+ float4 position = particles[index].pos;
+ float4 velocity = particles[index].vel;
+ position += ubo.deltaT * velocity;
+ particles[index].pos = position;
+}
\ No newline at end of file
diff --git a/data/hlsl/computeparticles/particle.comp b/data/hlsl/computeparticles/particle.comp
new file mode 100644
index 00000000..940faffb
--- /dev/null
+++ b/data/hlsl/computeparticles/particle.comp
@@ -0,0 +1,74 @@
+// Copyright 2020 Google LLC
+
+struct Particle
+{
+ float2 pos;
+ float2 vel;
+ float4 gradientPos;
+};
+
+// Binding 0 : Position storage buffer
+RWStructuredBuffer particles : register(u0);
+
+struct UBO
+{
+ float deltaT;
+ float destX;
+ float destY;
+ int particleCount;
+};
+
+cbuffer ubo : register(b1) { UBO ubo; }
+
+float2 attraction(float2 pos, float2 attractPos)
+{
+ float2 delta = attractPos - pos;
+ const float damp = 0.5;
+ float dDampedDot = dot(delta, delta) + damp;
+ float invDist = 1.0f / sqrt(dDampedDot);
+ float invDistCubed = invDist*invDist*invDist;
+ return delta * invDistCubed * 0.0035;
+}
+
+float2 repulsion(float2 pos, float2 attractPos)
+{
+ float2 delta = attractPos - pos;
+ float targetDistance = sqrt(dot(delta, delta));
+ return delta * (1.0 / (targetDistance * targetDistance * targetDistance)) * -0.000035;
+}
+
+[numthreads(256, 1, 1)]
+void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
+{
+ // Current SSBO index
+ uint index = GlobalInvocationID.x;
+ // Don't try to write beyond particle count
+ if (index >= ubo.particleCount)
+ return;
+
+ // Read position and velocity
+ float2 vVel = particles[index].vel.xy;
+ float2 vPos = particles[index].pos.xy;
+
+ float2 destPos = float2(ubo.destX, ubo.destY);
+
+ float2 delta = destPos - vPos;
+ float targetDistance = sqrt(dot(delta, delta));
+ vVel += repulsion(vPos, destPos.xy) * 0.05;
+
+ // Move by velocity
+ vPos += vVel * ubo.deltaT;
+
+ // collide with boundary
+ if ((vPos.x < -1.0) || (vPos.x > 1.0) || (vPos.y < -1.0) || (vPos.y > 1.0))
+ vVel = (-vVel * 0.1) + attraction(vPos, destPos) * 12;
+ else
+ particles[index].pos.xy = vPos;
+
+ // Write back
+ particles[index].vel.xy = vVel;
+ particles[index].gradientPos.x += 0.02 * ubo.deltaT;
+ if (particles[index].gradientPos.x > 1.0)
+ particles[index].gradientPos.x -= 1.0;
+}
+
diff --git a/data/hlsl/computeparticles/particle.frag b/data/hlsl/computeparticles/particle.frag
new file mode 100644
index 00000000..f3c386f8
--- /dev/null
+++ b/data/hlsl/computeparticles/particle.frag
@@ -0,0 +1,22 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t0);
+SamplerState samplerColorMap : register(s0);
+Texture2D textureGradientRamp : register(t1);
+SamplerState samplerGradientRamp : register(s1);
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float4 Color : COLOR0;
+[[vk::location(1)]] float GradientPos : POSITION0;
+[[vk::location(2)]] float2 CenterPos : POSITION1;
+[[vk::location(3)]] float PointSize : TEXCOORD0;
+};
+
+float4 main (VSOutput input) : SV_TARGET
+{
+ float3 color = textureGradientRamp.Sample(samplerGradientRamp, float2(input.GradientPos, 0.0)).rgb;
+ float2 PointCoord = (input.Pos.xy - input.CenterPos.xy) / input.PointSize + 0.5;
+ return float4(textureColorMap.Sample(samplerColorMap, PointCoord).rgb * color, 1.0);
+}
diff --git a/data/hlsl/computeparticles/particle.vert b/data/hlsl/computeparticles/particle.vert
new file mode 100644
index 00000000..a19c5990
--- /dev/null
+++ b/data/hlsl/computeparticles/particle.vert
@@ -0,0 +1,35 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float2 Pos : POSITION0;
+[[vk::location(1)]] float4 GradientPos : POSITION1;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::builtin("PointSize")]] float PSize : PSIZE;
+[[vk::location(0)]] float4 Color : COLOR0;
+[[vk::location(1)]] float GradientPos : POSITION0;
+[[vk::location(2)]] float2 CenterPos : POSITION1;
+[[vk::location(3)]] float PointSize : TEXCOORD0;
+};
+
+struct PushConsts
+{
+ float2 screendim;
+};
+
+[[vk::push_constant]] PushConsts pushConstants;
+
+VSOutput main (VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.PSize = output.PointSize = 8.0;
+ output.Color = float4(0.035, 0.035, 0.035, 0.035);
+ output.GradientPos = input.GradientPos.x;
+ output.Pos = float4(input.Pos.xy, 1.0, 1.0);
+ output.CenterPos = ((output.Pos.xy / output.Pos.w) + 1.0) * 0.5 * pushConstants.screendim;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/computeraytracing/raytracing.comp b/data/hlsl/computeraytracing/raytracing.comp
new file mode 100644
index 00000000..9f53c7dc
--- /dev/null
+++ b/data/hlsl/computeraytracing/raytracing.comp
@@ -0,0 +1,272 @@
+// Copyright 2020 Google LLC
+
+// Shader is looseley based on the ray tracing coding session by Inigo Quilez (www.iquilezles.org)
+
+RWTexture2D resultImage : register(u0);
+
+#define EPSILON 0.0001
+#define MAXLEN 1000.0
+#define SHADOW 0.5
+#define RAYBOUNCES 2
+#define REFLECTIONS true
+#define REFLECTIONSTRENGTH 0.4
+#define REFLECTIONFALLOFF 0.5
+
+struct Camera
+{
+ float3 pos;
+ float3 lookat;
+ float fov;
+};
+
+struct UBO
+{
+ float3 lightPos;
+ float aspectRatio;
+ float4 fogColor;
+ Camera camera;
+ float4x4 rotMat;
+};
+
+cbuffer ubo : register(b1) { UBO ubo; }
+
+struct Sphere
+{
+ float3 pos;
+ float radius;
+ float3 diffuse;
+ float specular;
+ int id;
+};
+
+struct Plane
+{
+ float3 normal;
+ float distance;
+ float3 diffuse;
+ float specular;
+ int id;
+};
+
+StructuredBuffer spheres : register(t2);
+StructuredBuffer planes : register(t3);
+
+void reflectRay(inout float3 rayD, in float3 mormal)
+{
+ rayD = rayD + 2.0 * -dot(mormal, rayD) * mormal;
+}
+
+// Lighting =========================================================
+
+float lightDiffuse(float3 normal, float3 lightDir)
+{
+ return clamp(dot(normal, lightDir), 0.1, 1.0);
+}
+
+float lightSpecular(float3 normal, float3 lightDir, float specularFactor)
+{
+ float3 viewVec = normalize(ubo.camera.pos);
+ float3 halfVec = normalize(lightDir + viewVec);
+ return pow(clamp(dot(normal, halfVec), 0.0, 1.0), specularFactor);
+}
+
+// Sphere ===========================================================
+
+float sphereIntersect(in float3 rayO, in float3 rayD, in Sphere sphere)
+{
+ float3 oc = rayO - sphere.pos;
+ float b = 2.0 * dot(oc, rayD);
+ float c = dot(oc, oc) - sphere.radius*sphere.radius;
+ float h = b*b - 4.0*c;
+ if (h < 0.0)
+ {
+ return -1.0;
+ }
+ float t = (-b - sqrt(h)) / 2.0;
+
+ return t;
+}
+
+float3 sphereNormal(in float3 pos, in Sphere sphere)
+{
+ return (pos - sphere.pos) / sphere.radius;
+}
+
+// Plane ===========================================================
+
+float planeIntersect(float3 rayO, float3 rayD, Plane plane)
+{
+ float d = dot(rayD, plane.normal);
+
+ if (d == 0.0)
+ return 0.0;
+
+ float t = -(plane.distance + dot(rayO, plane.normal)) / d;
+
+ if (t < 0.0)
+ return 0.0;
+
+ return t;
+}
+
+
+int intersect(in float3 rayO, in float3 rayD, inout float resT)
+{
+ int id = -1;
+
+ uint spheresLength;
+ uint spheresStride;
+ spheres.GetDimensions(spheresLength, spheresStride);
+
+ int i;
+ for (i = 0; i < spheresLength; i++)
+ {
+ float tSphere = sphereIntersect(rayO, rayD, spheres[i]);
+ if ((tSphere > EPSILON) && (tSphere < resT))
+ {
+ id = spheres[i].id;
+ resT = tSphere;
+ }
+ }
+
+ uint planesLength;
+ uint planesStride;
+ planes.GetDimensions(planesLength, planesStride);
+
+ for (i = 0; i < planesLength; i++)
+ {
+ float tplane = planeIntersect(rayO, rayD, planes[i]);
+ if ((tplane > EPSILON) && (tplane < resT))
+ {
+ id = planes[i].id;
+ resT = tplane;
+ }
+ }
+
+ return id;
+}
+
+float calcShadow(in float3 rayO, in float3 rayD, in int objectId, inout float t)
+{
+ uint spheresLength;
+ uint spheresStride;
+ spheres.GetDimensions(spheresLength, spheresStride);
+
+ for (int i = 0; i < spheresLength; i++)
+ {
+ if (spheres[i].id == objectId)
+ continue;
+ float tSphere = sphereIntersect(rayO, rayD, spheres[i]);
+ if ((tSphere > EPSILON) && (tSphere < t))
+ {
+ t = tSphere;
+ return SHADOW;
+ }
+ }
+ return 1.0;
+}
+
+float3 fog(in float t, in float3 color)
+{
+ return lerp(color, ubo.fogColor.rgb, clamp(sqrt(t*t)/20.0, 0.0, 1.0));
+}
+
+float3 renderScene(inout float3 rayO, inout float3 rayD, inout int id)
+{
+ float3 color = float3(0, 0, 0);
+ float t = MAXLEN;
+
+ // Get intersected object ID
+ int objectID = intersect(rayO, rayD, t);
+
+ if (objectID == -1)
+ {
+ return color;
+ }
+
+ float3 pos = rayO + t * rayD;
+ float3 lightVec = normalize(ubo.lightPos - pos);
+ float3 normal;
+
+ // Planes
+
+ // Spheres
+
+ uint planesLength;
+ uint planesStride;
+ planes.GetDimensions(planesLength, planesStride);
+
+ int i;
+ for (i = 0; i < planesLength; i++)
+ {
+ if (objectID == planes[i].id)
+ {
+ normal = planes[i].normal;
+ float diffuse = lightDiffuse(normal, lightVec);
+ float specular = lightSpecular(normal, lightVec, planes[i].specular);
+ color = diffuse * planes[i].diffuse + specular;
+ }
+ }
+
+ uint spheresLength;
+ uint spheresStride;
+ spheres.GetDimensions(spheresLength, spheresStride);
+
+ for (i = 0; i < spheresLength; i++)
+ {
+ if (objectID == spheres[i].id)
+ {
+ normal = sphereNormal(pos, spheres[i]);
+ float diffuse = lightDiffuse(normal, lightVec);
+ float specular = lightSpecular(normal, lightVec, spheres[i].specular);
+ color = diffuse * spheres[i].diffuse + specular;
+ }
+ }
+
+ if (id == -1)
+ return color;
+
+ id = objectID;
+
+ // Shadows
+ t = length(ubo.lightPos - pos);
+ color *= calcShadow(pos, lightVec, id, t);
+
+ // Fog
+ color = fog(t, color);
+
+ // Reflect ray for next render pass
+ reflectRay(rayD, normal);
+ rayO = pos;
+
+ return color;
+}
+
+[numthreads(16, 16, 1)]
+void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
+{
+ int2 dim;
+ resultImage.GetDimensions(dim.x, dim.y);
+ float2 uv = float2(GlobalInvocationID.xy) / dim;
+
+ float3 rayO = ubo.camera.pos;
+ float3 rayD = normalize(float3((-1.0 + 2.0 * uv) * float2(ubo.aspectRatio, 1.0), -1.0));
+
+ // Basic color path
+ int id = 0;
+ float3 finalColor = renderScene(rayO, rayD, id);
+
+ // Reflection
+ if (REFLECTIONS)
+ {
+ float reflectionStrength = REFLECTIONSTRENGTH;
+ for (int i = 0; i < RAYBOUNCES; i++)
+ {
+ float3 reflectionColor = renderScene(rayO, rayD, id);
+ finalColor = (1.0 - reflectionStrength) * finalColor + reflectionStrength * lerp(reflectionColor, finalColor, 1.0 - reflectionStrength);
+ reflectionStrength *= REFLECTIONFALLOFF;
+ }
+ }
+
+ resultImage[int2(GlobalInvocationID.xy)] = float4(finalColor, 0.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/computeraytracing/texture.frag b/data/hlsl/computeraytracing/texture.frag
new file mode 100644
index 00000000..99e548ad
--- /dev/null
+++ b/data/hlsl/computeraytracing/texture.frag
@@ -0,0 +1,9 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t0);
+SamplerState samplerColor : register(s0);
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ return textureColor.Sample(samplerColor, float2(inUV.x, 1.0 - inUV.y));
+}
\ No newline at end of file
diff --git a/data/hlsl/computeraytracing/texture.vert b/data/hlsl/computeraytracing/texture.vert
new file mode 100644
index 00000000..36d824cb
--- /dev/null
+++ b/data/hlsl/computeraytracing/texture.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * 2.0f + -1.0f, 0.0f, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/computeshader/edgedetect.comp b/data/hlsl/computeshader/edgedetect.comp
new file mode 100644
index 00000000..f3e0d425
--- /dev/null
+++ b/data/hlsl/computeshader/edgedetect.comp
@@ -0,0 +1,40 @@
+// Copyright 2020 Google LLC
+
+Texture2D inputImage : register(t0);
+RWTexture2D resultImage : register(u1);
+
+float conv(float kernel[9], in float data[9], in float denom, in float offset)
+{
+ float res = 0.0;
+ for (int i=0; i<9; ++i)
+ {
+ res += kernel[i] * data[i];
+ }
+ return saturate(res/denom + offset);
+}
+
+[numthreads(16, 16, 1)]
+void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
+{
+ float imageData[9];
+ // Fetch neighbouring texels
+ int n = -1;
+ for (int i=-1; i<2; ++i)
+ {
+ for(int j=-1; j<2; ++j)
+ {
+ n++;
+ float3 rgb = inputImage[uint2(GlobalInvocationID.x + i, GlobalInvocationID.y + j)].rgb;
+ imageData[n] = (rgb.r + rgb.g + rgb.b) / 3.0;
+ }
+ }
+
+ float kernel[9];
+ kernel[0] = -1.0/8.0; kernel[1] = -1.0/8.0; kernel[2] = -1.0/8.0;
+ kernel[3] = -1.0/8.0; kernel[4] = 1.0; kernel[5] = -1.0/8.0;
+ kernel[6] = -1.0/8.0; kernel[7] = -1.0/8.0; kernel[8] = -1.0/8.0;
+
+ float4 res = float4(conv(kernel, imageData, 0.1, 0.0).xxx, 1.0);
+
+ resultImage[int2(GlobalInvocationID.xy)] = res;
+}
diff --git a/data/hlsl/computeshader/emboss.comp b/data/hlsl/computeshader/emboss.comp
new file mode 100644
index 00000000..f2a07027
--- /dev/null
+++ b/data/hlsl/computeshader/emboss.comp
@@ -0,0 +1,40 @@
+// Copyright 2020 Google LLC
+
+Texture2D inputImage : register(t0);
+RWTexture2D resultImage : register(u1);
+
+float conv(in float kernel[9], in float data[9], in float denom, in float offset)
+{
+ float res = 0.0;
+ for (int i=0; i<9; ++i)
+ {
+ res += kernel[i] * data[i];
+ }
+ return saturate(res/denom + offset);
+}
+
+[numthreads(16, 16, 1)]
+void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
+{
+ float imageData[9];
+ // Fetch neighbouring texels
+ int n = -1;
+ for (int i=-1; i<2; ++i)
+ {
+ for(int j=-1; j<2; ++j)
+ {
+ n++;
+ float3 rgb = inputImage[uint2(GlobalInvocationID.x + i, GlobalInvocationID.y + j)].rgb;
+ imageData[n] = (rgb.r + rgb.g + rgb.b) / 3.0;
+ }
+ }
+
+ float kernel[9];
+ kernel[0] = -1.0; kernel[1] = 0.0; kernel[2] = 0.0;
+ kernel[3] = 0.0; kernel[4] = -1.0; kernel[5] = 0.0;
+ kernel[6] = 0.0; kernel[7] = 0.0; kernel[8] = 2.0;
+
+ float4 res = float4(conv(kernel, imageData, 1.0, 0.50).xxx, 1.0);
+
+ resultImage[int2(GlobalInvocationID.xy)] = res;
+}
\ No newline at end of file
diff --git a/data/hlsl/computeshader/sharpen.comp b/data/hlsl/computeshader/sharpen.comp
new file mode 100644
index 00000000..90a58266
--- /dev/null
+++ b/data/hlsl/computeshader/sharpen.comp
@@ -0,0 +1,49 @@
+// Copyright 2020 Google LLC
+
+Texture2D inputImage : register(t0);
+RWTexture2D resultImage : register(u1);
+
+float conv(in float kernel[9], in float data[9], in float denom, in float offset)
+{
+ float res = 0.0;
+ for (int i=0; i<9; ++i)
+ {
+ res += kernel[i] * data[i];
+ }
+ return saturate(res/denom + offset);
+}
+
+[numthreads(16, 16, 1)]
+void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
+{
+ float r[9];
+ float g[9];
+ float b[9];
+
+ // Fetch neighbouring texels
+ int n = -1;
+ for (int i=-1; i<2; ++i)
+ {
+ for(int j=-1; j<2; ++j)
+ {
+ n++;
+ float3 rgb = inputImage[uint2(GlobalInvocationID.x + i, GlobalInvocationID.y + j)].rgb;
+ r[n] = rgb.r;
+ g[n] = rgb.g;
+ b[n] = rgb.b;
+ }
+ }
+
+ float kernel[9];
+ kernel[0] = -1.0; kernel[1] = -1.0; kernel[2] = -1.0;
+ kernel[3] = -1.0; kernel[4] = 9.0; kernel[5] = -1.0;
+ kernel[6] = -1.0; kernel[7] = -1.0; kernel[8] = -1.0;
+
+ float4 res = float4(
+ conv(kernel, r, 1.0, 0.0),
+ conv(kernel, g, 1.0, 0.0),
+ conv(kernel, b, 1.0, 0.0),
+ 1.0);
+
+ resultImage[int2(GlobalInvocationID.xy)] = res;
+}
\ No newline at end of file
diff --git a/data/hlsl/computeshader/texture.frag b/data/hlsl/computeshader/texture.frag
new file mode 100644
index 00000000..997a9419
--- /dev/null
+++ b/data/hlsl/computeshader/texture.frag
@@ -0,0 +1,9 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ return textureColor.Sample(samplerColor, inUV);
+}
\ No newline at end of file
diff --git a/data/hlsl/computeshader/texture.vert b/data/hlsl/computeshader/texture.vert
new file mode 100644
index 00000000..8021fe95
--- /dev/null
+++ b/data/hlsl/computeshader/texture.vert
@@ -0,0 +1,29 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+ [[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/conditionalrender/model.frag b/data/hlsl/conditionalrender/model.frag
new file mode 100644
index 00000000..2c14be89
--- /dev/null
+++ b/data/hlsl/conditionalrender/model.frag
@@ -0,0 +1,21 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 ambient = float3(0.1, 0.1, 0.1);
+ float3 diffuse = max(dot(N, L), 0.0) * float3(1.0, 1.0, 1.0);
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75);
+ return float4((ambient + diffuse) * input.Color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/conditionalrender/model.vert b/data/hlsl/conditionalrender/model.vert
new file mode 100644
index 00000000..929321e1
--- /dev/null
+++ b/data/hlsl/conditionalrender/model.vert
@@ -0,0 +1,57 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct Node
+{
+ float4x4 transform;
+};
+
+cbuffer NodeBuf : register(b0, space1) { Node node; }
+
+struct PushConstant
+{
+ float4 baseColorFactor;
+};
+
+[[vk::push_constant]] PushConstant material;
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = material.baseColorFactor.rgb;
+ float4 pos = float4(input.Pos, 1.0);
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, mul(node.transform, pos))));
+
+ output.Normal = mul((float4x3)mul(ubo.view, mul(ubo.model, node.transform)), input.Normal).xyz;
+
+ float4 localpos = mul(ubo.view, mul(ubo.model, mul(node.transform, pos)));
+ float3 lightPos = float3(10.0f, -10.0f, 10.0f);
+ output.LightVec = lightPos.xyz - localpos.xyz;
+ output.ViewVec = -localpos.xyz;
+ return output;
+}
diff --git a/data/hlsl/conservativeraster/fullscreen.frag b/data/hlsl/conservativeraster/fullscreen.frag
new file mode 100644
index 00000000..661ddf44
--- /dev/null
+++ b/data/hlsl/conservativeraster/fullscreen.frag
@@ -0,0 +1,9 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ return textureColor.Sample(samplerColor, inUV);
+}
\ No newline at end of file
diff --git a/data/hlsl/conservativeraster/fullscreen.vert b/data/hlsl/conservativeraster/fullscreen.vert
new file mode 100644
index 00000000..b13c2bf2
--- /dev/null
+++ b/data/hlsl/conservativeraster/fullscreen.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/conservativeraster/triangle.frag b/data/hlsl/conservativeraster/triangle.frag
new file mode 100644
index 00000000..2387dd14
--- /dev/null
+++ b/data/hlsl/conservativeraster/triangle.frag
@@ -0,0 +1,6 @@
+// Copyright 2020 Google LLC
+
+float4 main([[vk::location(0)]] float3 Color : COLOR0) : SV_TARGET
+{
+ return float4(Color, 1);
+}
\ No newline at end of file
diff --git a/data/hlsl/conservativeraster/triangle.vert b/data/hlsl/conservativeraster/triangle.vert
new file mode 100644
index 00000000..e7c529be
--- /dev/null
+++ b/data/hlsl/conservativeraster/triangle.vert
@@ -0,0 +1,29 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/conservativeraster/triangleoverlay.frag b/data/hlsl/conservativeraster/triangleoverlay.frag
new file mode 100644
index 00000000..9892e709
--- /dev/null
+++ b/data/hlsl/conservativeraster/triangleoverlay.frag
@@ -0,0 +1,6 @@
+// Copyright 2020 Google LLC
+
+float4 main() : SV_TARGET
+{
+ return float4(1.0, 1.0, 1.0, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/debugmarker/colorpass.frag b/data/hlsl/debugmarker/colorpass.frag
new file mode 100644
index 00000000..2387dd14
--- /dev/null
+++ b/data/hlsl/debugmarker/colorpass.frag
@@ -0,0 +1,6 @@
+// Copyright 2020 Google LLC
+
+float4 main([[vk::location(0)]] float3 Color : COLOR0) : SV_TARGET
+{
+ return float4(Color, 1);
+}
\ No newline at end of file
diff --git a/data/hlsl/debugmarker/colorpass.vert b/data/hlsl/debugmarker/colorpass.vert
new file mode 100644
index 00000000..089cd426
--- /dev/null
+++ b/data/hlsl/debugmarker/colorpass.vert
@@ -0,0 +1,29 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.Pos = mul(ubo.projection, mul(ubo.model, input.Pos));
+ return output;
+}
diff --git a/data/hlsl/debugmarker/postprocess.frag b/data/hlsl/debugmarker/postprocess.frag
new file mode 100644
index 00000000..32bef01b
--- /dev/null
+++ b/data/hlsl/debugmarker/postprocess.frag
@@ -0,0 +1,36 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ // Single pass gauss blur
+
+ const float2 texOffset = float2(0.01, 0.01);
+
+ float2 tc0 = inUV + float2(-texOffset.x, -texOffset.y);
+ float2 tc1 = inUV + float2( 0.0, -texOffset.y);
+ float2 tc2 = inUV + float2(+texOffset.x, -texOffset.y);
+ float2 tc3 = inUV + float2(-texOffset.x, 0.0);
+ float2 tc4 = inUV + float2( 0.0, 0.0);
+ float2 tc5 = inUV + float2(+texOffset.x, 0.0);
+ float2 tc6 = inUV + float2(-texOffset.x, +texOffset.y);
+ float2 tc7 = inUV + float2( 0.0, +texOffset.y);
+ float2 tc8 = inUV + float2(+texOffset.x, +texOffset.y);
+
+ float4 col0 = textureColor.Sample(samplerColor, tc0);
+ float4 col1 = textureColor.Sample(samplerColor, tc1);
+ float4 col2 = textureColor.Sample(samplerColor, tc2);
+ float4 col3 = textureColor.Sample(samplerColor, tc3);
+ float4 col4 = textureColor.Sample(samplerColor, tc4);
+ float4 col5 = textureColor.Sample(samplerColor, tc5);
+ float4 col6 = textureColor.Sample(samplerColor, tc6);
+ float4 col7 = textureColor.Sample(samplerColor, tc7);
+ float4 col8 = textureColor.Sample(samplerColor, tc8);
+
+ float4 sum = (1.0 * col0 + 2.0 * col1 + 1.0 * col2 +
+ 2.0 * col3 + 4.0 * col4 + 2.0 * col5 +
+ 1.0 * col6 + 2.0 * col7 + 1.0 * col8) / 16.0;
+ return float4(sum.rgb, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/debugmarker/postprocess.vert b/data/hlsl/debugmarker/postprocess.vert
new file mode 100644
index 00000000..fca6ef51
--- /dev/null
+++ b/data/hlsl/debugmarker/postprocess.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * float2(2.0f, 2.0f) + float2(-1.0f, -1.0f), 0.0f, 1.0f);
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/debugmarker/toon.frag b/data/hlsl/debugmarker/toon.frag
new file mode 100644
index 00000000..fa2e7a35
--- /dev/null
+++ b/data/hlsl/debugmarker/toon.frag
@@ -0,0 +1,37 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t1);
+SamplerState samplerColorMap : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ // Desaturate color
+ float3 color = float3(lerp(input.Color, dot(float3(0.2126,0.7152,0.0722), input.Color).xxx, 0.65));
+
+ // High ambient colors because mesh materials are pretty dark
+ float3 ambient = color * float3(1.0, 1.0, 1.0);
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * color;
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75);
+
+ float intensity = dot(N,L);
+ float shade = 1.0;
+ shade = intensity < 0.5 ? 0.75 : shade;
+ shade = intensity < 0.35 ? 0.6 : shade;
+ shade = intensity < 0.25 ? 0.5 : shade;
+ shade = intensity < 0.1 ? 0.25 : shade;
+
+ return float4(input.Color * 3.0 * shade, 1);
+}
\ No newline at end of file
diff --git a/data/hlsl/debugmarker/toon.vert b/data/hlsl/debugmarker/toon.vert
new file mode 100644
index 00000000..3755608d
--- /dev/null
+++ b/data/hlsl/debugmarker/toon.vert
@@ -0,0 +1,44 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.UV = input.UV;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+
+ float4 pos = mul(ubo.model, float4(input.Pos, 1.0));
+ output.Normal = mul((float4x3)ubo.model, input.Normal).xyz;
+ float3 lPos = mul((float4x3)ubo.model, ubo.lightPos.xyz).xyz;
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/deferred/debug.frag b/data/hlsl/deferred/debug.frag
new file mode 100644
index 00000000..0c3520db
--- /dev/null
+++ b/data/hlsl/deferred/debug.frag
@@ -0,0 +1,22 @@
+// Copyright 2020 Google LLC
+
+Texture2D texturePosition : register(t1);
+SamplerState samplerPosition : register(s1);
+Texture2D textureNormal : register(t2);
+SamplerState samplerNormal : register(s2);
+Texture2D textureAlbedo : register(t3);
+SamplerState samplerAlbedo : register(s3);
+
+float4 main([[vk::location(0)]] float3 inUV : TEXCOORD0) : SV_TARGET
+{
+ float3 components[3];
+ components[0] = texturePosition.Sample(samplerPosition, inUV.xy).rgb;
+ components[1] = textureNormal.Sample(samplerNormal, inUV.xy).rgb;
+ components[2] = textureAlbedo.Sample(samplerAlbedo, inUV.xy).rgb;
+ // Uncomment to display specular component
+ //components[2] = float3(textureAlbedo.Sample(samplerAlbedo, inUV.st).a);
+
+ // Select component depending on z coordinate of quad
+ int index = int(inUV.z);
+ return float4(components[index], 1);
+}
\ No newline at end of file
diff --git a/data/hlsl/deferred/debug.vert b/data/hlsl/deferred/debug.vert
new file mode 100644
index 00000000..1cc167bf
--- /dev/null
+++ b/data/hlsl/deferred/debug.vert
@@ -0,0 +1,30 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float3(input.UV.xy, input.Normal.z);
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/deferred/deferred.frag b/data/hlsl/deferred/deferred.frag
new file mode 100644
index 00000000..24c62201
--- /dev/null
+++ b/data/hlsl/deferred/deferred.frag
@@ -0,0 +1,73 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureposition : register(t1);
+SamplerState samplerposition : register(s1);
+Texture2D textureNormal : register(t2);
+SamplerState samplerNormal : register(s2);
+Texture2D textureAlbedo : register(t3);
+SamplerState samplerAlbedo : register(s3);
+
+struct Light {
+ float4 position;
+ float3 color;
+ float radius;
+};
+
+struct UBO
+{
+ Light lights[6];
+ float4 viewPos;
+};
+
+cbuffer ubo : register(b4) { UBO ubo; }
+
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ // Get G-Buffer values
+ float3 fragPos = textureposition.Sample(samplerposition, inUV).rgb;
+ float3 normal = textureNormal.Sample(samplerNormal, inUV).rgb;
+ float4 albedo = textureAlbedo.Sample(samplerAlbedo, inUV);
+
+ #define lightCount 6
+ #define ambient 0.0
+
+ // Ambient part
+ float3 fragcolor = albedo.rgb * ambient;
+
+ for(int i = 0; i < lightCount; ++i)
+ {
+ // Vector to light
+ float3 L = ubo.lights[i].position.xyz - fragPos;
+ // Distance from light to fragment position
+ float dist = length(L);
+
+ // Viewer to fragment
+ float3 V = ubo.viewPos.xyz - fragPos;
+ V = normalize(V);
+
+ //if(dist < ubo.lights[i].radius)
+ {
+ // Light to fragment
+ L = normalize(L);
+
+ // Attenuation
+ float atten = ubo.lights[i].radius / (pow(dist, 2.0) + 1.0);
+
+ // Diffuse part
+ float3 N = normalize(normal);
+ float NdotL = max(0.0, dot(N, L));
+ float3 diff = ubo.lights[i].color * albedo.rgb * NdotL * atten;
+
+ // Specular part
+ // Specular map values are stored in alpha of albedo mrt
+ float3 R = reflect(-L, N);
+ float NdotR = max(0.0, dot(R, V));
+ float3 spec = ubo.lights[i].color * albedo.a * pow(NdotR, 16.0) * atten;
+
+ fragcolor += diff + spec;
+ }
+ }
+
+ return float4(fragcolor, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/deferred/deferred.vert b/data/hlsl/deferred/deferred.vert
new file mode 100644
index 00000000..b13c2bf2
--- /dev/null
+++ b/data/hlsl/deferred/deferred.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/deferred/mrt.frag b/data/hlsl/deferred/mrt.frag
new file mode 100644
index 00000000..264e7224
--- /dev/null
+++ b/data/hlsl/deferred/mrt.frag
@@ -0,0 +1,40 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+Texture2D textureNormalMap : register(t2);
+SamplerState samplerNormalMap : register(s2);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 WorldPos : POSITION0;
+[[vk::location(4)]] float3 Tangent : TEXCOORD1;
+};
+
+struct FSOutput
+{
+ float4 Position : SV_TARGET0;
+ float4 Normal : SV_TARGET1;
+ float4 Albedo : SV_TARGET2;
+};
+
+FSOutput main(VSOutput input)
+{
+ FSOutput output = (FSOutput)0;
+ output.Position = float4(input.WorldPos, 1.0);
+
+ // Calculate normal in tangent space
+ float3 N = normalize(input.Normal);
+ N.y = -N.y;
+ float3 T = normalize(input.Tangent);
+ float3 B = cross(N, T);
+ float3x3 TBN = float3x3(T, B, N);
+ float3 tnorm = mul(normalize(textureNormalMap.Sample(samplerNormalMap, input.UV).xyz * 2.0 - float3(1.0, 1.0, 1.0)), TBN);
+ output.Normal = float4(tnorm, 1.0);
+
+ output.Albedo = textureColor.Sample(samplerColor, input.UV);
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/deferred/mrt.vert b/data/hlsl/deferred/mrt.vert
new file mode 100644
index 00000000..06c25cc6
--- /dev/null
+++ b/data/hlsl/deferred/mrt.vert
@@ -0,0 +1,54 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 Normal : NORMAL0;
+[[vk::location(4)]] float3 Tangent : TEXCOORD1;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+ float4 instancePos[3];
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 WorldPos : POSITION0;
+[[vk::location(4)]] float3 Tangent : TEXCOORD1;
+};
+
+VSOutput main(VSInput input, uint InstanceIndex : SV_InstanceID)
+{
+ VSOutput output = (VSOutput)0;
+ float4 tmpPos = input.Pos + ubo.instancePos[InstanceIndex];
+
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, tmpPos)));
+
+ output.UV = input.UV;
+ output.UV.y = 1.0 - output.UV.y;
+
+ // Vertex position in world space
+ output.WorldPos = mul(ubo.model, tmpPos).xyz;
+ // GL to Vulkan coord space
+ output.WorldPos.y = -output.WorldPos.y;
+
+ // Normal in world space
+ output.Normal = normalize(input.Normal);
+ output.Tangent = normalize(input.Tangent);
+
+ // Currently just vertex color
+ output.Color = input.Color;
+ return output;
+}
diff --git a/data/hlsl/deferredmultisampling/debug.frag b/data/hlsl/deferredmultisampling/debug.frag
new file mode 100644
index 00000000..f8b3135f
--- /dev/null
+++ b/data/hlsl/deferredmultisampling/debug.frag
@@ -0,0 +1,53 @@
+// Copyright 2020 Google LLC
+
+Texture2DMS texturePosition : register(t1);
+SamplerState samplerPosition : register(s1);
+Texture2DMS textureNormal : register(t2);
+SamplerState samplerNormal : register(s2);
+Texture2DMS textureAlbedo : register(t3);
+SamplerState samplerAlbedo : register(s3);
+
+[[vk::constant_id(0)]] const int NUM_SAMPLES = 8;
+
+float4 resolve(Texture2DMS tex, int2 uv)
+{
+ float4 result = float4(0.0, 0.0, 0.0, 0.0);
+ int count = 0;
+ for (int i = 0; i < NUM_SAMPLES; i++)
+ {
+ uint status = 0;
+ float4 val = tex.Load(uv, i, int2(0, 0), status);
+ result += val;
+ count++;
+ }
+ return result / float(NUM_SAMPLES);
+}
+
+float4 main([[vk::location(0)]] float3 inUV : TEXCOORD0) : SV_TARGET
+{
+ int2 attDim; int sampleCount;
+ texturePosition.GetDimensions(attDim.x, attDim.y, sampleCount);
+ int2 UV = int2(inUV.xy * attDim * 2.0);
+
+ int index = 0;
+ if (inUV.x > 0.5)
+ {
+ index = 1;
+ UV.x -= attDim.x;
+ }
+ if (inUV.y > 0.5)
+ {
+ index = 2;
+ UV.y -= attDim.y;
+ }
+
+ float3 components[3];
+ components[0] = resolve(texturePosition, UV).rgb;
+ components[1] = resolve(textureNormal, UV).rgb;
+ components[2] = resolve(textureAlbedo, UV).rgb;
+ // Uncomment to display specular component
+ //components[2] = float3(textureAlbedo.Sample(samplerAlbedo, inUV.xt).a);
+
+ // Select component depending on UV
+ return float4(components[index], 1);
+}
\ No newline at end of file
diff --git a/data/hlsl/deferredmultisampling/debug.vert b/data/hlsl/deferredmultisampling/debug.vert
new file mode 100644
index 00000000..bc833b69
--- /dev/null
+++ b/data/hlsl/deferredmultisampling/debug.vert
@@ -0,0 +1,23 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float3((VertexIndex << 1) & 2, VertexIndex & 2, 0.0);
+ output.Pos = float4(output.UV.xy * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/deferredmultisampling/deferred.frag b/data/hlsl/deferredmultisampling/deferred.frag
new file mode 100644
index 00000000..e758cac1
--- /dev/null
+++ b/data/hlsl/deferredmultisampling/deferred.frag
@@ -0,0 +1,104 @@
+// Copyright 2020 Google LLC
+
+Texture2DMS texturePosition : register(t1);
+SamplerState samplerPosition : register(s1);
+Texture2DMS textureNormal : register(t2);
+SamplerState samplerNormal : register(s2);
+Texture2DMS textureAlbedo : register(t3);
+SamplerState samplerAlbedo : register(s3);
+
+struct Light {
+ float4 position;
+ float3 color;
+ float radius;
+};
+
+struct UBO
+{
+ Light lights[6];
+ float4 viewPos;
+ int2 windowSize;
+};
+
+cbuffer ubo : register(b4) { UBO ubo; }
+
+[[vk::constant_id(0)]] const int NUM_SAMPLES = 8;
+
+#define NUM_LIGHTS 6
+
+// Manual resolve for MSAA samples
+float4 resolve(Texture2DMS tex, int2 uv)
+{
+ float4 result = float4(0.0, 0.0, 0.0, 0.0);
+ for (int i = 0; i < NUM_SAMPLES; i++)
+ {
+ uint status = 0;
+ float4 val = tex.Load(uv, i, int2(0, 0), status);
+ result += val;
+ }
+ // Average resolved samples
+ return result / float(NUM_SAMPLES);
+}
+
+float3 calculateLighting(float3 pos, float3 normal, float4 albedo)
+{
+ float3 result = float3(0.0, 0.0, 0.0);
+
+ for(int i = 0; i < NUM_LIGHTS; ++i)
+ {
+ // Vector to light
+ float3 L = ubo.lights[i].position.xyz - pos;
+ // Distance from light to fragment position
+ float dist = length(L);
+
+ // Viewer to fragment
+ float3 V = ubo.viewPos.xyz - pos;
+ V = normalize(V);
+
+ // Light to fragment
+ L = normalize(L);
+
+ // Attenuation
+ float atten = ubo.lights[i].radius / (pow(dist, 2.0) + 1.0);
+
+ // Diffuse part
+ float3 N = normalize(normal);
+ float NdotL = max(0.0, dot(N, L));
+ float3 diff = ubo.lights[i].color * albedo.rgb * NdotL * atten;
+
+ // Specular part
+ float3 R = reflect(-L, N);
+ float NdotR = max(0.0, dot(R, V));
+ float3 spec = ubo.lights[i].color * albedo.a * pow(NdotR, 8.0) * atten;
+
+ result += diff + spec;
+ }
+ return result;
+}
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ int2 attDim; int sampleCount;
+ texturePosition.GetDimensions(attDim.x, attDim.y, sampleCount);
+ int2 UV = int2(inUV * attDim);
+
+ #define ambient 0.15
+
+ // Ambient part
+ float4 alb = resolve(textureAlbedo, UV);
+ float3 fragColor = float3(0.0, 0.0, 0.0);
+
+ // Calualte lighting for every MSAA sample
+ for (int i = 0; i < NUM_SAMPLES; i++)
+ {
+ uint status = 0;
+ float3 pos = texturePosition.Load(UV, i, int2(0, 0), status).rgb;
+ float3 normal = textureNormal.Load(UV, i, int2(0, 0), status).rgb;
+ float4 albedo = textureAlbedo.Load(UV, i, int2(0, 0), status);
+ fragColor += calculateLighting(pos, normal, albedo);
+ }
+
+ fragColor = (alb.rgb * ambient) + fragColor / float(NUM_SAMPLES);
+
+ return float4(fragColor, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/deferredmultisampling/deferred.vert b/data/hlsl/deferredmultisampling/deferred.vert
new file mode 100644
index 00000000..93fadbaa
--- /dev/null
+++ b/data/hlsl/deferredmultisampling/deferred.vert
@@ -0,0 +1,23 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/deferredmultisampling/mrt.frag b/data/hlsl/deferredmultisampling/mrt.frag
new file mode 100644
index 00000000..264e7224
--- /dev/null
+++ b/data/hlsl/deferredmultisampling/mrt.frag
@@ -0,0 +1,40 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+Texture2D textureNormalMap : register(t2);
+SamplerState samplerNormalMap : register(s2);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 WorldPos : POSITION0;
+[[vk::location(4)]] float3 Tangent : TEXCOORD1;
+};
+
+struct FSOutput
+{
+ float4 Position : SV_TARGET0;
+ float4 Normal : SV_TARGET1;
+ float4 Albedo : SV_TARGET2;
+};
+
+FSOutput main(VSOutput input)
+{
+ FSOutput output = (FSOutput)0;
+ output.Position = float4(input.WorldPos, 1.0);
+
+ // Calculate normal in tangent space
+ float3 N = normalize(input.Normal);
+ N.y = -N.y;
+ float3 T = normalize(input.Tangent);
+ float3 B = cross(N, T);
+ float3x3 TBN = float3x3(T, B, N);
+ float3 tnorm = mul(normalize(textureNormalMap.Sample(samplerNormalMap, input.UV).xyz * 2.0 - float3(1.0, 1.0, 1.0)), TBN);
+ output.Normal = float4(tnorm, 1.0);
+
+ output.Albedo = textureColor.Sample(samplerColor, input.UV);
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/deferredmultisampling/mrt.vert b/data/hlsl/deferredmultisampling/mrt.vert
new file mode 100644
index 00000000..06c25cc6
--- /dev/null
+++ b/data/hlsl/deferredmultisampling/mrt.vert
@@ -0,0 +1,54 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 Normal : NORMAL0;
+[[vk::location(4)]] float3 Tangent : TEXCOORD1;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+ float4 instancePos[3];
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 WorldPos : POSITION0;
+[[vk::location(4)]] float3 Tangent : TEXCOORD1;
+};
+
+VSOutput main(VSInput input, uint InstanceIndex : SV_InstanceID)
+{
+ VSOutput output = (VSOutput)0;
+ float4 tmpPos = input.Pos + ubo.instancePos[InstanceIndex];
+
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, tmpPos)));
+
+ output.UV = input.UV;
+ output.UV.y = 1.0 - output.UV.y;
+
+ // Vertex position in world space
+ output.WorldPos = mul(ubo.model, tmpPos).xyz;
+ // GL to Vulkan coord space
+ output.WorldPos.y = -output.WorldPos.y;
+
+ // Normal in world space
+ output.Normal = normalize(input.Normal);
+ output.Tangent = normalize(input.Tangent);
+
+ // Currently just vertex color
+ output.Color = input.Color;
+ return output;
+}
diff --git a/data/hlsl/deferredshadows/debug.frag b/data/hlsl/deferredshadows/debug.frag
new file mode 100644
index 00000000..0aae5d87
--- /dev/null
+++ b/data/hlsl/deferredshadows/debug.frag
@@ -0,0 +1,26 @@
+// Copyright 2020 Google LLC
+
+Texture2D texturePosition : register(t1);
+SamplerState samplerPosition : register(s1);
+Texture2D textureNormal : register(t2);
+SamplerState samplerNormal : register(s2);
+Texture2D textureAlbedo : register(t3);
+SamplerState samplerAlbedo : register(s3);
+Texture2DArray textureDepth : register(t5);
+SamplerState samplerDepth : register(s5);
+
+float LinearizeDepth(float depth)
+{
+ float n = 0.1; // camera z near
+ float f = 64.0; // camera z far
+ float z = depth;
+ return (2.0 * n) / (f + n - z * (f - n));
+}
+
+float4 main([[vk::location(0)]] float3 inUV : TEXCOORD0) : SV_TARGET
+{
+ // Display depth from light's point-of-view
+ // inUV.w = number of light source
+ float depth = textureDepth.Sample(samplerDepth, float3(inUV)).r;
+ return float4((1.0 - LinearizeDepth(depth)).xxx, 0.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/deferredshadows/debug.vert b/data/hlsl/deferredshadows/debug.vert
new file mode 100644
index 00000000..f6ddeda6
--- /dev/null
+++ b/data/hlsl/deferredshadows/debug.vert
@@ -0,0 +1,32 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input, uint InstanceIndex : SV_InstanceID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float3(input.UV.xy, InstanceIndex);
+ float4 tmpPos = float4(input.Pos, 1.0);
+ tmpPos.y += InstanceIndex;
+ tmpPos.xy *= float2(1.0/4.0, 1.0/3.0);
+ output.Pos = mul(ubo.projection, mul(ubo.modelview, tmpPos));
+ return output;
+}
diff --git a/data/hlsl/deferredshadows/deferred.frag b/data/hlsl/deferredshadows/deferred.frag
new file mode 100644
index 00000000..3ee86330
--- /dev/null
+++ b/data/hlsl/deferredshadows/deferred.frag
@@ -0,0 +1,146 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureposition : register(t1);
+SamplerState samplerposition : register(s1);
+Texture2D textureNormal : register(t2);
+SamplerState samplerNormal : register(s2);
+Texture2D textureAlbedo : register(t3);
+SamplerState samplerAlbedo : register(s3);
+// Depth from the light's point of view
+//layout (binding = 5) uniform sampler2DShadow samplerShadowMap;
+Texture2DArray textureShadowMap : register(t5);
+SamplerState samplerShadowMap : register(s5);
+
+#define LIGHT_COUNT 3
+#define SHADOW_FACTOR 0.25
+#define AMBIENT_LIGHT 0.1
+#define USE_PCF
+
+struct Light
+{
+ float4 position;
+ float4 target;
+ float4 color;
+ float4x4 viewMatrix;
+};
+
+struct UBO
+{
+ float4 viewPos;
+ Light lights[LIGHT_COUNT];
+ int useShadows;
+};
+
+cbuffer ubo : register(b4) { UBO ubo; }
+
+float textureProj(float4 P, float layer, float2 offset)
+{
+ float shadow = 1.0;
+ float4 shadowCoord = P / P.w;
+ shadowCoord.xy = shadowCoord.xy * 0.5 + 0.5;
+
+ if (shadowCoord.z > -1.0 && shadowCoord.z < 1.0)
+ {
+ float dist = textureShadowMap.Sample(samplerShadowMap, float3(shadowCoord.xy + offset, layer)).r;
+ if (shadowCoord.w > 0.0 && dist < shadowCoord.z)
+ {
+ shadow = SHADOW_FACTOR;
+ }
+ }
+ return shadow;
+}
+
+float filterPCF(float4 sc, float layer)
+{
+ int2 texDim; int elements; int levels;
+ textureShadowMap.GetDimensions(0, texDim.x, texDim.y, elements, levels);
+ float scale = 1.5;
+ float dx = scale * 1.0 / float(texDim.x);
+ float dy = scale * 1.0 / float(texDim.y);
+
+ float shadowFactor = 0.0;
+ int count = 0;
+ int range = 1;
+
+ for (int x = -range; x <= range; x++)
+ {
+ for (int y = -range; y <= range; y++)
+ {
+ shadowFactor += textureProj(sc, layer, float2(dx*x, dy*y));
+ count++;
+ }
+
+ }
+ return shadowFactor / count;
+}
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ // Get G-Buffer values
+ float3 fragPos = textureposition.Sample(samplerposition, inUV).rgb;
+ float3 normal = textureNormal.Sample(samplerNormal, inUV).rgb;
+ float4 albedo = textureAlbedo.Sample(samplerAlbedo, inUV);
+
+ // Ambient part
+ float3 fragcolor = albedo.rgb * AMBIENT_LIGHT;
+
+ float3 N = normalize(normal);
+
+ float shadow = 0.0;
+
+ for(int i = 0; i < LIGHT_COUNT; ++i)
+ {
+ // Vector to light
+ float3 L = ubo.lights[i].position.xyz - fragPos;
+ // Distance from light to fragment position
+ float dist = length(L);
+ L = normalize(L);
+
+ // Viewer to fragment
+ float3 V = ubo.viewPos.xyz - fragPos;
+ V = normalize(V);
+
+ float lightCosInnerAngle = cos(radians(15.0));
+ float lightCosOuterAngle = cos(radians(25.0));
+ float lightRange = 100.0;
+
+ // Direction vector from source to target
+ float3 dir = normalize(ubo.lights[i].position.xyz - ubo.lights[i].target.xyz);
+
+ // Dual cone spot light with smooth transition between inner and outer angle
+ float cosDir = dot(L, dir);
+ float spotEffect = smoothstep(lightCosOuterAngle, lightCosInnerAngle, cosDir);
+ float heightAttenuation = smoothstep(lightRange, 0.0f, dist);
+
+ // Diffuse lighting
+ float NdotL = max(0.0, dot(N, L));
+ float3 diff = NdotL.xxx;
+
+ // Specular lighting
+ float3 R = reflect(-L, N);
+ float NdotR = max(0.0, dot(R, V));
+ float3 spec = (pow(NdotR, 16.0) * albedo.a * 2.5).xxx;
+
+ fragcolor += float3((diff + spec) * spotEffect * heightAttenuation) * ubo.lights[i].color.rgb * albedo.rgb;
+ }
+
+ // Shadow calculations in a separate pass
+ if (ubo.useShadows > 0)
+ {
+ for(int i = 0; i < LIGHT_COUNT; ++i)
+ {
+ float4 shadowClip = mul(ubo.lights[i].viewMatrix, float4(fragPos, 1.0));
+
+ float shadowFactor;
+ #ifdef USE_PCF
+ shadowFactor= filterPCF(shadowClip, i);
+ #else
+ shadowFactor = textureProj(shadowClip, i, float2(0.0, 0.0));
+ #endif
+
+ fragcolor *= shadowFactor;
+ }
+ }
+
+ return float4(fragcolor, 1);
+}
\ No newline at end of file
diff --git a/data/hlsl/deferredshadows/deferred.vert b/data/hlsl/deferredshadows/deferred.vert
new file mode 100644
index 00000000..37d5bf2a
--- /dev/null
+++ b/data/hlsl/deferredshadows/deferred.vert
@@ -0,0 +1,29 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV;
+ output.Pos = mul(ubo.projection, mul(ubo.modelview, float4(input.Pos.xyz, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/deferredshadows/mrt.frag b/data/hlsl/deferredshadows/mrt.frag
new file mode 100644
index 00000000..7b899821
--- /dev/null
+++ b/data/hlsl/deferredshadows/mrt.frag
@@ -0,0 +1,39 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+Texture2D textureNormalMap : register(t2);
+SamplerState samplerNormalMap : register(s2);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 WorldPos : POSITION0;
+[[vk::location(4)]] float3 Tangent : TEXCOORD1;
+};
+
+struct FSOutput
+{
+ float4 Position : SV_TARGET0;
+ float4 Normal : SV_TARGET1;
+ float4 Albedo : SV_TARGET2;
+};
+
+FSOutput main(VSOutput input)
+{
+ FSOutput output = (FSOutput)0;
+ output.Position = float4(input.WorldPos, 1.0);
+
+ // Calculate normal in tangent space
+ float3 N = normalize(input.Normal);
+ float3 T = normalize(input.Tangent);
+ float3 B = cross(N, T);
+ float3x3 TBN = float3x3(T, B, N);
+ float3 tnorm = mul(normalize(textureNormalMap.Sample(samplerNormalMap, input.UV).xyz * 2.0 - float3(1.0, 1.0, 1.0)), TBN);
+ output.Normal = float4(tnorm, 1.0);
+
+ output.Albedo = textureColor.Sample(samplerColor, input.UV);
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/deferredshadows/mrt.vert b/data/hlsl/deferredshadows/mrt.vert
new file mode 100644
index 00000000..c19ff218
--- /dev/null
+++ b/data/hlsl/deferredshadows/mrt.vert
@@ -0,0 +1,52 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 Normal : NORMAL0;
+[[vk::location(4)]] float3 Tangent : TEXCOORD1;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+ float4 instancePos[3];
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 WorldPos : POSITION0;
+[[vk::location(4)]] float3 Tangent : TEXCOORD1;
+};
+
+VSOutput main(VSInput input, uint InstanceIndex : SV_InstanceID)
+{
+ VSOutput output = (VSOutput)0;
+ float4 tmpPos = input.Pos + ubo.instancePos[InstanceIndex];
+
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, tmpPos)));
+
+ output.UV = input.UV;
+ output.UV.y = 1.0 - output.UV.y;
+
+ // Vertex position in world space
+ output.WorldPos = mul(ubo.model, tmpPos).xyz;
+
+ // Normal in world space
+ output.Normal = normalize(input.Normal);
+ output.Tangent = normalize(input.Tangent);
+
+ // Currently just vertex color
+ output.Color = input.Color;
+ return output;
+}
diff --git a/data/hlsl/deferredshadows/shadow.geom b/data/hlsl/deferredshadows/shadow.geom
new file mode 100644
index 00000000..e8321771
--- /dev/null
+++ b/data/hlsl/deferredshadows/shadow.geom
@@ -0,0 +1,39 @@
+// Copyright 2020 Google LLC
+
+#define LIGHT_COUNT 3
+
+struct UBO
+{
+ float4x4 mvp[LIGHT_COUNT];
+ float4 instancePos[3];
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] int InstanceIndex : TEXCOORD0;
+};
+
+struct GSOutput
+{
+ float4 Pos : SV_POSITION;
+ int Layer : SV_RenderTargetArrayIndex;
+};
+
+[maxvertexcount(3)]
+[instance(3)]
+void main(triangle VSOutput input[3], uint InvocationID : SV_GSInstanceID, inout TriangleStream outStream)
+{
+ float4 instancedPos = ubo.instancePos[input[0].InstanceIndex];
+ for (int i = 0; i < 3; i++)
+ {
+ float4 tmpPos = input[i].Pos + instancedPos;
+ GSOutput output = (GSOutput)0;
+ output.Pos = mul(ubo.mvp[InvocationID], tmpPos);
+ output.Layer = InvocationID;
+ outStream.Append( output );
+ }
+ outStream.RestartStrip();
+}
\ No newline at end of file
diff --git a/data/hlsl/deferredshadows/shadow.vert b/data/hlsl/deferredshadows/shadow.vert
new file mode 100644
index 00000000..f08ec8c7
--- /dev/null
+++ b/data/hlsl/deferredshadows/shadow.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] int InstanceIndex : TEXCOORD0;
+};
+
+VSOutput main([[vk::location(0)]] float4 Pos : POSITION0, uint InstanceIndex : SV_InstanceID)
+{
+ VSOutput output = (VSOutput)0;
+ output.InstanceIndex = InstanceIndex;
+ output.Pos = Pos;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/descriptorsets/cube.frag b/data/hlsl/descriptorsets/cube.frag
new file mode 100644
index 00000000..854726c3
--- /dev/null
+++ b/data/hlsl/descriptorsets/cube.frag
@@ -0,0 +1,16 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t1);
+SamplerState samplerColorMap : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ return textureColorMap.Sample(samplerColorMap, input.UV) * float4(input.Color, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/descriptorsets/cube.vert b/data/hlsl/descriptorsets/cube.vert
new file mode 100644
index 00000000..68f4df3e
--- /dev/null
+++ b/data/hlsl/descriptorsets/cube.vert
@@ -0,0 +1,35 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBOMatrices {
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+};
+
+cbuffer uboMatrices : register(b0) { UBOMatrices uboMatrices; };
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.UV = input.UV;
+ output.Pos = mul(uboMatrices.projection, mul(uboMatrices.view, mul(uboMatrices.model, float4(input.Pos.xyz, 1.0))));
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/displacement/base.frag b/data/hlsl/displacement/base.frag
new file mode 100644
index 00000000..c62eec65
--- /dev/null
+++ b/data/hlsl/displacement/base.frag
@@ -0,0 +1,26 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t2);
+SamplerState samplerColorMap : register(s2);
+
+struct DSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 EyePos : POSITION0;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(DSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(float3(1.0, 1.0, 1.0));
+
+ float3 Eye = normalize(-input.EyePos);
+ float3 Reflected = normalize(reflect(-input.LightVec, input.Normal));
+
+ float4 IAmbient = float4(0.0, 0.0, 0.0, 1.0);
+ float4 IDiffuse = float4(1.0, 1.0, 1.0, 1.0) * max(dot(input.Normal, input.LightVec), 0.0);
+
+ return float4((IAmbient + IDiffuse) * float4(textureColorMap.Sample(samplerColorMap, input.UV).rgb, 1.0));
+}
\ No newline at end of file
diff --git a/data/hlsl/displacement/base.vert b/data/hlsl/displacement/base.vert
new file mode 100644
index 00000000..439c5bb1
--- /dev/null
+++ b/data/hlsl/displacement/base.vert
@@ -0,0 +1,24 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct VSOutput
+{
+[[vk::location(2)]] float4 Pos : POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = float4(input.Pos.xyz, 1.0);
+ output.UV = input.UV * 3.0;
+ output.Normal = input.Normal;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/displacement/displacement.tesc b/data/hlsl/displacement/displacement.tesc
new file mode 100644
index 00000000..2973e726
--- /dev/null
+++ b/data/hlsl/displacement/displacement.tesc
@@ -0,0 +1,53 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float tessLevel;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+[[vk::location(2)]] float4 Pos : POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct HSOutput
+{
+[[vk::location(2)]] float4 Pos : POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct ConstantsHSOutput
+{
+ float TessLevelOuter[3] : SV_TessFactor;
+ float TessLevelInner : SV_InsideTessFactor;
+};
+
+ConstantsHSOutput ConstantsHS(InputPatch patch, uint InvocationID : SV_PrimitiveID)
+{
+ ConstantsHSOutput output = (ConstantsHSOutput)0;
+ output.TessLevelInner = ubo.tessLevel;
+ output.TessLevelOuter[0] = ubo.tessLevel;
+ output.TessLevelOuter[1] = ubo.tessLevel;
+ output.TessLevelOuter[2] = ubo.tessLevel;
+ return output;
+}
+
+[domain("tri")]
+[partitioning("integer")]
+[outputtopology("triangle_ccw")]
+[outputcontrolpoints(3)]
+[patchconstantfunc("ConstantsHS")]
+[maxtessfactor(20.0f)]
+HSOutput main(InputPatch patch, uint InvocationID : SV_OutputControlPointID)
+{
+ HSOutput output = (HSOutput)0;
+ output.Pos = patch[InvocationID].Pos;
+ output.Normal = patch[InvocationID].Normal;
+ output.UV = patch[InvocationID].UV;
+ return output;
+}
diff --git a/data/hlsl/displacement/displacement.tese b/data/hlsl/displacement/displacement.tese
new file mode 100644
index 00000000..0732c345
--- /dev/null
+++ b/data/hlsl/displacement/displacement.tese
@@ -0,0 +1,54 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 lightPos;
+ float tessAlpha;
+ float tessStrength;
+};
+
+cbuffer ubo : register(b1) { UBO ubo; }
+
+Texture2D textureDisplacementMap : register(t2);
+SamplerState samplerDisplacementMap : register(s2);
+
+struct HSOutput
+{
+[[vk::location(2)]] float4 Pos : POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct ConstantsHSOutput
+{
+ float TessLevelOuter[3] : SV_TessFactor;
+ float TessLevelInner : SV_InsideTessFactor;
+};
+
+struct DSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 EyesPos : POSITION0;
+[[vk::location(3)]] float3 LightVec : TEXCOORD1;
+};
+
+[domain("tri")]
+DSOutput main(ConstantsHSOutput input, float3 TessCoord : SV_DomainLocation, const OutputPatch patch)
+{
+ DSOutput output = (DSOutput)0;
+ output.Pos = (TessCoord.x * patch[0].Pos) + (TessCoord.y * patch[1].Pos) + (TessCoord.z * patch[2].Pos);
+ output.UV = mul(TessCoord.x, patch[0].UV) + mul(TessCoord.y, patch[1].UV) + mul(TessCoord.z, patch[2].UV);
+ output.Normal = TessCoord.x * patch[0].Normal + TessCoord.y * patch[1].Normal + TessCoord.z * patch[2].Normal;
+
+ output.Pos.xyz += normalize(output.Normal) * (max(textureDisplacementMap.SampleLevel(samplerDisplacementMap, output.UV.xy, 0).a, 0.0) * ubo.tessStrength);
+
+ output.EyesPos = output.Pos.xyz;
+ output.LightVec = normalize(ubo.lightPos.xyz - output.EyesPos);
+
+ output.Pos = mul(ubo.projection, mul(ubo.model, output.Pos));
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/distancefieldfonts/bitmap.frag b/data/hlsl/distancefieldfonts/bitmap.frag
new file mode 100644
index 00000000..456bfe86
--- /dev/null
+++ b/data/hlsl/distancefieldfonts/bitmap.frag
@@ -0,0 +1,9 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ return textureColor.Sample(samplerColor, inUV).aaaa;
+}
\ No newline at end of file
diff --git a/data/hlsl/distancefieldfonts/bitmap.vert b/data/hlsl/distancefieldfonts/bitmap.vert
new file mode 100644
index 00000000..379daee9
--- /dev/null
+++ b/data/hlsl/distancefieldfonts/bitmap.vert
@@ -0,0 +1,29 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/distancefieldfonts/sdf.frag b/data/hlsl/distancefieldfonts/sdf.frag
new file mode 100644
index 00000000..104284a9
--- /dev/null
+++ b/data/hlsl/distancefieldfonts/sdf.frag
@@ -0,0 +1,30 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+struct UBO
+{
+ float4 outlineColor;
+ float outlineWidth;
+ float outline;
+};
+
+cbuffer ubo : register(b2) { UBO ubo; }
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ float dist = textureColor.Sample(samplerColor, inUV).a;
+ float smoothWidth = fwidth(dist);
+ float alpha = smoothstep(0.5 - smoothWidth, 0.5 + smoothWidth, dist);
+ float3 rgb = alpha.xxx;
+
+ if (ubo.outline > 0.0)
+ {
+ float w = 1.0 - ubo.outlineWidth;
+ alpha = smoothstep(w - smoothWidth, w + smoothWidth, dist);
+ rgb += lerp(alpha.xxx, ubo.outlineColor.rgb, alpha);
+ }
+
+ return float4(rgb, alpha);
+}
\ No newline at end of file
diff --git a/data/hlsl/distancefieldfonts/sdf.vert b/data/hlsl/distancefieldfonts/sdf.vert
new file mode 100644
index 00000000..379daee9
--- /dev/null
+++ b/data/hlsl/distancefieldfonts/sdf.vert
@@ -0,0 +1,29 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/dynamicuniformbuffer/base.frag b/data/hlsl/dynamicuniformbuffer/base.frag
new file mode 100644
index 00000000..b800903c
--- /dev/null
+++ b/data/hlsl/dynamicuniformbuffer/base.frag
@@ -0,0 +1,6 @@
+// Copyright 2020 Google LLC
+
+float4 main([[vk::location(0)]] float3 Color : COLOR0) : SV_TARGET
+{
+ return float4(Color, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/dynamicuniformbuffer/base.vert b/data/hlsl/dynamicuniformbuffer/base.vert
new file mode 100644
index 00000000..7cb43933
--- /dev/null
+++ b/data/hlsl/dynamicuniformbuffer/base.vert
@@ -0,0 +1,36 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Color : COLOR0;
+};
+
+struct UboView
+{
+ float4x4 projection;
+ float4x4 view;
+};
+cbuffer uboView : register(b0) { UboView uboView; };
+
+struct UboInstance
+{
+ float4x4 model;
+};
+cbuffer uboInstance : register(b1) { UboInstance uboInstance; };
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ float4x4 modelView = mul(uboView.view, uboInstance.model);
+ float3 worldPos = mul(modelView, float4(input.Pos, 1.0)).xyz;
+ output.Pos = mul(uboView.projection, mul(modelView, float4(input.Pos.xyz, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/gears/gears.frag b/data/hlsl/gears/gears.frag
new file mode 100644
index 00000000..276b830a
--- /dev/null
+++ b/data/hlsl/gears/gears.frag
@@ -0,0 +1,22 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 EyePos : POSITION0;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 Eye = normalize(-input.EyePos);
+ float3 Reflected = normalize(reflect(-input.LightVec, input.Normal));
+
+ float4 IAmbient = float4(0.2, 0.2, 0.2, 1.0);
+ float4 IDiffuse = float4(0.5, 0.5, 0.5, 0.5) * max(dot(input.Normal, input.LightVec), 0.0);
+ float specular = 0.25;
+ float4 ISpecular = float4(0.5, 0.5, 0.5, 1.0) * pow(max(dot(Reflected, Eye), 0.0), 0.8) * specular;
+
+ return float4((IAmbient + IDiffuse) * float4(input.Color, 1.0) + ISpecular);
+}
\ No newline at end of file
diff --git a/data/hlsl/gears/gears.vert b/data/hlsl/gears/gears.vert
new file mode 100644
index 00000000..68dd4a2e
--- /dev/null
+++ b/data/hlsl/gears/gears.vert
@@ -0,0 +1,42 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 normal;
+ float4x4 view;
+ float3 lightpos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 EyePos : POSITION0;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = normalize(mul((float4x3)ubo.normal, input.Normal).xyz);
+ output.Color = input.Color;
+ float4x4 modelView = mul(ubo.view, ubo.model);
+ float4 pos = mul(modelView, input.Pos);
+ output.EyePos = mul(modelView, pos).xyz;
+ float4 lightPos = mul(float4(ubo.lightpos, 1.0), modelView);
+ output.LightVec = normalize(lightPos.xyz - output.EyePos);
+ output.Pos = mul(ubo.projection, pos);
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/geometryshader/base.frag b/data/hlsl/geometryshader/base.frag
new file mode 100644
index 00000000..b800903c
--- /dev/null
+++ b/data/hlsl/geometryshader/base.frag
@@ -0,0 +1,6 @@
+// Copyright 2020 Google LLC
+
+float4 main([[vk::location(0)]] float3 Color : COLOR0) : SV_TARGET
+{
+ return float4(Color, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/geometryshader/base.vert b/data/hlsl/geometryshader/base.vert
new file mode 100644
index 00000000..8179b490
--- /dev/null
+++ b/data/hlsl/geometryshader/base.vert
@@ -0,0 +1,21 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+};
+
+struct VSOutput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Pos = float4(input.Pos.xyz, 1.0);
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/geometryshader/mesh.frag b/data/hlsl/geometryshader/mesh.frag
new file mode 100644
index 00000000..189e9955
--- /dev/null
+++ b/data/hlsl/geometryshader/mesh.frag
@@ -0,0 +1,21 @@
+// Copyright 2020 Google LLC
+
+struct GSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(GSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 ambient = float3(0.1, 0.1, 0.1);
+ float3 diffuse = max(dot(N, L), 0.0) * float3(1.0, 1.0, 1.0);
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75);
+ return float4((ambient + diffuse) * input.Color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/geometryshader/mesh.vert b/data/hlsl/geometryshader/mesh.vert
new file mode 100644
index 00000000..cfa1dcf9
--- /dev/null
+++ b/data/hlsl/geometryshader/mesh.vert
@@ -0,0 +1,40 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+cbuffer ubo : register(b0) { UBO ubo; };
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.Pos = mul(ubo.projection, mul(ubo.model, input.Pos));
+
+ float4 pos = mul(ubo.model, float4(input.Pos.xyz, 1.0));
+ output.Normal = mul((float4x3)ubo.model, input.Normal).xyz;
+
+ float3 lightPos = float3(1.0f, -1.0f, 1.0f);
+ output.LightVec = lightPos.xyz - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
diff --git a/data/hlsl/geometryshader/normaldebug.geom b/data/hlsl/geometryshader/normaldebug.geom
new file mode 100644
index 00000000..7fba0fcd
--- /dev/null
+++ b/data/hlsl/geometryshader/normaldebug.geom
@@ -0,0 +1,43 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b1) { UBO ubo; }
+
+struct VSOutput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+};
+
+struct GSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+};
+
+[maxvertexcount(6)]
+void main(triangle VSOutput input[3], inout LineStream outStream)
+{
+ float normalLength = 0.02;
+ for(int i=0; i<3; i++)
+ {
+ float3 pos = input[i].Pos.xyz;
+ float3 normal = input[i].Normal.xyz;
+
+ GSOutput output = (GSOutput)0;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(pos, 1.0)));
+ output.Color = float3(1.0, 0.0, 0.0);
+ outStream.Append( output );
+
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(pos + normal * normalLength, 1.0)));
+ output.Color = float3(0.0, 0.0, 1.0);
+ outStream.Append( output );
+
+ outStream.RestartStrip();
+ }
+}
\ No newline at end of file
diff --git a/data/hlsl/gltfscene/mesh.frag b/data/hlsl/gltfscene/mesh.frag
new file mode 100644
index 00000000..15d11a51
--- /dev/null
+++ b/data/hlsl/gltfscene/mesh.frag
@@ -0,0 +1,26 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t0, space1);
+SamplerState samplerColorMap : register(s0, space1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 color = textureColorMap.Sample(samplerColorMap, input.UV) * float4(input.Color, 1.0);
+
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * input.Color;
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75);
+ return float4(diffuse * color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/gltfscene/mesh.vert b/data/hlsl/gltfscene/mesh.vert
new file mode 100644
index 00000000..a47967ac
--- /dev/null
+++ b/data/hlsl/gltfscene/mesh.vert
@@ -0,0 +1,49 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct PushConsts {
+ float4x4 model;
+};
+[[vk::push_constant]] PushConsts primitive;
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.UV = input.UV;
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(primitive.model, float4(input.Pos.xyz, 1.0))));
+
+ float4 pos = mul(ubo.view, float4(input.Pos, 1.0));
+ output.Normal = mul((float3x3)ubo.view, input.Normal);
+ float3 lPos = mul((float3x3)ubo.view, ubo.lightPos.xyz);
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/hdr/bloom.frag b/data/hlsl/hdr/bloom.frag
new file mode 100644
index 00000000..13c5e14a
--- /dev/null
+++ b/data/hlsl/hdr/bloom.frag
@@ -0,0 +1,62 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor0 : register(t0);
+SamplerState samplerColor0 : register(s0);
+Texture2D textureColor1 : register(t1);
+SamplerState samplerColor1 : register(s1);
+
+[[vk::constant_id(0)]] const int dir = 0;
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ // From the OpenGL Super bible
+ const float weights[] = { 0.0024499299678342,
+ 0.0043538453346397,
+ 0.0073599963704157,
+ 0.0118349786570722,
+ 0.0181026699707781,
+ 0.0263392293891488,
+ 0.0364543006660986,
+ 0.0479932050577658,
+ 0.0601029809166942,
+ 0.0715974486241365,
+ 0.0811305381519717,
+ 0.0874493212267511,
+ 0.0896631113333857,
+ 0.0874493212267511,
+ 0.0811305381519717,
+ 0.0715974486241365,
+ 0.0601029809166942,
+ 0.0479932050577658,
+ 0.0364543006660986,
+ 0.0263392293891488,
+ 0.0181026699707781,
+ 0.0118349786570722,
+ 0.0073599963704157,
+ 0.0043538453346397,
+ 0.0024499299678342};
+
+
+ const float blurScale = 0.003;
+ const float blurStrength = 1.0;
+
+ float ar = 1.0;
+ // Aspect ratio for vertical blur pass
+ if (dir == 1)
+ {
+ float2 ts;
+ textureColor1.GetDimensions(ts.x, ts.y);
+ ar = ts.y / ts.x;
+ }
+
+ float2 P = inUV.yx - float2(0, (25 >> 1) * ar * blurScale);
+
+ float4 color = float4(0.0, 0.0, 0.0, 0.0);
+ for (int i = 0; i < 25; i++)
+ {
+ float2 dv = float2(0.0, i * blurScale) * ar;
+ color += textureColor1.Sample(samplerColor1, P + dv) * weights[i] * blurStrength;
+ }
+
+ return color;
+}
\ No newline at end of file
diff --git a/data/hlsl/hdr/bloom.vert b/data/hlsl/hdr/bloom.vert
new file mode 100644
index 00000000..b13c2bf2
--- /dev/null
+++ b/data/hlsl/hdr/bloom.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/hdr/composition.frag b/data/hlsl/hdr/composition.frag
new file mode 100644
index 00000000..41c9be65
--- /dev/null
+++ b/data/hlsl/hdr/composition.frag
@@ -0,0 +1,11 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor0 : register(t0);
+SamplerState samplerColor0 : register(s0);
+Texture2D textureColor1 : register(t1);
+SamplerState samplerColor1 : register(s1);
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ return textureColor0.Sample(samplerColor0, inUV);
+}
\ No newline at end of file
diff --git a/data/hlsl/hdr/composition.vert b/data/hlsl/hdr/composition.vert
new file mode 100644
index 00000000..b13c2bf2
--- /dev/null
+++ b/data/hlsl/hdr/composition.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/hdr/gbuffer.frag b/data/hlsl/hdr/gbuffer.frag
new file mode 100644
index 00000000..4e412a75
--- /dev/null
+++ b/data/hlsl/hdr/gbuffer.frag
@@ -0,0 +1,108 @@
+// Copyright 2020 Google LLC
+
+TextureCube textureEnvMap : register(t1);
+SamplerState samplerEnvMap : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 UVW : TEXCOORD0;
+[[vk::location(1)]] float3 Pos : POSITION0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+struct FSOutput
+{
+ float4 Color0 : SV_TARGET0;
+ float4 Color1 : SV_TARGET1;
+};
+
+[[vk::constant_id(0)]] const int type = 0;
+
+#define PI 3.1415926
+#define TwoPI (2.0 * PI)
+
+struct UBO {
+ float4x4 projection;
+ float4x4 modelview;
+ float4x4 inverseModelview;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+cbuffer Exposure : register(b2)
+{
+ float exposure;
+}
+
+FSOutput main(VSOutput input)
+{
+ FSOutput output = (FSOutput)0;
+ float4 color;
+ float3 wcNormal;
+
+ switch (type) {
+ case 0: // Skybox
+ {
+ float3 normal = normalize(input.UVW);
+ color = textureEnvMap.Sample(samplerEnvMap, normal);
+ }
+ break;
+
+ case 1: // Reflect
+ {
+ float3 wViewVec = mul((float4x3)ubo.inverseModelview, normalize(input.ViewVec)).xyz;
+ float3 normal = normalize(input.Normal);
+ float3 wNormal = mul((float4x3)ubo.inverseModelview, normal).xyz;
+
+ float NdotL = max(dot(normal, input.LightVec), 0.0);
+
+ float3 eyeDir = normalize(input.ViewVec);
+ float3 halfVec = normalize(input.LightVec + eyeDir);
+ float NdotH = max(dot(normal, halfVec), 0.0);
+ float NdotV = max(dot(normal, eyeDir), 0.0);
+ float VdotH = max(dot(eyeDir, halfVec), 0.0);
+
+ // Geometric attenuation
+ float NH2 = 2.0 * NdotH;
+ float g1 = (NH2 * NdotV) / VdotH;
+ float g2 = (NH2 * NdotL) / VdotH;
+ float geoAtt = min(1.0, min(g1, g2));
+
+ const float F0 = 0.6;
+ const float k = 0.2;
+
+ // Fresnel (schlick approximation)
+ float fresnel = pow(1.0 - VdotH, 5.0);
+ fresnel *= (1.0 - F0);
+ fresnel += F0;
+
+ float spec = (fresnel * geoAtt) / (NdotV * NdotL * 3.14);
+
+ color = textureEnvMap.Sample(samplerEnvMap, reflect(-wViewVec, wNormal));
+
+ color = float4(color.rgb * NdotL * (k + spec * (1.0 - k)), 1.0);
+ }
+ break;
+
+ case 2: // Refract
+ {
+ float3 wViewVec = mul((float4x3)ubo.inverseModelview, normalize(input.ViewVec)).xyz;
+ float3 wNormal = mul((float4x3)ubo.inverseModelview, input.Normal).xyz;
+ color = textureEnvMap.Sample(samplerEnvMap, refract(-wViewVec, wNormal, 1.0/1.6));
+ }
+ break;
+ }
+
+
+ // Color with manual exposure into attachment 0
+ output.Color0.rgb = float3(1.0, 1.0, 1.0) - exp(-color.rgb * exposure);
+
+ // Bright parts for bloom into attachment 1
+ float l = dot(output.Color0.rgb, float3(0.2126, 0.7152, 0.0722));
+ float threshold = 0.75;
+ output.Color1.rgb = (l > threshold) ? output.Color0.rgb : float3(0.0, 0.0, 0.0);
+ output.Color1.a = 1.0;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/hdr/gbuffer.vert b/data/hlsl/hdr/gbuffer.vert
new file mode 100644
index 00000000..c833a812
--- /dev/null
+++ b/data/hlsl/hdr/gbuffer.vert
@@ -0,0 +1,51 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+};
+
+[[vk::constant_id(0)]] const int type = 0;
+
+struct UBO {
+ float4x4 projection;
+ float4x4 modelview;
+ float4x4 inverseModelview;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UVW : TEXCOORD0;
+[[vk::location(1)]] float3 WorldPos : POSITION0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UVW = input.Pos;
+
+ switch(type) {
+ case 0: // Skybox
+ output.WorldPos = mul((float4x3)ubo.modelview, input.Pos).xyz;
+ output.Pos = mul(ubo.projection, float4(output.WorldPos, 1.0));
+ break;
+ case 1: // Object
+ output.WorldPos = mul(ubo.modelview, float4(input.Pos, 1.0)).xyz;
+ output.Pos = mul(ubo.projection, mul(ubo.modelview, float4(input.Pos.xyz, 1.0)));
+ break;
+ }
+ output.WorldPos = mul(ubo.modelview, float4(input.Pos, 1.0)).xyz;
+ output.Normal = mul((float4x3)ubo.modelview, input.Normal).xyz;
+
+ float3 lightPos = float3(0.0f, -5.0f, 5.0f);
+ output.LightVec = lightPos.xyz - output.WorldPos.xyz;
+ output.ViewVec = -output.WorldPos.xyz;
+ return output;
+}
diff --git a/data/hlsl/imgui/scene.frag b/data/hlsl/imgui/scene.frag
new file mode 100644
index 00000000..cdb2d089
--- /dev/null
+++ b/data/hlsl/imgui/scene.frag
@@ -0,0 +1,20 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float diffuse = max(dot(N, L), 0.0);
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75);
+ return float4(diffuse * input.Color + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/imgui/scene.vert b/data/hlsl/imgui/scene.vert
new file mode 100644
index 00000000..f7a59099
--- /dev/null
+++ b/data/hlsl/imgui/scene.vert
@@ -0,0 +1,41 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+
+ float4 pos = mul(ubo.model, float4(input.Pos, 1.0));
+ output.Normal = mul((float4x3)ubo.model, input.Normal).xyz;
+ float3 lPos = mul((float4x3)ubo.model, ubo.lightPos.xyz).xyz;
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/imgui/ui.frag b/data/hlsl/imgui/ui.frag
new file mode 100644
index 00000000..562acfe4
--- /dev/null
+++ b/data/hlsl/imgui/ui.frag
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+Texture2D fontTexture : register(t0);
+SamplerState fontSampler : register(s0);
+
+struct VSOutput
+{
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float4 Color : COLOR0;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ return input.Color * fontTexture.Sample(fontSampler, input.UV);
+}
\ No newline at end of file
diff --git a/data/hlsl/imgui/ui.vert b/data/hlsl/imgui/ui.vert
new file mode 100644
index 00000000..df4e48eb
--- /dev/null
+++ b/data/hlsl/imgui/ui.vert
@@ -0,0 +1,33 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float2 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float4 Color : COLOR0;
+};
+
+struct PushConstants
+{
+ float2 scale;
+ float2 translate;
+};
+
+[[vk::push_constant]]
+PushConstants pushConstants;
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float4 Color : COLOR0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV;
+ output.Color = input.Color;
+ output.Pos = float4(input.Pos * pushConstants.scale + pushConstants.translate, 0.0, 1.0);
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/indirectdraw/ground.frag b/data/hlsl/indirectdraw/ground.frag
new file mode 100644
index 00000000..435309e9
--- /dev/null
+++ b/data/hlsl/indirectdraw/ground.frag
@@ -0,0 +1,27 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t2);
+SamplerState samplerColor : register(s2);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ // Last array layer is terrain tex
+ float4 color = textureColor.Sample(samplerColor, input.UV);
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 ambient = float3(0.65, 0.65, 0.65);
+ float3 diffuse = max(dot(N, L), 0.0) * input.Color;
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.1, 0.1, 0.1);
+ return float4((ambient + diffuse) * color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/indirectdraw/ground.vert b/data/hlsl/indirectdraw/ground.vert
new file mode 100644
index 00000000..52500dd3
--- /dev/null
+++ b/data/hlsl/indirectdraw/ground.vert
@@ -0,0 +1,45 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.UV = input.UV * 32.0;
+ output.Normal = input.Normal;
+
+ float4 pos = float4(input.Pos.xyz, 1.0);
+
+ output.Pos = mul(ubo.projection, mul(ubo.modelview, pos));
+
+ float4 wPos = mul(ubo.modelview, float4(pos.xyz, 1.0));
+ float4 lPos = float4(0.0, -5.0, 0.0, 1.0);
+ output.LightVec = lPos.xyz - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
diff --git a/data/hlsl/indirectdraw/indirectdraw.frag b/data/hlsl/indirectdraw/indirectdraw.frag
new file mode 100644
index 00000000..395a5a2b
--- /dev/null
+++ b/data/hlsl/indirectdraw/indirectdraw.frag
@@ -0,0 +1,29 @@
+// Copyright 2020 Google LLC
+
+Texture2DArray textureArray : register(t1);
+SamplerState samplerArray : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 color = textureArray.Sample(samplerArray, input.UV);
+
+ if (color.a < 0.5)
+ {
+ clip(-1);
+ }
+
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 ambient = float3(0.65, 0.65, 0.65);
+ float3 diffuse = max(dot(N, L), 0.0) * input.Color;
+ return float4((ambient + diffuse) * color.rgb, 1.0);
+}
diff --git a/data/hlsl/indirectdraw/indirectdraw.vert b/data/hlsl/indirectdraw/indirectdraw.vert
new file mode 100644
index 00000000..135bd612
--- /dev/null
+++ b/data/hlsl/indirectdraw/indirectdraw.vert
@@ -0,0 +1,82 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+[[vk::location(4)]] float3 instancePos : POSITION1;
+[[vk::location(5)]] float3 instanceRot : TEXCOORD1;
+[[vk::location(6)]] float instanceScale : TEXCOORD2;
+[[vk::location(7)]] int instanceTexIndex : TEXCOORD3;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.UV = float3(input.UV, input.instanceTexIndex);
+ output.UV.y = 1.0 - output.UV.y;
+
+ float4x4 mx, my, mz;
+
+ // rotate around x
+ float s = sin(input.instanceRot.x);
+ float c = cos(input.instanceRot.x);
+
+ mx[0] = float4(c, s, 0.0, 0.0);
+ mx[1] = float4(-s, c, 0.0, 0.0);
+ mx[2] = float4(0.0, 0.0, 1.0, 0.0);
+ mx[3] = float4(0.0, 0.0, 0.0, 1.0);
+
+ // rotate around y
+ s = sin(input.instanceRot.y);
+ c = cos(input.instanceRot.y);
+
+ my[0] = float4(c, 0.0, s, 0.0);
+ my[1] = float4(0.0, 1.0, 0.0, 0.0);
+ my[2] = float4(-s, 0.0, c, 0.0);
+ my[3] = float4(0.0, 0.0, 0.0, 1.0);
+
+ // rot around z
+ s = sin(input.instanceRot.z);
+ c = cos(input.instanceRot.z);
+
+ mz[0] = float4(1.0, 0.0, 0.0, 0.0);
+ mz[1] = float4(0.0, c, s, 0.0);
+ mz[2] = float4(0.0, -s, c, 0.0);
+ mz[3] = float4(0.0, 0.0, 0.0, 1.0);
+
+ float4x4 rotMat = mul(mz, mul(my, mx));
+
+ output.Normal = mul((float4x3)rotMat, input.Normal).xyz;
+
+ float4 pos = mul(rotMat, float4((input.Pos.xyz * input.instanceScale) + input.instancePos, 1.0));
+
+ output.Pos = mul(ubo.projection, mul(ubo.modelview, pos));
+
+ float4 wPos = mul(ubo.modelview, float4(pos.xyz, 1.0));
+ float4 lPos = float4(0.0, -5.0, 0.0, 1.0);
+ output.LightVec = lPos.xyz - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
diff --git a/data/hlsl/indirectdraw/skysphere.frag b/data/hlsl/indirectdraw/skysphere.frag
new file mode 100644
index 00000000..f6fbfa89
--- /dev/null
+++ b/data/hlsl/indirectdraw/skysphere.frag
@@ -0,0 +1,11 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t2);
+SamplerState samplerColor : register(s2);
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ const float4 gradientStart = float4(0.93, 0.9, 0.81, 1.0);
+ const float4 gradientEnd = float4(0.35, 0.5, 1.0, 1.0);
+ return lerp(gradientStart, gradientEnd, min(0.5 - inUV.y, 0.5)/0.15 + 0.5);
+}
\ No newline at end of file
diff --git a/data/hlsl/indirectdraw/skysphere.vert b/data/hlsl/indirectdraw/skysphere.vert
new file mode 100644
index 00000000..c16dd3f2
--- /dev/null
+++ b/data/hlsl/indirectdraw/skysphere.vert
@@ -0,0 +1,30 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2(input.UV.x, 1.0-input.UV.y);
+ // Skysphere always at center, only use rotation part of modelview matrix
+ output.Pos = mul(ubo.projection, float4(mul((float3x3)ubo.modelview, input.Pos.xyz), 1));
+ return output;
+}
diff --git a/data/hlsl/inlineuniformblocks/pbr.frag b/data/hlsl/inlineuniformblocks/pbr.frag
new file mode 100644
index 00000000..ad1bf284
--- /dev/null
+++ b/data/hlsl/inlineuniformblocks/pbr.frag
@@ -0,0 +1,119 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 WorldPos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+ float3 camPos;
+};
+cbuffer ubo : register(b0) { UBO ubo; };
+
+// Inline uniform block
+struct UniformInline {
+ float roughness;
+ float metallic;
+ float r;
+ float g;
+ float b;
+ float ambient;
+};
+cbuffer material : register(b0, space1) { UniformInline material; };
+
+#define PI 3.14159265359
+
+float3 materialcolor()
+{
+ return float3(material.r, material.g, material.b);
+}
+
+// Normal Distribution function --------------------------------------
+float D_GGX(float dotNH, float roughness)
+{
+ float alpha = roughness * roughness;
+ float alpha2 = alpha * alpha;
+ float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0;
+ return (alpha2)/(PI * denom*denom);
+}
+
+// Geometric Shadowing function --------------------------------------
+float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness)
+{
+ float r = (roughness + 1.0);
+ float k = (r*r) / 8.0;
+ float GL = dotNL / (dotNL * (1.0 - k) + k);
+ float GV = dotNV / (dotNV * (1.0 - k) + k);
+ return GL * GV;
+}
+
+// Fresnel function ----------------------------------------------------
+float3 F_Schlick(float cosTheta, float metallic)
+{
+ float3 F0 = lerp(float3(0.04, 0.04, 0.04), materialcolor(), metallic); // * material.specular
+ float3 F = F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
+ return F;
+}
+
+// Specular BRDF composition --------------------------------------------
+
+float3 BRDF(float3 L, float3 V, float3 N, float metallic, float roughness)
+{
+ // Precalculate vectors and dot products
+ float3 H = normalize (V + L);
+ float dotNV = clamp(dot(N, V), 0.0, 1.0);
+ float dotNL = clamp(dot(N, L), 0.0, 1.0);
+ float dotLH = clamp(dot(L, H), 0.0, 1.0);
+ float dotNH = clamp(dot(N, H), 0.0, 1.0);
+
+ // Light color fixed
+ float3 lightColor = float3(1.0, 1.0, 1.0);
+
+ float3 color = float3(0.0, 0.0, 0.0);
+
+ if (dotNL > 0.0)
+ {
+ float rroughness = max(0.05, roughness);
+ // D = Normal distribution (Distribution of the microfacets)
+ float D = D_GGX(dotNH, rroughness);
+ // G = Geometric shadowing term (Microfacets shadowing)
+ float G = G_SchlicksmithGGX(dotNL, dotNV, rroughness);
+ // F = Fresnel factor (Reflectance depending on angle of incidence)
+ float3 F = F_Schlick(dotNV, metallic);
+
+ float3 spec = D * F * G / (4.0 * dotNL * dotNV);
+
+ color += spec * dotNL * lightColor;
+ }
+
+ return color;
+}
+
+// ----------------------------------------------------------------------------
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 V = normalize(ubo.camPos - input.WorldPos);
+
+ float roughness = material.roughness;
+
+ // Specular contribution
+ float3 lightPos = float3(0.0f, 0.0f, 10.0f);
+ float3 Lo = float3(0.0, 0.0, 0.0);
+ float3 L = normalize(lightPos.xyz - input.WorldPos);
+ Lo += BRDF(L, V, N, material.metallic, roughness);
+
+ // Combine with ambient
+ float3 color = materialcolor() * material.ambient;
+ color += Lo;
+
+ // Gamma correct
+ color = pow(color, float3(0.4545, 0.4545, 0.4545));
+
+ return float4(color, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/inlineuniformblocks/pbr.vert b/data/hlsl/inlineuniformblocks/pbr.vert
new file mode 100644
index 00000000..b9f5c1b3
--- /dev/null
+++ b/data/hlsl/inlineuniformblocks/pbr.vert
@@ -0,0 +1,38 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+ float3 camPos;
+};
+cbuffer ubo : register(b0) { UBO ubo; };
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 WorldPos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+};
+
+struct PushConsts {
+ float3 objPos;
+};
+[[vk::push_constant]] PushConsts pushConsts;
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ float3 locPos = mul(ubo.model, float4(input.Pos, 1.0)).xyz;
+ output.WorldPos = locPos + pushConsts.objPos;
+ output.Normal = mul((float4x3)ubo.model, input.Normal).xyz;
+ output.Pos = mul(ubo.projection, mul(ubo.view, float4(output.WorldPos, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/inputattachments/attachmentread.frag b/data/hlsl/inputattachments/attachmentread.frag
new file mode 100644
index 00000000..28ef33ed
--- /dev/null
+++ b/data/hlsl/inputattachments/attachmentread.frag
@@ -0,0 +1,35 @@
+// Copyright 2020 Google LLC
+
+[[vk::input_attachment_index(0)]][[vk::binding(0)]] SubpassInput inputColor;
+[[vk::input_attachment_index(1)]][[vk::binding(1)]] SubpassInput inputDepth;
+
+struct UBO {
+ float2 brightnessContrast;
+ float2 range;
+ int attachmentIndex;
+};
+
+cbuffer ubo : register(b2) { UBO ubo; }
+
+float3 brightnessContrast(float3 color, float brightness, float contrast) {
+ return (color - 0.5) * contrast + 0.5 + brightness;
+}
+
+float4 main() : SV_TARGET
+{
+ // Apply brightness and contrast filer to color input
+ if (ubo.attachmentIndex == 0) {
+ // Read color from previous color input attachment
+ float3 color = inputColor.SubpassLoad().rgb;
+ return float4(brightnessContrast(color, ubo.brightnessContrast[0], ubo.brightnessContrast[1]), 1);
+ }
+
+ // Visualize depth input range
+ if (ubo.attachmentIndex == 1) {
+ // Read depth from previous depth input attachment
+ float depth = inputDepth.SubpassLoad().r;
+ return float4((depth - ubo.range[0]) * 1.0 / (ubo.range[1] - ubo.range[0]).xxx, 1);
+ }
+
+ return 0.xxxx;
+}
\ No newline at end of file
diff --git a/data/hlsl/inputattachments/attachmentread.vert b/data/hlsl/inputattachments/attachmentread.vert
new file mode 100644
index 00000000..fa447fcf
--- /dev/null
+++ b/data/hlsl/inputattachments/attachmentread.vert
@@ -0,0 +1,6 @@
+// Copyright 2020 Google LLC
+
+float4 main(uint VertexIndex : SV_VertexID) : SV_POSITION
+{
+ return float4(float2((VertexIndex << 1) & 2, VertexIndex & 2) * 2.0f - 1.0f, 0.0f, 1.0f);
+}
\ No newline at end of file
diff --git a/data/hlsl/inputattachments/attachmentwrite.frag b/data/hlsl/inputattachments/attachmentwrite.frag
new file mode 100644
index 00000000..35ea3f3a
--- /dev/null
+++ b/data/hlsl/inputattachments/attachmentwrite.frag
@@ -0,0 +1,24 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Color : COLOR0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ // Toon shading color attachment output
+ float intensity = dot(normalize(input.Normal), normalize(input.LightVec));
+ float shade = 1.0;
+ shade = intensity < 0.5 ? 0.75 : shade;
+ shade = intensity < 0.35 ? 0.6 : shade;
+ shade = intensity < 0.25 ? 0.5 : shade;
+ shade = intensity < 0.1 ? 0.25 : shade;
+
+ return float4(input.Color * 3.0 * shade, 1);
+
+ // Depth attachment does not need to be explicitly written
+}
\ No newline at end of file
diff --git a/data/hlsl/inputattachments/attachmentwrite.vert b/data/hlsl/inputattachments/attachmentwrite.vert
new file mode 100644
index 00000000..eff5642a
--- /dev/null
+++ b/data/hlsl/inputattachments/attachmentwrite.vert
@@ -0,0 +1,36 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+};
+
+struct UBO {
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, float4(input.Pos, 1.0))));
+ output.Color = input.Color;
+ output.Normal = input.Normal;
+ output.LightVec = float3(0.0f, 5.0f, 15.0f) - input.Pos;
+ output.ViewVec = -input.Pos.xyz;
+ return output;
+}
diff --git a/data/hlsl/instancing/instancing.frag b/data/hlsl/instancing/instancing.frag
new file mode 100644
index 00000000..1e3a0b78
--- /dev/null
+++ b/data/hlsl/instancing/instancing.frag
@@ -0,0 +1,25 @@
+// Copyright 2020 Google LLC
+
+Texture2DArray textureArray : register(t1);
+SamplerState samplerArray : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 color = textureArray.Sample(samplerArray, input.UV) * float4(input.Color, 1.0);
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.1) * input.Color;
+ float3 specular = (dot(N,L) > 0.0) ? pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75) * color.r : float3(0.0, 0.0, 0.0);
+ return float4(diffuse * color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/instancing/instancing.vert b/data/hlsl/instancing/instancing.vert
new file mode 100644
index 00000000..62e41234
--- /dev/null
+++ b/data/hlsl/instancing/instancing.vert
@@ -0,0 +1,89 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+
+// Instanced attributes
+[[vk::location(4)]] float3 instancePos : POSITION1;
+[[vk::location(5)]] float3 instanceRot : TEXCOORD1;
+[[vk::location(6)]] float instanceScale : TEXCOORD2;
+[[vk::location(7)]] int instanceTexIndex : TEXCOORD3;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+ float4 lightPos;
+ float locSpeed;
+ float globSpeed;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.UV = float3(input.UV, input.instanceTexIndex);
+
+ // rotate around x
+ float s = sin(input.instanceRot.x + ubo.locSpeed);
+ float c = cos(input.instanceRot.x + ubo.locSpeed);
+
+ float3x3 mx = { c, -s, 0.0,
+ s, c, 0.0,
+ 0.0, 0.0, 1.0 };
+
+ // rotate around y
+ s = sin(input.instanceRot.y + ubo.locSpeed);
+ c = cos(input.instanceRot.y + ubo.locSpeed);
+
+ float3x3 my = { c, 0.0, -s,
+ 0.0, 1.0, 0.0,
+ s, 0.0, c };
+
+ // rot around z
+ s = sin(input.instanceRot.z + ubo.locSpeed);
+ c = cos(input.instanceRot.z + ubo.locSpeed);
+
+ float3x3 mz = { 1.0, 0.0, 0.0,
+ 0.0, c, -s,
+ 0.0, s, c };
+
+ float3x3 rotMat = mul(mz, mul(my, mx));
+
+ float4x4 gRotMat;
+ s = sin(input.instanceRot.y + ubo.globSpeed);
+ c = cos(input.instanceRot.y + ubo.globSpeed);
+ gRotMat[0] = float4(c, 0.0, -s, 0.0);
+ gRotMat[1] = float4(0.0, 1.0, 0.0, 0.0);
+ gRotMat[2] = float4(s, 0.0, c, 0.0);
+ gRotMat[3] = float4(0.0, 0.0, 0.0, 1.0);
+
+ float4 locPos = float4(mul(rotMat, input.Pos.xyz), 1.0);
+ float4 pos = float4((locPos.xyz * input.instanceScale) + input.instancePos, 1.0);
+
+ output.Pos = mul(ubo.projection, mul(ubo.modelview, mul(gRotMat, pos)));
+ output.Normal = mul((float3x3)mul(ubo.modelview, gRotMat), mul(rotMat, input.Normal));
+
+ pos = mul(ubo.modelview, float4(input.Pos.xyz + input.instancePos, 1.0));
+ float3 lPos = mul((float3x3)ubo.modelview, ubo.lightPos.xyz);
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
diff --git a/data/hlsl/instancing/planet.frag b/data/hlsl/instancing/planet.frag
new file mode 100644
index 00000000..8fca3642
--- /dev/null
+++ b/data/hlsl/instancing/planet.frag
@@ -0,0 +1,25 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t1);
+SamplerState samplerColorMap : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 color = textureColorMap.Sample(samplerColorMap, input.UV) * float4(input.Color, 1.0) * 1.5;
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * input.Color;
+ float3 specular = pow(max(dot(R, V), 0.0), 4.0) * float3(0.5, 0.5, 0.5) * color.r;
+ return float4(diffuse * color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/instancing/planet.vert b/data/hlsl/instancing/planet.vert
new file mode 100644
index 00000000..a2ed98df
--- /dev/null
+++ b/data/hlsl/instancing/planet.vert
@@ -0,0 +1,43 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.UV = input.UV * float2(10.0, 6.0);
+ output.Pos = mul(ubo.projection, mul(ubo.modelview, float4(input.Pos.xyz, 1.0)));
+
+ float4 pos = mul(ubo.modelview, float4(input.Pos, 1.0));
+ output.Normal = mul((float3x3)ubo.modelview, input.Normal);
+ float3 lPos = mul((float3x3)ubo.modelview, ubo.lightPos.xyz);
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/instancing/starfield.frag b/data/hlsl/instancing/starfield.frag
new file mode 100644
index 00000000..a32fbaae
--- /dev/null
+++ b/data/hlsl/instancing/starfield.frag
@@ -0,0 +1,30 @@
+// Copyright 2020 Google LLC
+
+#define HASHSCALE3 float3(443.897, 441.423, 437.195)
+#define STARFREQUENCY 0.01
+
+// Hash function by Dave Hoskins (https://www.shadertoy.com/view/4djSRW)
+float hash33(float3 p3)
+{
+ p3 = frac(p3 * HASHSCALE3);
+ p3 += dot(p3, p3.yxz+float3(19.19, 19.19, 19.19));
+ return frac((p3.x + p3.y)*p3.z + (p3.x+p3.z)*p3.y + (p3.y+p3.z)*p3.x);
+}
+
+float3 starField(float3 pos)
+{
+ float3 color = float3(0.0, 0.0, 0.0);
+ float threshhold = (1.0 - STARFREQUENCY);
+ float rnd = hash33(pos);
+ if (rnd >= threshhold)
+ {
+ float starCol = pow((rnd - threshhold) / (1.0 - threshhold), 16.0);
+ color += starCol.xxx;
+ }
+ return color;
+}
+
+float4 main([[vk::location(0)]] float3 inUVW : TEXCOORD0) : SV_TARGET
+{
+ return float4(starField(inUVW), 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/instancing/starfield.vert b/data/hlsl/instancing/starfield.vert
new file mode 100644
index 00000000..cb7a40d2
--- /dev/null
+++ b/data/hlsl/instancing/starfield.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UVW : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UVW = float3((VertexIndex << 1) & 2, VertexIndex & 2, VertexIndex & 2);
+ output.Pos = float4(output.UVW.xy * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/mesh/mesh.frag b/data/hlsl/mesh/mesh.frag
new file mode 100644
index 00000000..2bc0a9c2
--- /dev/null
+++ b/data/hlsl/mesh/mesh.frag
@@ -0,0 +1,26 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t1);
+SamplerState samplerColorMap : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 color = textureColorMap.Sample(samplerColorMap, input.UV) * float4(input.Color, 1.0);
+
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * input.Color;
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75);
+ return float4(diffuse * color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/mesh/mesh.vert b/data/hlsl/mesh/mesh.vert
new file mode 100644
index 00000000..2ea7b03b
--- /dev/null
+++ b/data/hlsl/mesh/mesh.vert
@@ -0,0 +1,44 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.UV = input.UV;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+
+ float4 pos = mul(ubo.model, float4(input.Pos, 1.0));
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ float3 lPos = mul((float3x3)ubo.model, ubo.lightPos.xyz);
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/multisampling/scene.frag b/data/hlsl/multisampling/scene.frag
new file mode 100644
index 00000000..2bc0a9c2
--- /dev/null
+++ b/data/hlsl/multisampling/scene.frag
@@ -0,0 +1,26 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t1);
+SamplerState samplerColorMap : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 color = textureColorMap.Sample(samplerColorMap, input.UV) * float4(input.Color, 1.0);
+
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * input.Color;
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75);
+ return float4(diffuse * color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/multisampling/scene.vert b/data/hlsl/multisampling/scene.vert
new file mode 100644
index 00000000..4e5e9f4e
--- /dev/null
+++ b/data/hlsl/multisampling/scene.vert
@@ -0,0 +1,43 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 lightPos;
+};
+cbuffer ubo : register(b0) { UBO ubo; };
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.UV = input.UV;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+
+ float4 pos = mul(ubo.model, float4(input.Pos, 0.0));
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ float3 lPos = mul((float3x3)ubo.model, ubo.lightPos.xyz);
+ output.LightVec = lPos - input.Pos;
+ output.ViewVec = -input.Pos;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/multithreading/phong.frag b/data/hlsl/multithreading/phong.frag
new file mode 100644
index 00000000..5212cd15
--- /dev/null
+++ b/data/hlsl/multithreading/phong.frag
@@ -0,0 +1,20 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * input.Color;
+ float3 specular = pow(max(dot(R, V), 0.0), 8.0) * float3(0.75, 0.75, 0.75);
+ return float4(diffuse + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/multithreading/phong.vert b/data/hlsl/multithreading/phong.vert
new file mode 100644
index 00000000..1487ba17
--- /dev/null
+++ b/data/hlsl/multithreading/phong.vert
@@ -0,0 +1,49 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+};
+
+struct PushConsts
+{
+ float4x4 mvp;
+ float3 color;
+};
+[[vk::push_constant]]PushConsts pushConsts;
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+
+ if ( (input.Color.r == 1.0) && (input.Color.g == 0.0) && (input.Color.b == 0.0))
+ {
+ output.Color = pushConsts.color;
+ }
+ else
+ {
+ output.Color = input.Color;
+ }
+
+ output.Pos = mul(pushConsts.mvp, float4(input.Pos.xyz, 1.0));
+
+ float4 pos = mul(pushConsts.mvp, float4(input.Pos, 1.0));
+ output.Normal = mul((float3x3)pushConsts.mvp, input.Normal);
+// float3 lPos = ubo.lightPos.xyz;
+float3 lPos = float3(0.0, 0.0, 0.0);
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/multithreading/starsphere.frag b/data/hlsl/multithreading/starsphere.frag
new file mode 100644
index 00000000..e516740e
--- /dev/null
+++ b/data/hlsl/multithreading/starsphere.frag
@@ -0,0 +1,35 @@
+// Copyright 2020 Google LLC
+
+#define HASHSCALE3 float3(443.897, 441.423, 437.195)
+#define STARFREQUENCY 0.01
+
+// Hash function by Dave Hoskins (https://www.shadertoy.com/view/4djSRW)
+float hash33(float3 p3)
+{
+ p3 = frac(p3 * HASHSCALE3);
+ p3 += dot(p3, p3.yxz+float3(19.19, 19.19, 19.19));
+ return frac((p3.x + p3.y)*p3.z + (p3.x+p3.z)*p3.y + (p3.y+p3.z)*p3.x);
+}
+
+float3 starField(float3 pos)
+{
+ float3 color = float3(0.0, 0.0, 0.0);
+ float threshhold = (1.0 - STARFREQUENCY);
+ float rnd = hash33(pos);
+ if (rnd >= threshhold)
+ {
+ float starCol = pow((rnd - threshhold) / (1.0 - threshhold), 16.0);
+ color += starCol.xxx;
+ }
+ return color;
+}
+
+float4 main([[vk::location(0)]] float3 inUVW : TEXCOORD0) : SV_TARGET
+{
+ // Fake atmosphere at the bottom
+ float3 atmosphere = clamp(float3(0.1, 0.15, 0.4) * (inUVW.y - 5.0), 0.0, 1.0);
+
+ float3 color = starField(inUVW) + atmosphere;
+
+ return float4(color, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/multithreading/starsphere.vert b/data/hlsl/multithreading/starsphere.vert
new file mode 100644
index 00000000..13e48cb2
--- /dev/null
+++ b/data/hlsl/multithreading/starsphere.vert
@@ -0,0 +1,21 @@
+// Copyright 2020 Google LLC
+
+struct PushConsts
+{
+ float4x4 mvp;
+};
+[[vk::push_constant]]PushConsts pushConsts;
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UVW : TEXCOORD0;
+};
+
+VSOutput main([[vk::location(0)]] float3 Pos : POSITION0)
+{
+ VSOutput output = (VSOutput)0;
+ output.UVW = Pos;
+ output.Pos = mul(pushConsts.mvp, float4(Pos.xyz, 1.0));
+ return output;
+}
diff --git a/data/hlsl/multiview/multiview.frag b/data/hlsl/multiview/multiview.frag
new file mode 100644
index 00000000..2c14be89
--- /dev/null
+++ b/data/hlsl/multiview/multiview.frag
@@ -0,0 +1,21 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 ambient = float3(0.1, 0.1, 0.1);
+ float3 diffuse = max(dot(N, L), 0.0) * float3(1.0, 1.0, 1.0);
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75);
+ return float4((ambient + diffuse) * input.Color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/multiview/multiview.vert b/data/hlsl/multiview/multiview.vert
new file mode 100644
index 00000000..214db9cf
--- /dev/null
+++ b/data/hlsl/multiview/multiview.vert
@@ -0,0 +1,43 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+struct UBO
+{
+ float4x4 projection[2];
+ float4x4 modelview[2];
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+VSOutput main(VSInput input, uint ViewIndex : SV_ViewID)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.Normal = mul((float3x3)ubo.modelview[ViewIndex], input.Normal);
+
+ float4 pos = float4(input.Pos.xyz, 1.0);
+ float4 worldPos = mul(ubo.modelview[ViewIndex], pos);
+
+ float3 lPos = mul(ubo.modelview[ViewIndex], ubo.lightPos).xyz;
+ output.LightVec = lPos - worldPos.xyz;
+ output.ViewVec = -worldPos.xyz;
+
+ output.Pos = mul(ubo.projection[ViewIndex], worldPos);
+ return output;
+}
diff --git a/data/hlsl/multiview/viewdisplay.frag b/data/hlsl/multiview/viewdisplay.frag
new file mode 100644
index 00000000..da365d00
--- /dev/null
+++ b/data/hlsl/multiview/viewdisplay.frag
@@ -0,0 +1,25 @@
+// Copyright 2020 Google LLC
+
+Texture2DArray textureView : register(t1);
+SamplerState samplerView : register(s1);
+
+struct UBO
+{
+ [[vk::offset(272)]] float distortionAlpha;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+[[vk::constant_id(0)]] const float VIEW_LAYER = 0.0f;
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ const float alpha = ubo.distortionAlpha;
+
+ float2 p1 = float2(2.0 * inUV - 1.0);
+ float2 p2 = p1 / (1.0 - alpha * length(p1));
+ p2 = (p2 + 1.0) * 0.5;
+
+ bool inside = ((p2.x >= 0.0) && (p2.x <= 1.0) && (p2.y >= 0.0 ) && (p2.y <= 1.0));
+ return inside ? textureView.Sample(samplerView, float3(p2, VIEW_LAYER)) : float4(0.0, 0.0, 0.0, 0.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/multiview/viewdisplay.vert b/data/hlsl/multiview/viewdisplay.vert
new file mode 100644
index 00000000..b13c2bf2
--- /dev/null
+++ b/data/hlsl/multiview/viewdisplay.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/negativeviewportheight/quad.frag b/data/hlsl/negativeviewportheight/quad.frag
new file mode 100644
index 00000000..8236872c
--- /dev/null
+++ b/data/hlsl/negativeviewportheight/quad.frag
@@ -0,0 +1,9 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t0);
+SamplerState samplerColor : register(s0);
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ return textureColor.Sample(samplerColor, inUV);
+}
\ No newline at end of file
diff --git a/data/hlsl/negativeviewportheight/quad.vert b/data/hlsl/negativeviewportheight/quad.vert
new file mode 100644
index 00000000..1864c0be
--- /dev/null
+++ b/data/hlsl/negativeviewportheight/quad.vert
@@ -0,0 +1,21 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV;
+ output.Pos = float4(input.Pos, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/nv_ray_tracing_basic/closesthit.rchit b/data/hlsl/nv_ray_tracing_basic/closesthit.rchit
new file mode 100644
index 00000000..ace73d3d
--- /dev/null
+++ b/data/hlsl/nv_ray_tracing_basic/closesthit.rchit
@@ -0,0 +1,18 @@
+// Copyright 2020 Google LLC
+
+struct Attribute
+{
+ float2 attribs;
+};
+
+struct Payload
+{
+[[vk::location(0)]] float3 hitValue;
+};
+
+[shader("closesthit")]
+void main(inout Payload p, in float3 attribs)
+{
+ const float3 barycentricCoords = float3(1.0f - attribs.x - attribs.y, attribs.x, attribs.y);
+ p.hitValue = barycentricCoords;
+}
diff --git a/data/hlsl/nv_ray_tracing_basic/miss.rmiss b/data/hlsl/nv_ray_tracing_basic/miss.rmiss
new file mode 100644
index 00000000..d9e274c0
--- /dev/null
+++ b/data/hlsl/nv_ray_tracing_basic/miss.rmiss
@@ -0,0 +1,12 @@
+// Copyright 2020 Google LLC
+
+struct Payload
+{
+[[vk::location(0)]] float3 hitValue;
+};
+
+[shader("miss")]
+void main(inout Payload p)
+{
+ p.hitValue = float3(0.0, 0.0, 0.2);
+}
\ No newline at end of file
diff --git a/data/hlsl/nv_ray_tracing_basic/raygen.rgen b/data/hlsl/nv_ray_tracing_basic/raygen.rgen
new file mode 100644
index 00000000..d30bb92e
--- /dev/null
+++ b/data/hlsl/nv_ray_tracing_basic/raygen.rgen
@@ -0,0 +1,39 @@
+// Copyright 2020 Google LLC
+
+RaytracingAccelerationStructure rs : register(t0);
+RWTexture2D image : register(u1);
+
+struct CameraProperties
+{
+ float4x4 viewInverse;
+ float4x4 projInverse;
+};
+cbuffer cam : register(b2) { CameraProperties cam; };
+
+struct Payload
+{
+[[vk::location(0)]] float3 hitValue;
+};
+
+[shader("raygeneration")]
+void main()
+{
+ uint3 LaunchID = DispatchRaysIndex();
+ uint3 LaunchSize = DispatchRaysDimensions();
+
+ const float2 pixelCenter = float2(LaunchID.xy) + float2(0.5, 0.5);
+ const float2 inUV = pixelCenter/float2(LaunchSize.xy);
+ float2 d = inUV * 2.0 - 1.0;
+ float4 target = mul(cam.projInverse, float4(d.x, d.y, 1, 1));
+
+ RayDesc rayDesc;
+ rayDesc.Origin = mul(cam.viewInverse, float4(0,0,0,1)).xyz;
+ rayDesc.Direction = mul(cam.viewInverse, float4(normalize(target.xyz), 0)).xyz;
+ rayDesc.TMin = 0.001;
+ rayDesc.TMax = 10000.0;
+
+ Payload payload;
+ TraceRay(rs, RAY_FLAG_FORCE_OPAQUE, 0xff, 0, 0, 0, rayDesc, payload);
+
+ image[int2(LaunchID.xy)] = float4(payload.hitValue, 0.0);
+}
diff --git a/data/hlsl/nv_ray_tracing_reflections/closesthit.rchit b/data/hlsl/nv_ray_tracing_reflections/closesthit.rchit
new file mode 100644
index 00000000..8c8358a6
--- /dev/null
+++ b/data/hlsl/nv_ray_tracing_reflections/closesthit.rchit
@@ -0,0 +1,68 @@
+// Copyright 2020 Google LLC
+
+struct RayPayload
+{
+ float3 color;
+ float distance;
+ float3 normal;
+ float reflector;
+};
+
+RaytracingAccelerationStructure topLevelAS : register(t0);
+struct CameraProperties
+{
+ float4x4 viewInverse;
+ float4x4 projInverse;
+ float4 lightPos;
+};
+cbuffer cam : register(b2) { CameraProperties cam; };
+
+StructuredBuffer vertices : register(t3);
+StructuredBuffer indices : register(t4);
+
+struct Vertex
+{
+ float3 pos;
+ float3 normal;
+ float3 color;
+ float2 uv;
+ float _pad0;
+};
+
+Vertex unpack(uint index)
+{
+ float4 d0 = vertices[3 * index + 0];
+ float4 d1 = vertices[3 * index + 1];
+ float4 d2 = vertices[3 * index + 2];
+
+ Vertex v;
+ v.pos = d0.xyz;
+ v.normal = float3(d0.w, d1.x, d1.y);
+ v.color = float3(d1.z, d1.w, d2.x);
+ return v;
+}
+
+[shader("closesthit")]
+void main(inout RayPayload rayPayload, in float3 attribs)
+{
+ uint PrimitiveID = PrimitiveIndex();
+ int3 index = int3(indices[3 * PrimitiveID], indices[3 * PrimitiveID + 1], indices[3 * PrimitiveID + 2]);
+
+ Vertex v0 = unpack(index.x);
+ Vertex v1 = unpack(index.y);
+ Vertex v2 = unpack(index.z);
+
+ // Interpolate normal
+ const float3 barycentricCoords = float3(1.0f - attribs.x - attribs.y, attribs.x, attribs.y);
+ float3 normal = normalize(v0.normal * barycentricCoords.x + v1.normal * barycentricCoords.y + v2.normal * barycentricCoords.z);
+
+ // Basic lighting
+ float3 lightVector = normalize(cam.lightPos.xyz);
+ float dot_product = max(dot(lightVector, normal), 0.6);
+ rayPayload.color = v0.color * dot_product;
+ rayPayload.distance = RayTCurrent();
+ rayPayload.normal = normal;
+
+ // Objects with full white vertex color are treated as reflectors
+ rayPayload.reflector = ((v0.color.r == 1.0f) && (v0.color.g == 1.0f) && (v0.color.b == 1.0f)) ? 1.0f : 0.0f;
+}
diff --git a/data/hlsl/nv_ray_tracing_reflections/miss.rmiss b/data/hlsl/nv_ray_tracing_reflections/miss.rmiss
new file mode 100644
index 00000000..8f75824a
--- /dev/null
+++ b/data/hlsl/nv_ray_tracing_reflections/miss.rmiss
@@ -0,0 +1,25 @@
+// Copyright 2020 Google LLC
+
+struct RayPayload {
+ float3 color;
+ float distance;
+ float3 normal;
+ float reflector;
+};
+
+[shader("miss")]
+void main(inout RayPayload rayPayload)
+{
+ float3 worldRayDirection = WorldRayDirection();
+
+ // View-independent background gradient to simulate a basic sky background
+ const float3 gradientStart = float3(0.5, 0.6, 1.0);
+ const float3 gradientEnd = float3(1.0, 1.0, 1.0);
+ float3 unitDir = normalize(worldRayDirection);
+ float t = 0.5 * (unitDir.y + 1.0);
+ rayPayload.color = (1.0-t) * gradientStart + t * gradientEnd;
+
+ rayPayload.distance = -1.0f;
+ rayPayload.normal = float3(0, 0, 0);
+ rayPayload.reflector = 0.0f;
+}
\ No newline at end of file
diff --git a/data/hlsl/nv_ray_tracing_reflections/raygen.rgen b/data/hlsl/nv_ray_tracing_reflections/raygen.rgen
new file mode 100644
index 00000000..23d2cea8
--- /dev/null
+++ b/data/hlsl/nv_ray_tracing_reflections/raygen.rgen
@@ -0,0 +1,64 @@
+// Copyright 2020 Google LLC
+
+RaytracingAccelerationStructure rs : register(t0);
+RWTexture2D image : register(u1);
+
+struct CameraProperties
+{
+ float4x4 viewInverse;
+ float4x4 projInverse;
+ float4 lightPos;
+};
+cbuffer cam : register(b2) { CameraProperties cam; };
+
+
+struct RayPayload {
+ float3 color;
+ float distance;
+ float3 normal;
+ float reflector;
+};
+
+// Max. number of recursion is passed via a specialization constant
+[[vk::constant_id(0)]] const int MAX_RECURSION = 0;
+
+[shader("raygeneration")]
+void main()
+{
+ uint3 LaunchID = DispatchRaysIndex();
+ uint3 LaunchSize = DispatchRaysDimensions();
+
+ const float2 pixelCenter = float2(LaunchID.xy) + float2(0.5, 0.5);
+ const float2 inUV = pixelCenter/float2(LaunchSize.xy);
+ float2 d = inUV * 2.0 - 1.0;
+ float4 target = mul(cam.projInverse, float4(d.x, d.y, 1, 1));
+
+ RayDesc rayDesc;
+ rayDesc.Origin = mul(cam.viewInverse, float4(0,0,0,1)).xyz;
+ rayDesc.Direction = mul(cam.viewInverse, float4(normalize(target.xyz), 0)).xyz;
+ rayDesc.TMin = 0.001;
+ rayDesc.TMax = 10000.0;
+
+ float3 color = float3(0.0, 0.0, 0.0);
+
+ for (int i = 0; i < MAX_RECURSION; i++) {
+ RayPayload rayPayload;
+ TraceRay(rs, RAY_FLAG_FORCE_OPAQUE, 0xff, 0, 0, 0, rayDesc, rayPayload);
+ float3 hitColor = rayPayload.color;
+
+ if (rayPayload.distance < 0.0f) {
+ color += hitColor;
+ break;
+ } else if (rayPayload.reflector == 1.0f) {
+ const float3 hitPos = rayDesc.Origin + rayDesc.Direction * rayPayload.distance;
+ rayDesc.Origin = hitPos + rayPayload.normal * 0.001f;
+ rayDesc.Direction = reflect(rayDesc.Direction, rayPayload.normal);
+ } else {
+ color += hitColor;
+ break;
+ }
+
+ }
+
+ image[int2(LaunchID.xy)] = float4(color, 0.0);
+}
diff --git a/data/hlsl/nv_ray_tracing_shadows/closesthit.rchit b/data/hlsl/nv_ray_tracing_shadows/closesthit.rchit
new file mode 100644
index 00000000..6b990519
--- /dev/null
+++ b/data/hlsl/nv_ray_tracing_shadows/closesthit.rchit
@@ -0,0 +1,78 @@
+// Copyright 2020 Google LLC
+
+struct InPayload
+{
+ [[vk::location(0)]] float3 hitValue;
+};
+
+struct InOutPayload
+{
+ [[vk::location(2)]] bool shadowed;
+};
+
+RaytracingAccelerationStructure topLevelAS : register(t0);
+struct CameraProperties
+{
+ float4x4 viewInverse;
+ float4x4 projInverse;
+ float4 lightPos;
+};
+cbuffer cam : register(b2) { CameraProperties cam; };
+
+StructuredBuffer vertices : register(t3);
+StructuredBuffer indices : register(t4);
+
+struct Vertex
+{
+ float3 pos;
+ float3 normal;
+ float3 color;
+ float2 uv;
+ float _pad0;
+};
+
+Vertex unpack(uint index)
+{
+ float4 d0 = vertices[3 * index + 0];
+ float4 d1 = vertices[3 * index + 1];
+ float4 d2 = vertices[3 * index + 2];
+
+ Vertex v;
+ v.pos = d0.xyz;
+ v.normal = float3(d0.w, d1.x, d1.y);
+ v.color = float3(d1.z, d1.w, d2.x);
+ return v;
+}
+
+[shader("closesthit")]
+void main(in InPayload inPayload, inout InOutPayload inOutPayload, in float3 attribs)
+{
+ uint PrimitiveID = PrimitiveIndex();
+ int3 index = int3(indices[3 * PrimitiveID], indices[3 * PrimitiveID + 1], indices[3 * PrimitiveID + 2]);
+
+ Vertex v0 = unpack(index.x);
+ Vertex v1 = unpack(index.y);
+ Vertex v2 = unpack(index.z);
+
+ // Interpolate normal
+ const float3 barycentricCoords = float3(1.0f - attribs.x - attribs.y, attribs.x, attribs.y);
+ float3 normal = normalize(v0.normal * barycentricCoords.x + v1.normal * barycentricCoords.y + v2.normal * barycentricCoords.z);
+
+ // Basic lighting
+ float3 lightVector = normalize(cam.lightPos.xyz);
+ float dot_product = max(dot(lightVector, normal), 0.2);
+ inPayload.hitValue = v0.color * dot_product;
+
+ RayDesc rayDesc;
+ rayDesc.Origin = WorldRayOrigin() + WorldRayDirection() * RayTCurrent();
+ rayDesc.Direction = lightVector;
+ rayDesc.TMin = 0.001;
+ rayDesc.TMax = 100.0;
+
+ inOutPayload.shadowed = true;
+ // Offset indices to match shadow hit/miss index
+ TraceRay(topLevelAS, RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH | RAY_FLAG_FORCE_OPAQUE | RAY_FLAG_SKIP_CLOSEST_HIT_SHADER, 0xff, 1, 0, 1, rayDesc, inOutPayload);
+ if (inOutPayload.shadowed) {
+ inPayload.hitValue *= 0.3;
+ }
+}
diff --git a/data/hlsl/nv_ray_tracing_shadows/miss.rmiss b/data/hlsl/nv_ray_tracing_shadows/miss.rmiss
new file mode 100644
index 00000000..b142967a
--- /dev/null
+++ b/data/hlsl/nv_ray_tracing_shadows/miss.rmiss
@@ -0,0 +1,7 @@
+// Copyright 2020 Google LLC
+
+[shader("miss")]
+void main([[vk::location(0)]] in float3 hitValue)
+{
+ hitValue = float3(0.0, 0.0, 0.2);
+}
\ No newline at end of file
diff --git a/data/hlsl/nv_ray_tracing_shadows/raygen.rgen b/data/hlsl/nv_ray_tracing_shadows/raygen.rgen
new file mode 100644
index 00000000..0ccf0e44
--- /dev/null
+++ b/data/hlsl/nv_ray_tracing_shadows/raygen.rgen
@@ -0,0 +1,40 @@
+// Copyright 2020 Google LLC
+
+RaytracingAccelerationStructure rs : register(t0);
+RWTexture2D image : register(u1);
+
+struct CameraProperties
+{
+ float4x4 viewInverse;
+ float4x4 projInverse;
+ float4 lightPos;
+};
+cbuffer cam : register(b2) { CameraProperties cam; };
+
+struct Payload
+{
+ [[vk::location(0)]] float3 hitValue;
+};
+
+[shader("raygeneration")]
+void main()
+{
+ uint3 LaunchID = DispatchRaysIndex();
+ uint3 LaunchSize = DispatchRaysDimensions();
+
+ const float2 pixelCenter = float2(LaunchID.xy) + float2(0.5, 0.5);
+ const float2 inUV = pixelCenter/float2(LaunchSize.xy);
+ float2 d = inUV * 2.0 - 1.0;
+ float4 target = mul(cam.projInverse, float4(d.x, d.y, 1, 1));
+
+ RayDesc rayDesc;
+ rayDesc.Origin = mul(cam.viewInverse, float4(0,0,0,1)).xyz;
+ rayDesc.Direction = mul(cam.viewInverse, float4(normalize(target.xyz), 0)).xyz;
+ rayDesc.TMin = 0.001;
+ rayDesc.TMax = 10000.0;
+
+ Payload payload;
+ TraceRay(rs, RAY_FLAG_FORCE_OPAQUE, 0xff, 0, 0, 0, rayDesc, payload);
+
+ image[int2(LaunchID.xy)] = float4(payload.hitValue, 0.0);
+}
diff --git a/data/hlsl/nv_ray_tracing_shadows/shadow.rmiss b/data/hlsl/nv_ray_tracing_shadows/shadow.rmiss
new file mode 100644
index 00000000..7a104b6b
--- /dev/null
+++ b/data/hlsl/nv_ray_tracing_shadows/shadow.rmiss
@@ -0,0 +1,7 @@
+// Copyright 2020 Google LLC
+
+[shader("miss")]
+void main([[vk::location(2)]] in bool shadowed)
+{
+ shadowed = false;
+}
\ No newline at end of file
diff --git a/data/hlsl/occlusionquery/mesh.frag b/data/hlsl/occlusionquery/mesh.frag
new file mode 100644
index 00000000..9347ed10
--- /dev/null
+++ b/data/hlsl/occlusionquery/mesh.frag
@@ -0,0 +1,28 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float Visible : TEXCOORD3;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ if (input.Visible > 0.0)
+ {
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * input.Color;
+ float3 specular = pow(max(dot(R, V), 0.0), 8.0) * float3(0.75, 0.75, 0.75);
+ return float4(diffuse + specular, 1.0);
+ }
+ else
+ {
+ return float4(float3(0.1, 0.1, 0.1), 1.0);
+ }
+}
\ No newline at end of file
diff --git a/data/hlsl/occlusionquery/mesh.vert b/data/hlsl/occlusionquery/mesh.vert
new file mode 100644
index 00000000..4b20662a
--- /dev/null
+++ b/data/hlsl/occlusionquery/mesh.vert
@@ -0,0 +1,44 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+ float4 lightPos;
+ float visible;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float Visible : TEXCOORD3;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.Visible = ubo.visible;
+
+ output.Pos = mul(ubo.projection, mul(ubo.modelview, float4(input.Pos.xyz, 1.0)));
+
+ float4 pos = mul(ubo.modelview, float4(input.Pos, 1.0));
+ output.Normal = mul((float3x3)ubo.modelview, input.Normal);
+ output.LightVec = ubo.lightPos.xyz - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/occlusionquery/occluder.frag b/data/hlsl/occlusionquery/occluder.frag
new file mode 100644
index 00000000..e18b7b33
--- /dev/null
+++ b/data/hlsl/occlusionquery/occluder.frag
@@ -0,0 +1,6 @@
+// Copyright 2020 Google LLC
+
+float4 main([[vk::location(0)]] float3 Color : COLOR0) : SV_TARGET
+{
+ return float4(Color, 0.5);
+}
\ No newline at end of file
diff --git a/data/hlsl/occlusionquery/occluder.vert b/data/hlsl/occlusionquery/occluder.vert
new file mode 100644
index 00000000..dce12c8a
--- /dev/null
+++ b/data/hlsl/occlusionquery/occluder.vert
@@ -0,0 +1,31 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.Pos = mul(ubo.projection, mul(ubo.modelview, float4(input.Pos.xyz, 1.0)));
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/occlusionquery/simple.frag b/data/hlsl/occlusionquery/simple.frag
new file mode 100644
index 00000000..a898835c
--- /dev/null
+++ b/data/hlsl/occlusionquery/simple.frag
@@ -0,0 +1,6 @@
+// Copyright 2020 Google LLC
+
+float4 main([[vk::location(0)]] float3 Color : COLOR0) : SV_TARGET
+{
+ return float4(1.0, 1.0, 1.0, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/occlusionquery/simple.vert b/data/hlsl/occlusionquery/simple.vert
new file mode 100644
index 00000000..1618e05b
--- /dev/null
+++ b/data/hlsl/occlusionquery/simple.vert
@@ -0,0 +1,23 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+};
+
+VSOutput main([[vk::location(0)]] float3 Pos : POSITION0)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = mul(ubo.projection, mul(ubo.modelview, float4(Pos.xyz, 1.0)));
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/offscreen/mirror.frag b/data/hlsl/offscreen/mirror.frag
new file mode 100644
index 00000000..b9c68b7e
--- /dev/null
+++ b/data/hlsl/offscreen/mirror.frag
@@ -0,0 +1,42 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float4 ProjCoord : POSITION0;
+};
+
+float4 main(VSOutput input, bool FrontFacing : SV_IsFrontFace) : SV_TARGET
+{
+ float4 tmp = (1.0 / input.ProjCoord.w).xxxx;
+ float4 projCoord = input.ProjCoord * tmp;
+
+ // Scale and bias
+ projCoord += float4(1.0, 1.0, 1.0, 1.0);
+ projCoord *= float4(0.5, 0.5, 0.5, 0.5);
+
+ // Slow single pass blur
+ // For demonstration purposes only
+ const float blurSize = 1.0 / 512.0;
+
+ float4 color = float4(float3(0.0, 0.0, 0.0), 1.);
+
+ if (FrontFacing)
+ {
+ // Only render mirrored scene on front facing (upper) side of mirror surface
+ float4 reflection = float4(0.0, 0.0, 0.0, 0.0);
+ for (int x = -3; x <= 3; x++)
+ {
+ for (int y = -3; y <= 3; y++)
+ {
+ reflection += textureColor.Sample(samplerColor, float2(projCoord.x + x * blurSize, projCoord.y + y * blurSize)) / 49.0;
+ }
+ }
+ color += reflection;
+ }
+
+ return color;
+}
\ No newline at end of file
diff --git a/data/hlsl/offscreen/mirror.vert b/data/hlsl/offscreen/mirror.vert
new file mode 100644
index 00000000..671a3138
--- /dev/null
+++ b/data/hlsl/offscreen/mirror.vert
@@ -0,0 +1,32 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float4 ProjCoord : POSITION0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV;
+ output.ProjCoord = mul(ubo.projection, mul(ubo.view, mul(ubo.model, float4(input.Pos.xyz, 1.0))));
+ output.Pos = output.ProjCoord;
+ return output;
+}
diff --git a/data/hlsl/offscreen/phong.frag b/data/hlsl/offscreen/phong.frag
new file mode 100644
index 00000000..62c69695
--- /dev/null
+++ b/data/hlsl/offscreen/phong.frag
@@ -0,0 +1,26 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 EyePos : POSITION0;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 Eye = normalize(-input.EyePos);
+ float3 Reflected = normalize(reflect(-input.LightVec, input.Normal));
+
+ float4 IAmbient = float4(0.1, 0.1, 0.1, 1.0);
+ float4 IDiffuse = max(dot(input.Normal, input.LightVec), 0.0).xxxx;
+ float specular = 0.75;
+ float4 ISpecular = float4(0.0, 0.0, 0.0, 0.0);
+ if (dot(input.EyePos, input.Normal) < 0.0)
+ {
+ ISpecular = float4(0.5, 0.5, 0.5, 1.0) * pow(max(dot(Reflected, Eye), 0.0), 16.0) * specular;
+ }
+
+ return float4((IAmbient + IDiffuse) * float4(input.Color, 1.0) + ISpecular);
+}
\ No newline at end of file
diff --git a/data/hlsl/offscreen/phong.vert b/data/hlsl/offscreen/phong.vert
new file mode 100644
index 00000000..43656439
--- /dev/null
+++ b/data/hlsl/offscreen/phong.vert
@@ -0,0 +1,43 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+ float ClipDistance : SV_ClipDistance0;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 EyePos : POSITION0;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, input.Pos)));
+ output.EyePos = mul(ubo.view, mul(ubo.model, input.Pos)).xyz;
+ output.LightVec = normalize(ubo.lightPos.xyz - output.EyePos);
+
+ // Clip against reflection plane
+ float4 clipPlane = float4(0.0, -1.0, 0.0, 1.5);
+ output.ClipDistance = dot(input.Pos, clipPlane);
+ return output;
+}
diff --git a/data/hlsl/offscreen/quad.frag b/data/hlsl/offscreen/quad.frag
new file mode 100644
index 00000000..997a9419
--- /dev/null
+++ b/data/hlsl/offscreen/quad.frag
@@ -0,0 +1,9 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ return textureColor.Sample(samplerColor, inUV);
+}
\ No newline at end of file
diff --git a/data/hlsl/offscreen/quad.vert b/data/hlsl/offscreen/quad.vert
new file mode 100644
index 00000000..b8833fd7
--- /dev/null
+++ b/data/hlsl/offscreen/quad.vert
@@ -0,0 +1,28 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/parallaxmapping/parallax.frag b/data/hlsl/parallaxmapping/parallax.frag
new file mode 100644
index 00000000..dc0d86b6
--- /dev/null
+++ b/data/hlsl/parallaxmapping/parallax.frag
@@ -0,0 +1,148 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t1);
+SamplerState samplerColorMap : register(s1);
+Texture2D textureNormalHeightMap : register(t2);
+SamplerState samplerNormalHeightMap : register(s2);
+
+struct UBO
+{
+ float heightScale;
+ float parallaxBias;
+ float numLayers;
+ int mappingMode;
+};
+
+cbuffer ubo : register(b3) { UBO ubo; }
+
+struct VSOutput
+{
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float3 TangentLightPos : TEXCOORD1;
+[[vk::location(2)]] float3 TangentViewPos : TEXCOORD2;
+[[vk::location(3)]] float3 TangentFragPos : TEXCOORD3;
+};
+
+float2 parallax_uv(float2 uv, float3 view_dir, int type)
+{
+ if (type == 2) {
+ // Parallax mapping
+ float depth = 1.0 - textureNormalHeightMap.SampleLevel(samplerNormalHeightMap, uv, 0.0).a;
+ float2 p = view_dir.xy * (depth * (ubo.heightScale * 0.5) + ubo.parallaxBias) / view_dir.z;
+ return uv - p;
+ } else {
+ float layer_depth = 1.0 / ubo.numLayers;
+ float cur_layer_depth = 0.0;
+ float2 delta_uv = view_dir.xy * ubo.heightScale / (view_dir.z * ubo.numLayers);
+ float2 cur_uv = uv;
+
+ float depth_from_tex = 1.0 - textureNormalHeightMap.SampleLevel(samplerNormalHeightMap, cur_uv, 0.0).a;
+
+ for (int i = 0; i < 32; i++) {
+ cur_layer_depth += layer_depth;
+ cur_uv -= delta_uv;
+ depth_from_tex = 1.0 - textureNormalHeightMap.SampleLevel(samplerNormalHeightMap, cur_uv, 0.0).a;
+ if (depth_from_tex < cur_layer_depth) {
+ break;
+ }
+ }
+
+ if (type == 3) {
+ // Steep parallax mapping
+ return cur_uv;
+ } else {
+ // Parallax occlusion mapping
+ float2 prev_uv = cur_uv + delta_uv;
+ float next = depth_from_tex - cur_layer_depth;
+ float prev = 1.0 - textureNormalHeightMap.SampleLevel(samplerNormalHeightMap, prev_uv, 0.0).a - cur_layer_depth + layer_depth;
+ float weight = next / (next - prev);
+ return lerp(cur_uv, prev_uv, weight);
+ }
+ }
+}
+
+float2 parallaxMapping(float2 uv, float3 viewDir)
+{
+ float height = 1.0 - textureNormalHeightMap.SampleLevel(samplerNormalHeightMap, uv, 0.0).a;
+ float2 p = viewDir.xy * (height * (ubo.heightScale * 0.5) + ubo.parallaxBias) / viewDir.z;
+ return uv - p;
+}
+
+float2 steepParallaxMapping(float2 uv, float3 viewDir)
+{
+ float layerDepth = 1.0 / ubo.numLayers;
+ float currLayerDepth = 0.0;
+ float2 deltaUV = viewDir.xy * ubo.heightScale / (viewDir.z * ubo.numLayers);
+ float2 currUV = uv;
+ float height = 1.0 - textureNormalHeightMap.SampleLevel(samplerNormalHeightMap, currUV, 0.0).a;
+ for (int i = 0; i < ubo.numLayers; i++) {
+ currLayerDepth += layerDepth;
+ currUV -= deltaUV;
+ height = 1.0 - textureNormalHeightMap.SampleLevel(samplerNormalHeightMap, currUV, 0.0).a;
+ if (height < currLayerDepth) {
+ break;
+ }
+ }
+ return currUV;
+}
+
+float2 parallaxOcclusionMapping(float2 uv, float3 viewDir)
+{
+ float layerDepth = 1.0 / ubo.numLayers;
+ float currLayerDepth = 0.0;
+ float2 deltaUV = viewDir.xy * ubo.heightScale / (viewDir.z * ubo.numLayers);
+ float2 currUV = uv;
+ float height = 1.0 - textureNormalHeightMap.SampleLevel(samplerNormalHeightMap, currUV, 0.0).a;
+ for (int i = 0; i < ubo.numLayers; i++) {
+ currLayerDepth += layerDepth;
+ currUV -= deltaUV;
+ height = 1.0 - textureNormalHeightMap.SampleLevel(samplerNormalHeightMap, currUV, 0.0).a;
+ if (height < currLayerDepth) {
+ break;
+ }
+ }
+ float2 prevUV = currUV + deltaUV;
+ float nextDepth = height - currLayerDepth;
+ float prevDepth = 1.0 - textureNormalHeightMap.SampleLevel(samplerNormalHeightMap, prevUV, 0.0).a - currLayerDepth + layerDepth;
+ return lerp(currUV, prevUV, nextDepth / (nextDepth - prevDepth));
+}
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 V = normalize(input.TangentViewPos - input.TangentFragPos);
+ float2 uv = input.UV;
+
+ if (ubo.mappingMode == 0) {
+ // Color only
+ return textureColorMap.Sample(samplerColorMap, input.UV);
+ } else {
+ switch(ubo.mappingMode) {
+ case 2:
+ uv = parallaxMapping(input.UV, V);
+ break;
+ case 3:
+ uv = steepParallaxMapping(input.UV, V);
+ break;
+ case 4:
+ uv = parallaxOcclusionMapping(input.UV, V);
+ break;
+ }
+
+ // Discard fragments at texture border
+ if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
+ clip(-1);
+ }
+
+ float3 N = normalize(textureNormalHeightMap.SampleLevel(samplerNormalHeightMap, uv, 0.0).rgb * 2.0 - 1.0);
+ float3 L = normalize(input.TangentLightPos - input.TangentFragPos);
+ float3 R = reflect(-L, N);
+ float3 H = normalize(L + V);
+
+ float3 color = textureColorMap.Sample(samplerColorMap, uv).rgb;
+ float3 ambient = 0.2 * color;
+ float3 diffuse = max(dot(L, N), 0.0) * color;
+ float3 specular = float3(0.15, 0.15, 0.15) * pow(max(dot(N, H), 0.0), 32.0);
+
+ return float4(ambient + diffuse + specular, 1.0f);
+ }
+}
diff --git a/data/hlsl/parallaxmapping/parallax.vert b/data/hlsl/parallaxmapping/parallax.vert
new file mode 100644
index 00000000..e124e70f
--- /dev/null
+++ b/data/hlsl/parallaxmapping/parallax.vert
@@ -0,0 +1,48 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float3 Tangent : TEXCOORD1;
+[[vk::location(4)]] float3 BiTangent : TEXCOORD2;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+ float4 lightPos;
+ float4 cameraPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float3 TangentLightPos : TEXCOORD1;
+[[vk::location(2)]] float3 TangentViewPos : TEXCOORD2;
+[[vk::location(3)]] float3 TangentFragPos : TEXCOORD3;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, float4(input.Pos, 1.0f))));
+ output.TangentFragPos = mul(ubo.model, float4(input.Pos, 1.0)).xyz;
+ output.UV = input.UV;
+
+ float3 T = normalize(mul((float3x3)ubo.model, input.Tangent));
+ float3 B = normalize(mul((float3x3)ubo.model, input.BiTangent));
+ float3 N = normalize(mul((float3x3)ubo.model, input.Normal));
+ float3x3 TBN = transpose(float3x3(T, B, N));
+
+ output.TangentLightPos = mul(TBN, ubo.lightPos.xyz);
+ output.TangentViewPos = mul(TBN, ubo.cameraPos.xyz);
+ output.TangentFragPos = mul(TBN, output.TangentFragPos);
+ return output;
+}
diff --git a/data/hlsl/particlefire/normalmap.frag b/data/hlsl/particlefire/normalmap.frag
new file mode 100644
index 00000000..40ff7358
--- /dev/null
+++ b/data/hlsl/particlefire/normalmap.frag
@@ -0,0 +1,44 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t1);
+SamplerState samplerColorMap : register(s1);
+Texture2D textureNormalHeightMap : register(t2);
+SamplerState samplerNormalHeightMap : register(s2);
+
+#define lightRadius 45.0
+
+struct VSOutput
+{
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float3 LightVec : TEXCOORD2;
+[[vk::location(2)]] float3 LightVecB : TEXCOORD3;
+[[vk::location(3)]] float3 LightDir : TEXCOORD4;
+[[vk::location(4)]] float3 ViewVec : TEXCOORD1;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 specularColor = float3(0.85, 0.5, 0.0);
+
+ float invRadius = 1.0/lightRadius;
+ float ambient = 0.25;
+
+ float3 rgb, normal;
+
+ rgb = textureColorMap.Sample(samplerColorMap, input.UV).rgb;
+ normal = normalize((textureNormalHeightMap.Sample(samplerNormalHeightMap, input.UV).rgb - 0.5) * 2.0);
+
+ float distSqr = dot(input.LightVecB, input.LightVecB);
+ float3 lVec = input.LightVecB * rsqrt(distSqr);
+
+ float atten = max(clamp(1.0 - invRadius * sqrt(distSqr), 0.0, 1.0), ambient);
+ float diffuse = clamp(dot(lVec, normal), 0.0, 1.0);
+
+ float3 light = normalize(-input.LightVec);
+ float3 view = normalize(input.ViewVec);
+ float3 reflectDir = reflect(-light, normal);
+
+ float specular = pow(max(dot(view, reflectDir), 0.0), 4.0);
+
+ return float4((rgb * atten + (diffuse * rgb + 0.5 * specular * specularColor.rgb)) * atten, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/particlefire/normalmap.vert b/data/hlsl/particlefire/normalmap.vert
new file mode 100644
index 00000000..33beddb7
--- /dev/null
+++ b/data/hlsl/particlefire/normalmap.vert
@@ -0,0 +1,60 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float3 Tangent : TEXCOORD1;
+[[vk::location(4)]] float3 BiTangent : TEXCOORD2;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 normal;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float3 LightVec : TEXCOORD2;
+[[vk::location(2)]] float3 LightVecB : TEXCOORD3;
+[[vk::location(3)]] float3 LightDir : TEXCOORD4;
+[[vk::location(4)]] float3 ViewVec : TEXCOORD1;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ float3 vertexPosition = mul(ubo.model, float4(input.Pos, 1.0)).xyz;
+ output.LightDir = normalize(ubo.lightPos.xyz - vertexPosition);
+
+ // Setup (t)angent-(b)inormal-(n)ormal matrix for converting
+ // object coordinates into tangent space
+ float3x3 tbnMatrix;
+ tbnMatrix[0] = mul((float3x3)ubo.normal, input.Tangent);
+ tbnMatrix[1] = mul((float3x3)ubo.normal, input.BiTangent);
+ tbnMatrix[2] = mul((float3x3)ubo.normal, input.Normal);
+
+ output.LightVec.xyz = mul(float3(ubo.lightPos.xyz - vertexPosition), tbnMatrix);
+
+ float3 lightDist = ubo.lightPos.xyz - input.Pos;
+ output.LightVecB.x = dot(input.Tangent, lightDist);
+ output.LightVecB.y = dot(input.BiTangent, lightDist);
+ output.LightVecB.z = dot(input.Normal, lightDist);
+
+ output.ViewVec.x = dot(input.Tangent, input.Pos);
+ output.ViewVec.y = dot(input.BiTangent, input.Pos);
+ output.ViewVec.z = dot(input.Normal, input.Pos);
+
+ output.UV = input.UV;
+
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos, 1.0)));
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/particlefire/particle.frag b/data/hlsl/particlefire/particle.frag
new file mode 100644
index 00000000..f2a7d375
--- /dev/null
+++ b/data/hlsl/particlefire/particle.frag
@@ -0,0 +1,52 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureSmoke : register(t1);
+SamplerState samplerSmoke : register(s1);
+Texture2D textureFire : register(t2);
+SamplerState samplerFire : register(s2);
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float4 Color : COLOR0;
+[[vk::location(1)]] float Alpha : TEXCOODR0;
+[[vk::location(2)]] int Type : TEXCOODR1;
+[[vk::location(3)]] float Rotation : TEXCOODR2;
+[[vk::location(4)]] float2 CenterPos : POSITION1;
+[[vk::location(5)]] float PointSize : TEXCOORD3;
+};
+
+float4 main (VSOutput input) : SV_TARGET
+{
+ float4 color;
+ float alpha = (input.Alpha <= 1.0) ? input.Alpha : 2.0 - input.Alpha;
+
+ // Rotate texture coordinates
+ // Rotate UV
+ float rotCenter = 0.5;
+ float rotCos = cos(input.Rotation);
+ float rotSin = sin(input.Rotation);
+
+ float2 PointCoord = (input.Pos.xy - input.CenterPos.xy) / input.PointSize + 0.5;
+
+ float2 rotUV = float2(
+ rotCos * (PointCoord.x - rotCenter) + rotSin * (PointCoord.y - rotCenter) + rotCenter,
+ rotCos * (PointCoord.y - rotCenter) - rotSin * (PointCoord.x - rotCenter) + rotCenter);
+
+ float4 outFragColor;
+ if (input.Type == 0)
+ {
+ // Flame
+ color = textureFire.Sample(samplerFire, rotUV);
+ outFragColor.a = 0.0;
+ }
+ else
+ {
+ // Smoke
+ color = textureSmoke.Sample(samplerSmoke, rotUV);
+ outFragColor.a = color.a * alpha;
+ }
+
+ outFragColor.rgb = color.rgb * input.Color.rgb * alpha;
+ return outFragColor;
+}
\ No newline at end of file
diff --git a/data/hlsl/particlefire/particle.vert b/data/hlsl/particlefire/particle.vert
new file mode 100644
index 00000000..30794139
--- /dev/null
+++ b/data/hlsl/particlefire/particle.vert
@@ -0,0 +1,54 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float4 Color : COLOR0;
+[[vk::location(2)]] float Alpha : TEXCOORD0;
+[[vk::location(3)]] float Size : TEXCOORD1;
+[[vk::location(4)]] float Rotation : TEXCOORD2;
+[[vk::location(5)]] int Type : TEXCOORD3;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::builtin("PointSize")]] float PSize : PSIZE;
+[[vk::location(0)]] float4 Color : COLOR0;
+[[vk::location(1)]] float Alpha : TEXCOORD0;
+[[vk::location(2)]] int Type : TEXCOORD1;
+[[vk::location(3)]] float Rotation : TEXCOORD2;
+[[vk::location(4)]] float2 CenterPos : POSITION1;
+[[vk::location(5)]] float PointSize : TEXCOORD3;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+ float2 viewportDim;
+ float pointSize;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+VSOutput main (VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.Alpha = input.Alpha;
+ output.Type = input.Type;
+ output.Rotation = input.Rotation;
+
+ output.Pos = mul(ubo.projection, mul(ubo.modelview, float4(input.Pos.xyz, 1.0)));
+
+ // Base size of the point sprites
+ float spriteSize = 8.0 * input.Size;
+
+ // Scale particle size depending on camera projection
+ float4 eyePos = mul(ubo.modelview, float4(input.Pos.xyz, 1.0));
+ float4 projectedCorner = mul(ubo.projection, float4(0.5 * spriteSize, 0.5 * spriteSize, eyePos.z, eyePos.w));
+ output.PointSize = output.PSize = ubo.viewportDim.x * projectedCorner.x / projectedCorner.w;
+ output.CenterPos = ((output.Pos.xy / output.Pos.w) + 1.0) * 0.5 * ubo.viewportDim;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/pbrbasic/pbr.frag b/data/hlsl/pbrbasic/pbr.frag
new file mode 100644
index 00000000..51914df3
--- /dev/null
+++ b/data/hlsl/pbrbasic/pbr.frag
@@ -0,0 +1,133 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 WorldPos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+ float3 camPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct UBOShared {
+ float4 lights[4];
+};
+
+cbuffer uboParams : register(b1) { UBOShared uboParams; };
+
+struct PushConsts {
+[[vk::offset(12)]] float roughness;
+[[vk::offset(16)]] float metallic;
+[[vk::offset(20)]] float r;
+[[vk::offset(24)]] float g;
+[[vk::offset(28)]] float b;
+};
+
+[[vk::push_constant]] PushConsts material;
+
+static const float PI = 3.14159265359;
+
+//#define ROUGHNESS_PATTERN 1
+
+float3 materialcolor()
+{
+ return float3(material.r, material.g, material.b);
+}
+
+// Normal Distribution function --------------------------------------
+float D_GGX(float dotNH, float roughness)
+{
+ float alpha = roughness * roughness;
+ float alpha2 = alpha * alpha;
+ float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0;
+ return (alpha2)/(PI * denom*denom);
+}
+
+// Geometric Shadowing function --------------------------------------
+float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness)
+{
+ float r = (roughness + 1.0);
+ float k = (r*r) / 8.0;
+ float GL = dotNL / (dotNL * (1.0 - k) + k);
+ float GV = dotNV / (dotNV * (1.0 - k) + k);
+ return GL * GV;
+}
+
+// Fresnel function ----------------------------------------------------
+float3 F_Schlick(float cosTheta, float metallic)
+{
+ float3 F0 = lerp(float3(0.04, 0.04, 0.04), materialcolor(), metallic); // * material.specular
+ float3 F = F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
+ return F;
+}
+
+// Specular BRDF composition --------------------------------------------
+
+float3 BRDF(float3 L, float3 V, float3 N, float metallic, float roughness)
+{
+ // Precalculate vectors and dot products
+ float3 H = normalize (V + L);
+ float dotNV = clamp(dot(N, V), 0.0, 1.0);
+ float dotNL = clamp(dot(N, L), 0.0, 1.0);
+ float dotLH = clamp(dot(L, H), 0.0, 1.0);
+ float dotNH = clamp(dot(N, H), 0.0, 1.0);
+
+ // Light color fixed
+ float3 lightColor = float3(1.0, 1.0, 1.0);
+
+ float3 color = float3(0.0, 0.0, 0.0);
+
+ if (dotNL > 0.0)
+ {
+ float rroughness = max(0.05, roughness);
+ // D = Normal distribution (Distribution of the microfacets)
+ float D = D_GGX(dotNH, roughness);
+ // G = Geometric shadowing term (Microfacets shadowing)
+ float G = G_SchlicksmithGGX(dotNL, dotNV, roughness);
+ // F = Fresnel factor (Reflectance depending on angle of incidence)
+ float3 F = F_Schlick(dotNV, metallic);
+
+ float3 spec = D * F * G / (4.0 * dotNL * dotNV);
+
+ color += spec * dotNL * lightColor;
+ }
+
+ return color;
+}
+
+// ----------------------------------------------------------------------------
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 V = normalize(ubo.camPos - input.WorldPos);
+
+ float roughness = material.roughness;
+
+ // Add striped pattern to roughness based on vertex position
+#ifdef ROUGHNESS_PATTERN
+ roughness = max(roughness, step(frac(input.WorldPos.y * 2.02), 0.5));
+#endif
+
+ // Specular contribution
+ float3 Lo = float3(0.0, 0.0, 0.0);
+ for (int i = 0; i < 4; i++) {
+ float3 L = normalize(uboParams.lights[i].xyz - input.WorldPos);
+ Lo += BRDF(L, V, N, material.metallic, roughness);
+ };
+
+ // Combine with ambient
+ float3 color = materialcolor() * 0.02;
+ color += Lo;
+
+ // Gamma correct
+ color = pow(color, float3(0.4545, 0.4545, 0.4545));
+
+ return float4(color, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/pbrbasic/pbr.vert b/data/hlsl/pbrbasic/pbr.vert
new file mode 100644
index 00000000..c53e7dbb
--- /dev/null
+++ b/data/hlsl/pbrbasic/pbr.vert
@@ -0,0 +1,39 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+ float3 camPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 WorldPos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+};
+
+struct PushConsts {
+ float3 objPos;
+};
+[[vk::push_constant]] PushConsts pushConsts;
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ float3 locPos = mul(ubo.model, float4(input.Pos, 1.0)).xyz;
+ output.WorldPos = locPos + pushConsts.objPos;
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ output.Pos = mul(ubo.projection, mul(ubo.view, float4(output.WorldPos, 1.0)));
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/pbribl/filtercube.vert b/data/hlsl/pbribl/filtercube.vert
new file mode 100644
index 00000000..514b4dd2
--- /dev/null
+++ b/data/hlsl/pbribl/filtercube.vert
@@ -0,0 +1,25 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+};
+
+struct PushConsts {
+[[vk::offset(0)]] float4x4 mvp;
+};
+[[vk::push_constant]] PushConsts pushConsts;
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UVW : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UVW = input.Pos;
+ output.Pos = mul(pushConsts.mvp, float4(input.Pos.xyz, 1.0));
+ return output;
+}
diff --git a/data/hlsl/pbribl/genbrdflut.frag b/data/hlsl/pbribl/genbrdflut.frag
new file mode 100644
index 00000000..ca18d842
--- /dev/null
+++ b/data/hlsl/pbribl/genbrdflut.frag
@@ -0,0 +1,88 @@
+// Copyright 2020 Google LLC
+
+[[vk::constant_id(0)]] const uint NUM_SAMPLES = 1024u;
+
+#define PI 3.1415926536
+
+// Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/
+float random(float2 co)
+{
+ float a = 12.9898;
+ float b = 78.233;
+ float c = 43758.5453;
+ float dt= dot(co.xy ,float2(a,b));
+ float sn= fmod(dt,3.14);
+ return frac(sin(sn) * c);
+}
+
+float2 hammersley2d(uint i, uint N)
+{
+ // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
+ uint bits = (i << 16u) | (i >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ float rdi = float(bits) * 2.3283064365386963e-10;
+ return float2(float(i) /float(N), rdi);
+}
+
+// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf
+float3 importanceSample_GGX(float2 Xi, float roughness, float3 normal)
+{
+ // Maps a 2D point to a hemisphere with spread based on roughness
+ float alpha = roughness * roughness;
+ float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1;
+ float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y));
+ float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
+ float3 H = float3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);
+
+ // Tangent space
+ float3 up = abs(normal.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0);
+ float3 tangentX = normalize(cross(up, normal));
+ float3 tangentY = normalize(cross(normal, tangentX));
+
+ // Convert to world Space
+ return normalize(tangentX * H.x + tangentY * H.y + normal * H.z);
+}
+
+// Geometric Shadowing function
+float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness)
+{
+ float k = (roughness * roughness) / 2.0;
+ float GL = dotNL / (dotNL * (1.0 - k) + k);
+ float GV = dotNV / (dotNV * (1.0 - k) + k);
+ return GL * GV;
+}
+
+float2 BRDF(float NoV, float roughness)
+{
+ // Normal always points along z-axis for the 2D lookup
+ const float3 N = float3(0.0, 0.0, 1.0);
+ float3 V = float3(sqrt(1.0 - NoV*NoV), 0.0, NoV);
+
+ float2 LUT = float2(0.0, 0.0);
+ for(uint i = 0u; i < NUM_SAMPLES; i++) {
+ float2 Xi = hammersley2d(i, NUM_SAMPLES);
+ float3 H = importanceSample_GGX(Xi, roughness, N);
+ float3 L = 2.0 * dot(V, H) * H - V;
+
+ float dotNL = max(dot(N, L), 0.0);
+ float dotNV = max(dot(N, V), 0.0);
+ float dotVH = max(dot(V, H), 0.0);
+ float dotNH = max(dot(H, N), 0.0);
+
+ if (dotNL > 0.0) {
+ float G = G_SchlicksmithGGX(dotNL, dotNV, roughness);
+ float G_Vis = (G * dotVH) / (dotNH * dotNV);
+ float Fc = pow(1.0 - dotVH, 5.0);
+ LUT += float2((1.0 - Fc) * G_Vis, Fc * G_Vis);
+ }
+ }
+ return LUT / float(NUM_SAMPLES);
+}
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ return float4(BRDF(inUV.x, 1.0-inUV.y), 0.0, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/pbribl/genbrdflut.vert b/data/hlsl/pbribl/genbrdflut.vert
new file mode 100644
index 00000000..188b7298
--- /dev/null
+++ b/data/hlsl/pbribl/genbrdflut.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/pbribl/irradiancecube.frag b/data/hlsl/pbribl/irradiancecube.frag
new file mode 100644
index 00000000..66d63bf6
--- /dev/null
+++ b/data/hlsl/pbribl/irradiancecube.frag
@@ -0,0 +1,35 @@
+// Copyright 2020 Google LLC
+
+TextureCube textureEnv : register(t0);
+SamplerState samplerEnv : register(s0);
+
+struct PushConsts {
+[[vk::offset(64)]] float deltaPhi;
+[[vk::offset(68)]] float deltaTheta;
+};
+[[vk::push_constant]]PushConsts consts;
+
+#define PI 3.1415926535897932384626433832795
+
+float4 main([[vk::location(0)]] float3 inPos : TEXCOORD0) : SV_TARGET
+{
+ float3 N = normalize(inPos);
+ float3 up = float3(0.0, 1.0, 0.0);
+ float3 right = normalize(cross(up, N));
+ up = cross(N, right);
+
+ const float TWO_PI = PI * 2.0;
+ const float HALF_PI = PI * 0.5;
+
+ float3 color = float3(0.0, 0.0, 0.0);
+ uint sampleCount = 0u;
+ for (float phi = 0.0; phi < TWO_PI; phi += consts.deltaPhi) {
+ for (float theta = 0.0; theta < HALF_PI; theta += consts.deltaTheta) {
+ float3 tempVec = cos(phi) * right + sin(phi) * up;
+ float3 sampleVector = cos(theta) * N + sin(theta) * tempVec;
+ color += textureEnv.Sample(samplerEnv, sampleVector).rgb * cos(theta) * sin(theta);
+ sampleCount++;
+ }
+ }
+ return float4(PI * color / float(sampleCount), 1.0);
+}
diff --git a/data/hlsl/pbribl/pbribl.frag b/data/hlsl/pbribl/pbribl.frag
new file mode 100644
index 00000000..4f135c4d
--- /dev/null
+++ b/data/hlsl/pbribl/pbribl.frag
@@ -0,0 +1,170 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 WorldPos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO {
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+ float3 camPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct UBOParams {
+ float4 lights[4];
+ float exposure;
+ float gamma;
+};
+cbuffer uboParams : register(b1) { UBOParams uboParams; };
+
+struct PushConsts {
+[[vk::offset(12)]] float roughness;
+[[vk::offset(16)]] float metallic;
+[[vk::offset(20)]] float specular;
+[[vk::offset(24)]] float r;
+[[vk::offset(28)]] float g;
+[[vk::offset(32)]] float b;
+};
+[[vk::push_constant]] PushConsts material;
+
+TextureCube textureIrradiance : register(t2);
+SamplerState samplerIrradiance : register(s2);
+Texture2D textureBRDFLUT : register(t3);
+SamplerState samplerBRDFLUT : register(s3);
+TextureCube prefilteredMapTexture : register(t4);
+SamplerState prefilteredMapSampler : register(s4);
+
+#define PI 3.1415926535897932384626433832795
+#define ALBEDO float3(material.r, material.g, material.b)
+
+// From http://filmicgames.com/archives/75
+float3 Uncharted2Tonemap(float3 x)
+{
+ float A = 0.15;
+ float B = 0.50;
+ float C = 0.10;
+ float D = 0.20;
+ float E = 0.02;
+ float F = 0.30;
+ return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
+}
+
+// Normal Distribution function --------------------------------------
+float D_GGX(float dotNH, float roughness)
+{
+ float alpha = roughness * roughness;
+ float alpha2 = alpha * alpha;
+ float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0;
+ return (alpha2)/(PI * denom*denom);
+}
+
+// Geometric Shadowing function --------------------------------------
+float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness)
+{
+ float r = (roughness + 1.0);
+ float k = (r*r) / 8.0;
+ float GL = dotNL / (dotNL * (1.0 - k) + k);
+ float GV = dotNV / (dotNV * (1.0 - k) + k);
+ return GL * GV;
+}
+
+// Fresnel function ----------------------------------------------------
+float3 F_Schlick(float cosTheta, float3 F0)
+{
+ return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
+}
+float3 F_SchlickR(float cosTheta, float3 F0, float roughness)
+{
+ return F0 + (max((1.0 - roughness).xxx, F0) - F0) * pow(1.0 - cosTheta, 5.0);
+}
+
+float3 prefilteredReflection(float3 R, float roughness)
+{
+ const float MAX_REFLECTION_LOD = 9.0; // todo: param/const
+ float lod = roughness * MAX_REFLECTION_LOD;
+ float lodf = floor(lod);
+ float lodc = ceil(lod);
+ float3 a = prefilteredMapTexture.SampleLevel(prefilteredMapSampler, R, lodf).rgb;
+ float3 b = prefilteredMapTexture.SampleLevel(prefilteredMapSampler, R, lodc).rgb;
+ return lerp(a, b, lod - lodf);
+}
+
+float3 specularContribution(float3 L, float3 V, float3 N, float3 F0, float metallic, float roughness)
+{
+ // Precalculate vectors and dot products
+ float3 H = normalize (V + L);
+ float dotNH = clamp(dot(N, H), 0.0, 1.0);
+ float dotNV = clamp(dot(N, V), 0.0, 1.0);
+ float dotNL = clamp(dot(N, L), 0.0, 1.0);
+
+ // Light color fixed
+ float3 lightColor = float3(1.0, 1.0, 1.0);
+
+ float3 color = float3(0.0, 0.0, 0.0);
+
+ if (dotNL > 0.0) {
+ // D = Normal distribution (Distribution of the microfacets)
+ float D = D_GGX(dotNH, roughness);
+ // G = Geometric shadowing term (Microfacets shadowing)
+ float G = G_SchlicksmithGGX(dotNL, dotNV, roughness);
+ // F = Fresnel factor (Reflectance depending on angle of incidence)
+ float3 F = F_Schlick(dotNV, F0);
+ float3 spec = D * F * G / (4.0 * dotNL * dotNV + 0.001);
+ float3 kD = (float3(1.0, 1.0, 1.0) - F) * (1.0 - metallic);
+ color += (kD * ALBEDO / PI + spec) * dotNL;
+ }
+
+ return color;
+}
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 V = normalize(ubo.camPos - input.WorldPos);
+ float3 R = reflect(-V, N);
+
+ float metallic = material.metallic;
+ float roughness = material.roughness;
+
+ float3 F0 = float3(0.04, 0.04, 0.04);
+ F0 = lerp(F0, ALBEDO, metallic);
+
+ float3 Lo = float3(0.0, 0.0, 0.0);
+ for(int i = 0; i < 4; i++) {
+ float3 L = normalize(uboParams.lights[i].xyz - input.WorldPos);
+ Lo += specularContribution(L, V, N, F0, metallic, roughness);
+ }
+
+ float2 brdf = textureBRDFLUT.Sample(samplerBRDFLUT, float2(max(dot(N, V), 0.0), roughness)).rg;
+ float3 reflection = prefilteredReflection(R, roughness).rgb;
+ float3 irradiance = textureIrradiance.Sample(samplerIrradiance, N).rgb;
+
+ // Diffuse based on irradiance
+ float3 diffuse = irradiance * ALBEDO;
+
+ float3 F = F_SchlickR(max(dot(N, V), 0.0), F0, roughness);
+
+ // Specular reflectance
+ float3 specular = reflection * (F * brdf.x + brdf.y);
+
+ // Ambient part
+ float3 kD = 1.0 - F;
+ kD *= 1.0 - metallic;
+ float3 ambient = (kD * diffuse + specular);
+
+ float3 color = ambient + Lo;
+
+ // Tone mapping
+ color = Uncharted2Tonemap(color * uboParams.exposure);
+ color = color * (1.0f / Uncharted2Tonemap((11.2f).xxx));
+ // Gamma correction
+ color = pow(color, (1.0f / uboParams.gamma).xxx);
+
+ return float4(color, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/pbribl/pbribl.vert b/data/hlsl/pbribl/pbribl.vert
new file mode 100644
index 00000000..12d2e6e7
--- /dev/null
+++ b/data/hlsl/pbribl/pbribl.vert
@@ -0,0 +1,43 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+ float3 camPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 WorldPos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct PushConsts {
+ float3 objPos;
+};
+[[vk::push_constant]] PushConsts pushConsts;
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ float3 locPos = mul(ubo.model, float4(input.Pos, 1.0)).xyz;
+ output.WorldPos = locPos + pushConsts.objPos;
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ output.UV = input.UV;
+ output.UV.y = 1.0 - input.UV.y;
+ output.Pos = mul(ubo.projection, mul(ubo.view, float4(output.WorldPos, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/pbribl/prefilterenvmap.frag b/data/hlsl/pbribl/prefilterenvmap.frag
new file mode 100644
index 00000000..1f605d04
--- /dev/null
+++ b/data/hlsl/pbribl/prefilterenvmap.frag
@@ -0,0 +1,106 @@
+// Copyright 2020 Google LLC
+
+TextureCube textureEnv : register(t0);
+SamplerState samplerEnv : register(s0);
+
+struct PushConsts {
+[[vk::offset(64)]] float roughness;
+[[vk::offset(68)]] uint numSamples;
+};
+[[vk::push_constant]] PushConsts consts;
+
+#define PI 3.1415926536
+
+// Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/
+float random(float2 co)
+{
+ float a = 12.9898;
+ float b = 78.233;
+ float c = 43758.5453;
+ float dt= dot(co.xy ,float2(a,b));
+ float sn= fmod(dt,3.14);
+ return frac(sin(sn) * c);
+}
+
+float2 hammersley2d(uint i, uint N)
+{
+ // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
+ uint bits = (i << 16u) | (i >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ float rdi = float(bits) * 2.3283064365386963e-10;
+ return float2(float(i) /float(N), rdi);
+}
+
+// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf
+float3 importanceSample_GGX(float2 Xi, float roughness, float3 normal)
+{
+ // Maps a 2D point to a hemisphere with spread based on roughness
+ float alpha = roughness * roughness;
+ float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1;
+ float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y));
+ float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
+ float3 H = float3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);
+
+ // Tangent space
+ float3 up = abs(normal.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0);
+ float3 tangentX = normalize(cross(up, normal));
+ float3 tangentY = normalize(cross(normal, tangentX));
+
+ // Convert to world Space
+ return normalize(tangentX * H.x + tangentY * H.y + normal * H.z);
+}
+
+// Normal Distribution function
+float D_GGX(float dotNH, float roughness)
+{
+ float alpha = roughness * roughness;
+ float alpha2 = alpha * alpha;
+ float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0;
+ return (alpha2)/(PI * denom*denom);
+}
+
+float3 prefilterEnvMap(float3 R, float roughness)
+{
+ float3 N = R;
+ float3 V = R;
+ float3 color = float3(0.0, 0.0, 0.0);
+ float totalWeight = 0.0;
+ int2 envMapDims;
+ textureEnv.GetDimensions(envMapDims.x, envMapDims.y);
+ float envMapDim = float(envMapDims.x);
+ for(uint i = 0u; i < consts.numSamples; i++) {
+ float2 Xi = hammersley2d(i, consts.numSamples);
+ float3 H = importanceSample_GGX(Xi, roughness, N);
+ float3 L = 2.0 * dot(V, H) * H - V;
+ float dotNL = clamp(dot(N, L), 0.0, 1.0);
+ if(dotNL > 0.0) {
+ // Filtering based on https://placeholderart.wordpress.com/2015/07/28/implementation-notes-runtime-environment-map-filtering-for-image-based-lighting/
+
+ float dotNH = clamp(dot(N, H), 0.0, 1.0);
+ float dotVH = clamp(dot(V, H), 0.0, 1.0);
+
+ // Probability Distribution Function
+ float pdf = D_GGX(dotNH, roughness) * dotNH / (4.0 * dotVH) + 0.0001;
+ // Slid angle of current smple
+ float omegaS = 1.0 / (float(consts.numSamples) * pdf);
+ // Solid angle of 1 pixel across all cube faces
+ float omegaP = 4.0 * PI / (6.0 * envMapDim * envMapDim);
+ // Biased (+1.0) mip level for better result
+ float mipLevel = roughness == 0.0 ? 0.0 : max(0.5 * log2(omegaS / omegaP) + 1.0, 0.0f);
+ color += textureEnv.SampleLevel(samplerEnv, L, mipLevel).rgb * dotNL;
+ totalWeight += dotNL;
+
+ }
+ }
+ return (color / totalWeight);
+}
+
+
+float4 main([[vk::location(0)]] float3 inPos : POSITION0) : SV_TARGET
+{
+ float3 N = normalize(inPos);
+ return float4(prefilterEnvMap(N, consts.roughness), 1.0);
+}
diff --git a/data/hlsl/pbribl/skybox.frag b/data/hlsl/pbribl/skybox.frag
new file mode 100644
index 00000000..439c6287
--- /dev/null
+++ b/data/hlsl/pbribl/skybox.frag
@@ -0,0 +1,37 @@
+// Copyright 2020 Google LLC
+
+TextureCube textureEnv : register(t2);
+SamplerState samplerEnv : register(s2);
+
+struct UBOParams {
+ float4 lights[4];
+ float exposure;
+ float gamma;
+};
+cbuffer uboParams : register(b1) { UBOParams uboParams; };
+
+// From http://filmicworlds.com/blog/filmic-tonemapping-operators/
+float3 Uncharted2Tonemap(float3 color)
+{
+ float A = 0.15;
+ float B = 0.50;
+ float C = 0.10;
+ float D = 0.20;
+ float E = 0.02;
+ float F = 0.30;
+ float W = 11.2;
+ return ((color*(A*color+C*B)+D*E)/(color*(A*color+B)+D*F))-E/F;
+}
+
+float4 main([[vk::location(0)]] float3 inUVW : POSITION0) : SV_TARGET
+{
+ float3 color = textureEnv.Sample(samplerEnv, inUVW).rgb;
+
+ // Tone mapping
+ color = Uncharted2Tonemap(color * uboParams.exposure);
+ color = color * (1.0f / Uncharted2Tonemap((11.2f).xxx));
+ // Gamma correction
+ color = pow(color, (1.0f / uboParams.gamma).xxx);
+
+ return float4(color, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/pbribl/skybox.vert b/data/hlsl/pbribl/skybox.vert
new file mode 100644
index 00000000..26e3fb6d
--- /dev/null
+++ b/data/hlsl/pbribl/skybox.vert
@@ -0,0 +1,30 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UVW : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UVW = input.Pos;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/pbrtexture/filtercube.vert b/data/hlsl/pbrtexture/filtercube.vert
new file mode 100644
index 00000000..514b4dd2
--- /dev/null
+++ b/data/hlsl/pbrtexture/filtercube.vert
@@ -0,0 +1,25 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+};
+
+struct PushConsts {
+[[vk::offset(0)]] float4x4 mvp;
+};
+[[vk::push_constant]] PushConsts pushConsts;
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UVW : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UVW = input.Pos;
+ output.Pos = mul(pushConsts.mvp, float4(input.Pos.xyz, 1.0));
+ return output;
+}
diff --git a/data/hlsl/pbrtexture/genbrdflut.frag b/data/hlsl/pbrtexture/genbrdflut.frag
new file mode 100644
index 00000000..ca18d842
--- /dev/null
+++ b/data/hlsl/pbrtexture/genbrdflut.frag
@@ -0,0 +1,88 @@
+// Copyright 2020 Google LLC
+
+[[vk::constant_id(0)]] const uint NUM_SAMPLES = 1024u;
+
+#define PI 3.1415926536
+
+// Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/
+float random(float2 co)
+{
+ float a = 12.9898;
+ float b = 78.233;
+ float c = 43758.5453;
+ float dt= dot(co.xy ,float2(a,b));
+ float sn= fmod(dt,3.14);
+ return frac(sin(sn) * c);
+}
+
+float2 hammersley2d(uint i, uint N)
+{
+ // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
+ uint bits = (i << 16u) | (i >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ float rdi = float(bits) * 2.3283064365386963e-10;
+ return float2(float(i) /float(N), rdi);
+}
+
+// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf
+float3 importanceSample_GGX(float2 Xi, float roughness, float3 normal)
+{
+ // Maps a 2D point to a hemisphere with spread based on roughness
+ float alpha = roughness * roughness;
+ float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1;
+ float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y));
+ float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
+ float3 H = float3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);
+
+ // Tangent space
+ float3 up = abs(normal.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0);
+ float3 tangentX = normalize(cross(up, normal));
+ float3 tangentY = normalize(cross(normal, tangentX));
+
+ // Convert to world Space
+ return normalize(tangentX * H.x + tangentY * H.y + normal * H.z);
+}
+
+// Geometric Shadowing function
+float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness)
+{
+ float k = (roughness * roughness) / 2.0;
+ float GL = dotNL / (dotNL * (1.0 - k) + k);
+ float GV = dotNV / (dotNV * (1.0 - k) + k);
+ return GL * GV;
+}
+
+float2 BRDF(float NoV, float roughness)
+{
+ // Normal always points along z-axis for the 2D lookup
+ const float3 N = float3(0.0, 0.0, 1.0);
+ float3 V = float3(sqrt(1.0 - NoV*NoV), 0.0, NoV);
+
+ float2 LUT = float2(0.0, 0.0);
+ for(uint i = 0u; i < NUM_SAMPLES; i++) {
+ float2 Xi = hammersley2d(i, NUM_SAMPLES);
+ float3 H = importanceSample_GGX(Xi, roughness, N);
+ float3 L = 2.0 * dot(V, H) * H - V;
+
+ float dotNL = max(dot(N, L), 0.0);
+ float dotNV = max(dot(N, V), 0.0);
+ float dotVH = max(dot(V, H), 0.0);
+ float dotNH = max(dot(H, N), 0.0);
+
+ if (dotNL > 0.0) {
+ float G = G_SchlicksmithGGX(dotNL, dotNV, roughness);
+ float G_Vis = (G * dotVH) / (dotNH * dotNV);
+ float Fc = pow(1.0 - dotVH, 5.0);
+ LUT += float2((1.0 - Fc) * G_Vis, Fc * G_Vis);
+ }
+ }
+ return LUT / float(NUM_SAMPLES);
+}
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ return float4(BRDF(inUV.x, 1.0-inUV.y), 0.0, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/pbrtexture/genbrdflut.vert b/data/hlsl/pbrtexture/genbrdflut.vert
new file mode 100644
index 00000000..188b7298
--- /dev/null
+++ b/data/hlsl/pbrtexture/genbrdflut.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/pbrtexture/irradiancecube.frag b/data/hlsl/pbrtexture/irradiancecube.frag
new file mode 100644
index 00000000..66d63bf6
--- /dev/null
+++ b/data/hlsl/pbrtexture/irradiancecube.frag
@@ -0,0 +1,35 @@
+// Copyright 2020 Google LLC
+
+TextureCube textureEnv : register(t0);
+SamplerState samplerEnv : register(s0);
+
+struct PushConsts {
+[[vk::offset(64)]] float deltaPhi;
+[[vk::offset(68)]] float deltaTheta;
+};
+[[vk::push_constant]]PushConsts consts;
+
+#define PI 3.1415926535897932384626433832795
+
+float4 main([[vk::location(0)]] float3 inPos : TEXCOORD0) : SV_TARGET
+{
+ float3 N = normalize(inPos);
+ float3 up = float3(0.0, 1.0, 0.0);
+ float3 right = normalize(cross(up, N));
+ up = cross(N, right);
+
+ const float TWO_PI = PI * 2.0;
+ const float HALF_PI = PI * 0.5;
+
+ float3 color = float3(0.0, 0.0, 0.0);
+ uint sampleCount = 0u;
+ for (float phi = 0.0; phi < TWO_PI; phi += consts.deltaPhi) {
+ for (float theta = 0.0; theta < HALF_PI; theta += consts.deltaTheta) {
+ float3 tempVec = cos(phi) * right + sin(phi) * up;
+ float3 sampleVector = cos(theta) * N + sin(theta) * tempVec;
+ color += textureEnv.Sample(samplerEnv, sampleVector).rgb * cos(theta) * sin(theta);
+ sampleCount++;
+ }
+ }
+ return float4(PI * color / float(sampleCount), 1.0);
+}
diff --git a/data/hlsl/pbrtexture/pbrtexture.frag b/data/hlsl/pbrtexture/pbrtexture.frag
new file mode 100644
index 00000000..9a966178
--- /dev/null
+++ b/data/hlsl/pbrtexture/pbrtexture.frag
@@ -0,0 +1,189 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 WorldPos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO {
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+ float3 camPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct UBOParams {
+ float4 lights[4];
+ float exposure;
+ float gamma;
+};
+cbuffer uboParams : register(b1) { UBOParams uboParams; };
+
+TextureCube textureIrradiance : register(t2);
+SamplerState samplerIrradiance : register(s2);
+Texture2D textureBRDFLUT : register(t3);
+SamplerState samplerBRDFLUT : register(s3);
+TextureCube prefilteredMapTexture : register(t4);
+SamplerState prefilteredMapSampler : register(s4);
+
+Texture2D albedoMapTexture : register(t5);
+SamplerState albedoMapSampler : register(s5);
+Texture2D normalMapTexture : register(t6);
+SamplerState normalMapSampler : register(s6);
+Texture2D aoMapTexture : register(t7);
+SamplerState aoMapSampler : register(s7);
+Texture2D metallicMapTexture : register(t8);
+SamplerState metallicMapSampler : register(s8);
+Texture2D roughnessMapTexture : register(t9);
+SamplerState roughnessMapSampler : register(s9);
+
+#define PI 3.1415926535897932384626433832795
+#define ALBEDO(uv) pow(albedoMapTexture.Sample(albedoMapSampler, uv).rgb, float3(2.2, 2.2, 2.2))
+
+// From http://filmicgames.com/archives/75
+float3 Uncharted2Tonemap(float3 x)
+{
+ float A = 0.15;
+ float B = 0.50;
+ float C = 0.10;
+ float D = 0.20;
+ float E = 0.02;
+ float F = 0.30;
+ return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
+}
+
+// Normal Distribution function --------------------------------------
+float D_GGX(float dotNH, float roughness)
+{
+ float alpha = roughness * roughness;
+ float alpha2 = alpha * alpha;
+ float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0;
+ return (alpha2)/(PI * denom*denom);
+}
+
+// Geometric Shadowing function --------------------------------------
+float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness)
+{
+ float r = (roughness + 1.0);
+ float k = (r*r) / 8.0;
+ float GL = dotNL / (dotNL * (1.0 - k) + k);
+ float GV = dotNV / (dotNV * (1.0 - k) + k);
+ return GL * GV;
+}
+
+// Fresnel function ----------------------------------------------------
+float3 F_Schlick(float cosTheta, float3 F0)
+{
+ return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
+}
+float3 F_SchlickR(float cosTheta, float3 F0, float roughness)
+{
+ return F0 + (max((1.0 - roughness).xxx, F0) - F0) * pow(1.0 - cosTheta, 5.0);
+}
+
+float3 prefilteredReflection(float3 R, float roughness)
+{
+ const float MAX_REFLECTION_LOD = 9.0; // todo: param/const
+ float lod = roughness * MAX_REFLECTION_LOD;
+ float lodf = floor(lod);
+ float lodc = ceil(lod);
+ float3 a = prefilteredMapTexture.SampleLevel(prefilteredMapSampler, R, lodf).rgb;
+ float3 b = prefilteredMapTexture.SampleLevel(prefilteredMapSampler, R, lodc).rgb;
+ return lerp(a, b, lod - lodf);
+}
+
+float3 specularContribution(float2 inUV, float3 L, float3 V, float3 N, float3 F0, float metallic, float roughness)
+{
+ // Precalculate vectors and dot products
+ float3 H = normalize (V + L);
+ float dotNH = clamp(dot(N, H), 0.0, 1.0);
+ float dotNV = clamp(dot(N, V), 0.0, 1.0);
+ float dotNL = clamp(dot(N, L), 0.0, 1.0);
+
+ // Light color fixed
+ float3 lightColor = float3(1.0, 1.0, 1.0);
+
+ float3 color = float3(0.0, 0.0, 0.0);
+
+ if (dotNL > 0.0) {
+ // D = Normal distribution (Distribution of the microfacets)
+ float D = D_GGX(dotNH, roughness);
+ // G = Geometric shadowing term (Microfacets shadowing)
+ float G = G_SchlicksmithGGX(dotNL, dotNV, roughness);
+ // F = Fresnel factor (Reflectance depending on angle of incidence)
+ float3 F = F_Schlick(dotNV, F0);
+ float3 spec = D * F * G / (4.0 * dotNL * dotNV + 0.001);
+ float3 kD = (float3(1.0, 1.0, 1.0) - F) * (1.0 - metallic);
+ color += (kD * ALBEDO(inUV) / PI + spec) * dotNL;
+ }
+
+ return color;
+}
+
+// See http://www.thetenthplanet.de/archives/1180
+float3 perturbNormal(float2 inUV, float3 inWorldPos, float3 inNormal)
+{
+ float3 tangentNormal = normalMapTexture.Sample(normalMapSampler, inUV).xyz * 2.0 - 1.0;
+
+ float3 q1 = ddx(inWorldPos);
+ float3 q2 = ddy(inWorldPos);
+ float2 st1 = ddx(inUV);
+ float2 st2 = ddy(inUV);
+
+ float3 N = normalize(inNormal);
+ float3 T = normalize(q1 * st2.y - q2 * st1.y);
+ float3 B = -normalize(cross(N, T));
+ float3x3 TBN = transpose(float3x3(T, B, N));
+
+ return normalize(mul(TBN, tangentNormal));
+}
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 N = perturbNormal(input.UV, input.WorldPos, input.Normal);
+ float3 V = normalize(ubo.camPos - input.WorldPos);
+ float3 R = reflect(-V, N);
+
+ float metallic = metallicMapTexture.Sample(metallicMapSampler, input.UV).r;
+ float roughness = roughnessMapTexture.Sample(roughnessMapSampler, input.UV).r;
+
+ float3 F0 = float3(0.04, 0.04, 0.04);
+ F0 = lerp(F0, ALBEDO(input.UV), metallic);
+
+ float3 Lo = float3(0.0, 0.0, 0.0);
+ for(int i = 0; i < 4; i++) {
+ float3 L = normalize(uboParams.lights[i].xyz - input.WorldPos);
+ Lo += specularContribution(input.UV, L, V, N, F0, metallic, roughness);
+ }
+
+ float2 brdf = textureBRDFLUT.Sample(samplerBRDFLUT, float2(max(dot(N, V), 0.0), roughness)).rg;
+ float3 reflection = prefilteredReflection(R, roughness).rgb;
+ float3 irradiance = textureIrradiance.Sample(samplerIrradiance, N).rgb;
+
+ // Diffuse based on irradiance
+ float3 diffuse = irradiance * ALBEDO(input.UV);
+
+ float3 F = F_SchlickR(max(dot(N, V), 0.0), F0, roughness);
+
+ // Specular reflectance
+ float3 specular = reflection * (F * brdf.x + brdf.y);
+
+ // Ambient part
+ float3 kD = 1.0 - F;
+ kD *= 1.0 - metallic;
+ float3 ambient = (kD * diffuse + specular) * aoMapTexture.Sample(aoMapSampler, input.UV).rrr;
+
+ float3 color = ambient + Lo;
+
+ // Tone mapping
+ color = Uncharted2Tonemap(color * uboParams.exposure);
+ color = color * (1.0f / Uncharted2Tonemap((11.2f).xxx));
+ // Gamma correction
+ color = pow(color, (1.0f / uboParams.gamma).xxx);
+
+ return float4(color, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/pbrtexture/pbrtexture.vert b/data/hlsl/pbrtexture/pbrtexture.vert
new file mode 100644
index 00000000..5de805c6
--- /dev/null
+++ b/data/hlsl/pbrtexture/pbrtexture.vert
@@ -0,0 +1,38 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+ float3 camPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 WorldPos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ float3 locPos = mul(ubo.model, float4(input.Pos, 1.0)).xyz;
+ output.WorldPos = locPos;
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ output.UV = input.UV;
+ output.UV.y = 1.0 - input.UV.y;
+ output.Pos = mul(ubo.projection, mul(ubo.view, float4(output.WorldPos, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/pbrtexture/prefilterenvmap.frag b/data/hlsl/pbrtexture/prefilterenvmap.frag
new file mode 100644
index 00000000..1f605d04
--- /dev/null
+++ b/data/hlsl/pbrtexture/prefilterenvmap.frag
@@ -0,0 +1,106 @@
+// Copyright 2020 Google LLC
+
+TextureCube textureEnv : register(t0);
+SamplerState samplerEnv : register(s0);
+
+struct PushConsts {
+[[vk::offset(64)]] float roughness;
+[[vk::offset(68)]] uint numSamples;
+};
+[[vk::push_constant]] PushConsts consts;
+
+#define PI 3.1415926536
+
+// Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/
+float random(float2 co)
+{
+ float a = 12.9898;
+ float b = 78.233;
+ float c = 43758.5453;
+ float dt= dot(co.xy ,float2(a,b));
+ float sn= fmod(dt,3.14);
+ return frac(sin(sn) * c);
+}
+
+float2 hammersley2d(uint i, uint N)
+{
+ // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
+ uint bits = (i << 16u) | (i >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ float rdi = float(bits) * 2.3283064365386963e-10;
+ return float2(float(i) /float(N), rdi);
+}
+
+// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf
+float3 importanceSample_GGX(float2 Xi, float roughness, float3 normal)
+{
+ // Maps a 2D point to a hemisphere with spread based on roughness
+ float alpha = roughness * roughness;
+ float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1;
+ float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y));
+ float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
+ float3 H = float3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);
+
+ // Tangent space
+ float3 up = abs(normal.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0);
+ float3 tangentX = normalize(cross(up, normal));
+ float3 tangentY = normalize(cross(normal, tangentX));
+
+ // Convert to world Space
+ return normalize(tangentX * H.x + tangentY * H.y + normal * H.z);
+}
+
+// Normal Distribution function
+float D_GGX(float dotNH, float roughness)
+{
+ float alpha = roughness * roughness;
+ float alpha2 = alpha * alpha;
+ float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0;
+ return (alpha2)/(PI * denom*denom);
+}
+
+float3 prefilterEnvMap(float3 R, float roughness)
+{
+ float3 N = R;
+ float3 V = R;
+ float3 color = float3(0.0, 0.0, 0.0);
+ float totalWeight = 0.0;
+ int2 envMapDims;
+ textureEnv.GetDimensions(envMapDims.x, envMapDims.y);
+ float envMapDim = float(envMapDims.x);
+ for(uint i = 0u; i < consts.numSamples; i++) {
+ float2 Xi = hammersley2d(i, consts.numSamples);
+ float3 H = importanceSample_GGX(Xi, roughness, N);
+ float3 L = 2.0 * dot(V, H) * H - V;
+ float dotNL = clamp(dot(N, L), 0.0, 1.0);
+ if(dotNL > 0.0) {
+ // Filtering based on https://placeholderart.wordpress.com/2015/07/28/implementation-notes-runtime-environment-map-filtering-for-image-based-lighting/
+
+ float dotNH = clamp(dot(N, H), 0.0, 1.0);
+ float dotVH = clamp(dot(V, H), 0.0, 1.0);
+
+ // Probability Distribution Function
+ float pdf = D_GGX(dotNH, roughness) * dotNH / (4.0 * dotVH) + 0.0001;
+ // Slid angle of current smple
+ float omegaS = 1.0 / (float(consts.numSamples) * pdf);
+ // Solid angle of 1 pixel across all cube faces
+ float omegaP = 4.0 * PI / (6.0 * envMapDim * envMapDim);
+ // Biased (+1.0) mip level for better result
+ float mipLevel = roughness == 0.0 ? 0.0 : max(0.5 * log2(omegaS / omegaP) + 1.0, 0.0f);
+ color += textureEnv.SampleLevel(samplerEnv, L, mipLevel).rgb * dotNL;
+ totalWeight += dotNL;
+
+ }
+ }
+ return (color / totalWeight);
+}
+
+
+float4 main([[vk::location(0)]] float3 inPos : POSITION0) : SV_TARGET
+{
+ float3 N = normalize(inPos);
+ return float4(prefilterEnvMap(N, consts.roughness), 1.0);
+}
diff --git a/data/hlsl/pbrtexture/skybox.frag b/data/hlsl/pbrtexture/skybox.frag
new file mode 100644
index 00000000..439c6287
--- /dev/null
+++ b/data/hlsl/pbrtexture/skybox.frag
@@ -0,0 +1,37 @@
+// Copyright 2020 Google LLC
+
+TextureCube textureEnv : register(t2);
+SamplerState samplerEnv : register(s2);
+
+struct UBOParams {
+ float4 lights[4];
+ float exposure;
+ float gamma;
+};
+cbuffer uboParams : register(b1) { UBOParams uboParams; };
+
+// From http://filmicworlds.com/blog/filmic-tonemapping-operators/
+float3 Uncharted2Tonemap(float3 color)
+{
+ float A = 0.15;
+ float B = 0.50;
+ float C = 0.10;
+ float D = 0.20;
+ float E = 0.02;
+ float F = 0.30;
+ float W = 11.2;
+ return ((color*(A*color+C*B)+D*E)/(color*(A*color+B)+D*F))-E/F;
+}
+
+float4 main([[vk::location(0)]] float3 inUVW : POSITION0) : SV_TARGET
+{
+ float3 color = textureEnv.Sample(samplerEnv, inUVW).rgb;
+
+ // Tone mapping
+ color = Uncharted2Tonemap(color * uboParams.exposure);
+ color = color * (1.0f / Uncharted2Tonemap((11.2f).xxx));
+ // Gamma correction
+ color = pow(color, (1.0f / uboParams.gamma).xxx);
+
+ return float4(color, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/pbrtexture/skybox.vert b/data/hlsl/pbrtexture/skybox.vert
new file mode 100644
index 00000000..26e3fb6d
--- /dev/null
+++ b/data/hlsl/pbrtexture/skybox.vert
@@ -0,0 +1,30 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UVW : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UVW = input.Pos;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/pipelines/phong.frag b/data/hlsl/pipelines/phong.frag
new file mode 100644
index 00000000..343c91a3
--- /dev/null
+++ b/data/hlsl/pipelines/phong.frag
@@ -0,0 +1,29 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t1);
+SamplerState samplerColorMap : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ // Desaturate color
+ float3 color = lerp(input.Color, dot(float3(0.2126,0.7152,0.0722), input.Color).xxx, 0.65);
+
+ // High ambient colors because mesh materials are pretty dark
+ float3 ambient = color * float3(1.0, 1.0, 1.0);
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * color;
+ float3 specular = pow(max(dot(R, V), 0.0), 32.0) * float3(0.35, 0.35, 0.35);
+ return float4(ambient + diffuse * 1.75 + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/pipelines/phong.vert b/data/hlsl/pipelines/phong.vert
new file mode 100644
index 00000000..2ea7b03b
--- /dev/null
+++ b/data/hlsl/pipelines/phong.vert
@@ -0,0 +1,44 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.UV = input.UV;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+
+ float4 pos = mul(ubo.model, float4(input.Pos, 1.0));
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ float3 lPos = mul((float3x3)ubo.model, ubo.lightPos.xyz);
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/pipelines/toon.frag b/data/hlsl/pipelines/toon.frag
new file mode 100644
index 00000000..048b6b74
--- /dev/null
+++ b/data/hlsl/pipelines/toon.frag
@@ -0,0 +1,37 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t1);
+SamplerState samplerColorMap : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ // Desaturate color
+ float3 color = lerp(input.Color, dot(float3(0.2126,0.7152,0.0722), input.Color).xxx, 0.65);
+
+ // High ambient colors because mesh materials are pretty dark
+ float3 ambient = color * float3(1.0, 1.0, 1.0);
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * color;
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75);
+
+ float intensity = dot(N,L);
+ float shade = 1.0;
+ shade = intensity < 0.5 ? 0.75 : shade;
+ shade = intensity < 0.35 ? 0.6 : shade;
+ shade = intensity < 0.25 ? 0.5 : shade;
+ shade = intensity < 0.1 ? 0.25 : shade;
+
+ return float4(input.Color * 3.0 * shade, 1);
+}
\ No newline at end of file
diff --git a/data/hlsl/pipelines/toon.vert b/data/hlsl/pipelines/toon.vert
new file mode 100644
index 00000000..2ea7b03b
--- /dev/null
+++ b/data/hlsl/pipelines/toon.vert
@@ -0,0 +1,44 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.UV = input.UV;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+
+ float4 pos = mul(ubo.model, float4(input.Pos, 1.0));
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ float3 lPos = mul((float3x3)ubo.model, ubo.lightPos.xyz);
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/pipelines/wireframe.frag b/data/hlsl/pipelines/wireframe.frag
new file mode 100644
index 00000000..0ff24dd0
--- /dev/null
+++ b/data/hlsl/pipelines/wireframe.frag
@@ -0,0 +1,6 @@
+// Copyright 2020 Google LLC
+
+float4 main([[vk::location(0)]] float3 Color : COLOR0) : SV_TARGET
+{
+ return float4(Color * 1.5, 1);
+}
\ No newline at end of file
diff --git a/data/hlsl/pipelines/wireframe.vert b/data/hlsl/pipelines/wireframe.vert
new file mode 100644
index 00000000..089cd426
--- /dev/null
+++ b/data/hlsl/pipelines/wireframe.vert
@@ -0,0 +1,29 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.Pos = mul(ubo.projection, mul(ubo.model, input.Pos));
+ return output;
+}
diff --git a/data/hlsl/pipelinestatistics/scene.frag b/data/hlsl/pipelinestatistics/scene.frag
new file mode 100644
index 00000000..4cd20bf5
--- /dev/null
+++ b/data/hlsl/pipelinestatistics/scene.frag
@@ -0,0 +1,20 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * input.Color;
+ float3 specular = pow(max(dot(R, V), 0.0), 8.0) * float3(0.75, 0.75, 0.75);
+ return float4(diffuse + specular, 0.5);
+}
\ No newline at end of file
diff --git a/data/hlsl/pipelinestatistics/scene.tesc b/data/hlsl/pipelinestatistics/scene.tesc
new file mode 100644
index 00000000..bed96a0e
--- /dev/null
+++ b/data/hlsl/pipelinestatistics/scene.tesc
@@ -0,0 +1,52 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+struct HSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+struct ConstantsHSOutput
+{
+ float TessLevelOuter[3] : SV_TessFactor;
+ float TessLevelInner : SV_InsideTessFactor;
+};
+
+ConstantsHSOutput ConstantsHS(InputPatch patch, uint InvocationID : SV_PrimitiveID)
+{
+ ConstantsHSOutput output = (ConstantsHSOutput)0;
+ output.TessLevelInner = 2.0;
+ output.TessLevelOuter[0] = 1.0;
+ output.TessLevelOuter[1] = 1.0;
+ output.TessLevelOuter[2] = 1.0;
+ return output;
+}
+
+[domain("tri")]
+[partitioning("integer")]
+[outputtopology("triangle_ccw")]
+[outputcontrolpoints(3)]
+[patchconstantfunc("ConstantsHS")]
+[maxtessfactor(20.0f)]
+HSOutput main(InputPatch patch, uint InvocationID : SV_OutputControlPointID)
+{
+ HSOutput output = (HSOutput)0;
+ output.Pos = patch[InvocationID].Pos;
+ output.Normal = patch[InvocationID].Normal;
+ output.Color = patch[InvocationID].Color;
+ output.ViewVec = patch[InvocationID].ViewVec;
+ output.LightVec = patch[InvocationID].LightVec;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/pipelinestatistics/scene.tese b/data/hlsl/pipelinestatistics/scene.tese
new file mode 100644
index 00000000..1cccb2b2
--- /dev/null
+++ b/data/hlsl/pipelinestatistics/scene.tese
@@ -0,0 +1,39 @@
+// Copyright 2020 Google LLC
+
+struct HSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+struct ConstantsHSOutput
+{
+ float TessLevelOuter[3] : SV_TessFactor;
+ float TessLevelInner : SV_InsideTessFactor;
+};
+
+struct DSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+[domain("tri")]
+DSOutput main(ConstantsHSOutput input, float3 TessCoord : SV_DomainLocation, const OutputPatch patch)
+{
+ DSOutput output = (DSOutput)0;
+ output.Pos = (TessCoord.x * patch[2].Pos) +
+ (TessCoord.y * patch[1].Pos) +
+ (TessCoord.z * patch[0].Pos);
+ output.Normal = TessCoord.x * patch[2].Normal + TessCoord.y * patch[1].Normal + TessCoord.z * patch[0].Normal;
+ output.ViewVec = TessCoord.x * patch[2].ViewVec + TessCoord.y * patch[1].ViewVec + TessCoord.z * patch[0].ViewVec;
+ output.LightVec = TessCoord.x * patch[2].LightVec + TessCoord.y * patch[1].LightVec + TessCoord.z * patch[0].LightVec;
+ output.Color = patch[0].Color;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/pipelinestatistics/scene.vert b/data/hlsl/pipelinestatistics/scene.vert
new file mode 100644
index 00000000..a11fe37c
--- /dev/null
+++ b/data/hlsl/pipelinestatistics/scene.vert
@@ -0,0 +1,48 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+struct PushConsts {
+ float3 objPos;
+};
+[[vk::push_constant]] PushConsts pushConsts;
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+
+ float3 locPos = mul(ubo.modelview, float4(input.Pos, 1.0)).xyz;
+ float3 worldPos = mul(ubo.modelview, float4(input.Pos + pushConsts.objPos, 1.0)).xyz;
+ output.Pos = mul(ubo.projection, float4(worldPos, 1.0));
+
+ float4 pos = mul(ubo.modelview, float4(worldPos, 1.0));
+ output.Normal = mul((float3x3)ubo.modelview, input.Normal);
+ output.LightVec = ubo.lightPos.xyz - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/pushconstants/lights.frag b/data/hlsl/pushconstants/lights.frag
new file mode 100644
index 00000000..7b71cef6
--- /dev/null
+++ b/data/hlsl/pushconstants/lights.frag
@@ -0,0 +1,37 @@
+// Copyright 2020 Google LLC
+
+#define lightCount 6
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float4 LightVec[lightCount] : TEXCOORD1;
+};
+
+#define MAX_LIGHT_DIST 9.0 * 9.0
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 lightColor[lightCount];
+ lightColor[0] = float3(1.0, 0.0, 0.0);
+ lightColor[1] = float3(0.0, 1.0, 0.0);
+ lightColor[2] = float3(0.0, 0.0, 1.0);
+ lightColor[3] = float3(1.0, 0.0, 1.0);
+ lightColor[4] = float3(0.0, 1.0, 1.0);
+ lightColor[5] = float3(1.0, 1.0, 0.0);
+
+ float3 diffuse = float3(0.0, 0.0, 0.0);
+ // Just some very basic attenuation
+ for (int i = 0; i < lightCount; ++i)
+ {
+ float lRadius = MAX_LIGHT_DIST * input.LightVec[i].w;
+
+ float dist = min(dot(input.LightVec[i], input.LightVec[i]), lRadius) / lRadius;
+ float distFactor = 1.0 - dist;
+
+ diffuse += lightColor[i] * distFactor;
+ }
+
+ return float4(diffuse, 1);
+}
\ No newline at end of file
diff --git a/data/hlsl/pushconstants/lights.vert b/data/hlsl/pushconstants/lights.vert
new file mode 100644
index 00000000..f9db58e8
--- /dev/null
+++ b/data/hlsl/pushconstants/lights.vert
@@ -0,0 +1,50 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+#define lightCount 6
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 lightColor[lightCount];
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct PushConsts {
+ float4 lightPos[lightCount];
+};
+[[vk::push_constant]] PushConsts pushConsts;
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float4 LightVec[lightCount] : TEXCOORD1;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+
+ for (int i = 0; i < lightCount; ++i)
+ {
+ float4 worldPos = mul(ubo.model, float4(input.Pos.xyz, 1.0));
+ output.LightVec[i].xyz = pushConsts.lightPos[i].xyz - input.Pos.xyz;
+ // Store light radius in w
+ output.LightVec[i].w = pushConsts.lightPos[i].w;
+ }
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/pushdescriptors/cube.frag b/data/hlsl/pushdescriptors/cube.frag
new file mode 100644
index 00000000..69ede0b8
--- /dev/null
+++ b/data/hlsl/pushdescriptors/cube.frag
@@ -0,0 +1,16 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t2);
+SamplerState samplerColorMap : register(s2);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ return textureColorMap.Sample(samplerColorMap, input.UV) * float4(input.Color, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/pushdescriptors/cube.vert b/data/hlsl/pushdescriptors/cube.vert
new file mode 100644
index 00000000..9a8366a0
--- /dev/null
+++ b/data/hlsl/pushdescriptors/cube.vert
@@ -0,0 +1,38 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBOScene {
+ float4x4 projection;
+ float4x4 view;
+};
+cbuffer uboCamera : register(b0) { UBOScene uboCamera; };
+
+struct UBOModel {
+ float4x4 local;
+};
+cbuffer uboModel : register(b1) { UBOModel uboModel; };
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.UV = input.UV;
+ output.Pos = mul(uboCamera.projection, mul(uboCamera.view, mul(uboModel.local, float4(input.Pos.xyz, 1.0))));
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/radialblur/colorpass.frag b/data/hlsl/radialblur/colorpass.frag
new file mode 100644
index 00000000..08577814
--- /dev/null
+++ b/data/hlsl/radialblur/colorpass.frag
@@ -0,0 +1,23 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureGradientRamp : register(t1);
+SamplerState samplerGradientRamp : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Color : COLOR0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ // Use max. color channel value to detect bright glow emitters
+ if ((input.Color.r >= 0.9) || (input.Color.g >= 0.9) || (input.Color.b >= 0.9))
+ {
+ return float4(textureGradientRamp.Sample(samplerGradientRamp, input.UV).rgb, 1);
+ }
+ else
+ {
+ return float4(input.Color, 1);
+ }
+}
\ No newline at end of file
diff --git a/data/hlsl/radialblur/colorpass.vert b/data/hlsl/radialblur/colorpass.vert
new file mode 100644
index 00000000..a82eedea
--- /dev/null
+++ b/data/hlsl/radialblur/colorpass.vert
@@ -0,0 +1,32 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(2)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float gradientPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.UV = float2(ubo.gradientPos, 0.0f);
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/radialblur/phongpass.frag b/data/hlsl/radialblur/phongpass.frag
new file mode 100644
index 00000000..1360ff30
--- /dev/null
+++ b/data/hlsl/radialblur/phongpass.frag
@@ -0,0 +1,35 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureGradientRamp : register(t1);
+SamplerState samplerGradientRamp : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 EyePos : POSITION0;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+[[vk::location(4)]] float2 UV : TEXCOORD0;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ // No light calculations for glow color
+ // Use max. color channel value
+ // to detect bright glow emitters
+ if ((input.Color.r >= 0.9) || (input.Color.g >= 0.9) || (input.Color.b >= 0.9))
+ {
+ return float4(textureGradientRamp.Sample(samplerGradientRamp, input.UV).rgb, 1);
+ }
+ else
+ {
+ float3 Eye = normalize(-input.EyePos);
+ float3 Reflected = normalize(reflect(-input.LightVec, input.Normal));
+
+ float4 IAmbient = float4(0.2, 0.2, 0.2, 1.0);
+ float4 IDiffuse = float4(0.5, 0.5, 0.5, 0.5) * max(dot(input.Normal, input.LightVec), 0.0);
+ float specular = 0.25;
+ float4 ISpecular = float4(0.5, 0.5, 0.5, 1.0) * pow(max(dot(Reflected, Eye), 0.0), 4.0) * specular;
+ return float4((IAmbient + IDiffuse) * float4(input.Color, 1.0) + ISpecular);
+ }
+}
\ No newline at end of file
diff --git a/data/hlsl/radialblur/phongpass.vert b/data/hlsl/radialblur/phongpass.vert
new file mode 100644
index 00000000..22b8974b
--- /dev/null
+++ b/data/hlsl/radialblur/phongpass.vert
@@ -0,0 +1,40 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float gradientPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 EyePos : POSITION0;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+[[vk::location(4)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.UV = float2(ubo.gradientPos, 0.0);
+ output.Pos = mul(ubo.projection, mul(ubo.model, input.Pos));
+ output.EyePos = mul(ubo.model, input.Pos).xyz;
+ float4 lightPos = float4(0.0, 0.0, -5.0, 1.0);// * ubo.model;
+ output.LightVec = normalize(lightPos.xyz - input.Pos.xyz);
+ return output;
+}
diff --git a/data/hlsl/radialblur/radialblur.frag b/data/hlsl/radialblur/radialblur.frag
new file mode 100644
index 00000000..3e41875e
--- /dev/null
+++ b/data/hlsl/radialblur/radialblur.frag
@@ -0,0 +1,35 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+struct UBO
+{
+ float radialBlurScale;
+ float radialBlurStrength;
+ float2 radialOrigin;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ int2 texDim;
+ textureColor.GetDimensions(texDim.x, texDim.y);
+ float2 radialSize = float2(1.0 / texDim.x, 1.0 / texDim.y);
+
+ float2 UV = inUV;
+
+ float4 color = float4(0.0, 0.0, 0.0, 0.0);
+ UV += radialSize * 0.5 - ubo.radialOrigin;
+
+ #define samples 32
+
+ for (int i = 0; i < samples; i++)
+ {
+ float scale = 1.0 - ubo.radialBlurScale * (float(i) / float(samples-1));
+ color += textureColor.Sample(samplerColor, UV * scale + ubo.radialOrigin);
+ }
+
+ return (color / samples) * ubo.radialBlurStrength;
+}
\ No newline at end of file
diff --git a/data/hlsl/radialblur/radialblur.vert b/data/hlsl/radialblur/radialblur.vert
new file mode 100644
index 00000000..b13c2bf2
--- /dev/null
+++ b/data/hlsl/radialblur/radialblur.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/renderheadless/triangle.frag b/data/hlsl/renderheadless/triangle.frag
new file mode 100644
index 00000000..8a7faf06
--- /dev/null
+++ b/data/hlsl/renderheadless/triangle.frag
@@ -0,0 +1,6 @@
+// Copyright 2020 Google LLC
+
+float4 main([[vk::location(0)]] float3 Color : COLOR0) : SV_TARGET
+{
+ return float4(Color, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/renderheadless/triangle.vert b/data/hlsl/renderheadless/triangle.vert
new file mode 100644
index 00000000..6e5c2207
--- /dev/null
+++ b/data/hlsl/renderheadless/triangle.vert
@@ -0,0 +1,26 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Color : COLOR0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+};
+
+struct PushConsts {
+ float4x4 mvp;
+};
+[[vk::push_constant]] PushConsts pushConsts;
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.Pos = mul(pushConsts.mvp, float4(input.Pos.xyz, 1.0));
+ return output;
+}
diff --git a/data/hlsl/scenerendering/scene.frag b/data/hlsl/scenerendering/scene.frag
new file mode 100644
index 00000000..5cf6f627
--- /dev/null
+++ b/data/hlsl/scenerendering/scene.frag
@@ -0,0 +1,34 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t0, space1);
+SamplerState samplerColorMap : register(s0, space1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+struct Material
+{
+ float4 ambient;
+ float4 diffuse;
+ float4 specular;
+ float opacity;
+};
+[[vk::push_constant]] Material material;
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 color = textureColorMap.Sample(samplerColorMap, input.UV) * float4(input.Color, 1.0);
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * material.diffuse.rgb;
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * material.specular.rgb;
+ return float4((material.ambient.rgb + diffuse) * color.rgb + specular, 1.0-material.opacity);
+}
\ No newline at end of file
diff --git a/data/hlsl/scenerendering/scene.vert b/data/hlsl/scenerendering/scene.vert
new file mode 100644
index 00000000..7fa6d216
--- /dev/null
+++ b/data/hlsl/scenerendering/scene.vert
@@ -0,0 +1,47 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+ float4 lightPos;
+};
+cbuffer ubo : register(b0) { UBO ubo; };
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.UV = input.UV;
+
+ float4x4 modelView = mul(ubo.view, ubo.model);
+
+ output.Pos = mul(ubo.projection, mul(modelView, float4(input.Pos.xyz, 1.0)));
+
+ float4 pos = mul(modelView, float4(input.Pos, 0.0));
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ float3 lPos = mul((float3x3)ubo.model, ubo.lightPos.xyz);
+ output.LightVec = lPos - mul(ubo.model, float4(input.Pos, 1.0)).xyz;
+ output.ViewVec = -mul(ubo.model, float4(input.Pos, 1.0)).xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/screenshot/mesh.frag b/data/hlsl/screenshot/mesh.frag
new file mode 100644
index 00000000..2c14be89
--- /dev/null
+++ b/data/hlsl/screenshot/mesh.frag
@@ -0,0 +1,21 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 ambient = float3(0.1, 0.1, 0.1);
+ float3 diffuse = max(dot(N, L), 0.0) * float3(1.0, 1.0, 1.0);
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75);
+ return float4((ambient + diffuse) * input.Color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/screenshot/mesh.vert b/data/hlsl/screenshot/mesh.vert
new file mode 100644
index 00000000..38f9bc79
--- /dev/null
+++ b/data/hlsl/screenshot/mesh.vert
@@ -0,0 +1,41 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+};
+cbuffer ubo : register(b0) { UBO ubo; };
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, input.Pos)));
+
+ float4 pos = mul(ubo.view, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+
+ float3 lightPos = float3(1.0f, -1.0f, 1.0f);
+ output.LightVec = lightPos.xyz - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
diff --git a/data/hlsl/shadowmapomni/cubemapdisplay.frag b/data/hlsl/shadowmapomni/cubemapdisplay.frag
new file mode 100644
index 00000000..8b964fa3
--- /dev/null
+++ b/data/hlsl/shadowmapomni/cubemapdisplay.frag
@@ -0,0 +1,53 @@
+// Copyright 2020 Google LLC
+
+TextureCube shadowCubeMapTexture : register(t1);
+SamplerState shadowCubeMapSampler : register(s1);
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ float4 outFragColor = float4(0, 0, 0, 0);
+ outFragColor.rgb = float3(0.0, 0.0, 0.2);
+
+ float3 samplePos = float3(0, 0, 0);
+
+ // Crude statement to visualize different cube map faces based on UV coordinates
+ int x = int(floor(inUV.x / 0.25f));
+ int y = int(floor(inUV.y / (1.0 / 3.0)));
+ if (y == 1) {
+ float2 uv = float2(inUV.x * 4.0f, (inUV.y - 1.0/3.0) * 3.0);
+ uv = 2.0 * float2(uv.x - float(x) * 1.0, uv.y) - 1.0;
+ switch (x) {
+ case 0: // NEGATIVE_X
+ samplePos = float3(-1.0f, uv.y, uv.x);
+ break;
+ case 1: // POSITIVE_Z
+ samplePos = float3(uv.x, uv.y, 1.0f);
+ break;
+ case 2: // POSITIVE_X
+ samplePos = float3(1.0, uv.y, -uv.x);
+ break;
+ case 3: // NEGATIVE_Z
+ samplePos = float3(-uv.x, uv.y, -1.0f);
+ break;
+ }
+ } else {
+ if (x == 1) {
+ float2 uv = float2((inUV.x - 0.25) * 4.0, (inUV.y - float(y) / 3.0) * 3.0);
+ uv = 2.0 * uv - 1.0;
+ switch (y) {
+ case 0: // NEGATIVE_Y
+ samplePos = float3(uv.x, -1.0f, uv.y);
+ break;
+ case 2: // POSITIVE_Y
+ samplePos = float3(uv.x, 1.0f, -uv.y);
+ break;
+ }
+ }
+ }
+
+ if ((samplePos.x != 0.0f) && (samplePos.y != 0.0f)) {
+ float dist = length(shadowCubeMapTexture.Sample(shadowCubeMapSampler, samplePos).xyz) * 0.005;
+ outFragColor = float4(dist.xxx, 1.0);
+ }
+ return outFragColor;
+}
\ No newline at end of file
diff --git a/data/hlsl/shadowmapomni/cubemapdisplay.vert b/data/hlsl/shadowmapomni/cubemapdisplay.vert
new file mode 100644
index 00000000..41068e73
--- /dev/null
+++ b/data/hlsl/shadowmapomni/cubemapdisplay.vert
@@ -0,0 +1,25 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV.xy * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
+
diff --git a/data/hlsl/shadowmapomni/offscreen.frag b/data/hlsl/shadowmapomni/offscreen.frag
new file mode 100644
index 00000000..82c9fa9b
--- /dev/null
+++ b/data/hlsl/shadowmapomni/offscreen.frag
@@ -0,0 +1,14 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 LightPos : POSITION1;
+};
+
+float main(VSOutput input) : SV_TARGET
+{
+ // Store distance to light as 32 bit float value
+ float3 lightVec = input.Pos.xyz - input.LightPos;
+ return length(lightVec);
+}
\ No newline at end of file
diff --git a/data/hlsl/shadowmapomni/offscreen.vert b/data/hlsl/shadowmapomni/offscreen.vert
new file mode 100644
index 00000000..3c504104
--- /dev/null
+++ b/data/hlsl/shadowmapomni/offscreen.vert
@@ -0,0 +1,34 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float4 WorldPos : POSITION0;
+[[vk::location(1)]] float3 LightPos : POSITION1;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct PushConsts
+{
+ float4x4 view;
+};
+[[vk::push_constant]] PushConsts pushConsts;
+
+VSOutput main([[vk::location(0)]] float3 Pos : POSITION0)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = mul(ubo.projection, mul(pushConsts.view, mul(ubo.model, float4(Pos, 1.0))));
+
+ output.WorldPos = float4(Pos, 1.0);
+ output.LightPos = ubo.lightPos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/shadowmapomni/scene.frag b/data/hlsl/shadowmapomni/scene.frag
new file mode 100644
index 00000000..840d8298
--- /dev/null
+++ b/data/hlsl/shadowmapomni/scene.frag
@@ -0,0 +1,43 @@
+// Copyright 2020 Google LLC
+
+TextureCube shadowCubeMapTexture : register(t1);
+SamplerState shadowCubeMapSampler : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 EyePos : POSITION0;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+[[vk::location(4)]] float3 WorldPos : POSITION1;
+[[vk::location(5)]] float3 LightPos : POSITION2;
+};
+
+#define EPSILON 0.15
+#define SHADOW_OPACITY 0.5
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ // Lighting
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(float3(1.0, 1.0, 1.0));
+
+ float3 Eye = normalize(-input.EyePos);
+ float3 Reflected = normalize(reflect(-input.LightVec, input.Normal));
+
+ float4 IAmbient = float4(float3(0.05, 0.05, 0.05), 1.0);
+ float4 IDiffuse = float4(1.0, 1.0, 1.0, 1.0) * max(dot(input.Normal, input.LightVec), 0.0);
+
+ float4 outFragColor = float4(IAmbient + IDiffuse * float4(input.Color, 1.0));
+
+ // Shadow
+ float3 lightVec = input.WorldPos - input.LightPos;
+ float sampledDist = shadowCubeMapTexture.Sample(shadowCubeMapSampler, lightVec).r;
+ float dist = length(lightVec);
+
+ // Check if fragment is in shadow
+ float shadow = (dist <= sampledDist + EPSILON) ? 1.0 : SHADOW_OPACITY;
+
+ outFragColor.rgb *= shadow;
+ return outFragColor;
+}
\ No newline at end of file
diff --git a/data/hlsl/shadowmapomni/scene.vert b/data/hlsl/shadowmapomni/scene.vert
new file mode 100644
index 00000000..f6887c5f
--- /dev/null
+++ b/data/hlsl/shadowmapomni/scene.vert
@@ -0,0 +1,45 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 EyePos : POSITION0;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+[[vk::location(4)]] float3 WorldPos : POSITION1;
+[[vk::location(5)]] float3 LightPos : POSITION2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.Normal = input.Normal;
+
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, float4(input.Pos.xyz, 1.0))));
+ output.EyePos = mul(ubo.model, float4(input.Pos, 1.0f)).xyz;
+ output.LightVec = normalize(ubo.lightPos.xyz - input.Pos.xyz);
+ output.WorldPos = input.Pos;
+
+ output.LightPos = ubo.lightPos.xyz;
+ return output;
+}
+
diff --git a/data/hlsl/shadowmapping/offscreen.frag b/data/hlsl/shadowmapping/offscreen.frag
new file mode 100644
index 00000000..54d4ac24
--- /dev/null
+++ b/data/hlsl/shadowmapping/offscreen.frag
@@ -0,0 +1,6 @@
+// Copyright 2020 Google LLC
+
+float4 main() : SV_TARGET
+{
+ return float4(1.0, 0.0, 0.0, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/shadowmapping/offscreen.vert b/data/hlsl/shadowmapping/offscreen.vert
new file mode 100644
index 00000000..b20b1d1f
--- /dev/null
+++ b/data/hlsl/shadowmapping/offscreen.vert
@@ -0,0 +1,13 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float4x4 depthMVP;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+float4 main([[vk::location(0)]] float3 Pos : POSITION0) : SV_POSITION
+{
+ return mul(ubo.depthMVP, float4(Pos, 1.0));
+}
\ No newline at end of file
diff --git a/data/hlsl/shadowmapping/quad.frag b/data/hlsl/shadowmapping/quad.frag
new file mode 100644
index 00000000..fb90f429
--- /dev/null
+++ b/data/hlsl/shadowmapping/quad.frag
@@ -0,0 +1,18 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+float LinearizeDepth(float depth)
+{
+ float n = 1.0; // camera z near
+ float f = 128.0; // camera z far
+ float z = depth;
+ return (2.0 * n) / (f + n - z * (f - n));
+}
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ float depth = textureColor.Sample(samplerColor, inUV).r;
+ return float4((1.0-LinearizeDepth(depth)).xxx, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/shadowmapping/quad.vert b/data/hlsl/shadowmapping/quad.vert
new file mode 100644
index 00000000..75b0658c
--- /dev/null
+++ b/data/hlsl/shadowmapping/quad.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV, 0.0f, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/shadowmapping/scene.frag b/data/hlsl/shadowmapping/scene.frag
new file mode 100644
index 00000000..5ae6167d
--- /dev/null
+++ b/data/hlsl/shadowmapping/scene.frag
@@ -0,0 +1,68 @@
+// Copyright 2020 Google LLC
+
+Texture2D shadowMapTexture : register(t1);
+SamplerState shadowMapSampler : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+[[vk::location(4)]] float4 ShadowCoord : TEXCOORD3;
+};
+
+[[vk::constant_id(0)]] const int enablePCF = 0;
+
+#define ambient 0.1
+
+float textureProj(float4 shadowCoord, float2 off)
+{
+ float shadow = 1.0;
+ if ( shadowCoord.z > -1.0 && shadowCoord.z < 1.0 )
+ {
+ float dist = shadowMapTexture.Sample( shadowMapSampler, shadowCoord.xy + off ).r;
+ if ( shadowCoord.w > 0.0 && dist < shadowCoord.z )
+ {
+ shadow = ambient;
+ }
+ }
+ return shadow;
+}
+
+float filterPCF(float4 sc)
+{
+ int2 texDim;
+ shadowMapTexture.GetDimensions(texDim.x, texDim.y);
+ float scale = 1.5;
+ float dx = scale * 1.0 / float(texDim.x);
+ float dy = scale * 1.0 / float(texDim.y);
+
+ float shadowFactor = 0.0;
+ int count = 0;
+ int range = 1;
+
+ for (int x = -range; x <= range; x++)
+ {
+ for (int y = -range; y <= range; y++)
+ {
+ shadowFactor += textureProj(sc, float2(dx*x, dy*y));
+ count++;
+ }
+
+ }
+ return shadowFactor / count;
+}
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float shadow = (enablePCF == 1) ? filterPCF(input.ShadowCoord / input.ShadowCoord.w) : textureProj(input.ShadowCoord / input.ShadowCoord.w, float2(0.0, 0.0));
+
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = normalize(-reflect(L, N));
+ float3 diffuse = max(dot(N, L), ambient) * input.Color;
+
+ return float4(diffuse * shadow, 1.0);
+}
diff --git a/data/hlsl/shadowmapping/scene.vert b/data/hlsl/shadowmapping/scene.vert
new file mode 100644
index 00000000..583b6a8e
--- /dev/null
+++ b/data/hlsl/shadowmapping/scene.vert
@@ -0,0 +1,54 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+ float4x4 lightSpace;
+ float3 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+[[vk::location(4)]] float4 ShadowCoord : TEXCOORD3;
+};
+
+static const float4x4 biasMat = float4x4(
+ 0.5, 0.0, 0.0, 0.5,
+ 0.0, 0.5, 0.0, 0.5,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0 );
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.Normal = input.Normal;
+
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, float4(input.Pos.xyz, 1.0))));
+
+ float4 pos = mul(ubo.model, float4(input.Pos, 1.0));
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ output.LightVec = normalize(ubo.lightPos - input.Pos);
+ output.ViewVec = -pos.xyz;
+
+ output.ShadowCoord = mul(biasMat, mul(ubo.lightSpace, mul(ubo.model, float4(input.Pos, 1.0))));
+ return output;
+}
+
diff --git a/data/hlsl/shadowmappingcascade/debugshadowmap.frag b/data/hlsl/shadowmappingcascade/debugshadowmap.frag
new file mode 100644
index 00000000..32871804
--- /dev/null
+++ b/data/hlsl/shadowmappingcascade/debugshadowmap.frag
@@ -0,0 +1,16 @@
+// Copyright 2020 Google LLC
+
+Texture2DArray shadowMapTexture : register(t1);
+SamplerState shadowMapSampler : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] uint CascadeIndex : TEXCOORD1;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float depth = shadowMapTexture.Sample(shadowMapSampler, float3(input.UV, float(input.CascadeIndex))).r;
+ return float4(depth.xxx, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/shadowmappingcascade/debugshadowmap.vert b/data/hlsl/shadowmappingcascade/debugshadowmap.vert
new file mode 100644
index 00000000..6e8ae835
--- /dev/null
+++ b/data/hlsl/shadowmappingcascade/debugshadowmap.vert
@@ -0,0 +1,23 @@
+// Copyright 2020 Google LLC
+
+struct PushConsts {
+ float4 position;
+ uint cascadeIndex;
+};
+[[vk::push_constant]] PushConsts pushConsts;
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] uint CascadeIndex : TEXCOORD1;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.CascadeIndex = pushConsts.cascadeIndex;
+ output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/shadowmappingcascade/depthpass.frag b/data/hlsl/shadowmappingcascade/depthpass.frag
new file mode 100644
index 00000000..43939200
--- /dev/null
+++ b/data/hlsl/shadowmappingcascade/depthpass.frag
@@ -0,0 +1,12 @@
+// Copyright 2020 Google LLC
+
+Texture2D colorMapTexture : register(t0, space1);
+SamplerState colorMapSampler : register(s0, space1);
+
+void main([[vk::location(0)]] float2 inUV : TEXCOORD0)
+{
+ float alpha = colorMapTexture.Sample(colorMapSampler, inUV).a;
+ if (alpha < 0.5) {
+ clip(-1);
+ }
+}
\ No newline at end of file
diff --git a/data/hlsl/shadowmappingcascade/depthpass.vert b/data/hlsl/shadowmappingcascade/depthpass.vert
new file mode 100644
index 00000000..78e70e5b
--- /dev/null
+++ b/data/hlsl/shadowmappingcascade/depthpass.vert
@@ -0,0 +1,36 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+// todo: pass via specialization constant
+#define SHADOW_MAP_CASCADE_COUNT 4
+
+struct PushConsts {
+ float4 position;
+ uint cascadeIndex;
+};
+[[vk::push_constant]] PushConsts pushConsts;
+
+struct UBO {
+ float4x4 cascadeViewProjMat[SHADOW_MAP_CASCADE_COUNT];
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV;
+ float3 pos = input.Pos + pushConsts.position.xyz;
+ output.Pos = mul(ubo.cascadeViewProjMat[pushConsts.cascadeIndex], float4(pos, 1.0));
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/shadowmappingcascade/scene.frag b/data/hlsl/shadowmappingcascade/scene.frag
new file mode 100644
index 00000000..6a7388f4
--- /dev/null
+++ b/data/hlsl/shadowmappingcascade/scene.frag
@@ -0,0 +1,131 @@
+// Copyright 2020 Google LLC
+
+#define SHADOW_MAP_CASCADE_COUNT 4
+
+Texture2DArray shadowMapTexture : register(t1);
+SamplerState shadowMapSampler : register(s1);
+Texture2D colorMapTexture : register(t0, space1);
+SamplerState colorMapSampler : register(s0, space1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewPos : POSITION1;
+[[vk::location(3)]] float3 Pos : POSITION0;
+[[vk::location(4)]] float2 UV : TEXCOORD0;
+};
+
+[[vk::constant_id(0)]] const int enablePCF = 0;
+
+#define ambient 0.3
+
+struct UBO {
+ float4 cascadeSplits;
+ float4x4 cascadeViewProjMat[SHADOW_MAP_CASCADE_COUNT];
+ float4x4 inverseViewMat;
+ float3 lightDir;
+ float _pad;
+ int colorCascades;
+};
+cbuffer ubo : register(b2) { UBO ubo; };
+
+static const float4x4 biasMat = float4x4(
+ 0.5, 0.0, 0.0, 0.5,
+ 0.0, 0.5, 0.0, 0.5,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0
+);
+
+float textureProj(float4 shadowCoord, float2 offset, uint cascadeIndex)
+{
+ float shadow = 1.0;
+ float bias = 0.005;
+
+ if ( shadowCoord.z > -1.0 && shadowCoord.z < 1.0 ) {
+ float dist = shadowMapTexture.Sample(shadowMapSampler, float3(shadowCoord.xy + offset, cascadeIndex)).r;
+ if (shadowCoord.w > 0 && dist < shadowCoord.z - bias) {
+ shadow = ambient;
+ }
+ }
+ return shadow;
+
+}
+
+float filterPCF(float4 sc, uint cascadeIndex)
+{
+ int3 texDim;
+ shadowMapTexture.GetDimensions(texDim.x, texDim.y, texDim.z);
+ float scale = 0.75;
+ float dx = scale * 1.0 / float(texDim.x);
+ float dy = scale * 1.0 / float(texDim.y);
+
+ float shadowFactor = 0.0;
+ int count = 0;
+ int range = 1;
+
+ for (int x = -range; x <= range; x++) {
+ for (int y = -range; y <= range; y++) {
+ shadowFactor += textureProj(sc, float2(dx*x, dy*y), cascadeIndex);
+ count++;
+ }
+ }
+ return shadowFactor / count;
+}
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 outFragColor;
+ float4 color = colorMapTexture.Sample(colorMapSampler, input.UV);
+ if (color.a < 0.5) {
+ clip(-1);
+ }
+
+ // Get cascade index for the current fragment's view position
+ uint cascadeIndex = 0;
+ for(uint i = 0; i < SHADOW_MAP_CASCADE_COUNT - 1; ++i) {
+ if(input.ViewPos.z < ubo.cascadeSplits[i]) {
+ cascadeIndex = i + 1;
+ }
+ }
+
+ // Depth compare for shadowing
+ float4 shadowCoord = mul(biasMat, mul(ubo.cascadeViewProjMat[cascadeIndex], float4(input.Pos, 1.0)));
+
+ float shadow = 0;
+ if (enablePCF == 1) {
+ shadow = filterPCF(shadowCoord / shadowCoord.w, cascadeIndex);
+ } else {
+ shadow = textureProj(shadowCoord / shadowCoord.w, float2(0.0, 0.0), cascadeIndex);
+ }
+
+ // Directional light
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(-ubo.lightDir);
+ float3 H = normalize(L + input.ViewPos);
+ float diffuse = max(dot(N, L), ambient);
+ float3 lightColor = float3(1.0, 1.0, 1.0);
+ outFragColor.rgb = max(lightColor * (diffuse * color.rgb), float3(0.0, 0.0, 0.0));
+ outFragColor.rgb *= shadow;
+ outFragColor.a = color.a;
+
+ // Color cascades (if enabled)
+ if (ubo.colorCascades == 1) {
+ switch(cascadeIndex) {
+ case 0 :
+ outFragColor.rgb *= float3(1.0f, 0.25f, 0.25f);
+ break;
+ case 1 :
+ outFragColor.rgb *= float3(0.25f, 1.0f, 0.25f);
+ break;
+ case 2 :
+ outFragColor.rgb *= float3(0.25f, 0.25f, 1.0f);
+ break;
+ case 3 :
+ outFragColor.rgb *= float3(1.0f, 1.0f, 0.25f);
+ break;
+ }
+ }
+
+ return outFragColor;
+}
diff --git a/data/hlsl/shadowmappingcascade/scene.vert b/data/hlsl/shadowmappingcascade/scene.vert
new file mode 100644
index 00000000..957845b2
--- /dev/null
+++ b/data/hlsl/shadowmappingcascade/scene.vert
@@ -0,0 +1,47 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 Normal : NORMAL0;
+};
+
+struct UBO {
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewPos : POSITION1;
+[[vk::location(3)]] float3 WorldPos : POSITION0;
+[[vk::location(4)]] float2 UV : TEXCOORD0;
+};
+
+struct PushConsts {
+ float4 position;
+ uint cascadeIndex;
+};
+[[vk::push_constant]] PushConsts pushConsts;
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.Normal = input.Normal;
+ output.UV = input.UV;
+ float3 pos = input.Pos + pushConsts.position.xyz;
+ output.WorldPos = pos;
+ output.ViewPos = mul(ubo.view, float4(pos.xyz, 1.0)).xyz;
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, float4(pos.xyz, 1.0))));
+ return output;
+}
+
diff --git a/data/hlsl/skeletalanimation/mesh.frag b/data/hlsl/skeletalanimation/mesh.frag
new file mode 100644
index 00000000..4117babb
--- /dev/null
+++ b/data/hlsl/skeletalanimation/mesh.frag
@@ -0,0 +1,26 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t1);
+SamplerState samplerColorMap : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 color = textureColorMap.Sample(samplerColorMap, input.UV) * float4(input.Color, 1.0);
+
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.1) * float3(1.0, 1.0, 1.0) * input.Color;
+ float3 specular = pow(max(dot(R, V), 0.0), 32.0) * float3(0.5, 0.5, 0.5);
+ return float4(diffuse * color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/skeletalanimation/mesh.vert b/data/hlsl/skeletalanimation/mesh.vert
new file mode 100644
index 00000000..1a1d6b57
--- /dev/null
+++ b/data/hlsl/skeletalanimation/mesh.vert
@@ -0,0 +1,55 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+[[vk::location(4)]] float4 BoneWeights : TEXCOORD1;
+[[vk::location(5)]] int4 BoneIDs : TEXCOORD2;
+};
+
+#define MAX_BONES 64
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+ float4x4 bones[MAX_BONES];
+ float4 lightPos;
+ float4 viewPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ float4x4 boneTransform = ubo.bones[input.BoneIDs[0]] * input.BoneWeights[0];
+ boneTransform += ubo.bones[input.BoneIDs[1]] * input.BoneWeights[1];
+ boneTransform += ubo.bones[input.BoneIDs[2]] * input.BoneWeights[2];
+ boneTransform += ubo.bones[input.BoneIDs[3]] * input.BoneWeights[3];
+
+ output.Color = input.Color;
+ output.UV = input.UV;
+
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, mul(boneTransform, float4(input.Pos.xyz, 1.0)))));
+
+ float4 pos = mul(ubo.model, float4(input.Pos, 1.0));
+ output.Normal = mul((float3x3)(boneTransform), input.Normal);
+ output.LightVec = ubo.lightPos.xyz - pos.xyz;
+ output.ViewVec = ubo.viewPos.xyz - pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/skeletalanimation/texture.frag b/data/hlsl/skeletalanimation/texture.frag
new file mode 100644
index 00000000..75af0820
--- /dev/null
+++ b/data/hlsl/skeletalanimation/texture.frag
@@ -0,0 +1,31 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t1);
+SamplerState samplerColorMap : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 color = textureColorMap.Sample(samplerColorMap, input.UV);
+
+ float distSqr = dot(input.LightVec, input.LightVec);
+ float3 lVec = input.LightVec * rsqrt(distSqr);
+
+ const float attInvRadius = 1.0/5000.0;
+ float atten = max(clamp(1.0 - attInvRadius * sqrt(distSqr), 0.0, 1.0), 0.0);
+
+ // Fake drop shadow
+ const float shadowInvRadius = 1.0/2500.0;
+ float dropshadow = max(clamp(1.0 - shadowInvRadius * sqrt(distSqr), 0.0, 1.0), 0.0);
+
+ float4 outFragColor = float4(color.rgba * (1.0 - dropshadow));
+ outFragColor.rgb *= atten;
+ return outFragColor;
+}
\ No newline at end of file
diff --git a/data/hlsl/skeletalanimation/texture.vert b/data/hlsl/skeletalanimation/texture.vert
new file mode 100644
index 00000000..1b22deb6
--- /dev/null
+++ b/data/hlsl/skeletalanimation/texture.vert
@@ -0,0 +1,42 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+ float4 lightPos;
+ float4 viewPos;
+ float2 uvOffset;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV + ubo.uvOffset;
+ float4 pos = float4(input.Pos, 1.0);
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, pos)));
+
+ output.Normal = input.Normal;
+ output.LightVec = ubo.lightPos.xyz - pos.xyz;
+ output.ViewVec = ubo.viewPos.xyz - pos.xyz;
+ return output;
+}
diff --git a/data/hlsl/specializationconstants/uber.frag b/data/hlsl/specializationconstants/uber.frag
new file mode 100644
index 00000000..57ac65e6
--- /dev/null
+++ b/data/hlsl/specializationconstants/uber.frag
@@ -0,0 +1,73 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColormap : register(t1);
+SamplerState samplerColormap : register(s1);
+Texture2D textureDiscard : register(t2);
+SamplerState samplerDiscard : register(s2);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+// We use this constant to control the flow of the shader depending on the
+// lighting model selected at pipeline creation time
+[[vk::constant_id(0)]] const int LIGHTING_MODEL = 0;
+// Parameter for the toon shading part of the shader
+[[vk::constant_id(1)]] const /*float*/int PARAM_TOON_DESATURATION = 0.0f;
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ switch (LIGHTING_MODEL) {
+ case 0: // Phong
+ {
+ float3 ambient = input.Color * float3(0.25, 0.25, 0.25);
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * input.Color;
+ float3 specular = pow(max(dot(R, V), 0.0), 32.0) * float3(0.75, 0.75, 0.75);
+ return float4(ambient + diffuse * 1.75 + specular, 1.0);
+ }
+ case 1: // Toon
+ {
+
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float intensity = dot(N,L);
+ float3 color;
+ if (intensity > 0.98)
+ color = input.Color * 1.5;
+ else if (intensity > 0.9)
+ color = input.Color * 1.0;
+ else if (intensity > 0.5)
+ color = input.Color * 0.6;
+ else if (intensity > 0.25)
+ color = input.Color * 0.4;
+ else
+ color = input.Color * 0.2;
+ // Desaturate a bit
+ color = float3(lerp(color, dot(float3(0.2126,0.7152,0.0722), color).xxx, asfloat(PARAM_TOON_DESATURATION)));
+ return float4(color, 1);
+ }
+ case 2: // Textured
+ {
+ float4 color = textureColormap.Sample(samplerColormap, input.UV).rrra;
+ float3 ambient = color.rgb * float3(0.25, 0.25, 0.25) * input.Color;
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * color.rgb;
+ float specular = pow(max(dot(R, V), 0.0), 32.0) * color.a;
+ return float4(ambient + diffuse + specular.xxx, 1.0);
+ }
+ }
+
+ return float4(0, 0, 0, 0);
+}
\ No newline at end of file
diff --git a/data/hlsl/specializationconstants/uber.vert b/data/hlsl/specializationconstants/uber.vert
new file mode 100644
index 00000000..2ea7b03b
--- /dev/null
+++ b/data/hlsl/specializationconstants/uber.vert
@@ -0,0 +1,44 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.Color = input.Color;
+ output.UV = input.UV;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+
+ float4 pos = mul(ubo.model, float4(input.Pos, 1.0));
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ float3 lPos = mul((float3x3)ubo.model, ubo.lightPos.xyz);
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/sphericalenvmapping/sem.frag b/data/hlsl/sphericalenvmapping/sem.frag
new file mode 100644
index 00000000..7bee1db6
--- /dev/null
+++ b/data/hlsl/sphericalenvmapping/sem.frag
@@ -0,0 +1,21 @@
+// Copyright 2020 Google LLC
+
+Texture2DArray matCapTexture : register(t1);
+SamplerState matCapSampler : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Color : COLOR0;
+[[vk::location(1)]] float3 EyePos : POSITION0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] int TexIndex : TEXCOORD1;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 r = reflect( input.EyePos, input.Normal );
+ float3 r2 = float3( r.x, r.y, r.z + 1.0 );
+ float m = 2.0 * length( r2 );
+ float2 vN = r.xy / m + .5;
+ return float4( matCapTexture.Sample( matCapSampler, float3(vN, input.TexIndex)).rgb * (clamp(input.Color.r * 2, 0.0, 1.0)), 1.0 );
+}
diff --git a/data/hlsl/sphericalenvmapping/sem.vert b/data/hlsl/sphericalenvmapping/sem.vert
new file mode 100644
index 00000000..c2f4c10e
--- /dev/null
+++ b/data/hlsl/sphericalenvmapping/sem.vert
@@ -0,0 +1,42 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 normal;
+ float4x4 view;
+ int texIndex;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+[[vk::location(1)]] float3 EyePos : POSITION0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] int TexIndex : TEXCOORD1;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ float4x4 modelView = mul(ubo.view, ubo.model);
+ output.EyePos = normalize( mul(modelView, input.Pos ).xyz );
+ output.TexIndex = ubo.texIndex;
+ output.Normal = normalize( mul((float3x3)ubo.normal, input.Normal) );
+ float3 r = reflect( output.EyePos, output.Normal );
+ float m = 2.0 * sqrt( pow(r.x, 2.0) + pow(r.y, 2.0) + pow(r.z + 1.0, 2.0));
+ output.Pos = mul(ubo.projection, mul(modelView, input.Pos));
+ return output;
+}
diff --git a/data/hlsl/ssao/blur.frag b/data/hlsl/ssao/blur.frag
new file mode 100644
index 00000000..e370ddd6
--- /dev/null
+++ b/data/hlsl/ssao/blur.frag
@@ -0,0 +1,24 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureSSAO : register(t0);
+SamplerState samplerSSAO : register(s0);
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ const int blurRange = 2;
+ int n = 0;
+ int2 texDim;
+ textureSSAO.GetDimensions(texDim.x, texDim.y);
+ float2 texelSize = 1.0 / (float2)texDim;
+ float result = 0.0;
+ for (int x = -blurRange; x < blurRange; x++)
+ {
+ for (int y = -blurRange; y < blurRange; y++)
+ {
+ float2 offset = float2(float(x), float(y)) * texelSize;
+ result += textureSSAO.Sample(samplerSSAO, inUV + offset).r;
+ n++;
+ }
+ }
+ return result / (float(n));
+}
\ No newline at end of file
diff --git a/data/hlsl/ssao/composition.frag b/data/hlsl/ssao/composition.frag
new file mode 100644
index 00000000..b89db525
--- /dev/null
+++ b/data/hlsl/ssao/composition.frag
@@ -0,0 +1,56 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureposition : register(t0);
+SamplerState samplerposition : register(s0);
+Texture2D textureNormal : register(t1);
+SamplerState samplerNormal : register(s1);
+Texture2D textureAlbedo : register(t2);
+SamplerState samplerAlbedo : register(s2);
+Texture2D textureSSAO : register(t3);
+SamplerState samplerSSAO : register(s3);
+Texture2D textureSSAOBlur : register(t4);
+SamplerState samplerSSAOBlur : register(s4);
+struct UBO
+{
+ float4x4 _dummy;
+ int ssao;
+ int ssaoOnly;
+ int ssaoBlur;
+};
+cbuffer uboParams : register(b5) { UBO uboParams; };
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ float3 fragPos = textureposition.Sample(samplerposition, inUV).rgb;
+ float3 normal = normalize(textureNormal.Sample(samplerNormal, inUV).rgb * 2.0 - 1.0);
+ float4 albedo = textureAlbedo.Sample(samplerAlbedo, inUV);
+
+ float ssao = (uboParams.ssaoBlur == 1) ? textureSSAOBlur.Sample(samplerSSAOBlur, inUV).r : textureSSAO.Sample(samplerSSAO, inUV).r;
+
+ float3 lightPos = float3(0.0, 0.0, 0.0);
+ float3 L = normalize(lightPos - fragPos);
+ float NdotL = max(0.5, dot(normal, L));
+
+ float4 outFragColor;
+ if (uboParams.ssaoOnly == 1)
+ {
+ outFragColor.rgb = ssao.rrr;
+ }
+ else
+ {
+ float3 baseColor = albedo.rgb * NdotL;
+
+ if (uboParams.ssao == 1)
+ {
+ outFragColor.rgb = ssao.rrr;
+
+ if (uboParams.ssaoOnly != 1)
+ outFragColor.rgb *= baseColor;
+ }
+ else
+ {
+ outFragColor.rgb = baseColor;
+ }
+ }
+ return outFragColor;
+}
\ No newline at end of file
diff --git a/data/hlsl/ssao/fullscreen.vert b/data/hlsl/ssao/fullscreen.vert
new file mode 100644
index 00000000..b13c2bf2
--- /dev/null
+++ b/data/hlsl/ssao/fullscreen.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
diff --git a/data/hlsl/ssao/gbuffer.frag b/data/hlsl/ssao/gbuffer.frag
new file mode 100644
index 00000000..a95ef24f
--- /dev/null
+++ b/data/hlsl/ssao/gbuffer.frag
@@ -0,0 +1,34 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 WorldPos : POSITION0;
+};
+
+struct FSOutput
+{
+ float4 Position : SV_TARGET0;
+ float4 Normal : SV_TARGET1;
+ float4 Albedo : SV_TARGET2;
+};
+static const float NEAR_PLANE = 0.1f; //todo: specialization const
+static const float FAR_PLANE = 64.0f; //todo: specialization const
+
+float linearDepth(float depth)
+{
+ float z = depth * 2.0f - 1.0f;
+ return (2.0f * NEAR_PLANE * FAR_PLANE) / (FAR_PLANE + NEAR_PLANE - z * (FAR_PLANE - NEAR_PLANE));
+}
+
+FSOutput main(VSOutput input)
+{
+ FSOutput output = (FSOutput)0;
+ output.Position = float4(input.WorldPos, linearDepth(input.Pos.z));
+ output.Normal = float4(normalize(input.Normal) * 0.5 + 0.5, 1.0);
+ output.Albedo = float4(input.Color * 2.0, 1.0);
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/ssao/gbuffer.vert b/data/hlsl/ssao/gbuffer.vert
new file mode 100644
index 00000000..85f7e07d
--- /dev/null
+++ b/data/hlsl/ssao/gbuffer.vert
@@ -0,0 +1,45 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 WorldPos : POSITION0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, input.Pos)));
+
+ output.UV = input.UV;
+
+ // Vertex position in view space
+ output.WorldPos = mul(ubo.view, mul(ubo.model, input.Pos)).xyz;
+
+ // Normal in view space
+ float3x3 normalMatrix = (float3x3)mul(ubo.view, ubo.model);
+ output.Normal = mul(normalMatrix, input.Normal);
+
+ output.Color = input.Color;
+ return output;
+}
diff --git a/data/hlsl/ssao/ssao.frag b/data/hlsl/ssao/ssao.frag
new file mode 100644
index 00000000..966b2a87
--- /dev/null
+++ b/data/hlsl/ssao/ssao.frag
@@ -0,0 +1,73 @@
+// Copyright 2020 Google LLC
+
+Texture2D texturePositionDepth : register(t0);
+SamplerState samplerPositionDepth : register(s0);
+Texture2D textureNormal : register(t1);
+SamplerState samplerNormal : register(s1);
+Texture2D ssaoNoiseTexture : register(t2);
+SamplerState ssaoNoiseSampler : register(s2);
+
+#define SSAO_KERNEL_ARRAY_SIZE 64
+[[vk::constant_id(0)]] const int SSAO_KERNEL_SIZE = 64;
+[[vk::constant_id(1)]] const float SSAO_RADIUS = 0.5;
+
+struct UBOSSAOKernel
+{
+ float4 samples[SSAO_KERNEL_ARRAY_SIZE];
+};
+cbuffer uboSSAOKernel : register(b3) { UBOSSAOKernel uboSSAOKernel; };
+
+struct UBO
+{
+ float4x4 projection;
+};
+cbuffer ubo : register(b4) { UBO ubo; };
+
+float main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ // Get G-Buffer values
+ float3 fragPos = texturePositionDepth.Sample(samplerPositionDepth, inUV).rgb;
+ float3 normal = normalize(textureNormal.Sample(samplerNormal, inUV).rgb * 2.0 - 1.0);
+
+ // Get a random vector using a noise lookup
+ int2 texDim;
+ texturePositionDepth.GetDimensions(texDim.x, texDim.y);
+ int2 noiseDim;
+ ssaoNoiseTexture.GetDimensions(noiseDim.x, noiseDim.y);
+ const float2 noiseUV = float2(float(texDim.x)/float(noiseDim.x), float(texDim.y)/(noiseDim.y)) * inUV;
+ float3 randomVec = ssaoNoiseTexture.Sample(ssaoNoiseSampler, noiseUV).xyz * 2.0 - 1.0;
+
+ // Create TBN matrix
+ float3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
+ float3 bitangent = cross(tangent, normal);
+ float3x3 TBN = transpose(float3x3(tangent, bitangent, normal));
+
+ // Calculate occlusion value
+ float occlusion = 0.0f;
+ for(int i = 0; i < SSAO_KERNEL_SIZE; i++)
+ {
+ float3 samplePos = mul(TBN, uboSSAOKernel.samples[i].xyz);
+ samplePos = fragPos + samplePos * SSAO_RADIUS;
+
+ // project
+ float4 offset = float4(samplePos, 1.0f);
+ offset = mul(ubo.projection, offset);
+ offset.xyz /= offset.w;
+ offset.xyz = offset.xyz * 0.5f + 0.5f;
+
+ float sampleDepth = -texturePositionDepth.Sample(samplerPositionDepth, offset.xy).w;
+
+#define RANGE_CHECK 1
+#ifdef RANGE_CHECK
+ // Range check
+ float rangeCheck = smoothstep(0.0f, 1.0f, SSAO_RADIUS / abs(fragPos.z - sampleDepth));
+ occlusion += (sampleDepth >= samplePos.z ? 1.0f : 0.0f) * rangeCheck;
+#else
+ occlusion += (sampleDepth >= samplePos.z ? 1.0f : 0.0f);
+#endif
+ }
+ occlusion = 1.0 - (occlusion / float(SSAO_KERNEL_SIZE));
+
+ return occlusion;
+}
+
diff --git a/data/hlsl/stencilbuffer/outline.frag b/data/hlsl/stencilbuffer/outline.frag
new file mode 100644
index 00000000..9892e709
--- /dev/null
+++ b/data/hlsl/stencilbuffer/outline.frag
@@ -0,0 +1,6 @@
+// Copyright 2020 Google LLC
+
+float4 main() : SV_TARGET
+{
+ return float4(1.0, 1.0, 1.0, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/stencilbuffer/outline.vert b/data/hlsl/stencilbuffer/outline.vert
new file mode 100644
index 00000000..7f1f17a7
--- /dev/null
+++ b/data/hlsl/stencilbuffer/outline.vert
@@ -0,0 +1,24 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 lightPos;
+ float outlineWidth;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+float4 main(VSInput input) : SV_POSITION
+{
+ // Extrude along normal
+ float4 pos = float4(input.Pos.xyz + input.Normal * ubo.outlineWidth, input.Pos.w);
+ return mul(ubo.projection, mul(ubo.model, pos));
+}
diff --git a/data/hlsl/stencilbuffer/toon.frag b/data/hlsl/stencilbuffer/toon.frag
new file mode 100644
index 00000000..990105ff
--- /dev/null
+++ b/data/hlsl/stencilbuffer/toon.frag
@@ -0,0 +1,32 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t1);
+SamplerState samplerColorMap : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 color;
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float intensity = dot(N,L);
+ if (intensity > 0.98)
+ color = input.Color * 1.5;
+ else if (intensity > 0.9)
+ color = input.Color * 1.0;
+ else if (intensity > 0.5)
+ color = input.Color * 0.6;
+ else if (intensity > 0.25)
+ color = input.Color * 0.4;
+ else
+ color = input.Color * 0.2;
+ // Desaturate a bit
+ color = lerp(color, dot(float3(0.2126,0.7152,0.0722), color).xxx, 0.1);
+ return float4(color, 1);
+}
\ No newline at end of file
diff --git a/data/hlsl/stencilbuffer/toon.vert b/data/hlsl/stencilbuffer/toon.vert
new file mode 100644
index 00000000..7ab4fdfe
--- /dev/null
+++ b/data/hlsl/stencilbuffer/toon.vert
@@ -0,0 +1,37 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = float3(1.0, 0.0, 0.0);
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ float4 pos = mul(ubo.model, float4(input.Pos, 1.0));
+ float3 lPos = mul((float3x3)ubo.model, ubo.lightPos.xyz);
+ output.LightVec = lPos - pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/subpasses/composition.frag b/data/hlsl/subpasses/composition.frag
new file mode 100644
index 00000000..29fd3113
--- /dev/null
+++ b/data/hlsl/subpasses/composition.frag
@@ -0,0 +1,69 @@
+// Copyright 2020 Google LLC
+
+[[vk::input_attachment_index(0)]][[vk::binding(0)]] SubpassInput samplerposition;
+[[vk::input_attachment_index(1)]][[vk::binding(1)]] SubpassInput samplerNormal;
+[[vk::input_attachment_index(2)]][[vk::binding(2)]] SubpassInput samplerAlbedo;
+
+#define MAX_NUM_LIGHTS 64
+[[vk::constant_id(0)]] const int NUM_LIGHTS = 64;
+
+struct Light {
+ float4 position;
+ float3 color;
+ float radius;
+};
+
+struct UBO
+{
+ float4 viewPos;
+ Light lights[MAX_NUM_LIGHTS];
+};
+
+cbuffer ubo : register(b3) { UBO ubo; }
+
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD) : SV_TARGET
+{
+ // Read G-Buffer values from previous sub pass
+ float3 fragPos = samplerposition.SubpassLoad().rgb;
+ float3 normal = samplerNormal.SubpassLoad().rgb;
+ float4 albedo = samplerAlbedo.SubpassLoad();
+
+ #define ambient 0.15
+
+ // Ambient part
+ float3 fragcolor = albedo.rgb * ambient;
+
+ for(int i = 0; i < NUM_LIGHTS; ++i)
+ {
+ // Vector to light
+ float3 L = ubo.lights[i].position.xyz - fragPos;
+ // Distance from light to fragment position
+ float dist = length(L);
+
+ // Viewer to fragment
+ float3 V = ubo.viewPos.xyz - fragPos;
+ V = normalize(V);
+
+ // Light to fragment
+ L = normalize(L);
+
+ // Attenuation
+ float atten = ubo.lights[i].radius / (pow(dist, 2.0) + 1.0);
+
+ // Diffuse part
+ float3 N = normalize(normal);
+ float NdotL = max(0.0, dot(N, L));
+ float3 diff = ubo.lights[i].color * albedo.rgb * NdotL * atten;
+
+ // Specular part
+ // Specular map values are stored in alpha of albedo mrt
+ float3 R = reflect(-L, N);
+ float NdotR = max(0.0, dot(R, V));
+ //float3 spec = ubo.lights[i].color * albedo.a * pow(NdotR, 32.0) * atten;
+
+ fragcolor += diff;// + spec;
+ }
+
+ return float4(fragcolor, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/subpasses/composition.vert b/data/hlsl/subpasses/composition.vert
new file mode 100644
index 00000000..188b7298
--- /dev/null
+++ b/data/hlsl/subpasses/composition.vert
@@ -0,0 +1,15 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(uint VertexIndex : SV_VertexID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
+ output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f);
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/subpasses/gbuffer.frag b/data/hlsl/subpasses/gbuffer.frag
new file mode 100644
index 00000000..2e278903
--- /dev/null
+++ b/data/hlsl/subpasses/gbuffer.frag
@@ -0,0 +1,45 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 WorldPos : POSITION0;
+};
+
+struct FSOutput
+{
+[[vk::location(0)]] float4 Color : SV_TARGET0;
+[[vk::location(1)]] float4 Position : SV_TARGET1;
+[[vk::location(2)]] float4 Normal : SV_TARGET2;
+[[vk::location(3)]] float4 Albedo : SV_TARGET3;
+};
+
+[[vk::constant_id(0)]] const float NEAR_PLANE = 0.1f;
+[[vk::constant_id(1)]] const float FAR_PLANE = 256.0f;
+
+float linearDepth(float depth)
+{
+ float z = depth * 2.0f - 1.0f;
+ return (2.0f * NEAR_PLANE * FAR_PLANE) / (FAR_PLANE + NEAR_PLANE - z * (FAR_PLANE - NEAR_PLANE));
+}
+
+FSOutput main(VSOutput input)
+{
+ FSOutput output = (FSOutput)0;
+ output.Position = float4(input.WorldPos, 1.0);
+
+ float3 N = normalize(input.Normal);
+ N.y = -N.y;
+ output.Normal = float4(N, 1.0);
+
+ output.Albedo.rgb = input.Color;
+
+ // Store linearized depth in alpha component
+ output.Position.a = linearDepth(input.Pos.z);
+
+ // Write color attachments to avoid undefined behaviour (validation error)
+ output.Color = float4(0.0, 0.0, 0.0, 0.0);
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/subpasses/gbuffer.vert b/data/hlsl/subpasses/gbuffer.vert
new file mode 100644
index 00000000..d4f7d73e
--- /dev/null
+++ b/data/hlsl/subpasses/gbuffer.vert
@@ -0,0 +1,44 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 WorldPos : POSITION0;
+[[vk::location(3)]] float3 Tangent : TEXCOORD1;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, input.Pos)));
+
+ // Vertex position in world space
+ output.WorldPos = mul(ubo.model, input.Pos).xyz;
+ // GL to Vulkan coord space
+ output.WorldPos.y = -output.WorldPos.y;
+
+ // Normal in world space
+ output.Normal = mul((float3x3)ubo.model, normalize(input.Normal));
+
+ // Currently just vertex color
+ output.Color = input.Color;
+ return output;
+}
diff --git a/data/hlsl/subpasses/transparent.frag b/data/hlsl/subpasses/transparent.frag
new file mode 100644
index 00000000..28b46bc1
--- /dev/null
+++ b/data/hlsl/subpasses/transparent.frag
@@ -0,0 +1,33 @@
+// Copyright 2020 Google LLC
+
+[[vk::input_attachment_index(0)]][[vk::binding(1)]] SubpassInput samplerPositionDepth;
+Texture2D textureTexture : register(t2);
+SamplerState samplerTexture : register(s2);
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+[[vk::constant_id(0)]] const float NEAR_PLANE = 0.1f;
+[[vk::constant_id(1)]] const float FAR_PLANE = 256.0f;
+
+float linearDepth(float depth)
+{
+ float z = depth * 2.0f - 1.0f;
+ return (2.0f * NEAR_PLANE * FAR_PLANE) / (FAR_PLANE + NEAR_PLANE - z * (FAR_PLANE - NEAR_PLANE));
+}
+
+float4 main (VSOutput input) : SV_TARGET
+{
+ // Sample depth from deferred depth buffer and discard if obscured
+ float depth = samplerPositionDepth.SubpassLoad().a;
+ if ((depth != 0.0) && (linearDepth(input.Pos.z) > depth))
+ {
+ clip(-1);
+ };
+
+ return textureTexture.Sample(samplerTexture, input.UV);
+}
diff --git a/data/hlsl/subpasses/transparent.vert b/data/hlsl/subpasses/transparent.vert
new file mode 100644
index 00000000..4d327410
--- /dev/null
+++ b/data/hlsl/subpasses/transparent.vert
@@ -0,0 +1,35 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 view;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main (VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.UV = input.UV;
+
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, float4(input.Pos.xyz, 1.0))));
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/terraintessellation/skysphere.frag b/data/hlsl/terraintessellation/skysphere.frag
new file mode 100644
index 00000000..a40c1b13
--- /dev/null
+++ b/data/hlsl/terraintessellation/skysphere.frag
@@ -0,0 +1,10 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t1);
+SamplerState samplerColorMap : register(s1);
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOODR0) : SV_TARGET
+{
+ float4 color = textureColorMap.Sample(samplerColorMap, inUV);
+ return float4(color.rgb, 1.0);
+}
diff --git a/data/hlsl/terraintessellation/skysphere.vert b/data/hlsl/terraintessellation/skysphere.vert
new file mode 100644
index 00000000..d6f65906
--- /dev/null
+++ b/data/hlsl/terraintessellation/skysphere.vert
@@ -0,0 +1,29 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 mvp;
+};
+cbuffer ubo : register(b0) { UBO ubo; };
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = mul(ubo.mvp, float4(input.Pos, 1.0));
+ output.UV = input.UV;
+ output.UV.y = 1.0 - output.UV.y;
+ return output;
+}
diff --git a/data/hlsl/terraintessellation/terrain.frag b/data/hlsl/terraintessellation/terrain.frag
new file mode 100644
index 00000000..ee1a2991
--- /dev/null
+++ b/data/hlsl/terraintessellation/terrain.frag
@@ -0,0 +1,65 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureHeight : register(t1);
+SamplerState samplerHeight : register(s1);
+Texture2DArray textureLayers : register(t2);
+SamplerState samplerLayers : register(s2);
+
+struct DSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+[[vk::location(4)]] float3 EyePos : POSITION1;
+[[vk::location(5)]] float3 WorldPos : POSITION0;
+};
+
+float3 sampleTerrainLayer(float2 inUV)
+{
+ // Define some layer ranges for sampling depending on terrain height
+ float2 layers[6];
+ layers[0] = float2(-10.0, 10.0);
+ layers[1] = float2(5.0, 45.0);
+ layers[2] = float2(45.0, 80.0);
+ layers[3] = float2(75.0, 100.0);
+ layers[4] = float2(95.0, 140.0);
+ layers[5] = float2(140.0, 190.0);
+
+ float3 color = float3(0.0, 0.0, 0.0);
+
+ // Get height from displacement map
+ float height = textureHeight.SampleLevel(samplerHeight, inUV, 0.0).r * 255.0;
+
+ for (int i = 0; i < 6; i++)
+ {
+ float range = layers[i].y - layers[i].x;
+ float weight = (range - abs(height - layers[i].y)) / range;
+ weight = max(0.0, weight);
+ color += weight * textureLayers.Sample(samplerLayers, float3(inUV * 16.0, i)).rgb;
+ }
+
+ return color;
+}
+
+float fog(float density, float4 FragCoord)
+{
+ const float LOG2 = -1.442695;
+ float dist = FragCoord.z / FragCoord.w * 0.1;
+ float d = density * dist;
+ return 1.0 - clamp(exp2(d * d * LOG2), 0.0, 1.0);
+}
+
+float4 main(DSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 ambient = float3(0.5, 0.5, 0.5);
+ float3 diffuse = max(dot(N, L), 0.0) * float3(1.0, 1.0, 1.0);
+
+ float4 color = float4((ambient + diffuse) * sampleTerrainLayer(input.UV), 1.0);
+
+ const float4 fogColor = float4(0.47, 0.5, 0.67, 0.0);
+ return lerp(color, fogColor, fog(0.25, input.Pos));
+}
diff --git a/data/hlsl/terraintessellation/terrain.tesc b/data/hlsl/terraintessellation/terrain.tesc
new file mode 100644
index 00000000..595546f5
--- /dev/null
+++ b/data/hlsl/terraintessellation/terrain.tesc
@@ -0,0 +1,141 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+ float4 lightPos;
+ float4 frustumPlanes[6];
+ float displacementFactor;
+ float tessellationFactor;
+ float2 viewportDim;
+ float tessellatedEdgeSize;
+};
+cbuffer ubo : register(b0) { UBO ubo; };
+
+Texture2D textureHeight : register(t1);
+SamplerState samplerHeight : register(s1);
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct HSOutput
+{
+[[vk::location(2)]] float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct ConstantsHSOutput
+{
+ float TessLevelOuter[4] : SV_TessFactor;
+ float TessLevelInner[2] : SV_InsideTessFactor;
+};
+
+// Calculate the tessellation factor based on screen space
+// dimensions of the edge
+float screenSpaceTessFactor(float4 p0, float4 p1)
+{
+ // Calculate edge mid point
+ float4 midPoint = 0.5 * (p0 + p1);
+ // Sphere radius as distance between the control points
+ float radius = distance(p0, p1) / 2.0;
+
+ // View space
+ float4 v0 = mul(ubo.modelview, midPoint);
+
+ // Project into clip space
+ float4 clip0 = mul(ubo.projection, (v0 - float4(radius, float3(0.0, 0.0, 0.0))));
+ float4 clip1 = mul(ubo.projection, (v0 + float4(radius, float3(0.0, 0.0, 0.0))));
+
+ // Get normalized device coordinates
+ clip0 /= clip0.w;
+ clip1 /= clip1.w;
+
+ // Convert to viewport coordinates
+ clip0.xy *= ubo.viewportDim;
+ clip1.xy *= ubo.viewportDim;
+
+ // Return the tessellation factor based on the screen size
+ // given by the distance of the two edge control points in screen space
+ // and a reference (min.) tessellation size for the edge set by the application
+ return clamp(distance(clip0, clip1) / ubo.tessellatedEdgeSize * ubo.tessellationFactor, 1.0, 64.0);
+}
+
+// Checks the current's patch visibility against the frustum using a sphere check
+// Sphere radius is given by the patch size
+bool frustumCheck(float4 Pos, float2 inUV)
+{
+ // Fixed radius (increase if patch size is increased in example)
+ const float radius = 8.0f;
+ float4 pos = Pos;
+ pos.y -= textureHeight.SampleLevel(samplerHeight, inUV, 0.0).r * ubo.displacementFactor;
+
+ // Check sphere against frustum planes
+ for (int i = 0; i < 6; i++) {
+ if (dot(pos, ubo.frustumPlanes[i]) + radius < 0.0)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+ConstantsHSOutput ConstantsHS(InputPatch patch)
+{
+ ConstantsHSOutput output = (ConstantsHSOutput)0;
+
+ if (!frustumCheck(patch[0].Pos, patch[0].UV))
+ {
+ output.TessLevelInner[0] = 0.0;
+ output.TessLevelInner[1] = 0.0;
+ output.TessLevelOuter[0] = 0.0;
+ output.TessLevelOuter[1] = 0.0;
+ output.TessLevelOuter[2] = 0.0;
+ output.TessLevelOuter[3] = 0.0;
+ }
+ else
+ {
+ if (ubo.tessellationFactor > 0.0)
+ {
+ output.TessLevelOuter[0] = screenSpaceTessFactor(patch[3].Pos, patch[0].Pos);
+ output.TessLevelOuter[1] = screenSpaceTessFactor(patch[0].Pos, patch[1].Pos);
+ output.TessLevelOuter[2] = screenSpaceTessFactor(patch[1].Pos, patch[2].Pos);
+ output.TessLevelOuter[3] = screenSpaceTessFactor(patch[2].Pos, patch[3].Pos);
+ output.TessLevelInner[0] = lerp(output.TessLevelOuter[0], output.TessLevelOuter[3], 0.5);
+ output.TessLevelInner[1] = lerp(output.TessLevelOuter[2], output.TessLevelOuter[1], 0.5);
+ }
+ else
+ {
+ // Tessellation factor can be set to zero by example
+ // to demonstrate a simple passthrough
+ output.TessLevelInner[0] = 1.0;
+ output.TessLevelInner[1] = 1.0;
+ output.TessLevelOuter[0] = 1.0;
+ output.TessLevelOuter[1] = 1.0;
+ output.TessLevelOuter[2] = 1.0;
+ output.TessLevelOuter[3] = 1.0;
+ }
+ }
+
+ return output;
+}
+
+[domain("quad")]
+[partitioning("integer")]
+[outputtopology("triangle_cw")]
+[outputcontrolpoints(4)]
+[patchconstantfunc("ConstantsHS")]
+[maxtessfactor(20.0f)]
+HSOutput main(InputPatch patch, uint InvocationID : SV_OutputControlPointID)
+{
+ HSOutput output = (HSOutput)0;
+ output.Pos = patch[InvocationID].Pos;
+ output.Normal = patch[InvocationID].Normal;
+ output.UV = patch[InvocationID].UV;
+ return output;
+}
diff --git a/data/hlsl/terraintessellation/terrain.tese b/data/hlsl/terraintessellation/terrain.tese
new file mode 100644
index 00000000..c9646108
--- /dev/null
+++ b/data/hlsl/terraintessellation/terrain.tese
@@ -0,0 +1,71 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 modelview;
+ float4 lightPos;
+ float4 frustumPlanes[6];
+ float displacementFactor;
+ float tessellationFactor;
+ float2 viewportDim;
+ float tessellatedEdgeSize;
+};
+cbuffer ubo : register(b0) { UBO ubo; };
+
+Texture2D displacementMapTexture : register(t1);
+SamplerState displacementMapSampler : register(s1);
+
+struct HSOutput
+{
+[[vk::location(2)]] float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct ConstantsHSOutput
+{
+ float TessLevelOuter[4] : SV_TessFactor;
+ float TessLevelInner[2] : SV_InsideTessFactor;
+};
+
+struct DSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+[[vk::location(4)]] float3 EyePos : POSITION1;
+[[vk::location(5)]] float3 WorldPos : POSITION0;
+};
+
+[domain("quad")]
+DSOutput main(ConstantsHSOutput input, float2 TessCoord : SV_DomainLocation, const OutputPatch patch)
+{
+ // Interpolate UV coordinates
+ DSOutput output = (DSOutput)0;
+ float2 uv1 = lerp(patch[0].UV, patch[1].UV, TessCoord.x);
+ float2 uv2 = lerp(patch[3].UV, patch[2].UV, TessCoord.x);
+ output.UV = lerp(uv1, uv2, TessCoord.y);
+
+ float3 n1 = lerp(patch[0].Normal, patch[1].Normal, TessCoord.x);
+ float3 n2 = lerp(patch[3].Normal, patch[2].Normal, TessCoord.x);
+ output.Normal = lerp(n1, n2, TessCoord.y);
+
+ // Interpolate positions
+ float4 pos1 = lerp(patch[0].Pos, patch[1].Pos, TessCoord.x);
+ float4 pos2 = lerp(patch[3].Pos, patch[2].Pos, TessCoord.x);
+ float4 pos = lerp(pos1, pos2, TessCoord.y);
+ // Displace
+ pos.y -= displacementMapTexture.SampleLevel(displacementMapSampler, output.UV, 0.0).r * ubo.displacementFactor;
+ // Perspective projection
+ output.Pos = mul(ubo.projection, mul(ubo.modelview, pos));
+
+ // Calculate vectors for lighting based on tessellated position
+ output.ViewVec = -pos.xyz;
+ output.LightVec = normalize(ubo.lightPos.xyz + output.ViewVec);
+ output.WorldPos = pos.xyz;
+ output.EyePos = mul(ubo.modelview, pos).xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/terraintessellation/terrain.vert b/data/hlsl/terraintessellation/terrain.vert
new file mode 100644
index 00000000..06898dfe
--- /dev/null
+++ b/data/hlsl/terraintessellation/terrain.vert
@@ -0,0 +1,24 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = float4(input.Pos.xyz, 1.0);
+ output.UV = input.UV;
+ output.Normal = input.Normal;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/tessellation/base.frag b/data/hlsl/tessellation/base.frag
new file mode 100644
index 00000000..0a34282b
--- /dev/null
+++ b/data/hlsl/tessellation/base.frag
@@ -0,0 +1,20 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColorMap : register(t2);
+SamplerState samplerColorMap : register(s2);
+
+struct DSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+float4 main(DSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(float3(0.0, -4.0, 4.0));
+
+ float4 color = textureColorMap.Sample(samplerColorMap, input.UV);
+
+ return float4(clamp(max(dot(N,L), 0.0), 0.2, 1.0) * color.rgb * 1.5, 1);
+}
diff --git a/data/hlsl/tessellation/base.vert b/data/hlsl/tessellation/base.vert
new file mode 100644
index 00000000..3fcb8aec
--- /dev/null
+++ b/data/hlsl/tessellation/base.vert
@@ -0,0 +1,24 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = float4(input.Pos.xyz, 1.0);
+ output.Normal = input.Normal;
+ output.UV = input.UV;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/tessellation/passthrough.tesc b/data/hlsl/tessellation/passthrough.tesc
new file mode 100644
index 00000000..738b2229
--- /dev/null
+++ b/data/hlsl/tessellation/passthrough.tesc
@@ -0,0 +1,46 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct HSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct ConstantsHSOutput
+{
+ float TessLevelOuter[3] : SV_TessFactor;
+ float TessLevelInner : SV_InsideTessFactor;
+};
+
+ConstantsHSOutput ConstantsHS(InputPatch patch, uint InvocationID : SV_PrimitiveID)
+{
+ ConstantsHSOutput output = (ConstantsHSOutput)0;
+ output.TessLevelInner = 1;
+ output.TessLevelOuter[0] = 1;
+ output.TessLevelOuter[1] = 1;
+ output.TessLevelOuter[2] = 1;
+ return output;
+}
+
+[domain("tri")]
+[partitioning("integer")]
+[outputtopology("triangle_ccw")]
+[outputcontrolpoints(3)]
+[patchconstantfunc("ConstantsHS")]
+[maxtessfactor(20.0f)]
+HSOutput main(InputPatch patch, uint InvocationID : SV_OutputControlPointID)
+{
+ HSOutput output = (HSOutput)0;
+ output.Pos = patch[InvocationID].Pos;
+ output.Normal = patch[InvocationID].Normal;
+ output.UV = patch[InvocationID].UV;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/tessellation/passthrough.tese b/data/hlsl/tessellation/passthrough.tese
new file mode 100644
index 00000000..535a55ad
--- /dev/null
+++ b/data/hlsl/tessellation/passthrough.tese
@@ -0,0 +1,44 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float tessAlpha;
+};
+
+cbuffer ubo : register(b1) { UBO ubo; }
+
+struct HSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct ConstantsHSOutput
+{
+ float TessLevelOuter[3] : SV_TessFactor;
+ float TessLevelInner : SV_InsideTessFactor;
+};
+
+struct DSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+[domain("tri")]
+DSOutput main(ConstantsHSOutput input, float3 TessCoord : SV_DomainLocation, const OutputPatch patch)
+{
+ DSOutput output = (DSOutput)0;
+ output.Pos = (TessCoord.x * patch[0].Pos) +
+ (TessCoord.y * patch[1].Pos) +
+ (TessCoord.z * patch[2].Pos);
+ output.Pos = mul(ubo.projection, mul(ubo.model, output.Pos));
+
+ output.Normal = TessCoord.x*patch[0].Normal + TessCoord.y*patch[1].Normal + TessCoord.z*patch[2].Normal;
+ output.UV = TessCoord.x*patch[0].UV + TessCoord.y*patch[1].UV + TessCoord.z*patch[2].UV;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/tessellation/pntriangles.tesc b/data/hlsl/tessellation/pntriangles.tesc
new file mode 100644
index 00000000..37f52f0e
--- /dev/null
+++ b/data/hlsl/tessellation/pntriangles.tesc
@@ -0,0 +1,128 @@
+// Copyright 2020 Google LLC
+
+// PN patch data
+struct PnPatch
+{
+ float b210;
+ float b120;
+ float b021;
+ float b012;
+ float b102;
+ float b201;
+ float b111;
+ float n110;
+ float n011;
+ float n101;
+};
+
+// tessellation levels
+struct UBO
+{
+ float tessLevel;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct HSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float2 UV : TEXCOORD0;
+[[vk::location(6)]] float pnPatch[10] : TEXCOORD6;
+};
+
+struct ConstantsHSOutput
+{
+ float TessLevelOuter[3] : SV_TessFactor;
+ float TessLevelInner : SV_InsideTessFactor;
+};
+
+void SetPnPatch(out float output[10], PnPatch patch)
+{
+ output[0] = patch.b210;
+ output[1] = patch.b120;
+ output[2] = patch.b021;
+ output[3] = patch.b012;
+ output[4] = patch.b102;
+ output[5] = patch.b201;
+ output[6] = patch.b111;
+ output[7] = patch.n110;
+ output[8] = patch.n011;
+ output[9] = patch.n101;
+}
+
+float wij(float4 iPos, float3 iNormal, float4 jPos)
+{
+ return dot(jPos.xyz - iPos.xyz, iNormal);
+}
+
+float vij(float4 iPos, float3 iNormal, float4 jPos, float3 jNormal)
+{
+ float3 Pj_minus_Pi = jPos.xyz
+ - iPos.xyz;
+ float3 Ni_plus_Nj = iNormal+jNormal;
+ return 2.0*dot(Pj_minus_Pi, Ni_plus_Nj)/dot(Pj_minus_Pi, Pj_minus_Pi);
+}
+
+ConstantsHSOutput ConstantsHS(InputPatch patch, uint InvocationID : SV_PrimitiveID)
+{
+ ConstantsHSOutput output = (ConstantsHSOutput)0;
+ output.TessLevelOuter[0] = ubo.tessLevel;
+ output.TessLevelOuter[1] = ubo.tessLevel;
+ output.TessLevelOuter[2] = ubo.tessLevel;
+ output.TessLevelInner = ubo.tessLevel;
+ return output;
+}
+
+[domain("tri")]
+[partitioning("fractional_odd")]
+[outputtopology("triangle_ccw")]
+[outputcontrolpoints(3)]
+[patchconstantfunc("ConstantsHS")]
+[maxtessfactor(20.0f)]
+HSOutput main(InputPatch patch, uint InvocationID : SV_OutputControlPointID)
+{
+ HSOutput output = (HSOutput)0;
+ // get data
+ output.Pos = patch[InvocationID].Pos;
+ output.Normal = patch[InvocationID].Normal;
+ output.UV = patch[InvocationID].UV;
+
+ // set base
+ float P0 = patch[0].Pos[InvocationID];
+ float P1 = patch[1].Pos[InvocationID];
+ float P2 = patch[2].Pos[InvocationID];
+ float N0 = patch[0].Normal[InvocationID];
+ float N1 = patch[1].Normal[InvocationID];
+ float N2 = patch[2].Normal[InvocationID];
+
+ // compute control points
+ PnPatch pnPatch;
+ pnPatch.b210 = (2.0*P0 + P1 - wij(patch[0].Pos, patch[0].Normal, patch[1].Pos)*N0)/3.0;
+ pnPatch.b120 = (2.0*P1 + P0 - wij(patch[1].Pos, patch[1].Normal, patch[0].Pos)*N1)/3.0;
+ pnPatch.b021 = (2.0*P1 + P2 - wij(patch[1].Pos, patch[1].Normal, patch[2].Pos)*N1)/3.0;
+ pnPatch.b012 = (2.0*P2 + P1 - wij(patch[2].Pos, patch[2].Normal, patch[1].Pos)*N2)/3.0;
+ pnPatch.b102 = (2.0*P2 + P0 - wij(patch[2].Pos, patch[2].Normal, patch[0].Pos)*N2)/3.0;
+ pnPatch.b201 = (2.0*P0 + P2 - wij(patch[0].Pos, patch[0].Normal, patch[2].Pos)*N0)/3.0;
+ float E = ( pnPatch.b210
+ + pnPatch.b120
+ + pnPatch.b021
+ + pnPatch.b012
+ + pnPatch.b102
+ + pnPatch.b201 ) / 6.0;
+ float V = (P0 + P1 + P2)/3.0;
+ pnPatch.b111 = E + (E - V)*0.5;
+ pnPatch.n110 = N0+N1-vij(patch[0].Pos, patch[0].Normal, patch[1].Pos, patch[1].Normal)*(P1-P0);
+ pnPatch.n011 = N1+N2-vij(patch[1].Pos, patch[1].Normal, patch[2].Pos, patch[2].Normal)*(P2-P1);
+ pnPatch.n101 = N2+N0-vij(patch[2].Pos, patch[2].Normal, patch[0].Pos, patch[0].Normal)*(P0-P2);
+ SetPnPatch(output.pnPatch, pnPatch);
+
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/tessellation/pntriangles.tese b/data/hlsl/tessellation/pntriangles.tese
new file mode 100644
index 00000000..2969504d
--- /dev/null
+++ b/data/hlsl/tessellation/pntriangles.tese
@@ -0,0 +1,126 @@
+// Copyright 2020 Google LLC
+
+// PN patch data
+struct PnPatch
+{
+ float b210;
+ float b120;
+ float b021;
+ float b012;
+ float b102;
+ float b201;
+ float b111;
+ float n110;
+ float n011;
+ float n101;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float tessAlpha;
+};
+
+cbuffer ubo : register(b1) { UBO ubo; }
+
+struct HSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float2 UV : TEXCOORD0;
+[[vk::location(6)]] float pnPatch[10] : TEXCOORD6;
+};
+
+struct ConstantsHSOutput
+{
+ float TessLevelOuter[3] : SV_TessFactor;
+ float TessLevelInner : SV_InsideTessFactor;
+};
+
+struct DSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+#define uvw TessCoord
+
+PnPatch GetPnPatch(float pnPatch[10])
+{
+ PnPatch output;
+ output.b210 = pnPatch[0];
+ output.b120 = pnPatch[1];
+ output.b021 = pnPatch[2];
+ output.b012 = pnPatch[3];
+ output.b102 = pnPatch[4];
+ output.b201 = pnPatch[5];
+ output.b111 = pnPatch[6];
+ output.n110 = pnPatch[7];
+ output.n011 = pnPatch[8];
+ output.n101 = pnPatch[9];
+ return output;
+}
+
+[domain("tri")]
+DSOutput main(ConstantsHSOutput input, float3 TessCoord : SV_DomainLocation, const OutputPatch patch)
+{
+ PnPatch pnPatch[3];
+ pnPatch[0] = GetPnPatch(patch[0].pnPatch);
+ pnPatch[1] = GetPnPatch(patch[1].pnPatch);
+ pnPatch[2] = GetPnPatch(patch[2].pnPatch);
+
+ DSOutput output = (DSOutput)0;
+ float3 uvwSquared = uvw * uvw;
+ float3 uvwCubed = uvwSquared * uvw;
+
+ // extract control points
+ float3 b210 = float3(pnPatch[0].b210, pnPatch[1].b210, pnPatch[2].b210);
+ float3 b120 = float3(pnPatch[0].b120, pnPatch[1].b120, pnPatch[2].b120);
+ float3 b021 = float3(pnPatch[0].b021, pnPatch[1].b021, pnPatch[2].b021);
+ float3 b012 = float3(pnPatch[0].b012, pnPatch[1].b012, pnPatch[2].b012);
+ float3 b102 = float3(pnPatch[0].b102, pnPatch[1].b102, pnPatch[2].b102);
+ float3 b201 = float3(pnPatch[0].b201, pnPatch[1].b201, pnPatch[2].b201);
+ float3 b111 = float3(pnPatch[0].b111, pnPatch[1].b111, pnPatch[2].b111);
+
+ // extract control normals
+ float3 n110 = normalize(float3(pnPatch[0].n110, pnPatch[1].n110, pnPatch[2].n110));
+ float3 n011 = normalize(float3(pnPatch[0].n011, pnPatch[1].n011, pnPatch[2].n011));
+ float3 n101 = normalize(float3(pnPatch[0].n101, pnPatch[1].n101, pnPatch[2].n101));
+
+ // compute texcoords
+ output.UV = TessCoord[2]*patch[0].UV + TessCoord[0]*patch[1].UV + TessCoord[1]*patch[2].UV;
+
+ // normal
+ // Barycentric normal
+ float3 barNormal = TessCoord[2]*patch[0].Normal + TessCoord[0]*patch[1].Normal + TessCoord[1]*patch[2].Normal;
+ float3 pnNormal = patch[0].Normal*uvwSquared[2] + patch[1].Normal*uvwSquared[0] + patch[2].Normal*uvwSquared[1]
+ + n110*uvw[2]*uvw[0] + n011*uvw[0]*uvw[1]+ n101*uvw[2]*uvw[1];
+ output.Normal = ubo.tessAlpha*pnNormal + (1.0-ubo.tessAlpha) * barNormal;
+
+ // compute interpolated pos
+ float3 barPos = TessCoord[2]*patch[0].Pos.xyz
+ + TessCoord[0]*patch[1].Pos.xyz
+ + TessCoord[1]*patch[2].Pos.xyz;
+
+ // save some computations
+ uvwSquared *= 3.0;
+
+ // compute PN position
+ float3 pnPos = patch[0].Pos.xyz*uvwCubed[2]
+ + patch[1].Pos.xyz*uvwCubed[0]
+ + patch[2].Pos.xyz*uvwCubed[1]
+ + b210*uvwSquared[2]*uvw[0]
+ + b120*uvwSquared[0]*uvw[2]
+ + b201*uvwSquared[2]*uvw[1]
+ + b021*uvwSquared[0]*uvw[1]
+ + b102*uvwSquared[1]*uvw[2]
+ + b012*uvwSquared[1]*uvw[0]
+ + b111*6.0*uvw[0]*uvw[1]*uvw[2];
+
+ // final position and normal
+ float3 finalPos = (1.0-ubo.tessAlpha)*barPos + ubo.tessAlpha*pnPos;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(finalPos,1.0)));
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/textoverlay/mesh.frag b/data/hlsl/textoverlay/mesh.frag
new file mode 100644
index 00000000..f2eb9b6f
--- /dev/null
+++ b/data/hlsl/textoverlay/mesh.frag
@@ -0,0 +1,20 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float diffuse = max(dot(N, L), 0.0);
+ float specular = pow(max(dot(R, V), 0.0), 1.0);
+ return float4(((diffuse + specular) * 0.25).xxx, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/textoverlay/mesh.vert b/data/hlsl/textoverlay/mesh.vert
new file mode 100644
index 00000000..2abf875a
--- /dev/null
+++ b/data/hlsl/textoverlay/mesh.vert
@@ -0,0 +1,41 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Normal = input.Normal;
+ output.UV = input.UV;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+
+ float4 pos = mul(ubo.model, float4(input.Pos, 1.0));
+ output.Normal = mul((float3x3)ubo.model, normalize(input.Normal));
+ float3 lPos = mul((float3x3)ubo.model, ubo.lightPos.xyz);
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = -pos.xyz;
+ return output;
+}
\ No newline at end of file
diff --git a/data/hlsl/textoverlay/text.frag b/data/hlsl/textoverlay/text.frag
new file mode 100644
index 00000000..7525bd19
--- /dev/null
+++ b/data/hlsl/textoverlay/text.frag
@@ -0,0 +1,10 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureFont : register(t0);
+SamplerState samplerFont : register(s0);
+
+float4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
+{
+ float color = textureFont.Sample(samplerFont, inUV).r;
+ return color.xxxx;
+}
diff --git a/data/hlsl/textoverlay/text.vert b/data/hlsl/textoverlay/text.vert
new file mode 100644
index 00000000..5de88481
--- /dev/null
+++ b/data/hlsl/textoverlay/text.vert
@@ -0,0 +1,21 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float2 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = float4(input.Pos, 0.0, 1.0);
+ output.UV = input.UV;
+ return output;
+}
diff --git a/data/hlsl/texture/texture.frag b/data/hlsl/texture/texture.frag
new file mode 100644
index 00000000..78ce0f93
--- /dev/null
+++ b/data/hlsl/texture/texture.frag
@@ -0,0 +1,27 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float LodBias : TEXCOORD3;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 color = textureColor.SampleLevel(samplerColor, input.UV, input.LodBias);
+
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * float3(1.0, 1.0, 1.0);
+ float specular = pow(max(dot(R, V), 0.0), 16.0) * color.a;
+
+ return float4(diffuse * color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/texture/texture.vert b/data/hlsl/texture/texture.vert
new file mode 100644
index 00000000..133d53b1
--- /dev/null
+++ b/data/hlsl/texture/texture.vert
@@ -0,0 +1,47 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 viewPos;
+ float lodBias;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float LodBias : TEXCOORD3;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV;
+ output.LodBias = ubo.lodBias;
+
+ float3 worldPos = mul(ubo.model, float4(input.Pos, 1.0)).xyz;
+
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+
+ float4 pos = mul(ubo.model, float4(input.Pos, 1.0));
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ float3 lightPos = float3(0.0, 0.0, 0.0);
+ float3 lPos = mul((float3x3)ubo.model, lightPos.xyz);
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = ubo.viewPos.xyz - pos.xyz;
+ return output;
+}
diff --git a/data/hlsl/texture3d/texture3d.frag b/data/hlsl/texture3d/texture3d.frag
new file mode 100644
index 00000000..f9375205
--- /dev/null
+++ b/data/hlsl/texture3d/texture3d.frag
@@ -0,0 +1,27 @@
+// Copyright 2020 Google LLC
+
+Texture3D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 UV : TEXCOORD0;
+[[vk::location(1)]] float LodBias : TEXCOORD3;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 color = textureColor.Sample(samplerColor, input.UV);
+
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.0) * float3(1.0, 1.0, 1.0);
+ float specular = pow(max(dot(R, V), 0.0), 16.0) * color.r;
+
+ return float4(diffuse * color.r + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/texture3d/texture3d.vert b/data/hlsl/texture3d/texture3d.vert
new file mode 100644
index 00000000..39c9681c
--- /dev/null
+++ b/data/hlsl/texture3d/texture3d.vert
@@ -0,0 +1,46 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 viewPos;
+ float depth;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UV : TEXCOORD0;
+[[vk::location(1)]] float LodBias : TEXCOORD3;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float3(input.UV, ubo.depth);
+
+ float3 worldPos = mul(ubo.model, float4(input.Pos, 1.0)).xyz;
+
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+
+ float4 pos = mul(ubo.model, float4(input.Pos, 1.0));
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ float3 lightPos = float3(0.0, 0.0, 0.0);
+ float3 lPos = mul((float3x3)ubo.model, lightPos.xyz);
+ output.LightVec = lPos - pos.xyz;
+ output.ViewVec = ubo.viewPos.xyz - pos.xyz;
+ return output;
+}
diff --git a/data/hlsl/texturearray/instancing.frag b/data/hlsl/texturearray/instancing.frag
new file mode 100644
index 00000000..85ed6eae
--- /dev/null
+++ b/data/hlsl/texturearray/instancing.frag
@@ -0,0 +1,9 @@
+// Copyright 2020 Google LLC
+
+Texture2DArray textureArray : register(t1);
+SamplerState samplerArray : register(s1);
+
+float4 main([[vk::location(0)]] float3 inUV : TEXCOORD0) : SV_TARGET
+{
+ return textureArray.Sample(samplerArray, inUV);
+}
\ No newline at end of file
diff --git a/data/hlsl/texturearray/instancing.vert b/data/hlsl/texturearray/instancing.vert
new file mode 100644
index 00000000..d9d77d52
--- /dev/null
+++ b/data/hlsl/texturearray/instancing.vert
@@ -0,0 +1,37 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+};
+
+struct Instance
+{
+ float4x4 model;
+ float4 arrayIndex;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ Instance instance[8];
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UV : TEXCOORD0;
+};
+
+VSOutput main(VSInput input, uint InstanceIndex : SV_InstanceID)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = float3(input.UV, ubo.instance[InstanceIndex].arrayIndex.x);
+ float4x4 modelView = mul(ubo.view, ubo.instance[InstanceIndex].model);
+ output.Pos = mul(ubo.projection, mul(modelView, float4(input.Pos, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/texturecubemap/reflect.frag b/data/hlsl/texturecubemap/reflect.frag
new file mode 100644
index 00000000..0725da78
--- /dev/null
+++ b/data/hlsl/texturecubemap/reflect.frag
@@ -0,0 +1,43 @@
+// Copyright 2020 Google LLC
+
+TextureCube textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 invModel;
+ float lodBias;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float LodBias : TEXCOORD3;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 cI = normalize (input.ViewVec);
+ float3 cR = reflect (cI, normalize(input.Normal));
+
+ cR = mul(ubo.invModel, float4(cR, 0.0)).xyz;
+ cR.x *= -1.0;
+
+ float4 color = textureColor.SampleLevel(samplerColor, cR, input.LodBias);
+
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 ambient = float3(0.5, 0.5, 0.5) * color.rgb;
+ float3 diffuse = max(dot(N, L), 0.0) * float3(1.0, 1.0, 1.0);
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.5, 0.5, 0.5);
+ return float4(ambient + diffuse * color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/texturecubemap/reflect.vert b/data/hlsl/texturecubemap/reflect.vert
new file mode 100644
index 00000000..9323ee4c
--- /dev/null
+++ b/data/hlsl/texturecubemap/reflect.vert
@@ -0,0 +1,42 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 invModel;
+ float lodBias;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 WorldPos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float LodBias : TEXCOORD3;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+
+ output.WorldPos = mul(ubo.model, float4(input.Pos, 1.0)).xyz;
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ output.LodBias = ubo.lodBias;
+
+ float3 lightPos = float3(0.0f, -5.0f, 5.0f);
+ output.LightVec = lightPos.xyz - output.WorldPos.xyz;
+ output.ViewVec = -output.WorldPos;
+ return output;
+}
diff --git a/data/hlsl/texturecubemap/skybox.frag b/data/hlsl/texturecubemap/skybox.frag
new file mode 100644
index 00000000..bd2ba96d
--- /dev/null
+++ b/data/hlsl/texturecubemap/skybox.frag
@@ -0,0 +1,9 @@
+// Copyright 2020 Google LLC
+
+TextureCube textureCubeMap : register(t1);
+SamplerState samplerCubeMap : register(s1);
+
+float4 main([[vk::location(0)]] float3 inUVW : TEXCOORD0) : SV_TARGET
+{
+ return textureCubeMap.Sample(samplerCubeMap, inUVW);
+}
\ No newline at end of file
diff --git a/data/hlsl/texturecubemap/skybox.vert b/data/hlsl/texturecubemap/skybox.vert
new file mode 100644
index 00000000..e15e7eab
--- /dev/null
+++ b/data/hlsl/texturecubemap/skybox.vert
@@ -0,0 +1,24 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UVW : TEXCOORD0;
+};
+
+VSOutput main([[vk::location(0)]] float3 Pos : POSITION0)
+{
+ VSOutput output = (VSOutput)0;
+ output.UVW = Pos;
+ output.UVW.x *= -1.0;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(Pos.xyz, 1.0)));
+ return output;
+}
diff --git a/data/hlsl/texturemipmapgen/texture.frag b/data/hlsl/texturemipmapgen/texture.frag
new file mode 100644
index 00000000..9f58e19d
--- /dev/null
+++ b/data/hlsl/texturemipmapgen/texture.frag
@@ -0,0 +1,27 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplers[3] : register(s2);
+
+struct VSOutput
+{
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float LodBias : TEXCOORD3;
+[[vk::location(2)]] int SamplerIndex : TEXCOORD4;
+[[vk::location(3)]] float3 Normal : NORMAL0;
+[[vk::location(4)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(5)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 color = textureColor.Sample(samplers[input.SamplerIndex], input.UV, int2(0, 0), input.LodBias);
+
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(L, N);
+ float3 diffuse = max(dot(N, L), 0.65) * float3(1.0, 1.0, 1.0);
+ float specular = pow(max(dot(R, V), 0.0), 16.0) * color.a;
+ return float4(diffuse * color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/texturemipmapgen/texture.vert b/data/hlsl/texturemipmapgen/texture.vert
new file mode 100644
index 00000000..8b5f3036
--- /dev/null
+++ b/data/hlsl/texturemipmapgen/texture.vert
@@ -0,0 +1,49 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float2 UV : TEXCOORD0;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 view;
+ float4x4 model;
+ float4 viewPos;
+ float lodBias;
+ int samplerIndex;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float LodBias : TEXCOORD3;
+[[vk::location(2)]] int SamplerIndex : TEXCOORD4;
+[[vk::location(3)]] float3 Normal : NORMAL0;
+[[vk::location(4)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(5)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV * float2(2.0, 1.0);
+ output.LodBias = ubo.lodBias;
+ output.SamplerIndex = ubo.samplerIndex;
+
+ float3 worldPos = mul(ubo.model, float4(input.Pos, 1.0)).xyz;
+
+ output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, float4(input.Pos.xyz, 1.0))));
+
+ output.Normal = mul((float3x3)ubo.model, input.Normal);
+ float3 lightPos = float3(-30.0, 0.0, 0.0);
+ output.LightVec = worldPos - lightPos;
+ output.ViewVec = ubo.viewPos.xyz - worldPos;
+ return output;
+}
diff --git a/data/hlsl/texturesparseresidency/sparseresidency.frag b/data/hlsl/texturesparseresidency/sparseresidency.frag
new file mode 100644
index 00000000..27458545
--- /dev/null
+++ b/data/hlsl/texturesparseresidency/sparseresidency.frag
@@ -0,0 +1,36 @@
+// Copyright 2020 Google LLC
+
+Texture2D textureColor : register(t1);
+SamplerState samplerColor : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float LodBias : TEXCOORD3;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float4 color = float4(0.0, 0.0, 0.0, 0.0);
+
+ // Fetch sparse until we get a valid texel
+ uint status;
+ float minLod = input.LodBias;
+ do
+ {
+ color = textureColor.SampleLevel(samplerColor, input.UV, minLod, 0, status);
+ minLod += 1.0f;
+ } while(!CheckAccessFullyMapped(status));
+
+ float3 N = normalize(input.Normal);
+
+ N = normalize((input.Normal - 0.5) * 2.0);
+
+ float3 L = normalize(input.LightVec);
+ float3 R = reflect(-L, N);
+ float3 diffuse = max(dot(N, L), 0.25) * color.rgb;
+ return float4(diffuse, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/texturesparseresidency/sparseresidency.vert b/data/hlsl/texturesparseresidency/sparseresidency.vert
new file mode 100644
index 00000000..b5fb1236
--- /dev/null
+++ b/data/hlsl/texturesparseresidency/sparseresidency.vert
@@ -0,0 +1,45 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 UV : TEXCOORD0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4 viewPos;
+ float lodBias;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float LodBias : TEXCOORD3;
+[[vk::location(2)]] float3 Normal : NORMAL0;
+[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.UV;
+ output.LodBias = ubo.lodBias;
+ output.Normal = input.Normal;
+
+ float3 worldPos = mul(ubo.model, float4(input.Pos, 1.0)).xyz;
+
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
+
+ float3 lightPos = float3(0.0, 50.0f, 0.0f);
+ output.LightVec = lightPos - input.Pos.xyz;
+ output.ViewVec = ubo.viewPos.xyz - worldPos.xyz;
+ return output;
+}
diff --git a/data/hlsl/triangle/triangle.frag b/data/hlsl/triangle/triangle.frag
new file mode 100644
index 00000000..8a7faf06
--- /dev/null
+++ b/data/hlsl/triangle/triangle.frag
@@ -0,0 +1,6 @@
+// Copyright 2020 Google LLC
+
+float4 main([[vk::location(0)]] float3 Color : COLOR0) : SV_TARGET
+{
+ return float4(Color, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/triangle/triangle.vert b/data/hlsl/triangle/triangle.vert
new file mode 100644
index 00000000..881674c8
--- /dev/null
+++ b/data/hlsl/triangle/triangle.vert
@@ -0,0 +1,30 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projectionMatrix;
+ float4x4 modelMatrix;
+ float4x4 viewMatrix;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Color : COLOR0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.Pos = mul(ubo.projectionMatrix, mul(ubo.viewMatrix, mul(ubo.modelMatrix, float4(input.Pos.xyz, 1.0))));
+ return output;
+}
diff --git a/data/hlsl/viewportarray/multiview.geom b/data/hlsl/viewportarray/multiview.geom
new file mode 100644
index 00000000..b1e609fd
--- /dev/null
+++ b/data/hlsl/viewportarray/multiview.geom
@@ -0,0 +1,56 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float4x4 projection[2];
+ float4x4 modelview[2];
+ float4 lightPos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+};
+
+struct GSOutput
+{
+ float4 Pos : SV_POSITION;
+ uint ViewportIndex : SV_ViewportArrayIndex;
+ uint PrimitiveID : SV_PrimitiveID;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOOR1;
+[[vk::location(3)]] float3 LightVec : TEXCOOR2;
+};
+
+[maxvertexcount(3)]
+[instance(2)]
+void main(triangle VSOutput input[3], inout TriangleStream outStream, uint InvocationID : SV_GSInstanceID, uint PrimitiveID : SV_PrimitiveID)
+{
+ for(int i = 0; i < 3; i++)
+ {
+ GSOutput output = (GSOutput)0;
+ output.Normal = mul((float3x3)ubo.modelview[InvocationID], input[i].Normal);
+ output.Color = input[i].Color;
+
+ float4 pos = input[i].Pos;
+ float4 worldPos = mul(ubo.modelview[InvocationID], pos);
+
+ float3 lPos = mul(ubo.modelview[InvocationID], ubo.lightPos).xyz;
+ output.LightVec = lPos - worldPos.xyz;
+ output.ViewVec = -worldPos.xyz;
+
+ output.Pos = mul(ubo.projection[InvocationID], worldPos);
+
+ // Set the viewport index that the vertex will be emitted to
+ output.ViewportIndex = InvocationID;
+ output.PrimitiveID = PrimitiveID;
+ outStream.Append( output );
+ }
+
+ outStream.RestartStrip();
+}
\ No newline at end of file
diff --git a/data/hlsl/viewportarray/scene.frag b/data/hlsl/viewportarray/scene.frag
new file mode 100644
index 00000000..189e9955
--- /dev/null
+++ b/data/hlsl/viewportarray/scene.frag
@@ -0,0 +1,21 @@
+// Copyright 2020 Google LLC
+
+struct GSOutput
+{
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+[[vk::location(2)]] float3 ViewVec : TEXCOORD1;
+[[vk::location(3)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(GSOutput input) : SV_TARGET
+{
+ float3 N = normalize(input.Normal);
+ float3 L = normalize(input.LightVec);
+ float3 V = normalize(input.ViewVec);
+ float3 R = reflect(-L, N);
+ float3 ambient = float3(0.1, 0.1, 0.1);
+ float3 diffuse = max(dot(N, L), 0.0) * float3(1.0, 1.0, 1.0);
+ float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75);
+ return float4((ambient + diffuse) * input.Color.rgb + specular, 1.0);
+}
\ No newline at end of file
diff --git a/data/hlsl/viewportarray/scene.vert b/data/hlsl/viewportarray/scene.vert
new file mode 100644
index 00000000..1aeca832
--- /dev/null
+++ b/data/hlsl/viewportarray/scene.vert
@@ -0,0 +1,24 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float3 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+};
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 Normal : NORMAL0;
+[[vk::location(1)]] float3 Color : COLOR0;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.Color = input.Color;
+ output.Normal = input.Normal;
+ output.Pos = float4(input.Pos.xyz, 1.0);
+ return output;
+}
diff --git a/data/hlsl/vulkanscene/logo.frag b/data/hlsl/vulkanscene/logo.frag
new file mode 100644
index 00000000..e4a8c9df
--- /dev/null
+++ b/data/hlsl/vulkanscene/logo.frag
@@ -0,0 +1,22 @@
+// Copyright 2020 Google LLC
+
+struct VSOutput
+{
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 EyePos : POSITION0;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 Eye = normalize(-input.EyePos);
+ float3 Reflected = normalize(reflect(-input.LightVec, input.Normal));
+
+ float4 diff = float4(input.Color, 1.0) * max(dot(input.Normal, input.LightVec), 0.0);
+ float shininess = 0.0;
+ float4 spec = float4(1.0, 1.0, 1.0, 1.0) * pow(max(dot(Reflected, Eye), 0.0), 2.5) * shininess;
+
+ return float4((diff + spec).rgb, 1);
+}
\ No newline at end of file
diff --git a/data/hlsl/vulkanscene/logo.vert b/data/hlsl/vulkanscene/logo.vert
new file mode 100644
index 00000000..dc458eee
--- /dev/null
+++ b/data/hlsl/vulkanscene/logo.vert
@@ -0,0 +1,45 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 TexCoord : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 normal;
+ float4x4 view;
+ float3 lightpos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 EyePos : POSITION0;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ float4x4 modelView = mul(ubo.view, ubo.model);
+ float4 pos = mul(modelView, input.Pos);
+ output.UV = input.TexCoord.xy;
+ output.Normal = normalize(mul((float3x3)ubo.normal, input.Normal));
+ output.Color = input.Color;
+ output.Pos = mul(ubo.projection, pos);
+ output.EyePos = mul(modelView, pos).xyz;
+ float4 lightPos = mul(modelView, float4(1.0, 2.0, 0.0, 1.0));
+ output.LightVec = normalize(lightPos.xyz - output.EyePos);
+ return output;
+}
diff --git a/data/hlsl/vulkanscene/mesh.frag b/data/hlsl/vulkanscene/mesh.frag
new file mode 100644
index 00000000..5770537a
--- /dev/null
+++ b/data/hlsl/vulkanscene/mesh.frag
@@ -0,0 +1,48 @@
+// Copyright 2020 Google LLC
+
+Texture2D tex : register(t1);
+SamplerState samp : register(s1);
+
+struct VSOutput
+{
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 EyePos : POSITION0;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+float specpart(float3 L, float3 N, float3 H)
+{
+ if (dot(N, L) > 0.0)
+ {
+ return pow(clamp(dot(H, N), 0.0, 1.0), 64.0);
+ }
+ return 0.0;
+}
+
+float4 main(VSOutput input) : SV_TARGET
+{
+ float3 Eye = normalize(-input.EyePos);
+ float3 Reflected = normalize(reflect(-input.LightVec, input.Normal));
+
+ float3 halfVec = normalize(input.LightVec + input.EyePos);
+ float diff = clamp(dot(input.LightVec, input.Normal), 0.0, 1.0);
+ float spec = specpart(input.LightVec, input.Normal, halfVec);
+ float intensity = 0.1 + diff + spec;
+
+ float4 IAmbient = float4(0.2, 0.2, 0.2, 1.0);
+ float4 IDiffuse = float4(0.5, 0.5, 0.5, 0.5) * max(dot(input.Normal, input.LightVec), 0.0);
+ float shininess = 0.75;
+ float4 ISpecular = float4(0.5, 0.5, 0.5, 1.0) * pow(max(dot(Reflected, Eye), 0.0), 2.0) * shininess;
+
+ float4 outFragColor = float4((IAmbient + IDiffuse) * float4(input.Color, 1.0) + ISpecular);
+
+ // Some manual saturation
+ if (intensity > 0.95)
+ outFragColor *= 2.25;
+ if (intensity < 0.15)
+ outFragColor = float4(0.1, 0.1, 0.1, 0.1);
+
+ return outFragColor;
+}
\ No newline at end of file
diff --git a/data/hlsl/vulkanscene/mesh.vert b/data/hlsl/vulkanscene/mesh.vert
new file mode 100644
index 00000000..77490e46
--- /dev/null
+++ b/data/hlsl/vulkanscene/mesh.vert
@@ -0,0 +1,45 @@
+// Copyright 2020 Google LLC
+
+struct VSInput
+{
+[[vk::location(0)]] float4 Pos : POSITION0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float2 TexCoord : TEXCOORD0;
+[[vk::location(3)]] float3 Color : COLOR0;
+};
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+ float4x4 normal;
+ float4x4 view;
+ float3 lightpos;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float2 UV : TEXCOORD0;
+[[vk::location(1)]] float3 Normal : NORMAL0;
+[[vk::location(2)]] float3 Color : COLOR0;
+[[vk::location(3)]] float3 EyePos : POSITION0;
+[[vk::location(4)]] float3 LightVec : TEXCOORD2;
+};
+
+VSOutput main(VSInput input)
+{
+ VSOutput output = (VSOutput)0;
+ output.UV = input.TexCoord.xy;
+ output.Normal = normalize(mul((float3x3)ubo.normal, input.Normal));
+ output.Color = input.Color;
+ float4x4 modelView = mul(ubo.view, ubo.model);
+ float4 pos = mul(modelView, input.Pos);
+ output.Pos = mul(ubo.projection, pos);
+ output.EyePos = mul(modelView, pos).xyz;
+ float4 lightPos = mul(modelView, float4(ubo.lightpos, 1.0));
+ output.LightVec = normalize(lightPos.xyz - output.EyePos);
+ return output;
+}
diff --git a/data/hlsl/vulkanscene/skybox.frag b/data/hlsl/vulkanscene/skybox.frag
new file mode 100644
index 00000000..bd2ba96d
--- /dev/null
+++ b/data/hlsl/vulkanscene/skybox.frag
@@ -0,0 +1,9 @@
+// Copyright 2020 Google LLC
+
+TextureCube textureCubeMap : register(t1);
+SamplerState samplerCubeMap : register(s1);
+
+float4 main([[vk::location(0)]] float3 inUVW : TEXCOORD0) : SV_TARGET
+{
+ return textureCubeMap.Sample(samplerCubeMap, inUVW);
+}
\ No newline at end of file
diff --git a/data/hlsl/vulkanscene/skybox.vert b/data/hlsl/vulkanscene/skybox.vert
new file mode 100644
index 00000000..ebc7739d
--- /dev/null
+++ b/data/hlsl/vulkanscene/skybox.vert
@@ -0,0 +1,23 @@
+// Copyright 2020 Google LLC
+
+struct UBO
+{
+ float4x4 projection;
+ float4x4 model;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+struct VSOutput
+{
+ float4 Pos : SV_POSITION;
+[[vk::location(0)]] float3 UVW : TEXCOORD0;
+};
+
+VSOutput main([[vk::location(0)]] float3 Pos : POSITION0)
+{
+ VSOutput output = (VSOutput)0;
+ output.UVW = Pos;
+ output.Pos = mul(ubo.projection, mul(ubo.model, float4(Pos.xyz, 1.0)));
+ return output;
+}
diff --git a/data/shaders/hdr/bloom.frag.spv b/data/shaders/hdr/bloom.frag.spv
index 57d69057..65e7d382 100644
Binary files a/data/shaders/hdr/bloom.frag.spv and b/data/shaders/hdr/bloom.frag.spv differ
diff --git a/data/shaders/hdr/bloom.vert.spv b/data/shaders/hdr/bloom.vert.spv
index 4040f608..ffcd1a84 100644
Binary files a/data/shaders/hdr/bloom.vert.spv and b/data/shaders/hdr/bloom.vert.spv differ
diff --git a/data/shaders/hdr/composition.frag.spv b/data/shaders/hdr/composition.frag.spv
index 39ff5dff..1a334e0e 100644
Binary files a/data/shaders/hdr/composition.frag.spv and b/data/shaders/hdr/composition.frag.spv differ
diff --git a/data/shaders/hdr/composition.vert.spv b/data/shaders/hdr/composition.vert.spv
index 4040f608..ffcd1a84 100644
Binary files a/data/shaders/hdr/composition.vert.spv and b/data/shaders/hdr/composition.vert.spv differ
diff --git a/data/shaders/hdr/gbuffer.frag b/data/shaders/hdr/gbuffer.frag
index 3ffccf2a..b920dad3 100644
--- a/data/shaders/hdr/gbuffer.frag
+++ b/data/shaders/hdr/gbuffer.frag
@@ -2,12 +2,17 @@
layout (binding = 1) uniform samplerCube samplerEnvMap;
+layout (binding = 0) uniform UBO {
+ mat4 projection;
+ mat4 modelview;
+ mat4 inverseModelview;
+} ubo;
+
layout (location = 0) in vec3 inUVW;
layout (location = 1) in vec3 inPos;
layout (location = 2) in vec3 inNormal;
layout (location = 3) in vec3 inViewVec;
layout (location = 4) in vec3 inLightVec;
-layout (location = 5) in mat4 inInvModelView;
layout (location = 0) out vec4 outColor0;
layout (location = 1) out vec4 outColor1;
@@ -17,37 +22,37 @@ layout (constant_id = 0) const int type = 0;
#define PI 3.1415926
#define TwoPI (2.0 * PI)
-layout (binding = 2) uniform UBO {
+layout (binding = 2) uniform Exposure {
float exposure;
-} ubo;
+} exposure;
-void main()
+void main()
{
vec4 color;
vec3 wcNormal;
switch (type) {
- case 0: // Skybox
+ case 0: // Skybox
{
vec3 normal = normalize(inUVW);
color = texture(samplerEnvMap, normal);
}
break;
-
+
case 1: // Reflect
{
- vec3 wViewVec = mat3(inInvModelView) * normalize(inViewVec);
+ vec3 wViewVec = mat3(ubo.inverseModelview) * normalize(inViewVec);
vec3 normal = normalize(inNormal);
- vec3 wNormal = mat3(inInvModelView) * normal;
+ vec3 wNormal = mat3(ubo.inverseModelview) * normal;
float NdotL = max(dot(normal, inLightVec), 0.0);
- vec3 eyeDir = normalize(inViewVec);
+ vec3 eyeDir = normalize(inViewVec);
vec3 halfVec = normalize(inLightVec + eyeDir);
- float NdotH = max(dot(normal, halfVec), 0.0);
- float NdotV = max(dot(normal, eyeDir), 0.0);
+ float NdotH = max(dot(normal, halfVec), 0.0);
+ float NdotV = max(dot(normal, eyeDir), 0.0);
float VdotH = max(dot(eyeDir, halfVec), 0.0);
-
+
// Geometric attenuation
float NH2 = 2.0 * NdotH;
float g1 = (NH2 * NdotV) / VdotH;
@@ -61,27 +66,27 @@ void main()
float fresnel = pow(1.0 - VdotH, 5.0);
fresnel *= (1.0 - F0);
fresnel += F0;
-
+
float spec = (fresnel * geoAtt) / (NdotV * NdotL * 3.14);
-
- color = texture(samplerEnvMap, reflect(-wViewVec, wNormal));
+
+ color = texture(samplerEnvMap, reflect(-wViewVec, wNormal));
color = vec4(color.rgb * NdotL * (k + spec * (1.0 - k)), 1.0);
}
break;
- case 2: // Refract
+ case 2: // Refract
{
- vec3 wViewVec = mat3(inInvModelView) * normalize(inViewVec);
- vec3 wNormal = mat3(inInvModelView) * inNormal;
- color = texture(samplerEnvMap, refract(-wViewVec, wNormal, 1.0/1.6));
+ vec3 wViewVec = mat3(ubo.inverseModelview) * normalize(inViewVec);
+ vec3 wNormal = mat3(ubo.inverseModelview) * inNormal;
+ color = texture(samplerEnvMap, refract(-wViewVec, wNormal, 1.0/1.6));
}
break;
}
// Color with manual exposure into attachment 0
- outColor0.rgb = vec3(1.0) - exp(-color.rgb * ubo.exposure);
+ outColor0.rgb = vec3(1.0) - exp(-color.rgb * exposure.exposure);
// Bright parts for bloom into attachment 1
float l = dot(outColor0.rgb, vec3(0.2126, 0.7152, 0.0722));
diff --git a/data/shaders/hdr/gbuffer.frag.spv b/data/shaders/hdr/gbuffer.frag.spv
index 9b9afd9b..57f315b3 100644
Binary files a/data/shaders/hdr/gbuffer.frag.spv and b/data/shaders/hdr/gbuffer.frag.spv differ
diff --git a/data/shaders/hdr/gbuffer.vert b/data/shaders/hdr/gbuffer.vert
index 5d69f03c..ef9f0ad7 100644
--- a/data/shaders/hdr/gbuffer.vert
+++ b/data/shaders/hdr/gbuffer.vert
@@ -8,6 +8,7 @@ layout (constant_id = 0) const int type = 0;
layout (binding = 0) uniform UBO {
mat4 projection;
mat4 modelview;
+ mat4 inverseModelview;
} ubo;
layout (location = 0) out vec3 outUVW;
@@ -15,14 +16,13 @@ layout (location = 1) out vec3 outPos;
layout (location = 2) out vec3 outNormal;
layout (location = 3) out vec3 outViewVec;
layout (location = 4) out vec3 outLightVec;
-layout (location = 5) out mat4 outInvModelView;
-out gl_PerVertex
+out gl_PerVertex
{
vec4 gl_Position;
};
-void main()
+void main()
{
outUVW = inPos;
@@ -37,11 +37,9 @@ void main()
break;
}
outPos = vec3(ubo.modelview * vec4(inPos, 1.0));
- outNormal = mat3(ubo.modelview) * inNormal;
-
- outInvModelView = inverse(ubo.modelview);
+ outNormal = mat3(ubo.modelview) * inNormal;
vec3 lightPos = vec3(0.0f, -5.0f, 5.0f);
outLightVec = lightPos.xyz - outPos.xyz;
- outViewVec = -outPos.xyz;
+ outViewVec = -outPos.xyz;
}
diff --git a/data/shaders/hdr/gbuffer.vert.spv b/data/shaders/hdr/gbuffer.vert.spv
index 2743ab44..6563548c 100644
Binary files a/data/shaders/hdr/gbuffer.vert.spv and b/data/shaders/hdr/gbuffer.vert.spv differ
diff --git a/data/shaders/texturecubemap/reflect.frag b/data/shaders/texturecubemap/reflect.frag
index a7990182..161f4cd4 100644
--- a/data/shaders/texturecubemap/reflect.frag
+++ b/data/shaders/texturecubemap/reflect.frag
@@ -2,21 +2,28 @@
layout (binding = 1) uniform samplerCube samplerColor;
+layout (binding = 0) uniform UBO
+{
+ mat4 projection;
+ mat4 model;
+ mat4 invModel;
+ float lodBias;
+} ubo;
+
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inNormal;
layout (location = 2) in float inLodBias;
layout (location = 3) in vec3 inViewVec;
layout (location = 4) in vec3 inLightVec;
-layout (location = 5) in mat4 inInvModelView;
layout (location = 0) out vec4 outFragColor;
-void main()
+void main()
{
vec3 cI = normalize (inPos);
vec3 cR = reflect (cI, normalize(inNormal));
- cR = vec3(inInvModelView * vec4(cR, 0.0));
+ cR = vec3(ubo.invModel * vec4(cR, 0.0));
cR.x *= -1.0;
vec4 color = texture(samplerColor, cR, inLodBias);
@@ -28,5 +35,5 @@ void main()
vec3 ambient = vec3(0.5) * color.rgb;
vec3 diffuse = max(dot(N, L), 0.0) * vec3(1.0);
vec3 specular = pow(max(dot(R, V), 0.0), 16.0) * vec3(0.5);
- outFragColor = vec4(ambient + diffuse * color.rgb + specular, 1.0);
+ outFragColor = vec4(ambient + diffuse * color.rgb + specular, 1.0);
}
\ No newline at end of file
diff --git a/data/shaders/texturecubemap/reflect.frag.spv b/data/shaders/texturecubemap/reflect.frag.spv
index badefb38..9e5a3629 100644
Binary files a/data/shaders/texturecubemap/reflect.frag.spv and b/data/shaders/texturecubemap/reflect.frag.spv differ
diff --git a/data/shaders/texturecubemap/reflect.vert b/data/shaders/texturecubemap/reflect.vert
index 3017f3d4..1da8c387 100644
--- a/data/shaders/texturecubemap/reflect.vert
+++ b/data/shaders/texturecubemap/reflect.vert
@@ -3,10 +3,11 @@
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inNormal;
-layout (binding = 0) uniform UBO
+layout (binding = 0) uniform UBO
{
mat4 projection;
mat4 model;
+ mat4 invModel;
float lodBias;
} ubo;
@@ -15,24 +16,21 @@ layout (location = 1) out vec3 outNormal;
layout (location = 2) out float outLodBias;
layout (location = 3) out vec3 outViewVec;
layout (location = 4) out vec3 outLightVec;
-layout (location = 5) out mat4 outInvModelView;
-out gl_PerVertex
+out gl_PerVertex
{
vec4 gl_Position;
};
-void main()
+void main()
{
gl_Position = ubo.projection * ubo.model * vec4(inPos.xyz, 1.0);
-
+
outPos = vec3(ubo.model * vec4(inPos, 1.0));
- outNormal = mat3(ubo.model) * inNormal;
+ outNormal = mat3(ubo.model) * inNormal;
outLodBias = ubo.lodBias;
-
- outInvModelView = inverse(ubo.model);
vec3 lightPos = vec3(0.0f, -5.0f, 5.0f);
outLightVec = lightPos.xyz - outPos.xyz;
- outViewVec = -outPos.xyz;
+ outViewVec = -outPos.xyz;
}
diff --git a/data/shaders/texturecubemap/reflect.vert.spv b/data/shaders/texturecubemap/reflect.vert.spv
index 9c7c86ad..ebceaeae 100644
Binary files a/data/shaders/texturecubemap/reflect.vert.spv and b/data/shaders/texturecubemap/reflect.vert.spv differ
diff --git a/data/shaders/texturecubemap/skybox.frag.spv b/data/shaders/texturecubemap/skybox.frag.spv
index 54a894cc..87e4fe98 100644
Binary files a/data/shaders/texturecubemap/skybox.frag.spv and b/data/shaders/texturecubemap/skybox.frag.spv differ
diff --git a/data/shaders/texturecubemap/skybox.vert.spv b/data/shaders/texturecubemap/skybox.vert.spv
index 52290c71..c823cbb3 100644
Binary files a/data/shaders/texturecubemap/skybox.vert.spv and b/data/shaders/texturecubemap/skybox.vert.spv differ
diff --git a/examples/computeparticles/computeparticles.cpp b/examples/computeparticles/computeparticles.cpp
index c11b4c38..306a425e 100644
--- a/examples/computeparticles/computeparticles.cpp
+++ b/examples/computeparticles/computeparticles.cpp
@@ -183,6 +183,15 @@ public:
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphics.pipeline);
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphics.pipelineLayout, 0, 1, &graphics.descriptorSet, 0, NULL);
+ glm::vec2 screendim = glm::vec2((float)width, (float)height);
+ vkCmdPushConstants(
+ drawCmdBuffers[i],
+ graphics.pipelineLayout,
+ VK_SHADER_STAGE_VERTEX_BIT,
+ 0,
+ sizeof(glm::vec2),
+ &screendim);
+
VkDeviceSize offsets[1] = { 0 };
vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &compute.storageBuffer.buffer, offsets);
vkCmdDraw(drawCmdBuffers[i], PARTICLE_COUNT, 1, 0, 0);
@@ -262,7 +271,7 @@ public:
vkCmdDispatch(compute.commandBuffer, PARTICLE_COUNT / 256, 1, 1);
// Add barrier to ensure that compute shader has finished writing to the buffer
- // Without this the (rendering) vertex shader may display incomplete results (partial data from last frame)
+ // Without this the (rendering) vertex shader may display incomplete results (partial data from last frame)
if (graphics.queueFamilyIndex != compute.queueFamilyIndex)
{
VkBufferMemoryBarrier buffer_barrier =
@@ -308,7 +317,7 @@ public:
VkDeviceSize storageBufferSize = particleBuffer.size() * sizeof(Particle);
// Staging
- // SSBO won't be changed on the host after upload so copy to device local memory
+ // SSBO won't be changed on the host after upload so copy to device local memory
vks::Buffer stagingBuffer;
@@ -438,6 +447,15 @@ public:
&graphics.descriptorSetLayout,
1);
+ VkPushConstantRange pushConstantRange =
+ vks::initializers::pushConstantRange(
+ VK_SHADER_STAGE_VERTEX_BIT,
+ sizeof(glm::vec2),
+ 0);
+
+ pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
+ pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange;
+
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &graphics.pipelineLayout));
}
@@ -632,7 +650,7 @@ public:
vkUpdateDescriptorSets(device, static_cast(computeWriteDescriptorSets.size()), computeWriteDescriptorSets.data(), 0, NULL);
- // Create pipeline
+ // Create pipeline
VkComputePipelineCreateInfo computePipelineCreateInfo = vks::initializers::computePipelineCreateInfo(compute.pipelineLayout, 0);
computePipelineCreateInfo.stage = loadShader(getAssetPath() + "shaders/computeparticles/particle.comp.spv", VK_SHADER_STAGE_COMPUTE_BIT);
VK_CHECK_RESULT(vkCreateComputePipelines(device, pipelineCache, 1, &computePipelineCreateInfo, nullptr, &compute.pipeline));
@@ -785,7 +803,7 @@ public:
}
void prepare()
- {
+ {
VulkanExampleBase::prepare();
// We will be using the queue family indices to check if graphics and compute queue families differ
// If that's the case, we need additional barriers for acquiring and releasing resources
@@ -818,7 +836,7 @@ public:
timer = 0.f;
}
}
-
+
updateUniformBuffers();
}
diff --git a/examples/hdr/hdr.cpp b/examples/hdr/hdr.cpp
index 93dd6d92..cedec593 100644
--- a/examples/hdr/hdr.cpp
+++ b/examples/hdr/hdr.cpp
@@ -58,6 +58,7 @@ public:
struct UBOVS {
glm::mat4 projection;
glm::mat4 modelview;
+ glm::mat4 inverseModelview;
} uboVS;
struct UBOParams {
@@ -603,7 +604,7 @@ public:
models.objects.push_back(model);
}
// Load HDR cube map
- textures.envmap.loadFromFile(getAssetPath() + "textures/hdr/uffizi_cube.ktx", VK_FORMAT_R16G16B16A16_SFLOAT, vulkanDevice, queue);
+ textures.envmap.loadFromFile(getAssetPath() + "textures/hdr/uffizi_cube.ktx", VK_FORMAT_R16G16B16A16_SFLOAT, vulkanDevice, queue);
}
void setupDescriptorPool()
@@ -613,7 +614,7 @@ public:
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 6)
};
uint32_t numDescriptorSets = 4;
- VkDescriptorPoolCreateInfo descriptorPoolInfo =
+ VkDescriptorPoolCreateInfo descriptorPoolInfo =
vks::initializers::descriptorPoolCreateInfo(static_cast(poolSizes.size()), poolSizes.data(), numDescriptorSets);
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
}
@@ -621,12 +622,12 @@ public:
void setupDescriptorSetLayout()
{
std::vector setLayoutBindings = {
- vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0),
+ vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0),
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1),
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, 2),
};
- VkDescriptorSetLayoutCreateInfo descriptorLayoutInfo =
+ VkDescriptorSetLayoutCreateInfo descriptorLayoutInfo =
vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings.data(), static_cast(setLayoutBindings.size()));
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutInfo, nullptr, &descriptorSetLayouts.models));
@@ -691,7 +692,7 @@ public:
};
vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
- // Bloom filter
+ // Bloom filter
allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.bloomFilter, 1);
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.bloomFilter));
@@ -744,7 +745,7 @@ public:
VkPipelineColorBlendStateCreateInfo colorBlendState =
vks::initializers::pipelineColorBlendStateCreateInfo(
- 1,
+ 1,
&blendAttachmentState);
VkPipelineDepthStencilStateCreateInfo depthStencilState =
@@ -839,7 +840,7 @@ public:
dir = 0;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.bloom[1]));
- // Object rendering pipelines
+ // Object rendering pipelines
rasterizationState.cullMode = VK_CULL_MODE_BACK_BIT;
// Vertex bindings an attributes for model rendering
@@ -922,6 +923,7 @@ public:
{
uboVS.projection = camera.matrices.perspective;
uboVS.modelview = camera.matrices.view;
+ uboVS.inverseModelview = glm::inverse(camera.matrices.view);
memcpy(uniformBuffers.matrices.mapped, &uboVS, sizeof(uboVS));
}
diff --git a/examples/texturecubemap/texturecubemap.cpp b/examples/texturecubemap/texturecubemap.cpp
index 2a77ba66..6ae3eb24 100644
--- a/examples/texturecubemap/texturecubemap.cpp
+++ b/examples/texturecubemap/texturecubemap.cpp
@@ -55,6 +55,7 @@ public:
struct UBOVS {
glm::mat4 projection;
glm::mat4 modelView;
+ glm::mat4 inverseModelview;
float lodBias = 0.0f;
} uboVS;
@@ -440,10 +441,10 @@ public:
{
std::vector setLayoutBindings =
{
- // Binding 0 : Vertex shader uniform buffer
+ // Binding 0 : Uniform buffer
vks::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
- VK_SHADER_STAGE_VERTEX_BIT,
+ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
0),
// Binding 1 : Fragment shader image sampler
vks::initializers::descriptorSetLayoutBinding(
@@ -620,7 +621,7 @@ public:
// Prepare and initialize uniform buffer containing shader uniforms
void prepareUniformBuffers()
{
- // Objact vertex shader uniform buffer
+ // Object vertex shader uniform buffer
VK_CHECK_RESULT(vulkanDevice->createBuffer(
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
@@ -646,6 +647,7 @@ public:
// 3D object
uboVS.projection = camera.matrices.perspective;
uboVS.modelView = camera.matrices.view;
+ uboVS.inverseModelview = glm::inverse(camera.matrices.view);
memcpy(uniformBuffers.object.mapped, &uboVS, sizeof(uboVS));
// Skybox
uboVS.modelView = camera.matrices.view;