mirror of
https://github.com/godotengine/godot.git
synced 2025-12-08 06:09:55 +00:00
Rewrite Radiance and Reflection probes to use Octahedral maps.
Co-authored-by: clayjohn <claynjohn@gmail.com>
This commit is contained in:
parent
25203e24c4
commit
c78c3ba894
48 changed files with 1513 additions and 1557 deletions
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "../oct_inc.glsl"
|
||||
|
||||
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
||||
|
||||
#define FLAG_HORIZONTAL (1 << 0)
|
||||
|
|
@ -35,16 +37,17 @@ layout(push_constant, std430) uniform Params {
|
|||
// DOF.
|
||||
float camera_z_far;
|
||||
float camera_z_near;
|
||||
uint pad2[2];
|
||||
// Octmap.
|
||||
vec2 octmap_border_size;
|
||||
|
||||
vec4 set_color;
|
||||
}
|
||||
params;
|
||||
|
||||
#ifdef MODE_CUBEMAP_ARRAY_TO_PANORAMA
|
||||
layout(set = 0, binding = 0) uniform samplerCubeArray source_color;
|
||||
#elif defined(MODE_CUBEMAP_TO_PANORAMA)
|
||||
layout(set = 0, binding = 0) uniform samplerCube source_color;
|
||||
#ifdef MODE_OCTMAP_ARRAY_TO_PANORAMA
|
||||
layout(set = 0, binding = 0) uniform sampler2DArray source_color;
|
||||
#elif defined(MODE_OCTMAP_TO_PANORAMA)
|
||||
layout(set = 0, binding = 0) uniform sampler2D source_color;
|
||||
#elif !defined(MODE_SET_COLOR)
|
||||
layout(set = 0, binding = 0) uniform sampler2D source_color;
|
||||
#endif
|
||||
|
|
@ -262,7 +265,7 @@ void main() {
|
|||
imageStore(dest_buffer, pos + params.target, color);
|
||||
#endif // MODE_LINEARIZE_DEPTH_COPY
|
||||
|
||||
#if defined(MODE_CUBEMAP_TO_PANORAMA) || defined(MODE_CUBEMAP_ARRAY_TO_PANORAMA)
|
||||
#if defined(MODE_OCTMAP_TO_PANORAMA) || defined(MODE_OCTMAP_ARRAY_TO_PANORAMA)
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
vec2 uv = vec2(pos) / vec2(params.section.zw);
|
||||
|
|
@ -277,13 +280,13 @@ void main() {
|
|||
normal.y = cos(theta);
|
||||
normal.z = cos(phi) * sin(theta) * -1.0;
|
||||
|
||||
#ifdef MODE_CUBEMAP_TO_PANORAMA
|
||||
vec4 color = textureLod(source_color, normal, params.camera_z_far); //the biggest the lod the least the acne
|
||||
#ifdef MODE_OCTMAP_TO_PANORAMA
|
||||
vec4 color = textureLod(source_color, vec3_to_oct_with_border(normal, params.octmap_border_size), params.camera_z_far); //the biggest the lod the least the acne
|
||||
#else
|
||||
vec4 color = textureLod(source_color, vec4(normal, params.camera_z_far), 0.0); //the biggest the lod the least the acne
|
||||
vec4 color = textureLod(source_color, vec3(vec3_to_oct_with_border(normal, params.octmap_border_size), params.camera_z_far), 0.0); //the biggest the lod the least the acne
|
||||
#endif
|
||||
imageStore(dest_buffer, pos + params.target, color * params.luminance_multiplier);
|
||||
#endif // defined(MODE_CUBEMAP_TO_PANORAMA) || defined(MODE_CUBEMAP_ARRAY_TO_PANORAMA)
|
||||
#endif // defined(MODE_OCTMAP_TO_PANORAMA) || defined(MODE_OCTMAP_ARRAY_TO_PANORAMA)
|
||||
|
||||
#ifdef MODE_SET_COLOR
|
||||
imageStore(dest_buffer, pos + params.target, params.set_color);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
#[vertex]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
layout(location = 0) out vec2 uv_interp;
|
||||
|
||||
void main() {
|
||||
vec2 base_arr[3] = vec2[](vec2(-1.0, -3.0), vec2(-1.0, 1.0), vec2(3.0, 1.0));
|
||||
uv_interp = base_arr[gl_VertexIndex];
|
||||
gl_Position = vec4(uv_interp, 0.0, 1.0);
|
||||
}
|
||||
|
||||
#[fragment]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "../oct_inc.glsl"
|
||||
|
||||
layout(location = 0) in vec2 uv_interp;
|
||||
layout(location = 0) out vec4 frag_color;
|
||||
|
||||
layout(set = 0, binding = 0) uniform samplerCube source_cube;
|
||||
|
||||
layout(push_constant, std430) uniform Params {
|
||||
float border_size;
|
||||
}
|
||||
params;
|
||||
|
||||
void main() {
|
||||
vec3 dir = oct_to_vec3_with_border(uv_interp * 0.5 + 0.5, params.border_size);
|
||||
frag_color = vec4(texture(source_cube, dir).rgb, 1.0);
|
||||
}
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
// Copyright 2016 Activision Publishing, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
// is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#[compute]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#define BLOCK_SIZE 8
|
||||
|
||||
layout(local_size_x = BLOCK_SIZE, local_size_y = BLOCK_SIZE, local_size_z = 1) in;
|
||||
|
||||
layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
|
||||
|
||||
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
|
||||
|
||||
#include "cubemap_downsampler_inc.glsl"
|
||||
|
||||
void main() {
|
||||
uvec3 id = gl_GlobalInvocationID;
|
||||
uint face_size = params.face_size;
|
||||
|
||||
if (id.x < face_size && id.y < face_size) {
|
||||
float inv_face_size = 1.0 / float(face_size);
|
||||
|
||||
float u0 = (float(id.x) * 2.0 + 1.0 - 0.75) * inv_face_size - 1.0;
|
||||
float u1 = (float(id.x) * 2.0 + 1.0 + 0.75) * inv_face_size - 1.0;
|
||||
|
||||
float v0 = (float(id.y) * 2.0 + 1.0 - 0.75) * -inv_face_size + 1.0;
|
||||
float v1 = (float(id.y) * 2.0 + 1.0 + 0.75) * -inv_face_size + 1.0;
|
||||
|
||||
float weights[4];
|
||||
weights[0] = calcWeight(u0, v0);
|
||||
weights[1] = calcWeight(u1, v0);
|
||||
weights[2] = calcWeight(u0, v1);
|
||||
weights[3] = calcWeight(u1, v1);
|
||||
|
||||
const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
weights[i] = weights[i] * wsum + .125;
|
||||
}
|
||||
|
||||
vec3 dir;
|
||||
vec4 color;
|
||||
switch (id.z) {
|
||||
case 0:
|
||||
get_dir_0(dir, u0, v0);
|
||||
color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
|
||||
|
||||
get_dir_0(dir, u1, v0);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
|
||||
|
||||
get_dir_0(dir, u0, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
|
||||
|
||||
get_dir_0(dir, u1, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
|
||||
break;
|
||||
case 1:
|
||||
get_dir_1(dir, u0, v0);
|
||||
color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
|
||||
|
||||
get_dir_1(dir, u1, v0);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
|
||||
|
||||
get_dir_1(dir, u0, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
|
||||
|
||||
get_dir_1(dir, u1, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
|
||||
break;
|
||||
case 2:
|
||||
get_dir_2(dir, u0, v0);
|
||||
color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
|
||||
|
||||
get_dir_2(dir, u1, v0);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
|
||||
|
||||
get_dir_2(dir, u0, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
|
||||
|
||||
get_dir_2(dir, u1, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
|
||||
break;
|
||||
case 3:
|
||||
get_dir_3(dir, u0, v0);
|
||||
color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
|
||||
|
||||
get_dir_3(dir, u1, v0);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
|
||||
|
||||
get_dir_3(dir, u0, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
|
||||
|
||||
get_dir_3(dir, u1, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
|
||||
break;
|
||||
case 4:
|
||||
get_dir_4(dir, u0, v0);
|
||||
color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
|
||||
|
||||
get_dir_4(dir, u1, v0);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
|
||||
|
||||
get_dir_4(dir, u0, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
|
||||
|
||||
get_dir_4(dir, u1, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
|
||||
break;
|
||||
default:
|
||||
get_dir_5(dir, u0, v0);
|
||||
color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
|
||||
|
||||
get_dir_5(dir, u1, v0);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
|
||||
|
||||
get_dir_5(dir, u0, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
|
||||
|
||||
get_dir_5(dir, u1, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
|
||||
break;
|
||||
}
|
||||
imageStore(dest_cubemap, ivec3(id), color);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
layout(push_constant, std430) uniform Params {
|
||||
uint face_size;
|
||||
uint face_id; // only used in raster shader
|
||||
}
|
||||
params;
|
||||
|
||||
#define M_PI 3.14159265359
|
||||
|
||||
void get_dir_0(out vec3 dir, in float u, in float v) {
|
||||
dir[0] = 1.0;
|
||||
dir[1] = v;
|
||||
dir[2] = -u;
|
||||
}
|
||||
|
||||
void get_dir_1(out vec3 dir, in float u, in float v) {
|
||||
dir[0] = -1.0;
|
||||
dir[1] = v;
|
||||
dir[2] = u;
|
||||
}
|
||||
|
||||
void get_dir_2(out vec3 dir, in float u, in float v) {
|
||||
dir[0] = u;
|
||||
dir[1] = 1.0;
|
||||
dir[2] = -v;
|
||||
}
|
||||
|
||||
void get_dir_3(out vec3 dir, in float u, in float v) {
|
||||
dir[0] = u;
|
||||
dir[1] = -1.0;
|
||||
dir[2] = v;
|
||||
}
|
||||
|
||||
void get_dir_4(out vec3 dir, in float u, in float v) {
|
||||
dir[0] = u;
|
||||
dir[1] = v;
|
||||
dir[2] = 1.0;
|
||||
}
|
||||
|
||||
void get_dir_5(out vec3 dir, in float u, in float v) {
|
||||
dir[0] = -u;
|
||||
dir[1] = v;
|
||||
dir[2] = -1.0;
|
||||
}
|
||||
|
||||
float calcWeight(float u, float v) {
|
||||
float val = u * u + v * v + 1.0;
|
||||
return val * sqrt(val);
|
||||
}
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
// Copyright 2016 Activision Publishing, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
// is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
/* clang-format off */
|
||||
#[vertex]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "cubemap_downsampler_inc.glsl"
|
||||
|
||||
layout(location = 0) out vec2 uv_interp;
|
||||
/* clang-format on */
|
||||
|
||||
void main() {
|
||||
vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
|
||||
gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
|
||||
uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0 * float(params.face_size); // saturate(x) * 2.0
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
#[fragment]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "cubemap_downsampler_inc.glsl"
|
||||
|
||||
layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
|
||||
|
||||
layout(location = 0) in vec2 uv_interp;
|
||||
layout(location = 0) out vec4 frag_color;
|
||||
/* clang-format on */
|
||||
|
||||
void main() {
|
||||
// Converted from compute shader which uses absolute coordinates.
|
||||
// Could possibly simplify this
|
||||
float face_size = float(params.face_size);
|
||||
float inv_face_size = 1.0 / face_size;
|
||||
vec2 id = floor(uv_interp);
|
||||
|
||||
float u1 = (id.x * 2.0 + 1.0 + 0.75) * inv_face_size - 1.0;
|
||||
float u0 = (id.x * 2.0 + 1.0 - 0.75) * inv_face_size - 1.0;
|
||||
|
||||
float v0 = (id.y * 2.0 + 1.0 - 0.75) * -inv_face_size + 1.0;
|
||||
float v1 = (id.y * 2.0 + 1.0 + 0.75) * -inv_face_size + 1.0;
|
||||
|
||||
float weights[4];
|
||||
weights[0] = calcWeight(u0, v0);
|
||||
weights[1] = calcWeight(u1, v0);
|
||||
weights[2] = calcWeight(u0, v1);
|
||||
weights[3] = calcWeight(u1, v1);
|
||||
|
||||
const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
weights[i] = weights[i] * wsum + .125;
|
||||
}
|
||||
|
||||
vec3 dir;
|
||||
vec4 color;
|
||||
switch (params.face_id) {
|
||||
case 0:
|
||||
get_dir_0(dir, u0, v0);
|
||||
color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
|
||||
|
||||
get_dir_0(dir, u1, v0);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
|
||||
|
||||
get_dir_0(dir, u0, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
|
||||
|
||||
get_dir_0(dir, u1, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
|
||||
break;
|
||||
case 1:
|
||||
get_dir_1(dir, u0, v0);
|
||||
color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
|
||||
|
||||
get_dir_1(dir, u1, v0);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
|
||||
|
||||
get_dir_1(dir, u0, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
|
||||
|
||||
get_dir_1(dir, u1, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
|
||||
break;
|
||||
case 2:
|
||||
get_dir_2(dir, u0, v0);
|
||||
color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
|
||||
|
||||
get_dir_2(dir, u1, v0);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
|
||||
|
||||
get_dir_2(dir, u0, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
|
||||
|
||||
get_dir_2(dir, u1, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
|
||||
break;
|
||||
case 3:
|
||||
get_dir_3(dir, u0, v0);
|
||||
color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
|
||||
|
||||
get_dir_3(dir, u1, v0);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
|
||||
|
||||
get_dir_3(dir, u0, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
|
||||
|
||||
get_dir_3(dir, u1, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
|
||||
break;
|
||||
case 4:
|
||||
get_dir_4(dir, u0, v0);
|
||||
color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
|
||||
|
||||
get_dir_4(dir, u1, v0);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
|
||||
|
||||
get_dir_4(dir, u0, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
|
||||
|
||||
get_dir_4(dir, u1, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
|
||||
break;
|
||||
default:
|
||||
get_dir_5(dir, u0, v0);
|
||||
color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
|
||||
|
||||
get_dir_5(dir, u1, v0);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
|
||||
|
||||
get_dir_5(dir, u0, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
|
||||
|
||||
get_dir_5(dir, u1, v1);
|
||||
color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
|
||||
break;
|
||||
}
|
||||
frag_color = color;
|
||||
}
|
||||
|
|
@ -1,329 +0,0 @@
|
|||
// Copyright 2016 Activision Publishing, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
// is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#[compute]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#define GROUP_SIZE 64
|
||||
|
||||
layout(local_size_x = GROUP_SIZE, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
|
||||
layout(rgba16f, set = 2, binding = 0) uniform restrict writeonly imageCube dest_cubemap0;
|
||||
layout(rgba16f, set = 2, binding = 1) uniform restrict writeonly imageCube dest_cubemap1;
|
||||
layout(rgba16f, set = 2, binding = 2) uniform restrict writeonly imageCube dest_cubemap2;
|
||||
layout(rgba16f, set = 2, binding = 3) uniform restrict writeonly imageCube dest_cubemap3;
|
||||
layout(rgba16f, set = 2, binding = 4) uniform restrict writeonly imageCube dest_cubemap4;
|
||||
layout(rgba16f, set = 2, binding = 5) uniform restrict writeonly imageCube dest_cubemap5;
|
||||
layout(rgba16f, set = 2, binding = 6) uniform restrict writeonly imageCube dest_cubemap6;
|
||||
|
||||
#ifdef USE_HIGH_QUALITY
|
||||
#define NUM_TAPS 32
|
||||
#else
|
||||
#define NUM_TAPS 8
|
||||
#endif
|
||||
|
||||
#define BASE_RESOLUTION 128
|
||||
|
||||
#ifdef USE_HIGH_QUALITY
|
||||
layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
|
||||
vec4[7][5][3][24] coeffs;
|
||||
}
|
||||
data;
|
||||
#else
|
||||
layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
|
||||
vec4[7][5][6] coeffs;
|
||||
}
|
||||
data;
|
||||
#endif
|
||||
|
||||
void get_dir(out vec3 dir, in vec2 uv, in uint face) {
|
||||
switch (face) {
|
||||
case 0:
|
||||
dir = vec3(1.0, uv[1], -uv[0]);
|
||||
break;
|
||||
case 1:
|
||||
dir = vec3(-1.0, uv[1], uv[0]);
|
||||
break;
|
||||
case 2:
|
||||
dir = vec3(uv[0], 1.0, -uv[1]);
|
||||
break;
|
||||
case 3:
|
||||
dir = vec3(uv[0], -1.0, uv[1]);
|
||||
break;
|
||||
case 4:
|
||||
dir = vec3(uv[0], uv[1], 1.0);
|
||||
break;
|
||||
default:
|
||||
dir = vec3(-uv[0], uv[1], -1.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
// INPUT:
|
||||
// id.x = the linear address of the texel (ignoring face)
|
||||
// id.y = the face
|
||||
// -> use to index output texture
|
||||
// id.x = texel x
|
||||
// id.y = texel y
|
||||
// id.z = face
|
||||
uvec3 id = gl_GlobalInvocationID;
|
||||
|
||||
// determine which texel this is
|
||||
#ifndef USE_TEXTURE_ARRAY
|
||||
// NOTE (macOS/MoltenVK): Do not rename, "level" variable name conflicts with the Metal "level(float lod)" mipmap sampling function name.
|
||||
int mip_level = 0;
|
||||
if (id.x < (128 * 128)) {
|
||||
mip_level = 0;
|
||||
} else if (id.x < (128 * 128 + 64 * 64)) {
|
||||
mip_level = 1;
|
||||
id.x -= (128 * 128);
|
||||
} else if (id.x < (128 * 128 + 64 * 64 + 32 * 32)) {
|
||||
mip_level = 2;
|
||||
id.x -= (128 * 128 + 64 * 64);
|
||||
} else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16)) {
|
||||
mip_level = 3;
|
||||
id.x -= (128 * 128 + 64 * 64 + 32 * 32);
|
||||
} else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8)) {
|
||||
mip_level = 4;
|
||||
id.x -= (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16);
|
||||
} else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8 + 4 * 4)) {
|
||||
mip_level = 5;
|
||||
id.x -= (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8);
|
||||
} else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8 + 4 * 4 + 2 * 2)) {
|
||||
mip_level = 6;
|
||||
id.x -= (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8 + 4 * 4);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
int res = BASE_RESOLUTION >> mip_level;
|
||||
#else // Using Texture Arrays so all levels are the same resolution
|
||||
int res = BASE_RESOLUTION;
|
||||
int mip_level = int(id.x / (BASE_RESOLUTION * BASE_RESOLUTION));
|
||||
id.x -= mip_level * BASE_RESOLUTION * BASE_RESOLUTION;
|
||||
#endif
|
||||
|
||||
// determine dir / pos for the texel
|
||||
vec3 dir, adir, frameZ;
|
||||
{
|
||||
id.z = id.y;
|
||||
id.y = id.x / res;
|
||||
id.x -= id.y * res;
|
||||
|
||||
vec2 uv;
|
||||
uv.x = (float(id.x) * 2.0 + 1.0) / float(res) - 1.0;
|
||||
uv.y = -(float(id.y) * 2.0 + 1.0) / float(res) + 1.0;
|
||||
|
||||
get_dir(dir, uv, id.z);
|
||||
frameZ = normalize(dir);
|
||||
|
||||
adir = abs(dir);
|
||||
}
|
||||
|
||||
// GGX gather colors
|
||||
vec4 color = vec4(0.0);
|
||||
for (int axis = 0; axis < 3; axis++) {
|
||||
const int otherAxis0 = 1 - (axis & 1) - (axis >> 1);
|
||||
const int otherAxis1 = 2 - (axis >> 1);
|
||||
|
||||
float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - .75) / .25;
|
||||
if (frameweight > 0.0) {
|
||||
// determine frame
|
||||
vec3 UpVector;
|
||||
switch (axis) {
|
||||
case 0:
|
||||
UpVector = vec3(1, 0, 0);
|
||||
break;
|
||||
case 1:
|
||||
UpVector = vec3(0, 1, 0);
|
||||
break;
|
||||
default:
|
||||
UpVector = vec3(0, 0, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
vec3 frameX = normalize(cross(UpVector, frameZ));
|
||||
vec3 frameY = cross(frameZ, frameX);
|
||||
|
||||
// calculate parametrization for polynomial
|
||||
float Nx = dir[otherAxis0];
|
||||
float Ny = dir[otherAxis1];
|
||||
float Nz = adir[axis];
|
||||
|
||||
float NmaxXY = max(abs(Ny), abs(Nx));
|
||||
Nx /= NmaxXY;
|
||||
Ny /= NmaxXY;
|
||||
|
||||
float theta;
|
||||
if (Ny < Nx) {
|
||||
if (Ny <= -0.999) {
|
||||
theta = Nx;
|
||||
} else {
|
||||
theta = Ny;
|
||||
}
|
||||
} else {
|
||||
if (Ny >= 0.999) {
|
||||
theta = -Nx;
|
||||
} else {
|
||||
theta = -Ny;
|
||||
}
|
||||
}
|
||||
|
||||
float phi;
|
||||
if (Nz <= -0.999) {
|
||||
phi = -NmaxXY;
|
||||
} else if (Nz >= 0.999) {
|
||||
phi = NmaxXY;
|
||||
} else {
|
||||
phi = Nz;
|
||||
}
|
||||
|
||||
float theta2 = theta * theta;
|
||||
float phi2 = phi * phi;
|
||||
|
||||
// sample
|
||||
for (int iSuperTap = 0; iSuperTap < NUM_TAPS / 4; iSuperTap++) {
|
||||
const int index = (NUM_TAPS / 4) * axis + iSuperTap;
|
||||
|
||||
#ifdef USE_HIGH_QUALITY
|
||||
vec4 coeffsDir0[3];
|
||||
vec4 coeffsDir1[3];
|
||||
vec4 coeffsDir2[3];
|
||||
vec4 coeffsLevel[3];
|
||||
vec4 coeffsWeight[3];
|
||||
|
||||
for (int iCoeff = 0; iCoeff < 3; iCoeff++) {
|
||||
coeffsDir0[iCoeff] = data.coeffs[mip_level][0][iCoeff][index];
|
||||
coeffsDir1[iCoeff] = data.coeffs[mip_level][1][iCoeff][index];
|
||||
coeffsDir2[iCoeff] = data.coeffs[mip_level][2][iCoeff][index];
|
||||
coeffsLevel[iCoeff] = data.coeffs[mip_level][3][iCoeff][index];
|
||||
coeffsWeight[iCoeff] = data.coeffs[mip_level][4][iCoeff][index];
|
||||
}
|
||||
|
||||
for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
|
||||
// determine sample attributes (dir, weight, mip_level)
|
||||
vec3 sample_dir = frameX * (coeffsDir0[0][iSubTap] + coeffsDir0[1][iSubTap] * theta2 + coeffsDir0[2][iSubTap] * phi2) + frameY * (coeffsDir1[0][iSubTap] + coeffsDir1[1][iSubTap] * theta2 + coeffsDir1[2][iSubTap] * phi2) + frameZ * (coeffsDir2[0][iSubTap] + coeffsDir2[1][iSubTap] * theta2 + coeffsDir2[2][iSubTap] * phi2);
|
||||
|
||||
float sample_level = coeffsLevel[0][iSubTap] + coeffsLevel[1][iSubTap] * theta2 + coeffsLevel[2][iSubTap] * phi2;
|
||||
|
||||
float sample_weight = coeffsWeight[0][iSubTap] + coeffsWeight[1][iSubTap] * theta2 + coeffsWeight[2][iSubTap] * phi2;
|
||||
#else
|
||||
vec4 coeffsDir0 = data.coeffs[mip_level][0][index];
|
||||
vec4 coeffsDir1 = data.coeffs[mip_level][1][index];
|
||||
vec4 coeffsDir2 = data.coeffs[mip_level][2][index];
|
||||
vec4 coeffsLevel = data.coeffs[mip_level][3][index];
|
||||
vec4 coeffsWeight = data.coeffs[mip_level][4][index];
|
||||
|
||||
for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
|
||||
// determine sample attributes (dir, weight, mip_level)
|
||||
vec3 sample_dir = frameX * coeffsDir0[iSubTap] + frameY * coeffsDir1[iSubTap] + frameZ * coeffsDir2[iSubTap];
|
||||
|
||||
float sample_level = coeffsLevel[iSubTap];
|
||||
|
||||
float sample_weight = coeffsWeight[iSubTap];
|
||||
#endif
|
||||
|
||||
sample_weight *= frameweight;
|
||||
|
||||
// adjust for jacobian
|
||||
sample_dir /= max(abs(sample_dir[0]), max(abs(sample_dir[1]), abs(sample_dir[2])));
|
||||
sample_level += 0.75 * log2(dot(sample_dir, sample_dir));
|
||||
#ifndef USE_TEXTURE_ARRAY
|
||||
sample_level += float(mip_level) / 6.0; // Hack to increase the perceived roughness and reduce upscaling artifacts
|
||||
#endif
|
||||
// sample cubemap
|
||||
color.xyz += textureLod(source_cubemap, normalize(sample_dir), sample_level).xyz * sample_weight;
|
||||
color.w += sample_weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
color /= color.w;
|
||||
|
||||
// write color
|
||||
color.xyz = max(vec3(0.0), color.xyz);
|
||||
color.w = 1.0;
|
||||
#ifdef USE_TEXTURE_ARRAY
|
||||
id.xy *= uvec2(2, 2);
|
||||
#endif
|
||||
|
||||
switch (mip_level) {
|
||||
case 0:
|
||||
imageStore(dest_cubemap0, ivec3(id), color);
|
||||
#ifdef USE_TEXTURE_ARRAY
|
||||
imageStore(dest_cubemap0, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
|
||||
imageStore(dest_cubemap0, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
|
||||
imageStore(dest_cubemap0, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
|
||||
#endif
|
||||
break;
|
||||
case 1:
|
||||
imageStore(dest_cubemap1, ivec3(id), color);
|
||||
#ifdef USE_TEXTURE_ARRAY
|
||||
imageStore(dest_cubemap1, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
|
||||
imageStore(dest_cubemap1, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
|
||||
imageStore(dest_cubemap1, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
|
||||
#endif
|
||||
break;
|
||||
case 2:
|
||||
imageStore(dest_cubemap2, ivec3(id), color);
|
||||
#ifdef USE_TEXTURE_ARRAY
|
||||
imageStore(dest_cubemap2, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
|
||||
imageStore(dest_cubemap2, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
|
||||
imageStore(dest_cubemap2, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
|
||||
#endif
|
||||
break;
|
||||
case 3:
|
||||
imageStore(dest_cubemap3, ivec3(id), color);
|
||||
#ifdef USE_TEXTURE_ARRAY
|
||||
imageStore(dest_cubemap3, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
|
||||
imageStore(dest_cubemap3, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
|
||||
imageStore(dest_cubemap3, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
|
||||
#endif
|
||||
break;
|
||||
case 4:
|
||||
imageStore(dest_cubemap4, ivec3(id), color);
|
||||
#ifdef USE_TEXTURE_ARRAY
|
||||
imageStore(dest_cubemap4, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
|
||||
imageStore(dest_cubemap4, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
|
||||
imageStore(dest_cubemap4, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
|
||||
#endif
|
||||
break;
|
||||
case 5:
|
||||
imageStore(dest_cubemap5, ivec3(id), color);
|
||||
#ifdef USE_TEXTURE_ARRAY
|
||||
imageStore(dest_cubemap5, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
|
||||
imageStore(dest_cubemap5, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
|
||||
imageStore(dest_cubemap5, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
imageStore(dest_cubemap6, ivec3(id), color);
|
||||
#ifdef USE_TEXTURE_ARRAY
|
||||
imageStore(dest_cubemap6, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
|
||||
imageStore(dest_cubemap6, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
|
||||
imageStore(dest_cubemap6, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
#[compute]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#define GROUP_SIZE 8
|
||||
|
||||
layout(local_size_x = GROUP_SIZE, local_size_y = GROUP_SIZE, local_size_z = 1) in;
|
||||
|
||||
layout(set = 0, binding = 0) uniform samplerCube source_cube;
|
||||
|
||||
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
|
||||
|
||||
#include "cubemap_roughness_inc.glsl"
|
||||
|
||||
void main() {
|
||||
uvec3 id = gl_GlobalInvocationID;
|
||||
id.z += params.face_id;
|
||||
|
||||
vec2 uv = ((vec2(id.xy) * 2.0 + 1.0) / (params.face_size) - 1.0);
|
||||
vec3 N = texelCoordToVec(uv, id.z);
|
||||
|
||||
if (params.use_direct_write) {
|
||||
imageStore(dest_cubemap, ivec3(id), vec4(texture(source_cube, N).rgb, 1.0));
|
||||
} else {
|
||||
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
float solid_angle_texel = 4.0 * M_PI / (6.0 * params.face_size * params.face_size);
|
||||
float roughness2 = params.roughness * params.roughness;
|
||||
float roughness4 = roughness2 * roughness2;
|
||||
vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
|
||||
mat3 T;
|
||||
T[0] = normalize(cross(UpVector, N));
|
||||
T[1] = cross(N, T[0]);
|
||||
T[2] = N;
|
||||
|
||||
for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) {
|
||||
vec2 xi = Hammersley(sampleNum, params.sample_count);
|
||||
|
||||
vec3 H = T * ImportanceSampleGGX(xi, roughness4);
|
||||
float NdotH = dot(N, H);
|
||||
vec3 L = (2.0 * NdotH * H - N);
|
||||
|
||||
float ndotl = clamp(dot(N, L), 0.0, 1.0);
|
||||
|
||||
if (ndotl > 0.0) {
|
||||
float D = DistributionGGX(NdotH, roughness4);
|
||||
float pdf = D * NdotH / (4.0 * NdotH) + 0.0001;
|
||||
|
||||
float solid_angle_sample = 1.0 / (float(params.sample_count) * pdf + 0.0001);
|
||||
|
||||
float mipLevel = params.roughness == 0.0 ? 0.0 : 0.5 * log2(solid_angle_sample / solid_angle_texel);
|
||||
|
||||
sum.rgb += textureLod(source_cube, L, mipLevel).rgb * ndotl;
|
||||
sum.a += ndotl;
|
||||
}
|
||||
}
|
||||
sum /= sum.a;
|
||||
|
||||
imageStore(dest_cubemap, ivec3(id), vec4(sum.rgb, 1.0));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
#define M_PI 3.14159265359
|
||||
|
||||
layout(push_constant, std430) uniform Params {
|
||||
uint face_id;
|
||||
uint sample_count;
|
||||
float roughness;
|
||||
bool use_direct_write;
|
||||
float face_size;
|
||||
}
|
||||
params;
|
||||
|
||||
vec3 texelCoordToVec(vec2 uv, uint faceID) {
|
||||
mat3 faceUvVectors[6];
|
||||
|
||||
// -x
|
||||
faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
|
||||
faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
|
||||
faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
|
||||
|
||||
// +x
|
||||
faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
|
||||
faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
|
||||
faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
|
||||
|
||||
// -y
|
||||
faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
|
||||
faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
|
||||
faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
|
||||
|
||||
// +y
|
||||
faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
|
||||
faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
|
||||
faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
|
||||
|
||||
// -z
|
||||
faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
|
||||
faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
|
||||
faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
|
||||
|
||||
// +z
|
||||
faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
|
||||
faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
|
||||
faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
|
||||
|
||||
// out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
|
||||
vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
|
||||
return normalize(result);
|
||||
}
|
||||
|
||||
vec3 ImportanceSampleGGX(vec2 xi, float roughness4) {
|
||||
// Compute distribution direction
|
||||
float Phi = 2.0 * M_PI * xi.x;
|
||||
float CosTheta = sqrt((1.0 - xi.y) / (1.0 + (roughness4 - 1.0) * xi.y));
|
||||
float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
|
||||
|
||||
// Convert to spherical direction
|
||||
vec3 H;
|
||||
H.x = SinTheta * cos(Phi);
|
||||
H.y = SinTheta * sin(Phi);
|
||||
H.z = CosTheta;
|
||||
|
||||
return H;
|
||||
}
|
||||
|
||||
float DistributionGGX(float NdotH, float roughness4) {
|
||||
float NdotH2 = NdotH * NdotH;
|
||||
float denom = (NdotH2 * (roughness4 - 1.0) + 1.0);
|
||||
denom = M_PI * denom * denom;
|
||||
|
||||
return roughness4 / denom;
|
||||
}
|
||||
|
||||
float radicalInverse_VdC(uint bits) {
|
||||
bits = (bits << 16u) | (bits >> 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);
|
||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||
}
|
||||
|
||||
vec2 Hammersley(uint i, uint N) {
|
||||
return vec2(float(i) / float(N), radicalInverse_VdC(i));
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2016 Activision Publishing, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
// is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#[compute]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#define BLOCK_SIZE 8
|
||||
|
||||
#include "../oct_inc.glsl"
|
||||
|
||||
layout(local_size_x = BLOCK_SIZE, local_size_y = BLOCK_SIZE, local_size_z = 1) in;
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D source_octmap;
|
||||
|
||||
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D dest_octmap;
|
||||
|
||||
layout(push_constant, std430) uniform Params {
|
||||
float border_size;
|
||||
uint size;
|
||||
uint pad;
|
||||
uint pad2;
|
||||
}
|
||||
params;
|
||||
|
||||
// Use an approximation of the Jacobian.
|
||||
float calcWeight(float u, float v) {
|
||||
vec3 d = oct_to_vec3_with_border(vec2(u, v), params.border_size);
|
||||
return 1.0 / pow(abs(d.z) + 1.0, 3.0);
|
||||
}
|
||||
|
||||
void main() {
|
||||
uvec2 id = gl_GlobalInvocationID.xy;
|
||||
if (id.x < params.size && id.y < params.size) {
|
||||
float inv_size = 1.0 / float(params.size);
|
||||
uvec2 sample_id = id;
|
||||
|
||||
#ifdef USE_HIGH_QUALITY
|
||||
float u0 = (float(sample_id.x) * 2.0f + 1.0f - 0.75f) * inv_size - 1.0f;
|
||||
float u1 = (float(sample_id.x) * 2.0f + 1.0f + 0.75f) * inv_size - 1.0f;
|
||||
float v0 = (float(sample_id.y) * 2.0f + 1.0f - 0.75f) * inv_size - 1.0f;
|
||||
float v1 = (float(sample_id.y) * 2.0f + 1.0f + 0.75f) * inv_size - 1.0f;
|
||||
float weights[4];
|
||||
weights[0] = calcWeight(u0, v0);
|
||||
weights[1] = calcWeight(u1, v0);
|
||||
weights[2] = calcWeight(u0, v1);
|
||||
weights[3] = calcWeight(u1, v1);
|
||||
|
||||
const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
weights[i] = weights[i] * wsum + 0.125;
|
||||
}
|
||||
|
||||
vec4 color = textureLod(source_octmap, vec2(u0, v0) * 0.5f + 0.5f, 0.0) * weights[0];
|
||||
color += textureLod(source_octmap, vec2(u1, v0) * 0.5f + 0.5f, 0.0) * weights[1];
|
||||
color += textureLod(source_octmap, vec2(u0, v1) * 0.5f + 0.5f, 0.0) * weights[2];
|
||||
color += textureLod(source_octmap, vec2(u1, v1) * 0.5f + 0.5f, 0.0) * weights[3];
|
||||
imageStore(dest_octmap, ivec2(id), color);
|
||||
#else
|
||||
vec2 uv = (vec2(sample_id.xy) + 0.5) * inv_size;
|
||||
imageStore(dest_octmap, ivec2(id), textureLod(source_octmap, uv, 0.0));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright 2016 Activision Publishing, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
// is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
/* clang-format off */
|
||||
#[vertex]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "../oct_inc.glsl"
|
||||
|
||||
layout(push_constant, std430) uniform Params {
|
||||
uint size;
|
||||
}
|
||||
params;
|
||||
|
||||
layout(location = 0) out vec2 uv_interp;
|
||||
/* clang-format on */
|
||||
|
||||
void main() {
|
||||
vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
|
||||
gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
|
||||
uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
#[fragment]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "../oct_inc.glsl"
|
||||
|
||||
layout(push_constant, std430) uniform Params {
|
||||
uint size;
|
||||
}
|
||||
params;
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D source_octmap;
|
||||
|
||||
layout(location = 0) in vec2 uv_interp;
|
||||
layout(location = 0) out vec4 frag_color;
|
||||
/* clang-format on */
|
||||
|
||||
float calcWeight(float u, float v) {
|
||||
float val = u * u + v * v + 1.0;
|
||||
return val * sqrt(val);
|
||||
}
|
||||
|
||||
void main() {
|
||||
#ifdef USE_HIGH_QUALITY
|
||||
float inv_size = 1.0 / float(params.size);
|
||||
float u0 = (uv_interp.x * 2.0f - 0.75) * inv_size - 1.0f;
|
||||
float u1 = (uv_interp.x * 2.0f + 0.75) * inv_size - 1.0f;
|
||||
float v0 = (uv_interp.y * 2.0f - 0.75) * inv_size - 1.0f;
|
||||
float v1 = (uv_interp.y * 2.0f + 0.75) * inv_size - 1.0f;
|
||||
float weights[4];
|
||||
weights[0] = calcWeight(u0, v0);
|
||||
weights[1] = calcWeight(u1, v0);
|
||||
weights[2] = calcWeight(u0, v1);
|
||||
weights[3] = calcWeight(u1, v1);
|
||||
|
||||
const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
weights[i] = weights[i] * wsum + 0.125;
|
||||
}
|
||||
|
||||
frag_color = textureLod(source_octmap, vec2(u0, v0) * 0.5f + 0.5f, 0.0) * weights[0];
|
||||
frag_color += textureLod(source_octmap, vec2(u1, v0) * 0.5f + 0.5f, 0.0) * weights[1];
|
||||
frag_color += textureLod(source_octmap, vec2(u0, v1) * 0.5f + 0.5f, 0.0) * weights[2];
|
||||
frag_color += textureLod(source_octmap, vec2(u1, v1) * 0.5f + 0.5f, 0.0) * weights[3];
|
||||
#else
|
||||
frag_color = textureLod(source_octmap, uv_interp, 0.0);
|
||||
#endif
|
||||
}
|
||||
258
servers/rendering/renderer_rd/shaders/effects/octmap_filter.glsl
Normal file
258
servers/rendering/renderer_rd/shaders/effects/octmap_filter.glsl
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
// Copyright 2016 Activision Publishing, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
// is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#[compute]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#define GROUP_SIZE 64
|
||||
|
||||
#include "../oct_inc.glsl"
|
||||
|
||||
layout(local_size_x = GROUP_SIZE, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D source_octmap;
|
||||
layout(rgba16f, set = 2, binding = 0) uniform restrict writeonly image2D dest_octmap0;
|
||||
layout(rgba16f, set = 2, binding = 1) uniform restrict writeonly image2D dest_octmap1;
|
||||
layout(rgba16f, set = 2, binding = 2) uniform restrict writeonly image2D dest_octmap2;
|
||||
layout(rgba16f, set = 2, binding = 3) uniform restrict writeonly image2D dest_octmap3;
|
||||
layout(rgba16f, set = 2, binding = 4) uniform restrict writeonly image2D dest_octmap4;
|
||||
layout(rgba16f, set = 2, binding = 5) uniform restrict writeonly image2D dest_octmap5;
|
||||
|
||||
#ifdef USE_HIGH_QUALITY
|
||||
#define NUM_TAPS 32
|
||||
#else
|
||||
#define NUM_TAPS 8
|
||||
#endif
|
||||
|
||||
layout(push_constant, std430) uniform Params {
|
||||
vec2 border_size;
|
||||
vec2 pad;
|
||||
}
|
||||
params;
|
||||
|
||||
#define BASE_RESOLUTION 320
|
||||
|
||||
#ifdef USE_HIGH_QUALITY
|
||||
layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
|
||||
vec4[7][5][3][24] coeffs;
|
||||
}
|
||||
data;
|
||||
#else
|
||||
layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
|
||||
vec4[7][5][6] coeffs;
|
||||
}
|
||||
data;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
// NOTE (macOS/MoltenVK): Do not rename, "level" variable name conflicts with the Metal "level(float lod)" mipmap sampling function name.
|
||||
uvec2 id = gl_GlobalInvocationID.xy;
|
||||
uint mip_level = 0;
|
||||
#ifndef USE_TEXTURE_ARRAY
|
||||
uint res = BASE_RESOLUTION;
|
||||
while ((id.x >= (res * res)) && (res > 1)) {
|
||||
id.x -= res * res;
|
||||
res = res >> 1;
|
||||
mip_level++;
|
||||
}
|
||||
#else // Using Texture Arrays so all levels are the same resolution
|
||||
uint res = BASE_RESOLUTION;
|
||||
mip_level = id.x / (BASE_RESOLUTION * BASE_RESOLUTION);
|
||||
id.x -= mip_level * BASE_RESOLUTION * BASE_RESOLUTION;
|
||||
#endif
|
||||
// Determine the direction from the texel's position.
|
||||
id.y = id.x / res;
|
||||
id.x -= id.y * res;
|
||||
|
||||
vec2 inv_res = 1.0 / vec2(res);
|
||||
vec3 dir = oct_to_vec3_with_border((vec2(id.xy) + vec2(0.5)) * inv_res, params.border_size.y);
|
||||
vec3 adir = abs(dir);
|
||||
vec3 frameZ = dir;
|
||||
|
||||
// Gather colors using GGX.
|
||||
vec4 color = vec4(0.0);
|
||||
for (int axis = 0; axis < 3; axis++) {
|
||||
const int otherAxis0 = 1 - (axis & 1) - (axis >> 1);
|
||||
const int otherAxis1 = 2 - (axis >> 1);
|
||||
const float lowerBound = 0.57735; // 1 / sqrt(3), magnitude for each component on a vector where all the components are equal.
|
||||
float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - lowerBound) / (1.0 - lowerBound);
|
||||
if (frameweight > 0.0) {
|
||||
// determine frame
|
||||
vec3 UpVector;
|
||||
switch (axis) {
|
||||
case 0:
|
||||
UpVector = vec3(1, 0, 0);
|
||||
break;
|
||||
case 1:
|
||||
UpVector = vec3(0, 1, 0);
|
||||
break;
|
||||
default:
|
||||
UpVector = vec3(0, 0, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
vec3 frameX = normalize(cross(UpVector, frameZ));
|
||||
vec3 frameY = cross(frameZ, frameX);
|
||||
|
||||
// Calculate parametrization for polynomial.
|
||||
float Nx = dir[otherAxis0];
|
||||
float Ny = dir[otherAxis1];
|
||||
float Nz = adir[axis];
|
||||
|
||||
float NmaxXY = max(abs(Ny), abs(Nx));
|
||||
Nx /= NmaxXY;
|
||||
Ny /= NmaxXY;
|
||||
|
||||
float theta;
|
||||
if (Ny < Nx) {
|
||||
if (Ny <= -0.999) {
|
||||
theta = Nx;
|
||||
} else {
|
||||
theta = Ny;
|
||||
}
|
||||
} else {
|
||||
if (Ny >= 0.999) {
|
||||
theta = -Nx;
|
||||
} else {
|
||||
theta = -Ny;
|
||||
}
|
||||
}
|
||||
|
||||
float phi;
|
||||
if (Nz <= -0.999) {
|
||||
phi = -NmaxXY;
|
||||
} else if (Nz >= 0.999) {
|
||||
phi = NmaxXY;
|
||||
} else {
|
||||
phi = Nz;
|
||||
}
|
||||
|
||||
float theta2 = theta * theta;
|
||||
float phi2 = phi * phi;
|
||||
|
||||
// Sample. The coefficient table was computed with less mip levels than required, so we clamp the maximum level.
|
||||
uint coeff_mip_level = min(mip_level, 5);
|
||||
for (int iSuperTap = 0; iSuperTap < NUM_TAPS / 4; iSuperTap++) {
|
||||
const int index = (NUM_TAPS / 4) * axis + iSuperTap;
|
||||
|
||||
#ifdef USE_HIGH_QUALITY
|
||||
vec4 coeffsDir0[3];
|
||||
vec4 coeffsDir1[3];
|
||||
vec4 coeffsDir2[3];
|
||||
vec4 coeffsLevel[3];
|
||||
vec4 coeffsWeight[3];
|
||||
|
||||
for (int iCoeff = 0; iCoeff < 3; iCoeff++) {
|
||||
coeffsDir0[iCoeff] = data.coeffs[coeff_mip_level][0][iCoeff][index];
|
||||
coeffsDir1[iCoeff] = data.coeffs[coeff_mip_level][1][iCoeff][index];
|
||||
coeffsDir2[iCoeff] = data.coeffs[coeff_mip_level][2][iCoeff][index];
|
||||
coeffsLevel[iCoeff] = data.coeffs[coeff_mip_level][3][iCoeff][index];
|
||||
coeffsWeight[iCoeff] = data.coeffs[coeff_mip_level][4][iCoeff][index];
|
||||
}
|
||||
|
||||
for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
|
||||
// Determine sample attributes (dir, weight, coeff_mip_level)
|
||||
vec3 sample_dir = frameX * (coeffsDir0[0][iSubTap] + coeffsDir0[1][iSubTap] * theta2 + coeffsDir0[2][iSubTap] * phi2) + frameY * (coeffsDir1[0][iSubTap] + coeffsDir1[1][iSubTap] * theta2 + coeffsDir1[2][iSubTap] * phi2) + frameZ * (coeffsDir2[0][iSubTap] + coeffsDir2[1][iSubTap] * theta2 + coeffsDir2[2][iSubTap] * phi2);
|
||||
|
||||
float sample_level = coeffsLevel[0][iSubTap] + coeffsLevel[1][iSubTap] * theta2 + coeffsLevel[2][iSubTap] * phi2;
|
||||
|
||||
float sample_weight = coeffsWeight[0][iSubTap] + coeffsWeight[1][iSubTap] * theta2 + coeffsWeight[2][iSubTap] * phi2;
|
||||
#else
|
||||
vec4 coeffsDir0 = data.coeffs[coeff_mip_level][0][index];
|
||||
vec4 coeffsDir1 = data.coeffs[coeff_mip_level][1][index];
|
||||
vec4 coeffsDir2 = data.coeffs[coeff_mip_level][2][index];
|
||||
vec4 coeffsLevel = data.coeffs[coeff_mip_level][3][index];
|
||||
vec4 coeffsWeight = data.coeffs[coeff_mip_level][4][index];
|
||||
|
||||
for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
|
||||
// determine sample attributes (dir, weight, coeff_mip_level)
|
||||
vec3 sample_dir = frameX * coeffsDir0[iSubTap] + frameY * coeffsDir1[iSubTap] + frameZ * coeffsDir2[iSubTap];
|
||||
|
||||
float sample_level = coeffsLevel[iSubTap];
|
||||
|
||||
float sample_weight = coeffsWeight[iSubTap];
|
||||
#endif
|
||||
|
||||
sample_weight *= frameweight;
|
||||
|
||||
#ifdef USE_HIGH_QUALITY
|
||||
// Adjust for Jacobian.
|
||||
sample_dir /= max(abs(sample_dir[0]), max(abs(sample_dir[1]), abs(sample_dir[2])));
|
||||
sample_level += 0.75 * log2(dot(sample_dir, sample_dir));
|
||||
#endif
|
||||
|
||||
#ifndef USE_TEXTURE_ARRAY
|
||||
sample_level += float(mip_level) / 5.0; // Hack to increase the perceived roughness and reduce upscaling artifacts
|
||||
#endif
|
||||
// Sample Octmap.
|
||||
vec2 sample_uv = vec3_to_oct_with_border(normalize(sample_dir), params.border_size);
|
||||
color.rgb += textureLod(source_octmap, sample_uv, sample_level).rgb * sample_weight;
|
||||
color.a += sample_weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the result.
|
||||
color = vec4(max(vec3(0.0), color.rgb / color.a), 1.0);
|
||||
|
||||
#ifdef USE_TEXTURE_ARRAY
|
||||
id.xy *= uvec2(2, 2);
|
||||
#endif
|
||||
|
||||
if (mip_level > 5) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_TEXTURE_ARRAY
|
||||
#define IMAGE_STORE(x) \
|
||||
imageStore(x, ivec2(id), color); \
|
||||
imageStore(x, ivec2(id) + ivec2(1, 0), color); \
|
||||
imageStore(x, ivec2(id) + ivec2(0, 1), color); \
|
||||
imageStore(x, ivec2(id) + ivec2(1, 1), color)
|
||||
#else
|
||||
#define IMAGE_STORE(x) imageStore(x, ivec2(id), color)
|
||||
#endif
|
||||
|
||||
switch (mip_level) {
|
||||
case 0:
|
||||
IMAGE_STORE(dest_octmap0);
|
||||
break;
|
||||
case 1:
|
||||
IMAGE_STORE(dest_octmap1);
|
||||
break;
|
||||
case 2:
|
||||
IMAGE_STORE(dest_octmap2);
|
||||
break;
|
||||
case 3:
|
||||
IMAGE_STORE(dest_octmap3);
|
||||
break;
|
||||
case 4:
|
||||
IMAGE_STORE(dest_octmap4);
|
||||
break;
|
||||
case 5:
|
||||
default:
|
||||
IMAGE_STORE(dest_octmap5);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -26,8 +26,9 @@
|
|||
#VERSION_DEFINES
|
||||
|
||||
layout(push_constant, std430) uniform Params {
|
||||
vec2 border_size;
|
||||
int mip_level;
|
||||
uint face_id;
|
||||
int pad;
|
||||
}
|
||||
params;
|
||||
|
||||
|
|
@ -35,9 +36,9 @@ layout(location = 0) out vec2 uv_interp;
|
|||
/* clang-format on */
|
||||
|
||||
void main() {
|
||||
vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
|
||||
gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
|
||||
uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
|
||||
vec2 base_arr[3] = vec2[](vec2(-1.0, -3.0), vec2(-1.0, 1.0), vec2(3.0, 1.0));
|
||||
uv_interp = base_arr[gl_VertexIndex];
|
||||
gl_Position = vec4(uv_interp, 0.0, 1.0);
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
|
|
@ -47,13 +48,16 @@ void main() {
|
|||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "../oct_inc.glsl"
|
||||
|
||||
layout(push_constant, std430) uniform Params {
|
||||
vec2 border_size;
|
||||
int mip_level;
|
||||
uint face_id;
|
||||
int pad;
|
||||
}
|
||||
params;
|
||||
|
||||
layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
|
||||
layout(set = 0, binding = 0) uniform sampler2D source_octmap;
|
||||
|
||||
layout(location = 0) in vec2 uv_interp;
|
||||
layout(location = 0) out vec4 frag_color;
|
||||
|
|
@ -66,8 +70,6 @@ layout(location = 0) out vec4 frag_color;
|
|||
#define NUM_TAPS 8
|
||||
#endif
|
||||
|
||||
#define BASE_RESOLUTION 128
|
||||
|
||||
#ifdef USE_HIGH_QUALITY
|
||||
layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
|
||||
vec4[7][5][3][24] coeffs;
|
||||
|
|
@ -80,67 +82,35 @@ layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
|
|||
data;
|
||||
#endif
|
||||
|
||||
void get_dir(out vec3 dir, in vec2 uv, in uint face) {
|
||||
switch (face) {
|
||||
case 0:
|
||||
dir = vec3(1.0, uv[1], -uv[0]);
|
||||
break;
|
||||
case 1:
|
||||
dir = vec3(-1.0, uv[1], uv[0]);
|
||||
break;
|
||||
case 2:
|
||||
dir = vec3(uv[0], 1.0, -uv[1]);
|
||||
break;
|
||||
case 3:
|
||||
dir = vec3(uv[0], -1.0, uv[1]);
|
||||
break;
|
||||
case 4:
|
||||
dir = vec3(uv[0], uv[1], 1.0);
|
||||
break;
|
||||
default:
|
||||
dir = vec3(-uv[0], uv[1], -1.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
// determine dir / pos for the texel
|
||||
vec3 dir, adir, frameZ;
|
||||
{
|
||||
vec2 uv;
|
||||
uv.x = uv_interp.x;
|
||||
uv.y = 1.0 - uv_interp.y;
|
||||
uv = uv * 2.0 - 1.0;
|
||||
|
||||
get_dir(dir, uv, params.face_id);
|
||||
frameZ = normalize(dir);
|
||||
|
||||
adir = abs(dir);
|
||||
}
|
||||
|
||||
// determine which texel this is
|
||||
// NOTE (macOS/MoltenVK): Do not rename, "level" variable name conflicts with the Metal "level(float lod)" mipmap sampling function name.
|
||||
int mip_level = 0;
|
||||
|
||||
vec2 uv = uv_interp * 0.5 + 0.5;
|
||||
if (params.mip_level < 0) {
|
||||
// return as is
|
||||
frag_color.rgb = textureLod(source_cubemap, frameZ, 0.0).rgb;
|
||||
// Just copy the octmap directly.
|
||||
frag_color.rgb = textureLod(source_octmap, uv, 0.0).rgb;
|
||||
frag_color.a = 1.0;
|
||||
return;
|
||||
} else if (params.mip_level > 6) {
|
||||
// maximum level
|
||||
mip_level = 6;
|
||||
} else if (params.mip_level > 5) {
|
||||
// Limit the level.
|
||||
mip_level = 5;
|
||||
} else {
|
||||
// Use the level from the push constant.
|
||||
mip_level = params.mip_level;
|
||||
}
|
||||
|
||||
// GGX gather colors
|
||||
// Determine the direction from the texel's position.
|
||||
vec3 dir = oct_to_vec3_with_border(uv, params.border_size.y);
|
||||
vec3 adir = abs(dir);
|
||||
vec3 frameZ = dir;
|
||||
|
||||
// Gather colors using GGX.
|
||||
vec4 color = vec4(0.0);
|
||||
for (int axis = 0; axis < 3; axis++) {
|
||||
const int otherAxis0 = 1 - (axis & 1) - (axis >> 1);
|
||||
const int otherAxis1 = 2 - (axis >> 1);
|
||||
|
||||
float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - .75) / .25;
|
||||
const float lowerBound = 0.57735; // 1 / sqrt(3), magnitude for each component on a vector where all the components are equal.
|
||||
float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - lowerBound) / (1.0 - lowerBound);
|
||||
if (frameweight > 0.0) {
|
||||
// determine frame
|
||||
vec3 UpVector;
|
||||
|
|
@ -195,7 +165,7 @@ void main() {
|
|||
float theta2 = theta * theta;
|
||||
float phi2 = phi * phi;
|
||||
|
||||
// sample
|
||||
// Sample.
|
||||
for (int iSuperTap = 0; iSuperTap < NUM_TAPS / 4; iSuperTap++) {
|
||||
const int index = (NUM_TAPS / 4) * axis + iSuperTap;
|
||||
|
||||
|
|
@ -239,21 +209,15 @@ void main() {
|
|||
|
||||
sample_weight *= frameweight;
|
||||
|
||||
// adjust for jacobian
|
||||
sample_dir /= max(abs(sample_dir[0]), max(abs(sample_dir[1]), abs(sample_dir[2])));
|
||||
sample_level += 0.75 * log2(dot(sample_dir, sample_dir));
|
||||
// sample cubemap
|
||||
color.xyz += textureLod(source_cubemap, normalize(sample_dir), sample_level).xyz * sample_weight;
|
||||
color.w += sample_weight;
|
||||
// Sample Octmap.
|
||||
vec2 sample_uv = vec3_to_oct_with_border(normalize(sample_dir), params.border_size);
|
||||
color.rgb += textureLod(source_octmap, sample_uv, sample_level).rgb * sample_weight;
|
||||
color.a += sample_weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
color /= color.w;
|
||||
|
||||
// write color
|
||||
color.xyz = max(vec3(0.0), color.xyz);
|
||||
color.w = 1.0;
|
||||
|
||||
frag_color = color;
|
||||
// Write out the result.
|
||||
frag_color = vec4(max(vec3(0.0), color.rgb / color.a), 1.0);
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
#[compute]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#define GROUP_SIZE 8
|
||||
|
||||
layout(local_size_x = GROUP_SIZE, local_size_y = GROUP_SIZE, local_size_z = 1) in;
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D source_oct;
|
||||
|
||||
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D dest_octmap;
|
||||
|
||||
#include "../oct_inc.glsl"
|
||||
#include "octmap_roughness_inc.glsl"
|
||||
|
||||
void main() {
|
||||
uvec2 id = gl_GlobalInvocationID.xy;
|
||||
if (id.x < params.dest_size && id.y < params.dest_size) {
|
||||
vec2 inv_source_size = 1.0 / vec2(params.source_size);
|
||||
vec2 inv_dest_size = 1.0 / vec2(params.dest_size);
|
||||
vec2 uv = (vec2(id.xy) + 0.5) * inv_dest_size;
|
||||
if (params.use_direct_write) {
|
||||
imageStore(dest_octmap, ivec2(id), vec4(texture(source_oct, uv).rgb, 1.0));
|
||||
} else {
|
||||
vec3 N = oct_to_vec3_with_border(uv, params.border_size.y);
|
||||
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
float solid_angle_texel = 4.0 * M_PI / float(params.dest_size * params.dest_size);
|
||||
float roughness2 = params.roughness * params.roughness;
|
||||
float roughness4 = roughness2 * roughness2;
|
||||
vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
|
||||
mat3 T;
|
||||
T[0] = normalize(cross(UpVector, N));
|
||||
T[1] = cross(N, T[0]);
|
||||
T[2] = N;
|
||||
|
||||
for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) {
|
||||
vec2 xi = Hammersley(sampleNum, params.sample_count);
|
||||
|
||||
vec3 H = T * ImportanceSampleGGX(xi, roughness4);
|
||||
float NdotH = dot(N, H);
|
||||
vec3 L = (2.0 * NdotH * H - N);
|
||||
|
||||
float ndotl = clamp(dot(N, L), 0.0, 1.0);
|
||||
|
||||
if (ndotl > 0.0) {
|
||||
float D = DistributionGGX(NdotH, roughness4);
|
||||
float pdf = D * NdotH / (4.0 * NdotH) + 0.0001;
|
||||
|
||||
float solid_angle_sample = 1.0 / (float(params.sample_count) * pdf + 0.0001);
|
||||
|
||||
float mipLevel = params.roughness == 0.0 ? 0.0 : 0.5 * log2(solid_angle_sample / solid_angle_texel);
|
||||
|
||||
vec2 sample_uv = vec3_to_oct_with_border(L, params.border_size);
|
||||
sum.rgb += textureLod(source_oct, sample_uv, mipLevel).rgb * ndotl;
|
||||
sum.a += ndotl;
|
||||
}
|
||||
}
|
||||
|
||||
imageStore(dest_octmap, ivec2(id), vec4(sum.rgb / sum.a, 1.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#define M_PI 3.14159265359
|
||||
|
||||
layout(push_constant, std430) uniform Params {
|
||||
uint sample_count;
|
||||
float roughness;
|
||||
uint source_size;
|
||||
uint dest_size;
|
||||
|
||||
vec2 border_size;
|
||||
bool use_direct_write;
|
||||
uint pad;
|
||||
}
|
||||
params;
|
||||
|
||||
vec3 ImportanceSampleGGX(vec2 xi, float roughness4) {
|
||||
// Compute distribution direction
|
||||
float Phi = 2.0 * M_PI * xi.x;
|
||||
float CosTheta = sqrt((1.0 - xi.y) / (1.0 + (roughness4 - 1.0) * xi.y));
|
||||
float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
|
||||
|
||||
// Convert to spherical direction
|
||||
vec3 H;
|
||||
H.x = SinTheta * cos(Phi);
|
||||
H.y = SinTheta * sin(Phi);
|
||||
H.z = CosTheta;
|
||||
|
||||
return H;
|
||||
}
|
||||
|
||||
float DistributionGGX(float NdotH, float roughness4) {
|
||||
float NdotH2 = NdotH * NdotH;
|
||||
float denom = (NdotH2 * (roughness4 - 1.0) + 1.0);
|
||||
denom = M_PI * denom * denom;
|
||||
|
||||
return roughness4 / denom;
|
||||
}
|
||||
|
||||
float radicalInverse_VdC(uint bits) {
|
||||
bits = (bits << 16u) | (bits >> 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);
|
||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||
}
|
||||
|
||||
vec2 Hammersley(uint i, uint N) {
|
||||
return vec2(float(i) / float(N), radicalInverse_VdC(i));
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "cubemap_roughness_inc.glsl"
|
||||
#include "octmap_roughness_inc.glsl"
|
||||
|
||||
layout(location = 0) out vec2 uv_interp;
|
||||
/* clang-format on */
|
||||
|
|
@ -23,26 +23,24 @@ void main() {
|
|||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "cubemap_roughness_inc.glsl"
|
||||
#include "../oct_inc.glsl"
|
||||
#include "octmap_roughness_inc.glsl"
|
||||
|
||||
layout(location = 0) in vec2 uv_interp;
|
||||
|
||||
layout(set = 0, binding = 0) uniform samplerCube source_cube;
|
||||
layout(set = 0, binding = 0) uniform sampler2D source_oct;
|
||||
|
||||
layout(location = 0) out vec4 frag_color;
|
||||
/* clang-format on */
|
||||
|
||||
void main() {
|
||||
vec3 N = texelCoordToVec(uv_interp * 2.0 - 1.0, params.face_id);
|
||||
|
||||
//vec4 color = color_interp;
|
||||
|
||||
if (params.use_direct_write) {
|
||||
frag_color = vec4(texture(source_cube, N).rgb, 1.0);
|
||||
frag_color = vec4(texture(source_oct, uv_interp).rgb, 1.0);
|
||||
} else {
|
||||
vec2 inv_size = 1.0 / vec2(params.size);
|
||||
vec3 N = oct_to_vec3_with_border(uv_interp, params.border_size.y);
|
||||
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
float solid_angle_texel = 4.0 * M_PI / (6.0 * params.face_size * params.face_size);
|
||||
float solid_angle_texel = 4.0 * M_PI / (params.size * params.size);
|
||||
float roughness2 = params.roughness * params.roughness;
|
||||
float roughness4 = roughness2 * roughness2;
|
||||
vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
|
||||
|
|
@ -68,12 +66,12 @@ void main() {
|
|||
|
||||
float mipLevel = params.roughness == 0.0 ? 0.0 : 0.5 * log2(solid_angle_sample / solid_angle_texel);
|
||||
|
||||
sum.rgb += textureLod(source_cube, L, mipLevel).rgb * ndotl;
|
||||
vec2 sample_uv = vec3_to_oct_with_border(L, params.border_size);
|
||||
sum.rgb += textureLod(source_oct, sample_uv, mipLevel).rgb * ndotl;
|
||||
sum.a += ndotl;
|
||||
}
|
||||
}
|
||||
sum /= sum.a;
|
||||
|
||||
frag_color = vec4(sum.rgb, 1.0);
|
||||
frag_color = vec4(sum.rgb / sum.a, 1.0);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue