init
9
data/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
cmake_minimum_required(VERSION 3.19)
|
||||
|
||||
project(SharedUtils CXX C)
|
||||
|
||||
include(../CMake/CommonMacros.txt)
|
||||
|
||||
file(GLOB_RECURSE SHADER_FILES LIST_DIRECTORIES false RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} shaders/gltf/*.vert shaders/gltf/*.frag shaders/gltf/*.geom shaders/gltf/*.sp src/*.comp)
|
||||
|
||||
add_library(Shaders INTERFACE ${SHADER_FILES})
|
||||
BIN
data/OpenSans-Light.ttf
Normal file
BIN
data/brdfLUT.ktx
Normal file
BIN
data/immenstadter_horn_2k.hdr
Normal file
BIN
data/immenstadter_horn_2k_ReferenceMap.ktx
Normal file
BIN
data/immenstadter_horn_2k_charlie.ktx
Normal file
BIN
data/immenstadter_horn_2k_irradiance.ktx
Normal file
BIN
data/immenstadter_horn_2k_prefilter.ktx
Normal file
11
data/meshes/medieval_fantasy_book/license.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
Model Information:
|
||||
* title: Medieval Fantasy Book
|
||||
* source: https://sketchfab.com/3d-models/medieval-fantasy-book-06d5a80a04fc4c5ab552759e9a97d91a
|
||||
* author: Pixel (https://sketchfab.com/stefan.lengyel1)
|
||||
|
||||
Model License:
|
||||
* license type: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
* requirements: Author must be credited. Commercial use is allowed.
|
||||
|
||||
If you use this 3D model in your project be sure to copy paste this credit wherever you share it:
|
||||
This work is based on "Medieval Fantasy Book" (https://sketchfab.com/3d-models/medieval-fantasy-book-06d5a80a04fc4c5ab552759e9a97d91a) by Pixel (https://sketchfab.com/stefan.lengyel1) licensed under CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
BIN
data/meshes/medieval_fantasy_book/scene.bin
Normal file
1691
data/meshes/medieval_fantasy_book/scene.gltf
Normal file
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 146 KiB |
BIN
data/meshes/orrery/scene.bin
Normal file
4160
data/meshes/orrery/scene.gltf
Normal file
4
data/meshes/orrery/src.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
https://sketchfab.com/3d-models/orrery-44849150982d4c228fca951a66df604f
|
||||
|
||||
|
||||
Eranekao
|
||||
BIN
data/meshes/orrery/textures/earth_diffuse.jpg
Normal file
|
After Width: | Height: | Size: 768 KiB |
BIN
data/meshes/orrery/textures/jupiter_diffuse.jpg
Normal file
|
After Width: | Height: | Size: 549 KiB |
BIN
data/meshes/orrery/textures/mars_diffuse.jpg
Normal file
|
After Width: | Height: | Size: 655 KiB |
BIN
data/meshes/orrery/textures/mercury_diffuse.jpg
Normal file
|
After Width: | Height: | Size: 508 KiB |
BIN
data/meshes/orrery/textures/neptune_diffuse.jpg
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
data/meshes/orrery/textures/saturn_diffuse.jpg
Normal file
|
After Width: | Height: | Size: 227 KiB |
BIN
data/meshes/orrery/textures/saturnrings_diffuse.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
data/meshes/orrery/textures/stars_diffuse.png
Normal file
|
After Width: | Height: | Size: 3.5 MiB |
BIN
data/meshes/orrery/textures/stars_emissive.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
data/meshes/orrery/textures/stars_occlusion.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
data/meshes/orrery/textures/sun.jpg
Normal file
|
After Width: | Height: | Size: 833 KiB |
BIN
data/meshes/orrery/textures/uranus_diffuse.jpg
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
data/meshes/orrery/textures/venus_diffuse.jpg
Normal file
|
After Width: | Height: | Size: 696 KiB |
BIN
data/meshes/orrery/textures/wood_diffuse.png
Normal file
|
After Width: | Height: | Size: 3.5 MiB |
BIN
data/meshes/orrery/textures/wood_occlusion.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
data/piazza_bologni_1k.hdr
Normal file
BIN
data/piazza_bologni_1k_charlie.ktx
Normal file
BIN
data/piazza_bologni_1k_irradiance.ktx
Normal file
BIN
data/piazza_bologni_1k_prefilter.ktx
Normal file
BIN
data/rot_texture.bmp
Normal file
|
After Width: | Height: | Size: 102 B |
BIN
data/rubber_duck/scene.bin
Normal file
231
data/rubber_duck/scene.gltf
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
{
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 2,
|
||||
"componentType": 5126,
|
||||
"count": 5676,
|
||||
"max": [
|
||||
0.36252099275588989,
|
||||
0.51303797960281372,
|
||||
1.0525829792022705
|
||||
],
|
||||
"min": [
|
||||
-0.36252099275588989,
|
||||
-0.48232200741767883,
|
||||
0.00014600000577047467
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 2,
|
||||
"byteOffset": 68112,
|
||||
"componentType": 5126,
|
||||
"count": 5676,
|
||||
"max": [
|
||||
0.99994742870330811,
|
||||
0.99997341632843018,
|
||||
0.9999920129776001
|
||||
],
|
||||
"min": [
|
||||
-0.99994742870330811,
|
||||
-0.99984163045883179,
|
||||
-1
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 3,
|
||||
"componentType": 5126,
|
||||
"count": 5676,
|
||||
"max": [
|
||||
0.99985033273696899,
|
||||
0.99970757961273193,
|
||||
0.99825453758239746,
|
||||
1
|
||||
],
|
||||
"min": [
|
||||
-1,
|
||||
-0.99970918893814087,
|
||||
-0.99825495481491089,
|
||||
-1
|
||||
],
|
||||
"type": "VEC4"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"componentType": 5126,
|
||||
"count": 5676,
|
||||
"max": [
|
||||
0.9983140230178833,
|
||||
0.87805598974227905
|
||||
],
|
||||
"min": [
|
||||
0.00010900000052060932,
|
||||
0.00010900000052060932
|
||||
],
|
||||
"type": "VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView": 0,
|
||||
"componentType": 5125,
|
||||
"count": 33216,
|
||||
"max": [
|
||||
5675
|
||||
],
|
||||
"min": [
|
||||
0
|
||||
],
|
||||
"type": "SCALAR"
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"extras": {
|
||||
"author": "emilsvfx (https://sketchfab.com/emilsvfx)",
|
||||
"license": "CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)",
|
||||
"source": "https://sketchfab.com/models/a84cecb600c04eeba60d02f99b8b154b",
|
||||
"title": "Rubber Duck"
|
||||
},
|
||||
"generator": "Sketchfab-3.37.2",
|
||||
"version": "2.0"
|
||||
},
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 132864,
|
||||
"byteOffset": 0,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 45408,
|
||||
"byteOffset": 132864,
|
||||
"byteStride": 8,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 136224,
|
||||
"byteOffset": 178272,
|
||||
"byteStride": 12,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 90816,
|
||||
"byteOffset": 314496,
|
||||
"byteStride": 16,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34962
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"byteLength": 405312,
|
||||
"uri": "scene.bin"
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"uri": "textures/Duck_baseColor.png"
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"doubleSided": true,
|
||||
"emissiveFactor": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"name": "Duck",
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorFactor": [
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"baseColorTexture": {
|
||||
"index": 0,
|
||||
"texCoord": 0
|
||||
},
|
||||
"metallicFactor": 0,
|
||||
"roughnessFactor": 0.84349154199999998
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"NORMAL": 1,
|
||||
"POSITION": 0,
|
||||
"TANGENT": 2,
|
||||
"TEXCOORD_0": 3
|
||||
},
|
||||
"indices": 4,
|
||||
"material": 0,
|
||||
"mode": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"children": [
|
||||
1
|
||||
],
|
||||
"name": "RootNode (gltf orientation matrix)",
|
||||
"rotation": [
|
||||
-0.70710678118654746,
|
||||
-0,
|
||||
-0,
|
||||
0.70710678118654757
|
||||
]
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
2
|
||||
],
|
||||
"name": "RootNode (model correction matrix)"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
3
|
||||
],
|
||||
"name": "duck.obj.cleaner.materialmerger.gles"
|
||||
},
|
||||
{
|
||||
"mesh": 0,
|
||||
"name": ""
|
||||
}
|
||||
],
|
||||
"samplers": [
|
||||
{
|
||||
"magFilter": 9729,
|
||||
"minFilter": 9987,
|
||||
"wrapS": 10497,
|
||||
"wrapT": 10497
|
||||
}
|
||||
],
|
||||
"scene": 0,
|
||||
"scenes": [
|
||||
{
|
||||
"name": "OSG_Scene",
|
||||
"nodes": [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": [
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
BIN
data/rubber_duck/textures/Duck_baseColor.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
20
data/shaders/AlphaTest.sp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
|
||||
void runAlphaTest(float alpha, float alphaThreshold)
|
||||
{
|
||||
if (alphaThreshold > 0.0) {
|
||||
// http://alex-charlton.com/posts/Dithering_on_the_GPU/
|
||||
// https://forums.khronos.org/showthread.php/5091-screen-door-transparency
|
||||
mat4 thresholdMatrix = mat4(
|
||||
1.0 / 17.0, 9.0 / 17.0, 3.0 / 17.0, 11.0 / 17.0,
|
||||
13.0 / 17.0, 5.0 / 17.0, 15.0 / 17.0, 7.0 / 17.0,
|
||||
4.0 / 17.0, 12.0 / 17.0, 2.0 / 17.0, 10.0 / 17.0,
|
||||
16.0 / 17.0, 8.0 / 17.0, 14.0 / 17.0, 6.0 / 17.0
|
||||
);
|
||||
|
||||
alpha = clamp(alpha - 0.5 * thresholdMatrix[int(mod(gl_FragCoord.x, 4.0))][int(mod(gl_FragCoord.y, 4.0))], 0.0, 1.0);
|
||||
|
||||
if (alpha < alphaThreshold)
|
||||
discard;
|
||||
}
|
||||
}
|
||||
76
data/shaders/Blur.comp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
layout (local_size_x = 16, local_size_y = 16) in;
|
||||
|
||||
layout (set = 0, binding = 0) uniform texture2D kTextures2D[];
|
||||
layout (set = 0, binding = 1) uniform sampler kSamplers[];
|
||||
|
||||
layout (set = 0, binding = 2, rgba8) uniform writeonly image2D kTextures2DOut[];
|
||||
|
||||
ivec2 textureBindlessSize2D(uint textureid) {
|
||||
return textureSize(nonuniformEXT(kTextures2D[textureid]), 0);
|
||||
}
|
||||
|
||||
vec4 textureBindless2D(uint textureid, vec2 uv) {
|
||||
return textureLod(nonuniformEXT(sampler2D(kTextures2D[textureid], kSamplers[0])), uv, 0);
|
||||
}
|
||||
|
||||
layout (constant_id = 0) const bool kIsHorizontal = true;
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
uint texDepth;
|
||||
uint texIn;
|
||||
uint texOut;
|
||||
float depthThreshold;
|
||||
} pc;
|
||||
|
||||
const int kFilterSize = 17;
|
||||
|
||||
// https://drdesten.github.io/web/tools/gaussian_kernel/
|
||||
const float gaussWeights[kFilterSize] = float[](
|
||||
0.00001525878906,
|
||||
0.0002441406250,
|
||||
0.001831054688,
|
||||
0.008544921875,
|
||||
0.02777099609,
|
||||
0.06665039063,
|
||||
0.1221923828,
|
||||
0.1745605469,
|
||||
0.1963806152,
|
||||
0.1745605469,
|
||||
0.1221923828,
|
||||
0.06665039063,
|
||||
0.02777099609,
|
||||
0.008544921875,
|
||||
0.001831054688,
|
||||
0.0002441406250,
|
||||
0.00001525878906
|
||||
);
|
||||
|
||||
void main() {
|
||||
const vec2 size = textureBindlessSize2D(pc.texIn).xy;
|
||||
const vec2 xy = gl_GlobalInvocationID.xy;
|
||||
|
||||
if (xy.x > size.x || xy.y > size.y)
|
||||
return;
|
||||
|
||||
const vec2 texCoord = (gl_GlobalInvocationID.xy + vec2(0.5)) / size;
|
||||
|
||||
const float texScaler = 1.0 / (kIsHorizontal ? size.x : size.y);
|
||||
|
||||
vec3 c = vec3(0.0);
|
||||
|
||||
vec3 fragColor = textureBindless2D(pc.texIn, texCoord).rgb;
|
||||
float fragDepth = textureBindless2D(pc.texDepth, texCoord).r;
|
||||
|
||||
for ( int i = 0; i != kFilterSize; i++ ) {
|
||||
float offset = float(i - kFilterSize/2);
|
||||
vec2 uv = texCoord + texScaler * (kIsHorizontal ? vec2(offset, 0) : vec2(0, offset));
|
||||
vec3 color = textureBindless2D(pc.texIn, uv).rgb;
|
||||
float depth = textureBindless2D(pc.texDepth, uv).r;
|
||||
// bilateral blur
|
||||
float weight = clamp(abs(depth - fragDepth) * pc.depthThreshold, 0.0, 1.0);
|
||||
c += mix(color, fragColor, weight) * gaussWeights[i];
|
||||
}
|
||||
|
||||
imageStore(kTextures2DOut[pc.texOut], ivec2(xy), vec4(c, 1.0) );
|
||||
}
|
||||
13
data/shaders/Grid.frag
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
#version 460 core
|
||||
|
||||
#include <data/shaders/GridParameters.h>
|
||||
#include <data/shaders/GridCalculation.h>
|
||||
|
||||
layout (location=0) in vec2 uv;
|
||||
layout (location=1) in vec2 camPos;
|
||||
layout (location=0) out vec4 out_FragColor;
|
||||
|
||||
void main() {
|
||||
out_FragColor = gridColor(uv, camPos);
|
||||
}
|
||||
39
data/shaders/Grid.vert
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
#version 460 core
|
||||
|
||||
#include <data/shaders/GridParameters.h>
|
||||
|
||||
layout(push_constant) uniform PerFrameData {
|
||||
mat4 MVP;
|
||||
vec4 cameraPos;
|
||||
vec4 origin;
|
||||
};
|
||||
|
||||
layout (location=0) out vec2 uv;
|
||||
layout (location=1) out vec2 out_camPos;
|
||||
|
||||
const vec3 pos[4] = vec3[4](
|
||||
vec3(-1.0, 0.0, -1.0),
|
||||
vec3( 1.0, 0.0, -1.0),
|
||||
vec3( 1.0, 0.0, 1.0),
|
||||
vec3(-1.0, 0.0, 1.0)
|
||||
);
|
||||
|
||||
const int indices[6] = int[6](
|
||||
0, 1, 2, 2, 3, 0
|
||||
);
|
||||
|
||||
void main() {
|
||||
int idx = indices[gl_VertexIndex];
|
||||
vec3 position = pos[idx] * gridSize;
|
||||
|
||||
position.x += cameraPos.x;
|
||||
position.z += cameraPos.z;
|
||||
|
||||
position += origin.xyz;
|
||||
|
||||
out_camPos = cameraPos.xz;
|
||||
|
||||
gl_Position = MVP * vec4(position, 1.0);
|
||||
uv = position.xz;
|
||||
}
|
||||
54
data/shaders/GridCalculation.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
float log10(float x) {
|
||||
return log(x) / log(10.0);
|
||||
}
|
||||
|
||||
float satf(float x) {
|
||||
return clamp(x, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec2 satv(vec2 x) {
|
||||
return clamp(x, vec2(0.0), vec2(1.0));
|
||||
}
|
||||
|
||||
float max2(vec2 v) {
|
||||
return max(v.x, v.y);
|
||||
}
|
||||
|
||||
vec4 gridColor(vec2 uv, vec2 camPos) {
|
||||
vec2 dudv = vec2(
|
||||
length(vec2(dFdx(uv.x), dFdy(uv.x))),
|
||||
length(vec2(dFdx(uv.y), dFdy(uv.y)))
|
||||
);
|
||||
|
||||
float lodLevel = max(0.0, log10((length(dudv) * gridMinPixelsBetweenCells) / gridCellSize) + 1.0);
|
||||
float lodFade = fract(lodLevel);
|
||||
|
||||
// cell sizes for lod0, lod1 and lod2
|
||||
float lod0 = gridCellSize * pow(10.0, floor(lodLevel));
|
||||
float lod1 = lod0 * 10.0;
|
||||
float lod2 = lod1 * 10.0;
|
||||
|
||||
// each anti-aliased line covers up to 4 pixels
|
||||
dudv *= 4.0;
|
||||
|
||||
// set grid coordinates to the centers of anti-aliased lines for subsequent alpha calculations
|
||||
uv += dudv * 0.5;
|
||||
|
||||
// calculate absolute distances to cell line centers for each lod and pick max X/Y to get coverage alpha value
|
||||
float lod0a = max2( vec2(1.0) - abs(satv(mod(uv, lod0) / dudv) * 2.0 - vec2(1.0)) );
|
||||
float lod1a = max2( vec2(1.0) - abs(satv(mod(uv, lod1) / dudv) * 2.0 - vec2(1.0)) );
|
||||
float lod2a = max2( vec2(1.0) - abs(satv(mod(uv, lod2) / dudv) * 2.0 - vec2(1.0)) );
|
||||
|
||||
uv -= camPos;
|
||||
|
||||
// blend between falloff colors to handle LOD transition
|
||||
vec4 c = lod2a > 0.0 ? gridColorThick : lod1a > 0.0 ? mix(gridColorThick, gridColorThin, lodFade) : gridColorThin;
|
||||
|
||||
// calculate opacity falloff based on distance to grid extents
|
||||
float opacityFalloff = (1.0 - satf(length(uv) / gridSize));
|
||||
|
||||
// blend between LOD level alphas and scale with opacity falloff
|
||||
c.a *= (lod2a > 0.0 ? lod2a : lod1a > 0.0 ? lod1a : (lod0a * (1.0-lodFade))) * opacityFalloff;
|
||||
|
||||
return c;
|
||||
}
|
||||
14
data/shaders/GridParameters.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// extents of grid in world coordinates
|
||||
float gridSize = 100.0;
|
||||
|
||||
// size of one cell
|
||||
float gridCellSize = 0.025;
|
||||
|
||||
// color of thin lines
|
||||
vec4 gridColorThin = vec4(0.5, 0.5, 0.5, 1.0);
|
||||
|
||||
// color of thick lines (every tenth line)
|
||||
vec4 gridColorThick = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
// minimum number of pixels between cell lines before LOD switch should occur.
|
||||
const float gridMinPixelsBetweenCells = 2.0;
|
||||
12
data/shaders/Quad.frag
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
//
|
||||
|
||||
layout (location=0) in vec2 uv;
|
||||
layout (location=0) out vec4 out_FragColor;
|
||||
|
||||
layout(push_constant) uniform PerFrameData {
|
||||
uint textureId;
|
||||
};
|
||||
|
||||
void main() {
|
||||
out_FragColor = textureBindless2D(textureId, 0, uv);
|
||||
};
|
||||
11
data/shaders/Quad.vert
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
#version 460
|
||||
|
||||
layout (location=0) out vec2 uv;
|
||||
|
||||
// https://www.saschawillems.de/blog/2016/08/13/vulkan-tutorial-on-rendering-a-fullscreen-quad-without-buffers/
|
||||
void main() {
|
||||
uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
|
||||
gl_Position = vec4(uv * 2.0 + -1.0, 0.0, 1.0);
|
||||
}
|
||||
11
data/shaders/QuadFlip.vert
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
#version 460
|
||||
|
||||
layout (location=0) out vec2 uv;
|
||||
|
||||
// https://www.saschawillems.de/blog/2016/08/13/vulkan-tutorial-on-rendering-a-fullscreen-quad-without-buffers/
|
||||
void main() {
|
||||
uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
|
||||
gl_Position = vec4(uv * vec2(2, -2) + vec2(-1, 1), 0.0, 1.0);
|
||||
}
|
||||
19
data/shaders/Shadow.sp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
|
||||
float PCF3x3(vec3 uvw, uint textureid, uint samplerid) {
|
||||
float size = 1.0 / textureBindlessSize2D(textureid).x; // assume square texture
|
||||
float shadow = 0.0;
|
||||
for (int v=-1; v<=+1; v++)
|
||||
for (int u=-1; u<=+1; u++)
|
||||
shadow += textureBindless2DShadow(textureid, samplerid, uvw + size * vec3(u, v, 0));
|
||||
return shadow / 9;
|
||||
}
|
||||
|
||||
float shadow(vec4 s, uint textureid, uint samplerid) {
|
||||
s = s / s.w;
|
||||
if (s.z > -1.0 && s.z < 1.0) {
|
||||
float shadowSample = PCF3x3(vec3(s.x, 1.0 - s.y, s.z), textureid, samplerid);
|
||||
return mix(0.3, 1.0, shadowSample);
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
42
data/shaders/UtilsPBR.sp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
|
||||
const float M_PI = 3.141592653589793;
|
||||
|
||||
vec4 SRGBtoLINEAR(vec4 srgbIn) {
|
||||
vec3 linOut = pow(srgbIn.xyz,vec3(2.2));
|
||||
|
||||
return vec4(linOut, srgbIn.a);
|
||||
}
|
||||
|
||||
// http://www.thetenthplanet.de/archives/1180
|
||||
// modified to fix handedness of the resulting cotangent frame
|
||||
mat3 cotangentFrame( vec3 N, vec3 p, vec2 uv ) {
|
||||
// get edge vectors of the pixel triangle
|
||||
vec3 dp1 = dFdx( p );
|
||||
vec3 dp2 = dFdy( p );
|
||||
vec2 duv1 = dFdx( uv );
|
||||
vec2 duv2 = dFdy( uv );
|
||||
|
||||
// solve the linear system
|
||||
vec3 dp2perp = cross( dp2, N );
|
||||
vec3 dp1perp = cross( N, dp1 );
|
||||
vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;
|
||||
vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;
|
||||
|
||||
// construct a scale-invariant frame
|
||||
float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) );
|
||||
|
||||
// calculate handedness of the resulting cotangent frame
|
||||
float w = (dot(cross(N, T), B) < 0.0) ? -1.0 : 1.0;
|
||||
|
||||
// adjust tangent if needed
|
||||
T = T * w;
|
||||
|
||||
return mat3( T * invmax, B * invmax, N );
|
||||
}
|
||||
|
||||
vec3 perturbNormal(vec3 n, vec3 v, vec3 normalSample, vec2 uv) {
|
||||
vec3 map = normalize( 2.0 * normalSample - vec3(1.0) );
|
||||
mat3 TBN = cotangentFrame(n, v, uv);
|
||||
return normalize(TBN * map);
|
||||
}
|
||||
635
data/shaders/gltf/PBR.sp
Normal file
|
|
@ -0,0 +1,635 @@
|
|||
// Based on: https://github.com/KhronosGroup/glTF-WebGL-PBR/blob/master/shaders/pbr-frag.glsl
|
||||
|
||||
// Encapsulate the various inputs used by the various functions in the shading equation
|
||||
// We store values in this struct to simplify the integration of alternative implementations
|
||||
// of the shading terms, outlined in the Readme.MD Appendix.
|
||||
|
||||
struct PBRInfo {
|
||||
// geometry properties
|
||||
float NdotL; // cos angle between normal and light direction
|
||||
float NdotV; // cos angle between normal and view direction
|
||||
float NdotH; // cos angle between normal and half vector
|
||||
float LdotH; // cos angle between light direction and half vector
|
||||
float VdotH; // cos angle between view direction and half vector
|
||||
|
||||
// Normal
|
||||
vec3 n; // Sahding normal
|
||||
vec3 ng; // Geometry normal
|
||||
vec3 t; // Geometry tangent
|
||||
vec3 b; // Geometry bitangent
|
||||
|
||||
vec3 v; // vector from surface point to camera
|
||||
|
||||
// material properties
|
||||
float perceptualRoughness; // roughness value, as authored by the model creator (input to shader)
|
||||
vec3 reflectance0; // full reflectance color (normal incidence angle)
|
||||
vec3 reflectance90; // reflectance color at grazing angle
|
||||
float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2])
|
||||
vec3 diffuseColor; // color contribution from diffuse lighting
|
||||
vec3 specularColor; // color contribution from specular lighting
|
||||
|
||||
vec4 baseColor;
|
||||
float metallic;
|
||||
|
||||
float sheenRoughnessFactor;
|
||||
vec3 sheenColorFactor;
|
||||
|
||||
vec3 clearcoatF0;
|
||||
vec3 clearcoatF90;
|
||||
float clearcoatFactor;
|
||||
vec3 clearcoatNormal;
|
||||
float clearcoatRoughness;
|
||||
|
||||
// KHR_materials_specular
|
||||
float specularWeight; // product of specularFactor and specularTexture.a
|
||||
|
||||
float transmissionFactor;
|
||||
|
||||
float thickness;
|
||||
vec4 attenuation; // rgb - color, w - distance
|
||||
|
||||
// KHR_materials_iridescence
|
||||
float iridescenceFactor;
|
||||
float iridescenceIor;
|
||||
float iridescenceThickness;
|
||||
|
||||
// KHR_materials_anisotropy
|
||||
vec3 anisotropicT;
|
||||
vec3 anisotropicB;
|
||||
float anisotropyStrength;
|
||||
|
||||
float ior;
|
||||
};
|
||||
|
||||
const float M_PI = 3.141592653589793;
|
||||
|
||||
vec4 SRGBtoLINEAR(vec4 srgbIn) {
|
||||
vec3 linOut = pow(srgbIn.xyz,vec3(2.2));
|
||||
|
||||
return vec4(linOut, srgbIn.a);
|
||||
}
|
||||
|
||||
float clampedDot(vec3 x, vec3 y) {
|
||||
return clamp(dot(x, y), 0.0, 1.0);
|
||||
}
|
||||
|
||||
//
|
||||
// Fresnel
|
||||
//
|
||||
// http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
|
||||
// https://github.com/wdas/brdf/tree/master/src/brdfs
|
||||
// https://google.github.io/filament/Filament.md.html
|
||||
//
|
||||
|
||||
// The following equation models the Fresnel reflectance term of the spec equation (aka F())
|
||||
// Implementation of fresnel from [4], Equation 15
|
||||
vec3 F_Schlick(vec3 f0, vec3 f90, float VdotH) {
|
||||
return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);
|
||||
}
|
||||
|
||||
float F_Schlick(float f0, float f90, float VdotH) {
|
||||
float x = clamp(1.0 - VdotH, 0.0, 1.0);
|
||||
float x2 = x * x;
|
||||
float x5 = x * x2 * x2;
|
||||
return f0 + (f90 - f0) * x5;
|
||||
}
|
||||
|
||||
float F_Schlick(float f0, float VdotH) {
|
||||
float f90 = 1.0; //clamp(50.0 * f0, 0.0, 1.0);
|
||||
return F_Schlick(f0, f90, VdotH);
|
||||
}
|
||||
|
||||
vec3 F_Schlick(vec3 f0, float f90, float VdotH) {
|
||||
float x = clamp(1.0 - VdotH, 0.0, 1.0);
|
||||
float x2 = x * x;
|
||||
float x5 = x * x2 * x2;
|
||||
return f0 + (f90 - f0) * x5;
|
||||
}
|
||||
|
||||
vec3 F_Schlick(vec3 f0, float VdotH) {
|
||||
float f90 = 1.0; //clamp(dot(f0, vec3(50.0 * 0.33)), 0.0, 1.0);
|
||||
return F_Schlick(f0, f90, VdotH);
|
||||
}
|
||||
|
||||
vec3 Schlick_to_F0(vec3 f, vec3 f90, float VdotH) {
|
||||
float x = clamp(1.0 - VdotH, 0.0, 1.0);
|
||||
float x2 = x * x;
|
||||
float x5 = clamp(x * x2 * x2, 0.0, 0.9999);
|
||||
|
||||
return (f - f90 * x5) / (1.0 - x5);
|
||||
}
|
||||
|
||||
float Schlick_to_F0(float f, float f90, float VdotH) {
|
||||
float x = clamp(1.0 - VdotH, 0.0, 1.0);
|
||||
float x2 = x * x;
|
||||
float x5 = clamp(x * x2 * x2, 0.0, 0.9999);
|
||||
|
||||
return (f - f90 * x5) / (1.0 - x5);
|
||||
}
|
||||
|
||||
vec3 Schlick_to_F0(vec3 f, float VdotH) {
|
||||
return Schlick_to_F0(f, vec3(1.0), VdotH);
|
||||
}
|
||||
|
||||
float Schlick_to_F0(float f, float VdotH) {
|
||||
return Schlick_to_F0(f, 1.0, VdotH);
|
||||
}
|
||||
|
||||
// Smith Joint GGX
|
||||
// Note: Vis = G / (4 * NdotL * NdotV)
|
||||
// see Eric Heitz. 2014. Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs. Journal of Computer Graphics Techniques, 3
|
||||
// see Real-Time Rendering. Page 331 to 336.
|
||||
// see https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf/geometricshadowing(specularg)
|
||||
float V_GGX(float NdotL, float NdotV, float alphaRoughness) {
|
||||
float alphaRoughnessSq = alphaRoughness * alphaRoughness;
|
||||
|
||||
float GGXV = NdotL * sqrt(NdotV * NdotV * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);
|
||||
float GGXL = NdotV * sqrt(NdotL * NdotL * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);
|
||||
|
||||
float GGX = GGXV + GGXL;
|
||||
|
||||
return GGX > 0.0 ? 0.5 / GGX : 0.0;
|
||||
}
|
||||
|
||||
|
||||
// The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D())
|
||||
// Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz
|
||||
// Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games [1], Equation 3.
|
||||
float D_GGX(float NdotH, float alphaRoughness) {
|
||||
float alphaRoughnessSq = alphaRoughness * alphaRoughness;
|
||||
float f = (NdotH * NdotH) * (alphaRoughnessSq - 1.0) + 1.0;
|
||||
return alphaRoughnessSq / (M_PI * f * f);
|
||||
}
|
||||
|
||||
// specularWeight is introduced with KHR_materials_specular
|
||||
vec3 getIBLRadianceLambertian(float NdotV, vec3 n, float roughness, vec3 diffuseColor, vec3 F0, float specularWeight, EnvironmentMapDataGPU envMap) {
|
||||
vec2 brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
|
||||
|
||||
vec2 f_ab = sampleBRDF_LUT(brdfSamplePoint, envMap).rg;
|
||||
|
||||
vec3 irradiance = sampleEnvMapIrradiance(n.xyz, envMap).rgb;
|
||||
|
||||
// see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
|
||||
// Roughness dependent fresnel, from Fdez-Aguera
|
||||
|
||||
vec3 Fr = max(vec3(1.0 - roughness), F0) - F0;
|
||||
vec3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0);
|
||||
vec3 FssEss = specularWeight * k_S * f_ab.x + f_ab.y; // <--- GGX / specular light contribution (scale it down if the specularWeight is low)
|
||||
|
||||
// Multiple scattering, from Fdez-Aguera
|
||||
float Ems = (1.0 - (f_ab.x + f_ab.y));
|
||||
vec3 F_avg = specularWeight * (F0 + (1.0 - F0) / 21.0);
|
||||
vec3 FmsEms = Ems * FssEss * F_avg / (1.0 - F_avg * Ems);
|
||||
vec3 k_D = diffuseColor * (1.0 - FssEss + FmsEms); // we use +FmsEms as indicated by the formula in the blog post (might be a typo in the implementation)
|
||||
|
||||
return (FmsEms + k_D) * irradiance;
|
||||
}
|
||||
|
||||
//https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB
|
||||
vec3 getBRDFLambertian(vec3 f0, vec3 f90, vec3 diffuseColor, float specularWeight, float VdotH) {
|
||||
// see https://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/
|
||||
return (1.0 - specularWeight * F_Schlick(f0, f90, VdotH)) * (diffuseColor / M_PI);
|
||||
}
|
||||
|
||||
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB
|
||||
vec3 getBRDFSpecularGGX(vec3 f0, vec3 f90, float alphaRoughness, float specularWeight, float VdotH, float NdotL, float NdotV, float NdotH) {
|
||||
vec3 F = F_Schlick(f0, f90, VdotH);
|
||||
float Vis = V_GGX(NdotL, NdotV, alphaRoughness);
|
||||
float D = D_GGX(NdotH, alphaRoughness);
|
||||
|
||||
return specularWeight * F * Vis * D;
|
||||
}
|
||||
|
||||
vec3 getIBLRadianceGGX(vec3 n, vec3 v, float roughness, vec3 F0, float specularWeight, EnvironmentMapDataGPU envMap ) {
|
||||
float NdotV = clampedDot(n, v);
|
||||
|
||||
float mipCount = float(sampleEnvMapQueryLevels(envMap));
|
||||
float lod = roughness * float(mipCount - 1);
|
||||
vec3 reflection = normalize(reflect(-v, n));
|
||||
|
||||
vec2 brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
|
||||
vec3 f_ab = sampleBRDF_LUT(brdfSamplePoint, envMap).rgb;
|
||||
vec3 specularLight = sampleEnvMapLod(reflection.xyz, lod, envMap).rgb;
|
||||
|
||||
// see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
|
||||
// Roughness dependent fresnel, from Fdez-Aguera
|
||||
vec3 Fr = max(vec3(1.0 - roughness), F0) - F0;
|
||||
vec3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0);
|
||||
vec3 FssEss = k_S * f_ab.x + f_ab.y;
|
||||
|
||||
return specularWeight * specularLight * FssEss;
|
||||
}
|
||||
|
||||
// Calculation of the lighting contribution from an optional Image Based Light source.
|
||||
// Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1].
|
||||
// See our README.md on Environment Maps [3] for additional discussion.
|
||||
vec3 getIBLRadianceContributionGGX(PBRInfo pbrInputs, float specularWeight, EnvironmentMapDataGPU envMap) {
|
||||
vec3 n = pbrInputs.n;
|
||||
vec3 v = pbrInputs.v;
|
||||
vec3 reflection = normalize(reflect(-v, n));
|
||||
float mipCount = float(sampleEnvMapQueryLevels(envMap));
|
||||
float lod = pbrInputs.perceptualRoughness * (mipCount - 1);
|
||||
|
||||
// retrieve a scale and bias to F0. See [1], Figure 3
|
||||
vec2 brdfSamplePoint = clamp(vec2(pbrInputs.NdotV, pbrInputs.perceptualRoughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
|
||||
vec3 brdf = sampleBRDF_LUT(brdfSamplePoint, envMap).rgb;
|
||||
// HDR envmaps are already linear
|
||||
vec3 specularLight = sampleEnvMapLod(reflection.xyz, lod, envMap).rgb;
|
||||
|
||||
// see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
|
||||
// Roughness dependent fresnel, from Fdez-Aguera
|
||||
vec3 Fr = max(vec3(1.0 - pbrInputs.perceptualRoughness), pbrInputs.reflectance0) - pbrInputs.reflectance0;
|
||||
vec3 k_S = pbrInputs.reflectance0 + Fr * pow(1.0 - pbrInputs.NdotV, 5.0);
|
||||
vec3 FssEss = k_S * brdf.x + brdf.y;
|
||||
|
||||
return specularWeight * specularLight * FssEss;
|
||||
}
|
||||
|
||||
|
||||
// Disney Implementation of diffuse from Physically-Based Shading at Disney by Brent Burley. See Section 5.3.
|
||||
// http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf
|
||||
vec3 diffuseBurley(PBRInfo pbrInputs) {
|
||||
float f90 = 2.0 * pbrInputs.LdotH * pbrInputs.LdotH * pbrInputs.alphaRoughness - 0.5;
|
||||
|
||||
return (pbrInputs.diffuseColor / M_PI) * (1.0 + f90 * pow((1.0 - pbrInputs.NdotL), 5.0)) * (1.0 + f90 * pow((1.0 - pbrInputs.NdotV), 5.0));
|
||||
}
|
||||
|
||||
// The following equation models the Fresnel reflectance term of the spec equation (aka F())
|
||||
// Implementation of fresnel from [4], Equation 15
|
||||
vec3 specularReflection(PBRInfo pbrInputs) {
|
||||
return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0);
|
||||
}
|
||||
|
||||
// This calculates the specular geometric attenuation (aka G()),
|
||||
// where rougher material will reflect less light back to the viewer.
|
||||
// This implementation is based on [1] Equation 4, and we adopt their modifications to
|
||||
// alphaRoughness as input as originally proposed in [2].
|
||||
float geometricOcclusion(PBRInfo pbrInputs) {
|
||||
float NdotL = pbrInputs.NdotL;
|
||||
float NdotV = pbrInputs.NdotV;
|
||||
float rSqr = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness;
|
||||
|
||||
float attenuationL = 2.0 * NdotL / (NdotL + sqrt(rSqr + (1.0 - rSqr) * (NdotL * NdotL)));
|
||||
float attenuationV = 2.0 * NdotV / (NdotV + sqrt(rSqr + (1.0 - rSqr) * (NdotV * NdotV)));
|
||||
return attenuationL * attenuationV;
|
||||
}
|
||||
|
||||
// The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D())
|
||||
// Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz
|
||||
// Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games [1], Equation 3.
|
||||
float microfacetDistribution(PBRInfo pbrInputs) {
|
||||
float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness;
|
||||
float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0;
|
||||
return roughnessSq / (M_PI * f * f);
|
||||
}
|
||||
|
||||
vec3 getIBLRadianceCharlie(PBRInfo pbrInputs, EnvironmentMapDataGPU envMap) {
|
||||
float sheenRoughness = pbrInputs.sheenRoughnessFactor;
|
||||
vec3 sheenColor = pbrInputs.sheenColorFactor;
|
||||
float mipCount = float(sampleEnvMapQueryLevels(envMap));
|
||||
float lod = sheenRoughness * float(mipCount - 1);
|
||||
vec3 reflection = normalize(reflect(-pbrInputs.v, pbrInputs.n));
|
||||
|
||||
vec2 brdfSamplePoint = clamp(vec2(pbrInputs.NdotV, sheenRoughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
|
||||
float brdf = sampleBRDF_LUT(brdfSamplePoint, envMap).b;
|
||||
vec3 sheenSample = sampleCharlieEnvMapLod(reflection.xyz, lod, envMap).rgb;
|
||||
|
||||
return sheenSample * sheenColor * brdf;
|
||||
}
|
||||
|
||||
PBRInfo calculatePBRInputsMetallicRoughness(InputAttributes tc, vec4 albedo, vec4 mrSample, MetallicRoughnessDataGPU mat) {
|
||||
PBRInfo pbrInputs;
|
||||
|
||||
bool isSpecularGlossiness = (getMaterialType(mat) & 2) != 0;
|
||||
bool isSpecular = (getMaterialType(mat) & 0x10) != 0;
|
||||
|
||||
pbrInputs.ior = getIOR(mat);
|
||||
vec3 f0 = isSpecularGlossiness ? getSpecularFactor(mat) * mrSample.rgb : vec3(pow((pbrInputs.ior - 1)/(pbrInputs.ior + 1), 2));
|
||||
|
||||
float metallic = getMetallicFactor(mat);
|
||||
metallic = mrSample.b * metallic;
|
||||
metallic = clamp(metallic, 0.0, 1.0);
|
||||
|
||||
pbrInputs.baseColor = albedo;
|
||||
pbrInputs.metallic = metallic;
|
||||
pbrInputs.specularWeight = 1.0;
|
||||
|
||||
if (isSpecular) {
|
||||
vec3 dielectricSpecularF0 = min(f0 * getSpecularColorFactor(tc, mat), vec3(1.0));
|
||||
f0 = mix(dielectricSpecularF0, pbrInputs.baseColor.rgb, metallic);
|
||||
pbrInputs.specularWeight = getSpecularFactor(tc, mat);//u_KHR_materials_specular_specularFactor * specularTexture.a;
|
||||
//pbrInputs.diffuseColor = mix(pbrInputs.baseColor.rgb, vec3(0), metallic);
|
||||
}
|
||||
|
||||
float perceptualRoughness = isSpecularGlossiness ? getGlossinessFactor(mat): getRoughnessFactor(mat);
|
||||
|
||||
const float c_MinRoughness = 0.04;
|
||||
|
||||
// Metallic roughness:
|
||||
// Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
|
||||
// This layout intentionally reserves the 'r' channel for (optional) occlusion map data
|
||||
// Specular Glossiness:
|
||||
// Glossiness is stored in alpha channel
|
||||
perceptualRoughness = isSpecularGlossiness ? 1.0 - mrSample.a * perceptualRoughness : clamp(mrSample.g * perceptualRoughness, c_MinRoughness, 1.0);
|
||||
|
||||
// Roughness is authored as perceptual roughness; as is convention,
|
||||
// convert to material roughness by squaring the perceptual roughness [2].
|
||||
float alphaRoughness = perceptualRoughness * perceptualRoughness;
|
||||
|
||||
vec3 diffuseColor = isSpecularGlossiness ? pbrInputs.baseColor.rgb * (1.0 - max(max(f0.r, f0.g), f0.b)) : mix(pbrInputs.baseColor.rgb, vec3(0), metallic);
|
||||
vec3 specularColor = isSpecularGlossiness ? f0 : mix(f0, pbrInputs.baseColor.rgb, metallic);
|
||||
|
||||
// Compute reflectance.
|
||||
float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
|
||||
|
||||
// For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
|
||||
// For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
|
||||
float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
|
||||
vec3 specularEnvironmentR0 = specularColor.rgb;
|
||||
vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;
|
||||
|
||||
pbrInputs.alphaRoughness = alphaRoughness;
|
||||
|
||||
pbrInputs.perceptualRoughness = perceptualRoughness;
|
||||
pbrInputs.reflectance0 = specularEnvironmentR0;
|
||||
pbrInputs.reflectance90 = specularEnvironmentR90;
|
||||
|
||||
pbrInputs.diffuseColor = diffuseColor;
|
||||
pbrInputs.specularColor = specularColor;
|
||||
|
||||
return pbrInputs;
|
||||
}
|
||||
|
||||
vec3 calculatePBRLightContribution( inout PBRInfo pbrInputs, vec3 lightDirection, vec3 lightColor ) {
|
||||
vec3 n = pbrInputs.n;
|
||||
vec3 v = pbrInputs.v;
|
||||
vec3 l = normalize(lightDirection); // Vector from surface point to light
|
||||
vec3 h = normalize(l+v); // Half vector between both l and v
|
||||
|
||||
float NdotV = pbrInputs.NdotV;
|
||||
float NdotL = clamp(dot(n, l), 0.001, 1.0);
|
||||
float NdotH = clamp(dot(n, h), 0.0, 1.0);
|
||||
float LdotH = clamp(dot(l, h), 0.0, 1.0);
|
||||
float VdotH = clamp(dot(v, h), 0.0, 1.0);
|
||||
|
||||
vec3 color = vec3(0);
|
||||
|
||||
if (NdotL > 0.0 || NdotV > 0.0) {
|
||||
pbrInputs.NdotL = NdotL;
|
||||
pbrInputs.NdotH = NdotH;
|
||||
pbrInputs.LdotH = LdotH;
|
||||
pbrInputs.VdotH = VdotH;
|
||||
|
||||
// Calculate the shading terms for the microfacet specular shading model
|
||||
vec3 F = specularReflection(pbrInputs);
|
||||
float G = geometricOcclusion(pbrInputs);
|
||||
float D = microfacetDistribution(pbrInputs);
|
||||
|
||||
// Calculation of analytical lighting contribution
|
||||
vec3 diffuseContrib = (1.0 - F) * diffuseBurley(pbrInputs);
|
||||
vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV);
|
||||
// Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law)
|
||||
color = NdotL * lightColor * (diffuseContrib + specContrib);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
// http://www.thetenthplanet.de/archives/1180
|
||||
// modified to fix handedness of the resulting cotangent frame
|
||||
mat3 cotangentFrame( vec3 N, vec3 p, vec2 uv, inout PBRInfo pbrInputs ) {
|
||||
// get edge vectors of the pixel triangle
|
||||
vec3 dp1 = dFdx( p );
|
||||
vec3 dp2 = dFdy( p );
|
||||
vec2 duv1 = dFdx( uv );
|
||||
vec2 duv2 = dFdy( uv );
|
||||
|
||||
if (length(duv1) <= 1e-2) {
|
||||
duv1 = vec2(1.0, 0.0);
|
||||
}
|
||||
|
||||
if (length(duv2) <= 1e-2) {
|
||||
duv2 = vec2(0.0, 1.0);
|
||||
}
|
||||
|
||||
// solve the linear system
|
||||
vec3 dp2perp = cross( dp2, N );
|
||||
vec3 dp1perp = cross( N, dp1 );
|
||||
vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;
|
||||
vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;
|
||||
|
||||
// construct a scale-invariant frame
|
||||
float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) );
|
||||
|
||||
// calculate handedness of the resulting cotangent frame
|
||||
float w = dot(cross(N, T), B) < 0.0 ? -1.0 : 1.0;
|
||||
|
||||
// adjust tangent if needed
|
||||
T = T * w;
|
||||
|
||||
if (gl_FrontFacing == false) {
|
||||
N *= -1.0f;
|
||||
T *= -1.0f;
|
||||
B *= -1.0f;
|
||||
}
|
||||
|
||||
pbrInputs.t = T * invmax;
|
||||
pbrInputs.b = B * invmax;
|
||||
pbrInputs.ng = N;
|
||||
|
||||
return mat3( pbrInputs.t, pbrInputs.b, N );
|
||||
}
|
||||
|
||||
void perturbNormal(vec3 n, vec3 v, vec3 normalSample, vec2 uv, inout PBRInfo pbrInputs) {
|
||||
vec3 map = normalize( 2.0 * normalSample - vec3(1.0) );
|
||||
mat3 TBN = cotangentFrame(n, v, uv, pbrInputs);
|
||||
|
||||
pbrInputs.n = normalize(TBN * map);
|
||||
}
|
||||
|
||||
// Check normals - model has tangents and a normal map!
|
||||
|
||||
vec3 getVolumeTransmissionRay(vec3 n, vec3 v, float thickness, float ior, mat4 modelMatrix) {
|
||||
// direction of refracted light
|
||||
vec3 refractionVector = refract(-v, n, 1.0 / ior);
|
||||
|
||||
// compute rotation-independent scaling of the model matrix
|
||||
vec3 modelScale = vec3(length(modelMatrix[0].xyz),
|
||||
length(modelMatrix[1].xyz),
|
||||
length(modelMatrix[2].xyz));
|
||||
|
||||
// the thickness is specified in local space
|
||||
return normalize(refractionVector) * thickness * modelScale.xyz;
|
||||
}
|
||||
|
||||
vec3 applyVolumeAttenuation(vec3 radiance, float transmissionDistance, vec3 attenuationColor, float attenuationDistance) {
|
||||
if (attenuationDistance == 0.0) {
|
||||
// Attenuation distance is +∞ (which we indicate by zero), i.e. the transmitted color is not attenuated at all.
|
||||
return radiance;
|
||||
}
|
||||
|
||||
// Compute light attenuation using Beer's law.
|
||||
vec3 attenuationCoefficient = -log(attenuationColor) / attenuationDistance;
|
||||
vec3 transmittance = exp(-attenuationCoefficient * transmissionDistance); // Beer's law
|
||||
return transmittance * radiance;
|
||||
}
|
||||
|
||||
float applyIorToRoughness(float roughness, float ior) {
|
||||
// Scale roughness with IOR so that an IOR of 1.0 results in no microfacet refraction and
|
||||
// an IOR of 1.5 results in the default amount of microfacet refraction.
|
||||
return roughness * clamp(ior * 2.0 - 2.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
|
||||
vec3 getTransmissionSample(vec2 fragCoord, float roughness, float ior) {
|
||||
const ivec2 size = textureBindlessSize2D(perFrame.transmissionFramebuffer);
|
||||
const vec2 uv = fragCoord;
|
||||
float framebufferLod = log2(float(size.x)) * applyIorToRoughness(roughness, ior);
|
||||
vec3 transmittedLight = textureBindless2DLod(perFrame.transmissionFramebuffer, perFrame.transmissionFramebufferSampler, uv, framebufferLod).rgb;
|
||||
// DEBUG:
|
||||
// return vec3(uv, 0.0);
|
||||
return transmittedLight;
|
||||
}
|
||||
|
||||
vec3 getIBLVolumeRefraction(vec3 n, vec3 v, float perceptualRoughness, vec3 baseColor, vec3 f0, vec3 f90,
|
||||
vec3 position, mat4 modelMatrix, mat4 viewProjMatrix, float ior, float thickness, vec3 attenuationColor, float attenuationDistance)
|
||||
{
|
||||
vec3 transmissionRay = getVolumeTransmissionRay(n, v, thickness, ior, modelMatrix);
|
||||
vec3 refractedRayExit = position + transmissionRay;
|
||||
|
||||
// Project refracted vector on the framebuffer, while mapping to normalized device coordinates.
|
||||
vec4 ndcPos = viewProjMatrix * vec4(refractedRayExit, 1.0);
|
||||
vec2 refractionCoords = ndcPos.xy / ndcPos.w;
|
||||
refractionCoords += 1.0;
|
||||
refractionCoords /= 2.0;
|
||||
refractionCoords.y = 1.0- refractionCoords.y;
|
||||
|
||||
// Sample framebuffer to get pixel the refracted ray hits.
|
||||
vec3 transmittedLight = getTransmissionSample(refractionCoords, perceptualRoughness, ior);
|
||||
|
||||
vec3 attenuatedColor = applyVolumeAttenuation(transmittedLight, length(transmissionRay), attenuationColor, attenuationDistance);
|
||||
|
||||
// Sample GGX LUT to get the specular component.
|
||||
float NdotV = clampedDot(n, v);
|
||||
vec2 brdfSamplePoint = clamp(vec2(NdotV, perceptualRoughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
|
||||
vec2 brdf = sampleBRDF_LUT(brdfSamplePoint, getEnvironmentMap(getEnvironmentId())).rg;
|
||||
vec3 specularColor = f0 * brdf.x + f90 * brdf.y;
|
||||
|
||||
return (1.0 - specularColor) * attenuatedColor * baseColor;
|
||||
}
|
||||
|
||||
// https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_lights_punctual/README.md#range-property
|
||||
float getRangeAttenuation(float range, float distance) {
|
||||
if (range <= 0.0) {
|
||||
// negative range means unlimited
|
||||
return 1.0 / pow(distance, 2.0);
|
||||
}
|
||||
return max(min(1.0 - pow(distance / range, 4.0), 1.0), 0.0) / pow(distance, 2.0);
|
||||
}
|
||||
|
||||
// https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_lights_punctual/README.md#inner-and-outer-cone-angles
|
||||
float getSpotAttenuation(vec3 pointToLight, vec3 spotDirection, float outerConeCos, float innerConeCos) {
|
||||
float actualCos = dot(normalize(spotDirection), normalize(-pointToLight));
|
||||
|
||||
if (actualCos > outerConeCos) {
|
||||
if (actualCos < innerConeCos) {
|
||||
return smoothstep(outerConeCos, innerConeCos, actualCos);
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
vec3 getLightIntensity(Light light, vec3 pointToLight) {
|
||||
float rangeAttenuation = 1.0;
|
||||
float spotAttenuation = 1.0;
|
||||
|
||||
if (light.type != LightType_Directional) {
|
||||
rangeAttenuation = getRangeAttenuation(light.range, length(pointToLight));
|
||||
}
|
||||
if (light.type == LightType_Spot) {
|
||||
spotAttenuation = getSpotAttenuation(pointToLight, light.direction, light.outerConeCos, light.innerConeCos);
|
||||
}
|
||||
|
||||
return rangeAttenuation * spotAttenuation * light.intensity * light.color;
|
||||
}
|
||||
|
||||
// Estevez and Kulla http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
|
||||
float D_Charlie(float sheenRoughness, float NdotH) {
|
||||
sheenRoughness = max(sheenRoughness, 0.000001); //clamp (0,1]
|
||||
float alphaG = sheenRoughness * sheenRoughness;
|
||||
float invR = 1.0 / alphaG;
|
||||
float cos2h = NdotH * NdotH;
|
||||
float sin2h = 1.0 - cos2h;
|
||||
return (2.0 + invR) * pow(sin2h, invR * 0.5) / (2.0 * M_PI);
|
||||
}
|
||||
|
||||
float lambdaSheenNumericHelper(float x, float alphaG) {
|
||||
float oneMinusAlphaSq = (1.0 - alphaG) * (1.0 - alphaG);
|
||||
float a = mix(21.5473, 25.3245, oneMinusAlphaSq);
|
||||
float b = mix(3.82987, 3.32435, oneMinusAlphaSq);
|
||||
float c = mix(0.19823, 0.16801, oneMinusAlphaSq);
|
||||
float d = mix(-1.97760, -1.27393, oneMinusAlphaSq);
|
||||
float e = mix(-4.32054, -4.85967, oneMinusAlphaSq);
|
||||
return a / (1.0 + b * pow(x, c)) + d * x + e;
|
||||
}
|
||||
|
||||
float lambdaSheen(float cosTheta, float alphaG) {
|
||||
if (abs(cosTheta) < 0.5) {
|
||||
return exp(lambdaSheenNumericHelper(cosTheta, alphaG));
|
||||
}
|
||||
|
||||
return exp(2.0 * lambdaSheenNumericHelper(0.5, alphaG) - lambdaSheenNumericHelper(1.0 - cosTheta, alphaG));
|
||||
}
|
||||
|
||||
float V_Sheen(float NdotL, float NdotV, float sheenRoughness) {
|
||||
sheenRoughness = max(sheenRoughness, 0.000001); //clamp (0,1]
|
||||
float alphaG = sheenRoughness * sheenRoughness;
|
||||
|
||||
return clamp(1.0 / ((1.0 + lambdaSheen(NdotV, alphaG) + lambdaSheen(NdotL, alphaG)) * (4.0 * NdotV * NdotL)), 0.0, 1.0);
|
||||
}
|
||||
|
||||
// f_sheen
|
||||
vec3 getBRDFSpecularSheen(vec3 sheenColor, float sheenRoughness, float NdotL, float NdotV, float NdotH) {
|
||||
float sheenDistribution = D_Charlie(sheenRoughness, NdotH);
|
||||
float sheenVisibility = V_Sheen(NdotL, NdotV, sheenRoughness);
|
||||
return sheenColor * sheenDistribution * sheenVisibility;
|
||||
}
|
||||
|
||||
vec3 getPunctualRadianceSheen(vec3 sheenColor, float sheenRoughness, float NdotL, float NdotV, float NdotH) {
|
||||
return NdotL * getBRDFSpecularSheen(sheenColor, sheenRoughness, NdotL, NdotV, NdotH);
|
||||
}
|
||||
|
||||
// https://github.com/DassaultSystemes-Technology/dspbr-pt/blob/e7cfa6e9aab2b99065a90694e1f58564d675c1a4/packages/lib/shader/bsdfs/sheen.glsl#L16C1-L20C2
|
||||
float albedoSheenScalingFactor(float NdotV, float sheenRoughnessFactor) {
|
||||
float c = 1.0 - NdotV;
|
||||
float c3 = c * c * c;
|
||||
return 0.65584461 * c3 + 1.0 / (4.16526551 + exp(-7.97291361 * sqrt(sheenRoughnessFactor) + 6.33516894));
|
||||
}
|
||||
|
||||
float max3(vec3 v) {
|
||||
return max(max(v.x, v.y), v.z);
|
||||
}
|
||||
|
||||
vec3 getPunctualRadianceClearCoat(vec3 clearcoatNormal, vec3 v, vec3 l, vec3 h, float VdotH, vec3 f0, vec3 f90, float clearcoatRoughness) {
|
||||
float NdotL = clampedDot(clearcoatNormal, l);
|
||||
float NdotV = clampedDot(clearcoatNormal, v);
|
||||
float NdotH = clampedDot(clearcoatNormal, h);
|
||||
return NdotL * getBRDFSpecularGGX(f0, f90, clearcoatRoughness * clearcoatRoughness, 1.0, VdotH, NdotL, NdotV, NdotH);
|
||||
}
|
||||
|
||||
vec3 getPunctualRadianceTransmission(vec3 normal, vec3 view, vec3 pointToLight, float alphaRoughness, vec3 f0, vec3 f90, vec3 baseColor, float ior) {
|
||||
float transmissionRougness = applyIorToRoughness(alphaRoughness, ior);
|
||||
|
||||
vec3 n = normalize(normal); // Outward direction of surface point
|
||||
vec3 v = normalize(view); // Direction from surface point to view
|
||||
vec3 l = normalize(pointToLight);
|
||||
vec3 l_mirror = normalize(l + 2.0*n*dot(-l, n)); // Mirror light reflection vector on surface
|
||||
vec3 h = normalize(l_mirror + v); // Halfway vector between transmission light vector and v
|
||||
|
||||
float D = D_GGX(clamp(dot(n, h), 0.0, 1.0), transmissionRougness);
|
||||
vec3 F = F_Schlick(f0, f90, clamp(dot(v, h), 0.0, 1.0));
|
||||
float Vis = V_GGX(clamp(dot(n, l_mirror), 0.0, 1.0), clamp(dot(n, v), 0.0, 1.0), transmissionRougness);
|
||||
|
||||
// Transmission BTDF
|
||||
return (1.0 - F) * baseColor * D * Vis;
|
||||
}
|
||||
116
data/shaders/gltf/animation.comp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
//
|
||||
|
||||
#version 460
|
||||
#extension GL_EXT_buffer_reference : require
|
||||
#extension GL_EXT_scalar_block_layout : require
|
||||
|
||||
layout (local_size_x = 16, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
struct TransformsBuffer {
|
||||
uint mtxId;
|
||||
uint matId;
|
||||
uint nodeRef; // for CPU only
|
||||
uint meshRef; // for CPU only
|
||||
uint opaque; // for CPU only
|
||||
};
|
||||
|
||||
struct VertexSkinningData {
|
||||
vec4 pos;
|
||||
vec4 norm;
|
||||
uint bones[8];
|
||||
float weights[8];
|
||||
uint meshId;
|
||||
};
|
||||
|
||||
struct VertexData {
|
||||
vec3 pos;
|
||||
vec3 norm;
|
||||
vec4 color;
|
||||
vec4 uv;
|
||||
float padding[2];
|
||||
};
|
||||
|
||||
#define MAX_WEIGHTS 8
|
||||
|
||||
struct MorphState {
|
||||
uint meshId;
|
||||
uint morphTarget[MAX_WEIGHTS];
|
||||
float weights[MAX_WEIGHTS];
|
||||
};
|
||||
|
||||
layout(std430, buffer_reference) readonly buffer Matrices {
|
||||
mat4 matrix[];
|
||||
};
|
||||
|
||||
layout(scalar, buffer_reference) readonly buffer MorphStates {
|
||||
MorphState morphStates[];
|
||||
};
|
||||
|
||||
layout (scalar, buffer_reference) readonly buffer VertexSkinningBuffer {
|
||||
VertexSkinningData vertices[];
|
||||
};
|
||||
|
||||
layout (scalar, buffer_reference) writeonly buffer VertexBuffer {
|
||||
VertexData vertices[];
|
||||
};
|
||||
|
||||
layout (scalar, buffer_reference) readonly buffer MorphVertexBuffer {
|
||||
VertexData vertices[];
|
||||
};
|
||||
|
||||
layout(push_constant) uniform PerFrameData {
|
||||
Matrices matrices;
|
||||
MorphStates morphStates;
|
||||
MorphVertexBuffer morphTargets;
|
||||
VertexSkinningBuffer inBufferId;
|
||||
VertexBuffer outBufferId;
|
||||
uint numMorphStates;
|
||||
} pc;
|
||||
|
||||
void main()
|
||||
{
|
||||
// our vertex buffers are always padded to a 16-vertex boundary
|
||||
|
||||
uint index = gl_GlobalInvocationID.x;
|
||||
|
||||
VertexSkinningData inVtx = pc.inBufferId.vertices[index];
|
||||
vec4 inPos = vec4(inVtx.pos.xyz, 1.0);
|
||||
vec4 inNorm = vec4(inVtx.norm.xyz, 0.0);
|
||||
|
||||
// morphing
|
||||
if (inVtx.meshId < pc.numMorphStates) {
|
||||
MorphState ms = pc.morphStates.morphStates[inVtx.meshId];
|
||||
if (ms.meshId != ~0) {
|
||||
for (int m = 0; m != MAX_WEIGHTS; m++) {
|
||||
if (ms.weights[m] > 0) {
|
||||
VertexData mVtx = pc.morphTargets.vertices[ms.morphTarget[m] + index];
|
||||
inPos.xyz += mVtx.pos * ms.weights[m];
|
||||
inNorm.xyz += mVtx.norm * ms.weights[m];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vec4 pos = vec4(0);
|
||||
vec4 norm = vec4(0);
|
||||
|
||||
int i = 0;
|
||||
|
||||
// skinning
|
||||
for (; i != MAX_WEIGHTS; i++) {
|
||||
if (inVtx.bones[i] == ~0)
|
||||
break;
|
||||
|
||||
mat4 boneMat = pc.matrices.matrix[inVtx.bones[i]];
|
||||
pos += boneMat * inPos * inVtx.weights[i];
|
||||
norm += transpose(inverse(boneMat)) * inNorm * inVtx.weights[i];
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
pos.xyz = inPos.xyz;
|
||||
norm.xyz = inNorm.xyz;
|
||||
}
|
||||
|
||||
pc.outBufferId.vertices[index].pos = pos.xyz;
|
||||
pc.outBufferId.vertices[index].norm = normalize(norm.xyz);
|
||||
}
|
||||
51
data/shaders/gltf/common.sp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
|
||||
// gl_BaseInstance - transformId
|
||||
|
||||
layout(std430, buffer_reference) buffer Materials;
|
||||
layout(std430, buffer_reference) buffer Environments;
|
||||
layout(std430, buffer_reference) buffer Lights;
|
||||
|
||||
layout(std430, buffer_reference) buffer PerDrawData {
|
||||
mat4 model;
|
||||
mat4 view;
|
||||
mat4 proj;
|
||||
vec4 cameraPos;
|
||||
};
|
||||
|
||||
struct TransformsBuffer {
|
||||
uint mtxId;
|
||||
uint matId;
|
||||
uint nodeRef; // for CPU only
|
||||
uint meshRef; // for CPU only
|
||||
uint opaque; // for CPU only
|
||||
};
|
||||
|
||||
layout(std430, buffer_reference) readonly buffer Transforms {
|
||||
TransformsBuffer transforms[];
|
||||
};
|
||||
|
||||
layout(std430, buffer_reference) readonly buffer Matrices {
|
||||
mat4 matrix[];
|
||||
};
|
||||
|
||||
layout(push_constant) uniform PerFrameData {
|
||||
PerDrawData drawable;
|
||||
Materials materials;
|
||||
Environments environments;
|
||||
Lights lights;
|
||||
Transforms transforms;
|
||||
Matrices matrices;
|
||||
uint envId;
|
||||
uint transmissionFramebuffer;
|
||||
uint transmissionFramebufferSampler;
|
||||
uint lightsCount;
|
||||
} perFrame;
|
||||
|
||||
uint getEnvironmentId() {
|
||||
return perFrame.envId;
|
||||
}
|
||||
|
||||
mat4 getViewProjection() {
|
||||
return perFrame.drawable.proj * perFrame.drawable.view;
|
||||
}
|
||||
67
data/shaders/gltf/common_material.sp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
|
||||
struct MetallicRoughnessDataGPU {
|
||||
vec4 baseColorFactor;
|
||||
vec4 metallicRoughnessNormalOcclusion; // Packed metallicFactor, roughnessFactor, normalScale, occlusionStrength
|
||||
vec4 specularGlossiness; // Packed specularFactor.xyz, glossiness
|
||||
vec4 sheenFactors;
|
||||
vec4 clearcoatTransmissionThickness;
|
||||
vec4 specularFactors;
|
||||
vec4 attenuation;
|
||||
vec4 emissiveFactorAlphaCutoff; // vec3 emissiveFactor + float AlphaCutoff
|
||||
uint occlusionTexture;
|
||||
uint occlusionTextureSampler;
|
||||
uint occlusionTextureUV;
|
||||
uint emissiveTexture;
|
||||
uint emissiveTextureSampler;
|
||||
uint emissiveTextureUV;
|
||||
uint baseColorTexture;
|
||||
uint baseColorTextureSampler;
|
||||
uint baseColorTextureUV;
|
||||
uint metallicRoughnessTexture;
|
||||
uint metallicRoughnessTextureSampler;
|
||||
uint metallicRoughnessTextureUV;
|
||||
uint normalTexture;
|
||||
uint normalTextureSampler;
|
||||
uint normalTextureUV;
|
||||
uint sheenColorTexture;
|
||||
uint sheenColorTextureSampler;
|
||||
uint sheenColorTextureUV;
|
||||
uint sheenRoughnessTexture;
|
||||
uint sheenRoughnessTextureSampler;
|
||||
uint sheenRoughnessTextureUV;
|
||||
uint clearCoatTexture;
|
||||
uint clearCoatTextureSampler;
|
||||
uint clearCoatTextureUV;
|
||||
uint clearCoatRoughnessTexture;
|
||||
uint clearCoatRoughnessTextureSampler;
|
||||
uint clearCoatRoughnessTextureUV;
|
||||
uint clearCoatNormalTexture;
|
||||
uint clearCoatNormalTextureSampler;
|
||||
uint clearCoatNormalTextureUV;
|
||||
uint specularTexture;
|
||||
uint specularTextureSampler;
|
||||
uint specularTextureUV;
|
||||
uint specularColorTexture;
|
||||
uint specularColorTextureSampler;
|
||||
uint specularColorTextureUV;
|
||||
uint transmissionTexture;
|
||||
uint transmissionTextureSampler;
|
||||
uint transmissionTextureUV;
|
||||
uint thicknessTexture;
|
||||
uint thicknessTextureSampler;
|
||||
uint thicknessTextureUV;
|
||||
uint iridescenceTexture;
|
||||
uint iridescenceTextureSampler;
|
||||
uint iridescenceTextureUV;
|
||||
uint iridescenceThicknessTexture;
|
||||
uint iridescenceThicknessTextureSampler;
|
||||
uint iridescenceThicknessTextureUV;
|
||||
uint anisotropyTexture;
|
||||
uint anisotropyTextureSampler;
|
||||
uint anisotropyTextureUV;
|
||||
uint alphaMode;
|
||||
uint materialType;
|
||||
float ior;
|
||||
uint padding[2];
|
||||
};
|
||||
229
data/shaders/gltf/inputs.frag
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
#include <data/shaders/gltf/common.sp>
|
||||
#include <data/shaders/gltf/common_material.sp>
|
||||
|
||||
const int kMaxAttributes = 2;
|
||||
|
||||
struct InputAttributes {
|
||||
vec2 uv[kMaxAttributes];
|
||||
};
|
||||
|
||||
struct Light {
|
||||
vec3 direction;
|
||||
float range;
|
||||
|
||||
vec3 color;
|
||||
float intensity;
|
||||
|
||||
vec3 position;
|
||||
float innerConeCos;
|
||||
|
||||
float outerConeCos;
|
||||
int type;
|
||||
int padding[2];
|
||||
};
|
||||
|
||||
const int LightType_Directional = 0;
|
||||
const int LightType_Point = 1;
|
||||
const int LightType_Spot = 2;
|
||||
|
||||
struct EnvironmentMapDataGPU {
|
||||
uint envMapTexture;
|
||||
uint envMapTextureSampler;
|
||||
uint envMapTextureIrradiance;
|
||||
uint envMapTextureIrradianceSampler;
|
||||
uint texBRDFLUT;
|
||||
uint texBRDFLUTSampler;
|
||||
uint envMapTextureCharlie;
|
||||
uint envMapTextureCharlieSampler;
|
||||
};
|
||||
|
||||
layout(std430, buffer_reference) readonly buffer Materials {
|
||||
MetallicRoughnessDataGPU material[];
|
||||
};
|
||||
|
||||
layout(std430, buffer_reference) readonly buffer Environments {
|
||||
EnvironmentMapDataGPU environment[];
|
||||
};
|
||||
|
||||
layout(std430, buffer_reference) readonly buffer Lights {
|
||||
Light lights[];
|
||||
};
|
||||
|
||||
MetallicRoughnessDataGPU getMaterial(uint idx) {
|
||||
return perFrame.materials.material[idx];
|
||||
}
|
||||
|
||||
EnvironmentMapDataGPU getEnvironmentMap(uint idx) {
|
||||
return perFrame.environments.environment[idx];
|
||||
}
|
||||
|
||||
float getMetallicFactor(MetallicRoughnessDataGPU mat) {
|
||||
return mat.metallicRoughnessNormalOcclusion.x;
|
||||
}
|
||||
|
||||
float getRoughnessFactor(MetallicRoughnessDataGPU mat) {
|
||||
return mat.metallicRoughnessNormalOcclusion.y;
|
||||
}
|
||||
|
||||
float getNormalScale(MetallicRoughnessDataGPU mat) {
|
||||
return mat.metallicRoughnessNormalOcclusion.z;
|
||||
}
|
||||
|
||||
float getOcclusionFactor(MetallicRoughnessDataGPU mat) {
|
||||
return mat.metallicRoughnessNormalOcclusion.w;
|
||||
}
|
||||
|
||||
uint getMaterialType(MetallicRoughnessDataGPU mat) {
|
||||
return mat.materialType;
|
||||
}
|
||||
|
||||
vec3 getSpecularFactor(MetallicRoughnessDataGPU mat) {
|
||||
return mat.specularGlossiness.xyz;
|
||||
}
|
||||
|
||||
float getGlossinessFactor(MetallicRoughnessDataGPU mat) {
|
||||
return mat.specularGlossiness.w;
|
||||
}
|
||||
|
||||
vec4 getEmissiveFactorAlphaCutoff(MetallicRoughnessDataGPU mat) {
|
||||
return mat.emissiveFactorAlphaCutoff;
|
||||
}
|
||||
|
||||
vec4 getSheenColorFactor(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return textureBindless2D(mat.sheenColorTexture, mat.sheenColorTextureSampler, tc.uv[mat.sheenColorTextureUV]) * vec4(mat.sheenFactors.xyz, 1.0f);
|
||||
}
|
||||
|
||||
float getSheenRoughnessFactor(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return textureBindless2D(mat.sheenRoughnessTexture, mat.sheenRoughnessTextureSampler, tc.uv[mat.sheenRoughnessTextureUV]).a * mat.sheenFactors.a;
|
||||
}
|
||||
|
||||
float getClearcoatFactor(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return textureBindless2D(mat.clearCoatTexture, mat.clearCoatTextureSampler, tc.uv[mat.clearCoatTextureUV]).r * mat.clearcoatTransmissionThickness.x;
|
||||
}
|
||||
|
||||
float getClearcoatRoughnessFactor(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return textureBindless2D(mat.clearCoatRoughnessTexture, mat.clearCoatRoughnessTextureSampler, tc.uv[mat.clearCoatRoughnessTextureUV]).g * mat.clearcoatTransmissionThickness.y;
|
||||
}
|
||||
|
||||
float getTransmissionFactor(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return textureBindless2D(mat.transmissionTexture, mat.transmissionTextureSampler, tc.uv[mat.transmissionTextureUV]).r * mat.clearcoatTransmissionThickness.z;
|
||||
}
|
||||
|
||||
float getVolumeTickness(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return textureBindless2D(mat.thicknessTexture, mat.thicknessTextureSampler, tc.uv[mat.thicknessTextureUV]).g * mat.clearcoatTransmissionThickness.w;
|
||||
}
|
||||
|
||||
vec4 getVolumeAttenuation(MetallicRoughnessDataGPU mat) {
|
||||
return mat.attenuation;
|
||||
}
|
||||
|
||||
float getIOR(MetallicRoughnessDataGPU mat) {
|
||||
return mat.ior;
|
||||
}
|
||||
|
||||
vec3 getSpecularColorFactor(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return textureBindless2D(mat.specularColorTexture, mat.specularColorTextureSampler, tc.uv[mat.specularColorTextureUV]).rgb * mat.specularFactors.rgb;
|
||||
}
|
||||
|
||||
float getSpecularFactor(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return textureBindless2D(mat.specularTexture, mat.specularTextureSampler, tc.uv[mat.specularTextureUV]).a * mat.specularFactors.a;
|
||||
}
|
||||
|
||||
vec2 getNormalUV(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return mat.normalTextureUV > -1 ? tc.uv[mat.normalTextureUV] : tc.uv[0];
|
||||
}
|
||||
|
||||
vec4 sampleAO(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return textureBindless2D(mat.occlusionTexture, mat.occlusionTextureSampler, tc.uv[mat.occlusionTextureUV]);
|
||||
}
|
||||
|
||||
vec4 sampleEmissive(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
vec2 uv = mat.emissiveTextureUV > -1 ? tc.uv[mat.emissiveTextureUV] : tc.uv[0];
|
||||
return textureBindless2D(mat.emissiveTexture, mat.emissiveTextureSampler, uv) * vec4(mat.emissiveFactorAlphaCutoff.xyz, 1.0f);
|
||||
}
|
||||
|
||||
vec4 sampleAlbedo(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return textureBindless2D(mat.baseColorTexture, mat.baseColorTextureSampler, tc.uv[mat.baseColorTextureUV]) * mat.baseColorFactor;
|
||||
}
|
||||
|
||||
vec4 sampleMetallicRoughness(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return textureBindless2D(mat.metallicRoughnessTexture, mat.metallicRoughnessTextureSampler, tc.uv[mat.metallicRoughnessTextureUV]);
|
||||
}
|
||||
|
||||
vec4 sampleNormal(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return textureBindless2D(mat.normalTexture, mat.normalTextureSampler, tc.uv[mat.normalTextureUV]);// * mat.metallicRoughnessNormalOcclusion.z;
|
||||
}
|
||||
|
||||
vec4 sampleClearcoatNormal(InputAttributes tc, MetallicRoughnessDataGPU mat) {
|
||||
return textureBindless2D(mat.clearCoatNormalTexture, mat.clearCoatNormalTextureSampler, tc.uv[mat.clearCoatNormalTextureUV]);
|
||||
}
|
||||
|
||||
vec4 sampleBRDF_LUT(vec2 tc, EnvironmentMapDataGPU map) {
|
||||
return textureBindless2D(map.texBRDFLUT, map.texBRDFLUTSampler, tc);
|
||||
}
|
||||
|
||||
vec4 sampleEnvMap(vec3 tc, EnvironmentMapDataGPU map) {
|
||||
return textureBindlessCube(map.envMapTexture, map.envMapTextureSampler, tc);
|
||||
}
|
||||
|
||||
vec4 sampleEnvMapLod(vec3 tc, float lod, EnvironmentMapDataGPU map) {
|
||||
return textureBindlessCubeLod(map.envMapTexture, map.envMapTextureSampler, tc, lod);
|
||||
}
|
||||
|
||||
vec4 sampleCharlieEnvMapLod(vec3 tc, float lod, EnvironmentMapDataGPU map) {
|
||||
return textureBindlessCubeLod(map.envMapTextureCharlie, map.envMapTextureCharlieSampler, tc, lod);
|
||||
}
|
||||
|
||||
vec4 sampleEnvMapIrradiance(vec3 tc, EnvironmentMapDataGPU map) {
|
||||
return textureBindlessCube(map.envMapTextureIrradiance, map.envMapTextureIrradianceSampler, tc);
|
||||
}
|
||||
|
||||
int sampleEnvMapQueryLevels(EnvironmentMapDataGPU map) {
|
||||
return textureBindlessQueryLevelsCube(map.envMapTexture);
|
||||
}
|
||||
|
||||
vec4 sampleTransmissionFramebuffer(vec2 tc) {
|
||||
return textureBindless2D(perFrame.transmissionFramebuffer, perFrame.transmissionFramebufferSampler, tc);
|
||||
}
|
||||
|
||||
bool isMaterialTypeSheen(MetallicRoughnessDataGPU mat) {
|
||||
return (getMaterialType(mat) & 0x4) != 0;
|
||||
}
|
||||
|
||||
bool isMaterialTypeClearCoat(MetallicRoughnessDataGPU mat) {
|
||||
return (getMaterialType(mat) & 0x8) != 0;
|
||||
}
|
||||
|
||||
bool isMaterialTypeSpecular(MetallicRoughnessDataGPU mat) {
|
||||
return (getMaterialType(mat) & 0x10) != 0;
|
||||
}
|
||||
|
||||
bool isMaterialTypeTransmission(MetallicRoughnessDataGPU mat) {
|
||||
return (getMaterialType(mat) & 0x20) != 0;
|
||||
}
|
||||
|
||||
bool isMaterialTypeVolume(MetallicRoughnessDataGPU mat) {
|
||||
return (getMaterialType(mat) & 0x40) != 0;
|
||||
}
|
||||
|
||||
bool isMaterialTypeUnlit(MetallicRoughnessDataGPU mat) {
|
||||
return (getMaterialType(mat) & 0x80) != 0;
|
||||
}
|
||||
|
||||
|
||||
uint getLightsCount() {
|
||||
return perFrame.lightsCount;
|
||||
}
|
||||
|
||||
Light getLight(uint i) {
|
||||
return perFrame.lights.lights[i];
|
||||
}
|
||||
|
||||
mat4 getModel() {
|
||||
uint mtxId = perFrame.transforms.transforms[oBaseInstance].mtxId;
|
||||
return perFrame.drawable.model * perFrame.matrices.matrix[mtxId];
|
||||
}
|
||||
|
||||
uint getMaterialId() {
|
||||
return perFrame.transforms.transforms[oBaseInstance].matId;
|
||||
}
|
||||
28
data/shaders/gltf/inputs.vert
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#include <data/shaders/gltf/common.sp>
|
||||
|
||||
layout (location = 0) in vec3 pos;
|
||||
layout (location = 1) in vec3 normal;
|
||||
layout (location = 2) in vec4 color;
|
||||
layout (location = 3) in vec2 uv0;
|
||||
layout (location = 4) in vec2 uv1;
|
||||
|
||||
vec3 getPosition() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
vec3 getNormal() {
|
||||
return normal;
|
||||
}
|
||||
|
||||
vec4 getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
vec2 getTexCoord(uint i) {
|
||||
return i == 0 ? uv0 : uv1;
|
||||
}
|
||||
|
||||
mat4 getModel() {
|
||||
uint mtxId = perFrame.transforms.transforms[gl_BaseInstance].mtxId;
|
||||
return perFrame.drawable.model * perFrame.matrices.matrix[mtxId];
|
||||
}
|
||||
216
data/shaders/gltf/main.frag
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
//
|
||||
|
||||
layout (location=0) in vec4 uv0uv1;
|
||||
layout (location=1) in vec3 normal;
|
||||
layout (location=2) in vec3 worldPos;
|
||||
layout (location=3) in vec4 color;
|
||||
layout (location=4) in flat int oBaseInstance;
|
||||
|
||||
layout (location=0) out vec4 out_FragColor;
|
||||
|
||||
#include <data/shaders/gltf/inputs.frag>
|
||||
#include <data/shaders/gltf/PBR.sp>
|
||||
|
||||
void main()
|
||||
{
|
||||
InputAttributes tc;
|
||||
tc.uv[0] = uv0uv1.xy;
|
||||
tc.uv[1] = uv0uv1.zw;
|
||||
|
||||
MetallicRoughnessDataGPU mat = getMaterial(getMaterialId());
|
||||
EnvironmentMapDataGPU envMap = getEnvironmentMap(getEnvironmentId());
|
||||
|
||||
vec4 Kd = sampleAlbedo(tc, mat) * color;
|
||||
|
||||
if ((mat.alphaMode == 1) && (mat.emissiveFactorAlphaCutoff.w > Kd.a)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
if (isMaterialTypeUnlit(mat)) {
|
||||
out_FragColor = Kd;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
vec4 Kao = sampleAO(tc, mat);
|
||||
vec4 Ke = sampleEmissive(tc, mat);
|
||||
vec4 mrSample = sampleMetallicRoughness(tc, mat);
|
||||
|
||||
|
||||
bool isSheen = isMaterialTypeSheen(mat);
|
||||
bool isClearCoat = isMaterialTypeClearCoat(mat);
|
||||
bool isSpecular = isMaterialTypeSpecular(mat);
|
||||
bool isTransmission = isMaterialTypeTransmission(mat);
|
||||
bool isVolume = isMaterialTypeVolume(mat);
|
||||
|
||||
vec3 n = normalize(normal);
|
||||
|
||||
PBRInfo pbrInputs = calculatePBRInputsMetallicRoughness(tc, Kd, mrSample, mat);
|
||||
pbrInputs.n = n;
|
||||
pbrInputs.ng = n;
|
||||
|
||||
if (mat.normalTexture != ~0) {
|
||||
vec3 normalSample = sampleNormal(tc, mat).xyz;
|
||||
perturbNormal(n, worldPos, normalSample, getNormalUV(tc, mat), pbrInputs);
|
||||
n = pbrInputs.n;
|
||||
}
|
||||
vec3 v = normalize(perFrame.drawable.cameraPos.xyz - worldPos); // Vector from surface point to camera
|
||||
|
||||
pbrInputs.v = v;
|
||||
pbrInputs.NdotV = clamp(abs(dot(pbrInputs.n, pbrInputs.v)), 0.001, 1.0);
|
||||
|
||||
if (isSheen) {
|
||||
pbrInputs.sheenColorFactor = getSheenColorFactor(tc, mat).rgb;
|
||||
pbrInputs.sheenRoughnessFactor = getSheenRoughnessFactor(tc, mat);
|
||||
}
|
||||
|
||||
vec3 clearCoatContrib = vec3(0);
|
||||
|
||||
if (isClearCoat) {
|
||||
pbrInputs.clearcoatFactor = getClearcoatFactor(tc, mat);
|
||||
pbrInputs.clearcoatRoughness = clamp(getClearcoatRoughnessFactor(tc, mat), 0.0, 1.0);
|
||||
pbrInputs.clearcoatF0 = vec3(pow((pbrInputs.ior - 1.0) / (pbrInputs.ior + 1.0), 2.0));
|
||||
pbrInputs.clearcoatF90 = vec3(1.0);
|
||||
|
||||
|
||||
if (mat.clearCoatNormalTextureUV>-1) {
|
||||
pbrInputs.clearcoatNormal = mat3(pbrInputs.t, pbrInputs.b, pbrInputs.ng) * sampleClearcoatNormal(tc, mat).rgb;
|
||||
} else {
|
||||
pbrInputs.clearcoatNormal =pbrInputs.ng;
|
||||
}
|
||||
clearCoatContrib = getIBLRadianceGGX(pbrInputs.clearcoatNormal, pbrInputs.v, pbrInputs.clearcoatRoughness, pbrInputs.clearcoatF0, 1.0, envMap);
|
||||
}
|
||||
|
||||
if (isTransmission) {
|
||||
pbrInputs.transmissionFactor = getTransmissionFactor(tc, mat);
|
||||
}
|
||||
|
||||
if (isVolume) {
|
||||
pbrInputs.thickness = getVolumeTickness(tc, mat);
|
||||
pbrInputs.attenuation = getVolumeAttenuation(mat);
|
||||
}
|
||||
|
||||
// IBL contribution
|
||||
vec3 specularColor = getIBLRadianceContributionGGX(pbrInputs, pbrInputs.specularWeight, envMap);
|
||||
vec3 diffuseColor = getIBLRadianceLambertian(pbrInputs.NdotV, n, pbrInputs.perceptualRoughness, pbrInputs.diffuseColor, pbrInputs.reflectance0, pbrInputs.specularWeight, envMap);
|
||||
|
||||
vec3 transmission = vec3(0,0,0);
|
||||
if (isTransmission) {
|
||||
transmission += getIBLVolumeRefraction(
|
||||
pbrInputs.n, pbrInputs.v,
|
||||
pbrInputs.perceptualRoughness,
|
||||
pbrInputs.diffuseColor, pbrInputs.reflectance0, pbrInputs.reflectance90,
|
||||
worldPos, getModel(), getViewProjection(),
|
||||
pbrInputs.ior, pbrInputs.thickness, pbrInputs.attenuation.rgb, pbrInputs.attenuation.w);
|
||||
}
|
||||
|
||||
vec3 sheenColor = vec3(0);
|
||||
|
||||
if (isSheen) {
|
||||
sheenColor += getIBLRadianceCharlie(pbrInputs, envMap);
|
||||
}
|
||||
|
||||
|
||||
vec3 lights_diffuse = vec3(0);
|
||||
vec3 lights_specular = vec3(0);
|
||||
vec3 lights_sheen = vec3(0);
|
||||
vec3 lights_clearcoat = vec3(0);
|
||||
vec3 lights_transmission = vec3(0);
|
||||
|
||||
float albedoSheenScaling = 1.0;
|
||||
|
||||
for (uint i = 0; i < getLightsCount(); ++i)
|
||||
{
|
||||
Light light = getLight(i);
|
||||
|
||||
vec3 pointToLight = (light.type == LightType_Directional) ? -light.direction : light.position - worldPos;
|
||||
|
||||
// BSTF
|
||||
vec3 l = normalize(pointToLight);
|
||||
vec3 h = normalize(l + v);
|
||||
float NdotL = clampedDot(n, l);
|
||||
float NdotV = clampedDot(n, v);
|
||||
float NdotH = clampedDot(n, h);
|
||||
float LdotH = clampedDot(l, h);
|
||||
float VdotH = clampedDot(v, h);
|
||||
if (NdotL > 0.0 || NdotV > 0.0)
|
||||
{
|
||||
// Calculation of analytical light
|
||||
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB
|
||||
vec3 intensity = getLightIntensity(light, pointToLight);
|
||||
|
||||
lights_diffuse += intensity * NdotL * getBRDFLambertian(pbrInputs.reflectance0, pbrInputs.reflectance90, pbrInputs.diffuseColor, pbrInputs.specularWeight, VdotH);
|
||||
lights_specular += intensity * NdotL * getBRDFSpecularGGX(pbrInputs.reflectance0, pbrInputs.reflectance90, pbrInputs.alphaRoughness, pbrInputs.specularWeight, VdotH, NdotL, NdotV, NdotH);
|
||||
|
||||
if (isSheen) {
|
||||
lights_sheen += intensity * getPunctualRadianceSheen(pbrInputs.sheenColorFactor, pbrInputs.sheenRoughnessFactor, NdotL, NdotV, NdotH);
|
||||
albedoSheenScaling = min(1.0 - max3(pbrInputs.sheenColorFactor) * albedoSheenScalingFactor(NdotV, pbrInputs.sheenRoughnessFactor),
|
||||
1.0 - max3(pbrInputs.sheenColorFactor) * albedoSheenScalingFactor(NdotL, pbrInputs.sheenRoughnessFactor));
|
||||
}
|
||||
|
||||
if (isClearCoat) {
|
||||
lights_clearcoat += intensity * getPunctualRadianceClearCoat(pbrInputs.clearcoatNormal, v, l, h, VdotH,
|
||||
pbrInputs.clearcoatF0, pbrInputs.clearcoatF90, pbrInputs.clearcoatRoughness);
|
||||
}
|
||||
}
|
||||
// BDTF
|
||||
if (isTransmission) {
|
||||
// If the light ray travels through the geometry, use the point it exits the geometry again.
|
||||
// That will change the angle to the light source, if the material refracts the light ray.
|
||||
vec3 transmissionRay = getVolumeTransmissionRay(n, v, pbrInputs.thickness, pbrInputs.ior, getModel());
|
||||
pointToLight -= transmissionRay;
|
||||
l = normalize(pointToLight);
|
||||
|
||||
vec3 intensity = getLightIntensity(light, pointToLight);
|
||||
vec3 transmittedLight = intensity * getPunctualRadianceTransmission(n, v, l, pbrInputs.alphaRoughness, pbrInputs.reflectance0, pbrInputs.clearcoatF90, pbrInputs.diffuseColor, pbrInputs.ior);
|
||||
|
||||
if (isVolume) {
|
||||
transmittedLight = applyVolumeAttenuation(transmittedLight, length(transmissionRay), pbrInputs.attenuation.rgb, pbrInputs.attenuation.w);
|
||||
}
|
||||
|
||||
lights_transmission += transmittedLight;
|
||||
}
|
||||
}
|
||||
|
||||
// ambient occlusion
|
||||
float occlusion = Kao.r < 0.01 ? 1.0 : Kao.r;
|
||||
float occlusionStrength = getOcclusionFactor(mat);
|
||||
diffuseColor = lights_diffuse + mix(diffuseColor, diffuseColor * occlusion, occlusionStrength);
|
||||
specularColor = lights_specular + mix(specularColor, specularColor * occlusion, occlusionStrength);
|
||||
sheenColor = lights_sheen + mix(sheenColor, sheenColor * occlusion, occlusionStrength);
|
||||
|
||||
vec3 emissiveColor = Ke.rgb * sampleEmissive(tc, mat).rgb;
|
||||
|
||||
vec3 clearcoatFresnel = vec3(0);
|
||||
if (isClearCoat) {
|
||||
clearcoatFresnel = F_Schlick(pbrInputs.clearcoatF0, pbrInputs.clearcoatF90, clampedDot(pbrInputs.clearcoatNormal, pbrInputs.v));
|
||||
}
|
||||
|
||||
if (isTransmission) {
|
||||
diffuseColor = mix(diffuseColor, transmission, pbrInputs.transmissionFactor);
|
||||
}
|
||||
|
||||
vec3 color = specularColor + diffuseColor + emissiveColor + sheenColor;
|
||||
color = color * (1.0 - pbrInputs.clearcoatFactor * clearcoatFresnel) + clearCoatContrib;
|
||||
|
||||
|
||||
color = pow(color, vec3(1.0/2.2));
|
||||
out_FragColor = vec4(color, 1.0);
|
||||
|
||||
// DEBUG
|
||||
// out_FragColor = vec4((n + vec3(1.0))*0.5, 1.0);
|
||||
// out_FragColor = vec4((pbrInputs.n + vec3(1.0))*0.5, 1.0);
|
||||
// out_FragColor = vec4((normal + vec3(1.0))*0.5, 1.0);
|
||||
// out_FragColor = Kao;
|
||||
// out_FragColor = Ke;
|
||||
// out_FragColor = Kd;
|
||||
// vec2 MeR = mrSample.yz;
|
||||
// MeR.x *= getMetallicFactor(mat);
|
||||
// MeR.y *= getRoughnessFactor(mat);
|
||||
// out_FragColor = vec4(MeR.y,MeR.y,MeR.y, 1.0);
|
||||
// out_FragColor = vec4(MeR.x,MeR.x,MeR.x, 1.0);
|
||||
// out_FragColor = mrSample;
|
||||
// out_FragColor = vec4(transmission, 1.0);
|
||||
// out_FragColor = vec4(punctualColor, 1.0);
|
||||
}
|
||||
|
||||
28
data/shaders/gltf/main.vert
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
|
||||
layout (location=0) out vec4 oUV0UV1;
|
||||
layout (location=1) out vec3 oNormal;
|
||||
layout (location=2) out vec3 oWorldPos;
|
||||
layout (location=3) out vec4 oColor;
|
||||
layout (location=4) out flat int oBaseInstance;
|
||||
|
||||
#include <data/shaders/gltf/inputs.vert>
|
||||
|
||||
void main() {
|
||||
mat4 model = getModel();
|
||||
mat4 MVP = getViewProjection() * model;
|
||||
|
||||
vec3 pos = getPosition();
|
||||
gl_Position = MVP * vec4(pos, 1.0);
|
||||
|
||||
oUV0UV1 = vec4(getTexCoord(0), getTexCoord(1));
|
||||
oColor = getColor();
|
||||
|
||||
mat3 normalMatrix = transpose( inverse(mat3(model)) );
|
||||
|
||||
oNormal = normalMatrix * getNormal();
|
||||
vec4 posClip = model * vec4(pos, 1.0);
|
||||
oWorldPos = posClip.xyz/posClip.w;
|
||||
|
||||
oBaseInstance = gl_BaseInstance;
|
||||
}
|
||||
BIN
data/wood.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |