New lightmapper
-Added LocalVector (needed it) -Added stb_rect_pack (It's pretty cool, we could probably use it for other stuff too) -Fixes and changes all around the place -Added library for 128 bits fixed point (required for Delaunay3D)
This commit is contained in:
119
modules/denoise/SCsub
Normal file
119
modules/denoise/SCsub
Normal file
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import resource_to_cpp
|
||||
from platform_methods import run_in_subprocess
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env_oidn = env_modules.Clone()
|
||||
|
||||
# Thirdparty source files
|
||||
thirdparty_dir = "#thirdparty/oidn/"
|
||||
thirdparty_sources = [
|
||||
"core/api.cpp",
|
||||
"core/device.cpp",
|
||||
"core/filter.cpp",
|
||||
"core/network.cpp",
|
||||
"core/autoencoder.cpp",
|
||||
"core/transfer_function.cpp",
|
||||
"weights/rtlightmap_hdr.cpp",
|
||||
"mkl-dnn/src/common/batch_normalization.cpp",
|
||||
"mkl-dnn/src/common/concat.cpp",
|
||||
"mkl-dnn/src/common/convolution.cpp",
|
||||
"mkl-dnn/src/common/convolution_pd.cpp",
|
||||
"mkl-dnn/src/common/deconvolution.cpp",
|
||||
"mkl-dnn/src/common/eltwise.cpp",
|
||||
"mkl-dnn/src/common/engine.cpp",
|
||||
"mkl-dnn/src/common/inner_product.cpp",
|
||||
"mkl-dnn/src/common/inner_product_pd.cpp",
|
||||
"mkl-dnn/src/common/lrn.cpp",
|
||||
"mkl-dnn/src/common/memory.cpp",
|
||||
"mkl-dnn/src/common/memory_desc_wrapper.cpp",
|
||||
"mkl-dnn/src/common/mkldnn_debug.cpp",
|
||||
"mkl-dnn/src/common/mkldnn_debug_autogenerated.cpp",
|
||||
"mkl-dnn/src/common/pooling.cpp",
|
||||
"mkl-dnn/src/common/primitive.cpp",
|
||||
"mkl-dnn/src/common/primitive_attr.cpp",
|
||||
"mkl-dnn/src/common/primitive_desc.cpp",
|
||||
"mkl-dnn/src/common/primitive_exec_types.cpp",
|
||||
"mkl-dnn/src/common/primitive_iterator.cpp",
|
||||
"mkl-dnn/src/common/query.cpp",
|
||||
"mkl-dnn/src/common/reorder.cpp",
|
||||
"mkl-dnn/src/common/rnn.cpp",
|
||||
"mkl-dnn/src/common/scratchpad.cpp",
|
||||
"mkl-dnn/src/common/shuffle.cpp",
|
||||
"mkl-dnn/src/common/softmax.cpp",
|
||||
"mkl-dnn/src/common/stream.cpp",
|
||||
"mkl-dnn/src/common/sum.cpp",
|
||||
"mkl-dnn/src/common/utils.cpp",
|
||||
"mkl-dnn/src/common/verbose.cpp",
|
||||
"mkl-dnn/src/cpu/cpu_barrier.cpp",
|
||||
"mkl-dnn/src/cpu/cpu_concat.cpp",
|
||||
"mkl-dnn/src/cpu/cpu_engine.cpp",
|
||||
"mkl-dnn/src/cpu/cpu_memory.cpp",
|
||||
"mkl-dnn/src/cpu/cpu_reducer.cpp",
|
||||
"mkl-dnn/src/cpu/cpu_reorder.cpp",
|
||||
"mkl-dnn/src/cpu/cpu_sum.cpp",
|
||||
"mkl-dnn/src/cpu/jit_avx2_conv_kernel_f32.cpp",
|
||||
"mkl-dnn/src/cpu/jit_avx2_convolution.cpp",
|
||||
"mkl-dnn/src/cpu/jit_avx512_common_conv_kernel.cpp",
|
||||
"mkl-dnn/src/cpu/jit_avx512_common_conv_winograd_kernel_f32.cpp",
|
||||
"mkl-dnn/src/cpu/jit_avx512_common_convolution.cpp",
|
||||
"mkl-dnn/src/cpu/jit_avx512_common_convolution_winograd.cpp",
|
||||
"mkl-dnn/src/cpu/jit_avx512_core_fp32_wino_conv_2x3.cpp",
|
||||
"mkl-dnn/src/cpu/jit_avx512_core_fp32_wino_conv_4x3.cpp",
|
||||
"mkl-dnn/src/cpu/jit_avx512_core_fp32_wino_conv_4x3_kernel.cpp",
|
||||
"mkl-dnn/src/cpu/jit_sse42_conv_kernel_f32.cpp",
|
||||
"mkl-dnn/src/cpu/jit_sse42_convolution.cpp",
|
||||
"mkl-dnn/src/cpu/jit_transpose_src_utils.cpp",
|
||||
"mkl-dnn/src/cpu/jit_uni_eltwise.cpp",
|
||||
"mkl-dnn/src/cpu/jit_uni_pool_kernel_f32.cpp",
|
||||
"mkl-dnn/src/cpu/jit_uni_pooling.cpp",
|
||||
"mkl-dnn/src/cpu/jit_uni_reorder.cpp",
|
||||
"mkl-dnn/src/cpu/jit_uni_reorder_utils.cpp",
|
||||
"mkl-dnn/src/cpu/jit_utils/jit_utils.cpp",
|
||||
"mkl-dnn/src/cpu/jit_utils/jitprofiling/jitprofiling.c",
|
||||
"common/platform.cpp",
|
||||
"common/thread.cpp",
|
||||
"common/tensor.cpp",
|
||||
]
|
||||
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||
|
||||
thirdparty_include_dirs = [
|
||||
"",
|
||||
"include",
|
||||
"mkl-dnn/include",
|
||||
"mkl-dnn/src",
|
||||
"mkl-dnn/src/common",
|
||||
"mkl-dnn/src/cpu/xbyak",
|
||||
"mkl-dnn/src/cpu",
|
||||
]
|
||||
thirdparty_include_dirs = [thirdparty_dir + file for file in thirdparty_include_dirs]
|
||||
|
||||
|
||||
env_oidn.Prepend(CPPPATH=thirdparty_include_dirs)
|
||||
env_oidn.Append(
|
||||
CPPDEFINES=[
|
||||
"MKLDNN_THR=MKLDNN_THR_SEQ",
|
||||
"OIDN_STATIC_LIB",
|
||||
"__STDC_CONSTANT_MACROS",
|
||||
"__STDC_LIMIT_MACROS",
|
||||
"DISABLE_VERBOSE",
|
||||
"MKLDNN_ENABLE_CONCURRENT_EXEC",
|
||||
"NDEBUG",
|
||||
]
|
||||
)
|
||||
|
||||
env_thirdparty = env_oidn.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
|
||||
|
||||
weights_in_path = thirdparty_dir + "weights/rtlightmap_hdr.tza"
|
||||
weights_out_path = thirdparty_dir + "weights/rtlightmap_hdr.cpp"
|
||||
|
||||
env_thirdparty.Depends(weights_out_path, weights_in_path)
|
||||
env_thirdparty.CommandNoCache(weights_out_path, weights_in_path, resource_to_cpp.tza_to_cpp)
|
||||
|
||||
env_oidn.add_source_files(env.modules_sources, "denoise_wrapper.cpp")
|
||||
env_modules.add_source_files(env.modules_sources, ["register_types.cpp", "lightmap_denoiser.cpp"])
|
||||
6
modules/denoise/config.py
Normal file
6
modules/denoise/config.py
Normal file
@@ -0,0 +1,6 @@
|
||||
def can_build(env, platform):
|
||||
return env["tools"]
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
34
modules/denoise/denoise_wrapper.cpp
Normal file
34
modules/denoise/denoise_wrapper.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "denoise_wrapper.h"
|
||||
#include "thirdparty/oidn/include/OpenImageDenoise/oidn.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void *oidn_denoiser_init() {
|
||||
OIDNDeviceImpl *device = oidnNewDevice(OIDN_DEVICE_TYPE_CPU);
|
||||
oidnCommitDevice(device);
|
||||
return device;
|
||||
}
|
||||
|
||||
bool oidn_denoise(void *deviceptr, float *p_floats, int p_width, int p_height) {
|
||||
OIDNDeviceImpl *device = (OIDNDeviceImpl *)deviceptr;
|
||||
OIDNFilter filter = oidnNewFilter(device, "RTLightmap");
|
||||
oidnSetSharedFilterImage(filter, "color", (void *)p_floats, OIDN_FORMAT_FLOAT3, p_width, p_height, 0, 0, 0);
|
||||
oidnSetSharedFilterImage(filter, "output", (void *)p_floats, OIDN_FORMAT_FLOAT3, p_width, p_height, 0, 0, 0);
|
||||
oidnSetFilter1b(filter, "hdr", true);
|
||||
//oidnSetFilter1f(filter, "hdrScale", 1.0f);
|
||||
oidnCommitFilter(filter);
|
||||
oidnExecuteFilter(filter);
|
||||
|
||||
const char *msg;
|
||||
bool success = true;
|
||||
if (oidnGetDeviceError(device, &msg) != OIDN_ERROR_NONE) {
|
||||
printf("LightmapDenoiser: %s\n", msg);
|
||||
success = false;
|
||||
}
|
||||
|
||||
oidnReleaseFilter(filter);
|
||||
return success;
|
||||
}
|
||||
|
||||
void oidn_denoiser_finish(void *device) {
|
||||
oidnReleaseDevice((OIDNDeviceImpl *)device);
|
||||
}
|
||||
8
modules/denoise/denoise_wrapper.h
Normal file
8
modules/denoise/denoise_wrapper.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef DENOISE_WRAPPER_H
|
||||
#define DENOISE_WRAPPER_H
|
||||
|
||||
void *oidn_denoiser_init();
|
||||
bool oidn_denoise(void *device, float *p_floats, int p_width, int p_height);
|
||||
void oidn_denoiser_finish(void *device);
|
||||
|
||||
#endif // DENOISE_WRAPPER_H
|
||||
63
modules/denoise/lightmap_denoiser.cpp
Normal file
63
modules/denoise/lightmap_denoiser.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*************************************************************************/
|
||||
/* lightmap_denoiser.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "lightmap_denoiser.h"
|
||||
#include "denoise_wrapper.h"
|
||||
|
||||
LightmapDenoiser *LightmapDenoiserOIDN::create_oidn_denoiser() {
|
||||
return memnew(LightmapDenoiserOIDN);
|
||||
}
|
||||
|
||||
void LightmapDenoiserOIDN::make_default_denoiser() {
|
||||
create_function = create_oidn_denoiser;
|
||||
}
|
||||
|
||||
Ref<Image> LightmapDenoiserOIDN::denoise_image(const Ref<Image> &p_image) {
|
||||
|
||||
Ref<Image> img = p_image->duplicate();
|
||||
|
||||
img->convert(Image::FORMAT_RGBF);
|
||||
|
||||
Vector<uint8_t> data = img->get_data();
|
||||
if (!oidn_denoise(device, (float *)data.ptrw(), img->get_width(), img->get_height())) {
|
||||
return p_image;
|
||||
}
|
||||
|
||||
img->create(img->get_width(), img->get_height(), false, img->get_format(), data);
|
||||
return img;
|
||||
}
|
||||
|
||||
LightmapDenoiserOIDN::LightmapDenoiserOIDN() {
|
||||
device = oidn_denoiser_init();
|
||||
}
|
||||
|
||||
LightmapDenoiserOIDN::~LightmapDenoiserOIDN() {
|
||||
oidn_denoiser_finish(device);
|
||||
}
|
||||
57
modules/denoise/lightmap_denoiser.h
Normal file
57
modules/denoise/lightmap_denoiser.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*************************************************************************/
|
||||
/* lightmap_denoiser.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef LIGHTMAP_DENOISER_H
|
||||
#define LIGHTMAP_DENOISER_H
|
||||
|
||||
#include "core/object.h"
|
||||
#include "scene/3d/lightmapper.h"
|
||||
|
||||
struct OIDNDeviceImpl;
|
||||
|
||||
class LightmapDenoiserOIDN : public LightmapDenoiser {
|
||||
|
||||
GDCLASS(LightmapDenoiserOIDN, LightmapDenoiser);
|
||||
|
||||
protected:
|
||||
void *device = nullptr;
|
||||
|
||||
public:
|
||||
static LightmapDenoiser *create_oidn_denoiser();
|
||||
|
||||
Ref<Image> denoise_image(const Ref<Image> &p_image);
|
||||
|
||||
static void make_default_denoiser();
|
||||
|
||||
LightmapDenoiserOIDN();
|
||||
~LightmapDenoiserOIDN();
|
||||
};
|
||||
|
||||
#endif // LIGHTMAP_DENOISER_H
|
||||
41
modules/denoise/register_types.cpp
Normal file
41
modules/denoise/register_types.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "register_types.h"
|
||||
#include "core/engine.h"
|
||||
#include "lightmap_denoiser.h"
|
||||
|
||||
void register_denoise_types() {
|
||||
|
||||
LightmapDenoiserOIDN::make_default_denoiser();
|
||||
}
|
||||
|
||||
void unregister_denoise_types() {
|
||||
}
|
||||
32
modules/denoise/register_types.h
Normal file
32
modules/denoise/register_types.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
void register_denoise_types();
|
||||
void unregister_denoise_types();
|
||||
70
modules/denoise/resource_to_cpp.py
Normal file
70
modules/denoise/resource_to_cpp.py
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
## ======================================================================== ##
|
||||
## Copyright 2009-2019 Intel Corporation ##
|
||||
## ##
|
||||
## Licensed under the Apache License, Version 2.0 (the "License"); ##
|
||||
## you may not use this file except in compliance with the License. ##
|
||||
## You may obtain a copy of the License at ##
|
||||
## ##
|
||||
## http://www.apache.org/licenses/LICENSE-2.0 ##
|
||||
## ##
|
||||
## Unless required by applicable law or agreed to in writing, software ##
|
||||
## distributed under the License is distributed on an "AS IS" BASIS, ##
|
||||
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ##
|
||||
## See the License for the specific language governing permissions and ##
|
||||
## limitations under the License. ##
|
||||
## ======================================================================== ##
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
from array import array
|
||||
|
||||
# Generates a C++ file from the specified binary resource file
|
||||
def generate(in_path, out_path):
|
||||
|
||||
namespace = "oidn::weights"
|
||||
scopes = namespace.split("::")
|
||||
|
||||
file_name = os.path.basename(in_path)
|
||||
var_name = os.path.splitext(file_name)[0]
|
||||
|
||||
with open(in_path, "rb") as in_file, open(out_path, "w") as out_file:
|
||||
# Header
|
||||
out_file.write("// Generated from: %s\n" % file_name)
|
||||
out_file.write("#include <cstddef>\n\n")
|
||||
|
||||
# Open the namespaces
|
||||
for s in scopes:
|
||||
out_file.write("namespace %s {\n" % s)
|
||||
if scopes:
|
||||
out_file.write("\n")
|
||||
|
||||
# Read the file
|
||||
in_data = array("B", in_file.read())
|
||||
|
||||
# Write the size
|
||||
out_file.write("//const size_t %s_size = %d;\n\n" % (var_name, len(in_data)))
|
||||
|
||||
# Write the data
|
||||
out_file.write("unsigned char %s[] = {" % var_name)
|
||||
for i in range(len(in_data)):
|
||||
c = in_data[i]
|
||||
if i > 0:
|
||||
out_file.write(",")
|
||||
if (i + 1) % 20 == 1:
|
||||
out_file.write("\n")
|
||||
out_file.write("%d" % c)
|
||||
out_file.write("\n};\n")
|
||||
|
||||
# Close the namespaces
|
||||
if scopes:
|
||||
out_file.write("\n")
|
||||
for scope in reversed(scopes):
|
||||
out_file.write("} // namespace %s\n" % scope)
|
||||
|
||||
|
||||
def tza_to_cpp(target, source, env):
|
||||
for x in zip(source, target):
|
||||
generate(str(x[0]), str(x[1]))
|
||||
12
modules/lightmapper_rd/SCsub
Normal file
12
modules/lightmapper_rd/SCsub
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env_lightmapper_rd = env_modules.Clone()
|
||||
env_lightmapper_rd.GLSL_HEADER("lm_raster.glsl")
|
||||
env_lightmapper_rd.GLSL_HEADER("lm_compute.glsl")
|
||||
env_lightmapper_rd.GLSL_HEADER("lm_blendseams.glsl")
|
||||
|
||||
# Godot source files
|
||||
env_lightmapper_rd.add_source_files(env.modules_sources, "*.cpp")
|
||||
6
modules/lightmapper_rd/config.py
Normal file
6
modules/lightmapper_rd/config.py
Normal file
@@ -0,0 +1,6 @@
|
||||
def can_build(env, platform):
|
||||
return True
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
1754
modules/lightmapper_rd/lightmapper_rd.cpp
Normal file
1754
modules/lightmapper_rd/lightmapper_rd.cpp
Normal file
File diff suppressed because it is too large
Load Diff
229
modules/lightmapper_rd/lightmapper_rd.h
Normal file
229
modules/lightmapper_rd/lightmapper_rd.h
Normal file
@@ -0,0 +1,229 @@
|
||||
#ifndef LIGHTMAPPER_RD_H
|
||||
#define LIGHTMAPPER_RD_H
|
||||
|
||||
#include "core/local_vector.h"
|
||||
#include "scene/3d/lightmapper.h"
|
||||
#include "scene/resources/mesh.h"
|
||||
#include "servers/rendering/rendering_device.h"
|
||||
|
||||
class LightmapperRD : public Lightmapper {
|
||||
GDCLASS(LightmapperRD, Lightmapper)
|
||||
|
||||
struct MeshInstance {
|
||||
MeshData data;
|
||||
int slice = 0;
|
||||
Vector2i offset;
|
||||
};
|
||||
|
||||
struct Light {
|
||||
float position[3];
|
||||
uint32_t type = LIGHT_TYPE_DIRECTIONAL;
|
||||
float direction[3];
|
||||
float energy;
|
||||
float color[3];
|
||||
float size;
|
||||
float range;
|
||||
float attenuation;
|
||||
float spot_angle;
|
||||
float spot_attenuation;
|
||||
uint32_t static_bake;
|
||||
uint32_t pad[3];
|
||||
|
||||
bool operator<(const Light &p_light) const {
|
||||
return type < p_light.type;
|
||||
}
|
||||
};
|
||||
|
||||
struct Vertex {
|
||||
float position[3];
|
||||
float normal_z;
|
||||
float uv[2];
|
||||
float normal_xy[2];
|
||||
|
||||
bool operator==(const Vertex &p_vtx) const {
|
||||
return (position[0] == p_vtx.position[0]) &&
|
||||
(position[1] == p_vtx.position[1]) &&
|
||||
(position[2] == p_vtx.position[2]) &&
|
||||
(uv[0] == p_vtx.uv[0]) &&
|
||||
(uv[1] == p_vtx.uv[1]) &&
|
||||
(normal_xy[0] == p_vtx.normal_xy[0]) &&
|
||||
(normal_xy[1] == p_vtx.normal_xy[1]) &&
|
||||
(normal_z == p_vtx.normal_z);
|
||||
}
|
||||
};
|
||||
|
||||
struct Edge {
|
||||
Vector3 a;
|
||||
Vector3 b;
|
||||
Vector3 na;
|
||||
Vector3 nb;
|
||||
bool operator==(const Edge &p_seam) const {
|
||||
return a == p_seam.a && b == p_seam.b && na == p_seam.na && nb == p_seam.nb;
|
||||
}
|
||||
Edge() {
|
||||
}
|
||||
|
||||
Edge(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_na, const Vector3 &p_nb) {
|
||||
a = p_a;
|
||||
b = p_b;
|
||||
na = p_na;
|
||||
nb = p_nb;
|
||||
}
|
||||
};
|
||||
|
||||
struct Probe {
|
||||
float position[4];
|
||||
};
|
||||
|
||||
Vector<Probe> probe_positions;
|
||||
|
||||
struct EdgeHash {
|
||||
_FORCE_INLINE_ static uint32_t hash(const Edge &p_edge) {
|
||||
uint32_t h = hash_djb2_one_float(p_edge.a.x);
|
||||
h = hash_djb2_one_float(p_edge.a.y, h);
|
||||
h = hash_djb2_one_float(p_edge.a.z, h);
|
||||
h = hash_djb2_one_float(p_edge.b.x, h);
|
||||
h = hash_djb2_one_float(p_edge.b.y, h);
|
||||
h = hash_djb2_one_float(p_edge.b.z, h);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
struct EdgeUV2 {
|
||||
Vector2 a;
|
||||
Vector2 b;
|
||||
Vector2i indices;
|
||||
bool operator==(const EdgeUV2 &p_uv2) const {
|
||||
return a == p_uv2.a && b == p_uv2.b;
|
||||
}
|
||||
bool seam_found = false;
|
||||
EdgeUV2(Vector2 p_a, Vector2 p_b, Vector2i p_indices) {
|
||||
a = p_a;
|
||||
b = p_b;
|
||||
indices = p_indices;
|
||||
}
|
||||
EdgeUV2() {}
|
||||
};
|
||||
|
||||
struct Seam {
|
||||
Vector2i a;
|
||||
Vector2i b;
|
||||
uint32_t slice;
|
||||
bool operator<(const Seam &p_seam) const {
|
||||
return slice < p_seam.slice;
|
||||
}
|
||||
};
|
||||
|
||||
struct VertexHash {
|
||||
_FORCE_INLINE_ static uint32_t hash(const Vertex &p_vtx) {
|
||||
uint32_t h = hash_djb2_one_float(p_vtx.position[0]);
|
||||
h = hash_djb2_one_float(p_vtx.position[1], h);
|
||||
h = hash_djb2_one_float(p_vtx.position[2], h);
|
||||
h = hash_djb2_one_float(p_vtx.uv[0], h);
|
||||
h = hash_djb2_one_float(p_vtx.uv[1], h);
|
||||
h = hash_djb2_one_float(p_vtx.normal_xy[0], h);
|
||||
h = hash_djb2_one_float(p_vtx.normal_xy[1], h);
|
||||
h = hash_djb2_one_float(p_vtx.normal_z, h);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct Box {
|
||||
float min_bounds[3];
|
||||
float pad0;
|
||||
float max_bounds[3];
|
||||
float pad1;
|
||||
};
|
||||
|
||||
struct Triangle {
|
||||
uint32_t indices[3];
|
||||
uint32_t slice;
|
||||
bool operator<(const Triangle &p_triangle) const {
|
||||
return slice < p_triangle.slice;
|
||||
}
|
||||
};
|
||||
|
||||
Vector<MeshInstance> mesh_instances;
|
||||
|
||||
Vector<Light> lights;
|
||||
|
||||
struct TriangleSort {
|
||||
uint32_t cell_index;
|
||||
uint32_t triangle_index;
|
||||
bool operator<(const TriangleSort &p_triangle_sort) const {
|
||||
return cell_index < p_triangle_sort.cell_index; //sorting by triangle index in this case makes no sense
|
||||
}
|
||||
};
|
||||
|
||||
void _plot_triangle_into_triangle_index_list(int p_size, const Vector3i &p_ofs, const AABB &p_bounds, const Vector3 p_points[], uint32_t p_triangle_index, LocalVector<TriangleSort> &triangles, uint32_t p_grid_size);
|
||||
|
||||
struct RasterPushConstant {
|
||||
float atlas_size[2];
|
||||
float uv_offset[2];
|
||||
float to_cell_size[3];
|
||||
uint32_t base_triangle;
|
||||
float to_cell_offset[3];
|
||||
float bias;
|
||||
int32_t grid_size[3];
|
||||
uint32_t pad2;
|
||||
};
|
||||
|
||||
struct RasterSeamsPushConstant {
|
||||
|
||||
uint32_t base_index;
|
||||
uint32_t slice;
|
||||
float uv_offset[2];
|
||||
uint32_t debug;
|
||||
float blend;
|
||||
uint32_t pad[2];
|
||||
};
|
||||
|
||||
struct PushConstant {
|
||||
int32_t atlas_size[2];
|
||||
uint32_t ray_count;
|
||||
uint32_t ray_to;
|
||||
|
||||
float world_size[3];
|
||||
float bias;
|
||||
|
||||
float to_cell_offset[3];
|
||||
uint32_t ray_from;
|
||||
|
||||
float to_cell_size[3];
|
||||
uint32_t light_count;
|
||||
|
||||
int32_t grid_size;
|
||||
int32_t atlas_slice;
|
||||
int32_t region_ofs[2];
|
||||
|
||||
float environment_xform[12];
|
||||
};
|
||||
|
||||
Vector<Ref<Image>> bake_textures;
|
||||
Vector<Color> probe_values;
|
||||
|
||||
BakeError _blit_meshes_into_atlas(int p_max_texture_size, Vector<Ref<Image>> &albedo_images, Vector<Ref<Image>> &emission_images, AABB &bounds, Size2i &atlas_size, int &atlas_slices, BakeStepFunc p_step_function, void *p_bake_userdata);
|
||||
void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &grid_texture_sdf, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata);
|
||||
void _raster_geometry(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, int grid_size, AABB bounds, float p_bias, Vector<int> slice_triangle_count, RID position_tex, RID unocclude_tex, RID normal_tex, RID raster_depth_buffer, RID rasterize_shader, RID raster_base_uniform);
|
||||
|
||||
public:
|
||||
virtual void add_mesh(const MeshData &p_mesh);
|
||||
virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance);
|
||||
virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size);
|
||||
virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size);
|
||||
virtual void add_probe(const Vector3 &p_position);
|
||||
virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr);
|
||||
|
||||
int get_bake_texture_count() const;
|
||||
Ref<Image> get_bake_texture(int p_index) const;
|
||||
int get_bake_mesh_count() const;
|
||||
Variant get_bake_mesh_userdata(int p_index) const;
|
||||
Rect2 get_bake_mesh_uv_scale(int p_index) const;
|
||||
int get_bake_mesh_texture_slice(int p_index) const;
|
||||
int get_bake_probe_count() const;
|
||||
Vector3 get_bake_probe_point(int p_probe) const;
|
||||
Vector<Color> get_bake_probe_sh(int p_probe) const;
|
||||
|
||||
LightmapperRD();
|
||||
};
|
||||
|
||||
#endif // LIGHTMAPPER_H
|
||||
117
modules/lightmapper_rd/lm_blendseams.glsl
Normal file
117
modules/lightmapper_rd/lm_blendseams.glsl
Normal file
@@ -0,0 +1,117 @@
|
||||
/* clang-format off */
|
||||
[versions]
|
||||
|
||||
lines = "#define MODE_LINES"
|
||||
triangles = "#define MODE_TRIANGLES"
|
||||
|
||||
[vertex]
|
||||
|
||||
#version 450
|
||||
|
||||
VERSION_DEFINES
|
||||
|
||||
#include "lm_common_inc.glsl"
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
layout(push_constant, binding = 0, std430) uniform Params {
|
||||
uint base_index;
|
||||
uint slice;
|
||||
vec2 uv_offset;
|
||||
bool debug;
|
||||
float blend;
|
||||
uint pad[2];
|
||||
} params;
|
||||
|
||||
layout(location = 0) out vec3 uv_interp;
|
||||
|
||||
void main() {
|
||||
|
||||
#ifdef MODE_TRIANGLES
|
||||
|
||||
uint triangle_idx = params.base_index + gl_VertexIndex / 3;
|
||||
uint triangle_subidx = gl_VertexIndex % 3;
|
||||
|
||||
vec2 uv;
|
||||
if (triangle_subidx == 0) {
|
||||
uv = vertices.data[triangles.data[triangle_idx].indices.x].uv;
|
||||
} else if (triangle_subidx == 1) {
|
||||
uv = vertices.data[triangles.data[triangle_idx].indices.y].uv;
|
||||
} else {
|
||||
uv = vertices.data[triangles.data[triangle_idx].indices.z].uv;
|
||||
}
|
||||
|
||||
uv_interp = vec3(uv, float(params.slice));
|
||||
gl_Position = vec4((uv + params.uv_offset) * 2.0 - 1.0, 0.0001, 1.0);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MODE_LINES
|
||||
uint seam_idx = params.base_index + gl_VertexIndex / 4;
|
||||
uint seam_subidx = gl_VertexIndex % 4;
|
||||
|
||||
uint src_idx;
|
||||
uint dst_idx;
|
||||
|
||||
if (seam_subidx == 0) {
|
||||
src_idx = seams.data[seam_idx].b.x;
|
||||
dst_idx = seams.data[seam_idx].a.x;
|
||||
} else if (seam_subidx == 1) {
|
||||
src_idx = seams.data[seam_idx].b.y;
|
||||
dst_idx = seams.data[seam_idx].a.y;
|
||||
} else if (seam_subidx == 2) {
|
||||
src_idx = seams.data[seam_idx].a.x;
|
||||
dst_idx = seams.data[seam_idx].b.x;
|
||||
} else if (seam_subidx == 3) {
|
||||
src_idx = seams.data[seam_idx].a.y;
|
||||
dst_idx = seams.data[seam_idx].b.y;
|
||||
}
|
||||
|
||||
vec2 src_uv = vertices.data[src_idx].uv;
|
||||
vec2 dst_uv = vertices.data[dst_idx].uv + params.uv_offset;
|
||||
|
||||
uv_interp = vec3(src_uv, float(params.slice));
|
||||
gl_Position = vec4(dst_uv * 2.0 - 1.0, 0.0001, 1.0);
|
||||
;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
[fragment]
|
||||
|
||||
#version 450
|
||||
|
||||
VERSION_DEFINES
|
||||
|
||||
#include "lm_common_inc.glsl"
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
layout(push_constant, binding = 0, std430) uniform Params {
|
||||
uint base_index;
|
||||
uint slice;
|
||||
vec2 uv_offset;
|
||||
bool debug;
|
||||
float blend;
|
||||
uint pad[2];
|
||||
} params;
|
||||
|
||||
layout(location = 0) in vec3 uv_interp;
|
||||
|
||||
layout(location = 0) out vec4 dst_color;
|
||||
|
||||
layout(set = 1, binding = 0) uniform texture2DArray src_color_tex;
|
||||
|
||||
void main() {
|
||||
|
||||
if (params.debug) {
|
||||
#ifdef MODE_TRIANGLES
|
||||
dst_color = vec4(1, 0, 1, 1);
|
||||
#else
|
||||
dst_color = vec4(1, 1, 0, 1);
|
||||
#endif
|
||||
} else {
|
||||
vec4 src_color = textureLod(sampler2DArray(src_color_tex, linear_sampler), uv_interp, 0.0);
|
||||
dst_color = vec4(src_color.rgb, params.blend); //mix
|
||||
}
|
||||
}
|
||||
92
modules/lightmapper_rd/lm_common_inc.glsl
Normal file
92
modules/lightmapper_rd/lm_common_inc.glsl
Normal file
@@ -0,0 +1,92 @@
|
||||
|
||||
/* SET 0, static data that does not change between any call */
|
||||
|
||||
struct Vertex {
|
||||
vec3 position;
|
||||
float normal_z;
|
||||
vec2 uv;
|
||||
vec2 normal_xy;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 1, std430) restrict readonly buffer Vertices {
|
||||
Vertex data[];
|
||||
}
|
||||
vertices;
|
||||
|
||||
struct Triangle {
|
||||
uvec3 indices;
|
||||
uint slice;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 2, std430) restrict readonly buffer Triangles {
|
||||
Triangle data[];
|
||||
}
|
||||
triangles;
|
||||
|
||||
struct Box {
|
||||
vec3 min_bounds;
|
||||
uint pad0;
|
||||
vec3 max_bounds;
|
||||
uint pad1;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 3, std430) restrict readonly buffer Boxes {
|
||||
Box data[];
|
||||
}
|
||||
boxes;
|
||||
|
||||
layout(set = 0, binding = 4, std430) restrict readonly buffer GridIndices {
|
||||
uint data[];
|
||||
}
|
||||
grid_indices;
|
||||
|
||||
#define LIGHT_TYPE_DIRECTIONAL 0
|
||||
#define LIGHT_TYPE_OMNI 1
|
||||
#define LIGHT_TYPE_SPOT 2
|
||||
|
||||
struct Light {
|
||||
vec3 position;
|
||||
uint type;
|
||||
|
||||
vec3 direction;
|
||||
float energy;
|
||||
|
||||
vec3 color;
|
||||
float size;
|
||||
|
||||
float range;
|
||||
float attenuation;
|
||||
float spot_angle;
|
||||
float spot_attenuation;
|
||||
|
||||
bool static_bake;
|
||||
uint pad[3];
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 5, std430) restrict readonly buffer Lights {
|
||||
Light data[];
|
||||
}
|
||||
lights;
|
||||
|
||||
struct Seam {
|
||||
uvec2 a;
|
||||
uvec2 b;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 6, std430) restrict readonly buffer Seams {
|
||||
Seam data[];
|
||||
}
|
||||
seams;
|
||||
|
||||
layout(set = 0, binding = 7, std430) restrict readonly buffer Probes {
|
||||
vec4 data[];
|
||||
}
|
||||
probe_positions;
|
||||
|
||||
layout(set = 0, binding = 8) uniform utexture3D grid;
|
||||
layout(set = 0, binding = 9) uniform texture3D grid_sdf;
|
||||
|
||||
layout(set = 0, binding = 10) uniform texture2DArray albedo_tex;
|
||||
layout(set = 0, binding = 11) uniform texture2DArray emission_tex;
|
||||
|
||||
layout(set = 0, binding = 12) uniform sampler linear_sampler;
|
||||
657
modules/lightmapper_rd/lm_compute.glsl
Normal file
657
modules/lightmapper_rd/lm_compute.glsl
Normal file
@@ -0,0 +1,657 @@
|
||||
/* clang-format off */
|
||||
[versions]
|
||||
|
||||
primary = "#define MODE_DIRECT_LIGHT"
|
||||
secondary = "#define MODE_BOUNCE_LIGHT"
|
||||
dilate = "#define MODE_DILATE"
|
||||
unocclude = "#define MODE_UNOCCLUDE"
|
||||
light_probes = "#define MODE_LIGHT_PROBES"
|
||||
|
||||
[compute]
|
||||
|
||||
#version 450
|
||||
|
||||
VERSION_DEFINES
|
||||
|
||||
// One 2D local group focusing in one layer at a time, though all
|
||||
// in parallel (no barriers) makes more sense than a 3D local group
|
||||
// as this can take more advantage of the cache for each group.
|
||||
|
||||
#ifdef MODE_LIGHT_PROBES
|
||||
|
||||
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
#else
|
||||
|
||||
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
||||
|
||||
#endif
|
||||
|
||||
#include "lm_common_inc.glsl"
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#ifdef MODE_LIGHT_PROBES
|
||||
|
||||
layout(set = 1, binding = 0, std430) restrict buffer LightProbeData {
|
||||
vec4 data[];
|
||||
}
|
||||
light_probes;
|
||||
|
||||
layout(set = 1, binding = 1) uniform texture2DArray source_light;
|
||||
layout(set = 1, binding = 2) uniform texture2DArray source_direct_light; //also need the direct light, which was omitted
|
||||
layout(set = 1, binding = 3) uniform texture2D environment;
|
||||
#endif
|
||||
|
||||
#ifdef MODE_UNOCCLUDE
|
||||
|
||||
layout(rgba32f, set = 1, binding = 0) uniform restrict image2DArray position;
|
||||
layout(rgba32f, set = 1, binding = 1) uniform restrict readonly image2DArray unocclude;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(MODE_DIRECT_LIGHT) || defined(MODE_BOUNCE_LIGHT)
|
||||
|
||||
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2DArray dest_light;
|
||||
layout(set = 1, binding = 1) uniform texture2DArray source_light;
|
||||
layout(set = 1, binding = 2) uniform texture2DArray source_position;
|
||||
layout(set = 1, binding = 3) uniform texture2DArray source_normal;
|
||||
layout(rgba16f, set = 1, binding = 4) uniform restrict image2DArray accum_light;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MODE_BOUNCE_LIGHT
|
||||
layout(rgba32f, set = 1, binding = 5) uniform restrict image2DArray bounce_accum;
|
||||
layout(set = 1, binding = 6) uniform texture2D environment;
|
||||
#endif
|
||||
#ifdef MODE_DIRECT_LIGHT
|
||||
layout(rgba32f, set = 1, binding = 5) uniform restrict writeonly image2DArray primary_dynamic;
|
||||
#endif
|
||||
|
||||
#ifdef MODE_DILATE
|
||||
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2DArray dest_light;
|
||||
layout(set = 1, binding = 1) uniform texture2DArray source_light;
|
||||
#endif
|
||||
|
||||
layout(push_constant, binding = 0, std430) uniform Params {
|
||||
ivec2 atlas_size; // x used for light probe mode total probes
|
||||
uint ray_count;
|
||||
uint ray_to;
|
||||
|
||||
vec3 world_size;
|
||||
float bias;
|
||||
|
||||
vec3 to_cell_offset;
|
||||
uint ray_from;
|
||||
|
||||
vec3 to_cell_size;
|
||||
uint light_count;
|
||||
|
||||
int grid_size;
|
||||
int atlas_slice;
|
||||
ivec2 region_ofs;
|
||||
|
||||
mat3x4 env_transform;
|
||||
}
|
||||
params;
|
||||
|
||||
//check it, but also return distance and barycentric coords (for uv lookup)
|
||||
bool ray_hits_triangle(vec3 from, vec3 dir, float max_dist, vec3 p0, vec3 p1, vec3 p2, out float r_distance, out vec3 r_barycentric) {
|
||||
|
||||
const vec3 e0 = p1 - p0;
|
||||
const vec3 e1 = p0 - p2;
|
||||
vec3 triangleNormal = cross(e1, e0);
|
||||
|
||||
const vec3 e2 = (1.0 / dot(triangleNormal, dir)) * (p0 - from);
|
||||
const vec3 i = cross(dir, e2);
|
||||
|
||||
r_barycentric.y = dot(i, e1);
|
||||
r_barycentric.z = dot(i, e0);
|
||||
r_barycentric.x = 1.0 - (r_barycentric.z + r_barycentric.y);
|
||||
r_distance = dot(triangleNormal, e2);
|
||||
return (r_distance > params.bias) && (r_distance < max_dist) && all(greaterThanEqual(r_barycentric, vec3(0.0)));
|
||||
}
|
||||
|
||||
bool trace_ray(vec3 p_from, vec3 p_to
|
||||
#if defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
|
||||
,
|
||||
out uint r_triangle, out vec3 r_barycentric
|
||||
#endif
|
||||
#if defined(MODE_UNOCCLUDE)
|
||||
,
|
||||
out float r_distance, out vec3 r_normal
|
||||
#endif
|
||||
) {
|
||||
|
||||
/* world coords */
|
||||
|
||||
vec3 rel = p_to - p_from;
|
||||
float rel_len = length(rel);
|
||||
vec3 dir = normalize(rel);
|
||||
vec3 inv_dir = 1.0 / dir;
|
||||
|
||||
/* cell coords */
|
||||
|
||||
vec3 from_cell = (p_from - params.to_cell_offset) * params.to_cell_size;
|
||||
vec3 to_cell = (p_to - params.to_cell_offset) * params.to_cell_size;
|
||||
|
||||
//prepare DDA
|
||||
vec3 rel_cell = to_cell - from_cell;
|
||||
ivec3 icell = ivec3(from_cell);
|
||||
ivec3 iendcell = ivec3(to_cell);
|
||||
vec3 dir_cell = normalize(rel_cell);
|
||||
vec3 delta = abs(1.0 / dir_cell); //vec3(length(rel_cell)) / rel_cell);
|
||||
ivec3 step = ivec3(sign(rel_cell));
|
||||
vec3 side = (sign(rel_cell) * (vec3(icell) - from_cell) + (sign(rel_cell) * 0.5) + 0.5) * delta;
|
||||
|
||||
uint iters = 0;
|
||||
while (all(greaterThanEqual(icell, ivec3(0))) && all(lessThan(icell, ivec3(params.grid_size))) && iters < 1000) {
|
||||
|
||||
uvec2 cell_data = texelFetch(usampler3D(grid, linear_sampler), icell, 0).xy;
|
||||
if (cell_data.x > 0) { //triangles here
|
||||
|
||||
bool hit = false;
|
||||
#if defined(MODE_UNOCCLUDE)
|
||||
bool hit_backface = false;
|
||||
#endif
|
||||
float best_distance = 1e20;
|
||||
|
||||
for (uint i = 0; i < cell_data.x; i++) {
|
||||
uint tidx = grid_indices.data[cell_data.y + i];
|
||||
|
||||
//Ray-Box test
|
||||
vec3 t0 = (boxes.data[tidx].min_bounds - p_from) * inv_dir;
|
||||
vec3 t1 = (boxes.data[tidx].max_bounds - p_from) * inv_dir;
|
||||
vec3 tmin = min(t0, t1), tmax = max(t0, t1);
|
||||
|
||||
if (max(tmin.x, max(tmin.y, tmin.z)) <= min(tmax.x, min(tmax.y, tmax.z))) {
|
||||
continue; //ray box failed
|
||||
}
|
||||
|
||||
//prepare triangle vertices
|
||||
vec3 vtx0 = vertices.data[triangles.data[tidx].indices.x].position;
|
||||
vec3 vtx1 = vertices.data[triangles.data[tidx].indices.y].position;
|
||||
vec3 vtx2 = vertices.data[triangles.data[tidx].indices.z].position;
|
||||
#if defined(MODE_UNOCCLUDE)
|
||||
vec3 normal = -normalize(cross((vtx0 - vtx1), (vtx0 - vtx2)));
|
||||
|
||||
bool backface = dot(normal, dir) >= 0.0;
|
||||
#endif
|
||||
float distance;
|
||||
vec3 barycentric;
|
||||
|
||||
if (ray_hits_triangle(p_from, dir, rel_len, vtx0, vtx1, vtx2, distance, barycentric)) {
|
||||
#ifdef MODE_DIRECT_LIGHT
|
||||
return true; //any hit good
|
||||
#endif
|
||||
|
||||
#if defined(MODE_UNOCCLUDE)
|
||||
if (!backface) {
|
||||
// the case of meshes having both a front and back face in the same plane is more common than
|
||||
// expected, so if this is a front-face, bias it closer to the ray origin, so it always wins over the back-face
|
||||
distance = max(params.bias, distance - params.bias);
|
||||
}
|
||||
|
||||
hit = true;
|
||||
|
||||
if (distance < best_distance) {
|
||||
hit_backface = backface;
|
||||
best_distance = distance;
|
||||
r_distance = distance;
|
||||
r_normal = normal;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
|
||||
|
||||
hit = true;
|
||||
if (distance < best_distance) {
|
||||
best_distance = distance;
|
||||
r_triangle = tidx;
|
||||
r_barycentric = barycentric;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if defined(MODE_UNOCCLUDE)
|
||||
|
||||
if (hit) {
|
||||
return hit_backface;
|
||||
}
|
||||
#endif
|
||||
#if defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
|
||||
if (hit) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (icell == iendcell) {
|
||||
break;
|
||||
}
|
||||
|
||||
bvec3 mask = lessThanEqual(side.xyz, min(side.yzx, side.zxy));
|
||||
side += vec3(mask) * delta;
|
||||
icell += ivec3(vec3(mask)) * step;
|
||||
|
||||
iters++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const float PI = 3.14159265f;
|
||||
const float GOLDEN_ANGLE = PI * (3.0 - sqrt(5.0));
|
||||
|
||||
vec3 vogel_hemisphere(uint p_index, uint p_count, float p_offset) {
|
||||
float r = sqrt(float(p_index) + 0.5f) / sqrt(float(p_count));
|
||||
float theta = float(p_index) * GOLDEN_ANGLE + p_offset;
|
||||
float y = cos(r * PI * 0.5);
|
||||
float l = sin(r * PI * 0.5);
|
||||
return vec3(l * cos(theta), l * sin(theta), y);
|
||||
}
|
||||
|
||||
float quick_hash(vec2 pos) {
|
||||
return fract(sin(dot(pos * 19.19, vec2(49.5791, 97.413))) * 49831.189237);
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
#ifdef MODE_LIGHT_PROBES
|
||||
int probe_index = int(gl_GlobalInvocationID.x);
|
||||
if (probe_index >= params.atlas_size.x) { //too large, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
ivec2 atlas_pos = ivec2(gl_GlobalInvocationID.xy) + params.region_ofs;
|
||||
if (any(greaterThanEqual(atlas_pos, params.atlas_size))) { //too large, do nothing
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MODE_DIRECT_LIGHT
|
||||
|
||||
vec3 normal = texelFetch(sampler2DArray(source_normal, linear_sampler), ivec3(atlas_pos, params.atlas_slice), 0).xyz;
|
||||
if (length(normal) < 0.5) {
|
||||
return; //empty texel, no process
|
||||
}
|
||||
vec3 position = texelFetch(sampler2DArray(source_position, linear_sampler), ivec3(atlas_pos, params.atlas_slice), 0).xyz;
|
||||
|
||||
//go through all lights
|
||||
//start by own light (emissive)
|
||||
vec3 static_light = vec3(0.0);
|
||||
vec3 dynamic_light = vec3(0.0);
|
||||
|
||||
#ifdef USE_SH_LIGHTMAPS
|
||||
vec4 sh_accum[4] = vec4[](
|
||||
vec4(0.0, 0.0, 0.0, 1.0),
|
||||
vec4(0.0, 0.0, 0.0, 1.0),
|
||||
vec4(0.0, 0.0, 0.0, 1.0),
|
||||
vec4(0.0, 0.0, 0.0, 1.0));
|
||||
#endif
|
||||
|
||||
for (uint i = 0; i < params.light_count; i++) {
|
||||
|
||||
vec3 light_pos;
|
||||
float attenuation;
|
||||
if (lights.data[i].type == LIGHT_TYPE_DIRECTIONAL) {
|
||||
vec3 light_vec = lights.data[i].direction;
|
||||
light_pos = position - light_vec * length(params.world_size);
|
||||
attenuation = 1.0;
|
||||
} else {
|
||||
light_pos = lights.data[i].position;
|
||||
float d = distance(position, light_pos);
|
||||
if (d > lights.data[i].range) {
|
||||
continue;
|
||||
}
|
||||
|
||||
d /= lights.data[i].range;
|
||||
|
||||
attenuation = pow(max(1.0 - d, 0.0), lights.data[i].attenuation);
|
||||
|
||||
if (lights.data[i].type == LIGHT_TYPE_SPOT) {
|
||||
|
||||
vec3 rel = normalize(position - light_pos);
|
||||
float angle = acos(dot(rel, lights.data[i].direction));
|
||||
if (angle > lights.data[i].spot_angle) {
|
||||
continue; //invisible, dont try
|
||||
}
|
||||
|
||||
float d = clamp(angle / lights.data[i].spot_angle, 0, 1);
|
||||
attenuation *= pow(1.0 - d, lights.data[i].spot_attenuation);
|
||||
}
|
||||
}
|
||||
|
||||
vec3 light_dir = normalize(light_pos - position);
|
||||
attenuation *= max(0.0, dot(normal, light_dir));
|
||||
|
||||
if (attenuation <= 0.0001) {
|
||||
continue; //no need to do anything
|
||||
}
|
||||
|
||||
if (!trace_ray(position + light_dir * params.bias, light_pos)) {
|
||||
vec3 light = lights.data[i].color * lights.data[i].energy * attenuation;
|
||||
if (lights.data[i].static_bake) {
|
||||
static_light += light;
|
||||
#ifdef USE_SH_LIGHTMAPS
|
||||
|
||||
float c[4] = float[](
|
||||
0.282095, //l0
|
||||
0.488603 * light_dir.y, //l1n1
|
||||
0.488603 * light_dir.z, //l1n0
|
||||
0.488603 * light_dir.x //l1p1
|
||||
);
|
||||
|
||||
for (uint j = 0; j < 4; j++) {
|
||||
sh_accum[j].rgb += light * c[j] * (1.0 / 3.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
dynamic_light += light;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vec3 albedo = texelFetch(sampler2DArray(albedo_tex, linear_sampler), ivec3(atlas_pos, params.atlas_slice), 0).rgb;
|
||||
vec3 emissive = texelFetch(sampler2DArray(emission_tex, linear_sampler), ivec3(atlas_pos, params.atlas_slice), 0).rgb;
|
||||
|
||||
dynamic_light *= albedo; //if it will bounce, must multiply by albedo
|
||||
dynamic_light += emissive;
|
||||
|
||||
//keep for lightprobes
|
||||
imageStore(primary_dynamic, ivec3(atlas_pos, params.atlas_slice), vec4(dynamic_light, 1.0));
|
||||
|
||||
dynamic_light += static_light * albedo; //send for bounces
|
||||
imageStore(dest_light, ivec3(atlas_pos, params.atlas_slice), vec4(dynamic_light, 1.0));
|
||||
|
||||
#ifdef USE_SH_LIGHTMAPS
|
||||
//keep for adding at the end
|
||||
imageStore(accum_light, ivec3(atlas_pos, params.atlas_slice * 4 + 0), sh_accum[0]);
|
||||
imageStore(accum_light, ivec3(atlas_pos, params.atlas_slice * 4 + 1), sh_accum[1]);
|
||||
imageStore(accum_light, ivec3(atlas_pos, params.atlas_slice * 4 + 2), sh_accum[2]);
|
||||
imageStore(accum_light, ivec3(atlas_pos, params.atlas_slice * 4 + 3), sh_accum[3]);
|
||||
|
||||
#else
|
||||
imageStore(accum_light, ivec3(atlas_pos, params.atlas_slice), vec4(static_light, 1.0));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MODE_BOUNCE_LIGHT
|
||||
|
||||
vec3 normal = texelFetch(sampler2DArray(source_normal, linear_sampler), ivec3(atlas_pos, params.atlas_slice), 0).xyz;
|
||||
if (length(normal) < 0.5) {
|
||||
return; //empty texel, no process
|
||||
}
|
||||
|
||||
vec3 position = texelFetch(sampler2DArray(source_position, linear_sampler), ivec3(atlas_pos, params.atlas_slice), 0).xyz;
|
||||
|
||||
vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
|
||||
vec3 tangent = normalize(cross(v0, normal));
|
||||
vec3 bitangent = normalize(cross(tangent, normal));
|
||||
mat3 normal_mat = mat3(tangent, bitangent, normal);
|
||||
|
||||
#ifdef USE_SH_LIGHTMAPS
|
||||
vec4 sh_accum[4] = vec4[](
|
||||
vec4(0.0, 0.0, 0.0, 1.0),
|
||||
vec4(0.0, 0.0, 0.0, 1.0),
|
||||
vec4(0.0, 0.0, 0.0, 1.0),
|
||||
vec4(0.0, 0.0, 0.0, 1.0));
|
||||
#endif
|
||||
vec3 light_average = vec3(0.0);
|
||||
for (uint i = params.ray_from; i < params.ray_to; i++) {
|
||||
vec3 ray_dir = normal_mat * vogel_hemisphere(i, params.ray_count, quick_hash(vec2(atlas_pos)));
|
||||
|
||||
uint tidx;
|
||||
vec3 barycentric;
|
||||
|
||||
vec3 light;
|
||||
if (trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric)) {
|
||||
//hit a triangle
|
||||
vec2 uv0 = vertices.data[triangles.data[tidx].indices.x].uv;
|
||||
vec2 uv1 = vertices.data[triangles.data[tidx].indices.y].uv;
|
||||
vec2 uv2 = vertices.data[triangles.data[tidx].indices.z].uv;
|
||||
vec3 uvw = vec3(barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2, float(triangles.data[tidx].slice));
|
||||
|
||||
light = textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb;
|
||||
} else {
|
||||
//did not hit a triangle, reach out for the sky
|
||||
vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir);
|
||||
|
||||
vec2 st = vec2(
|
||||
atan(sky_dir.x, sky_dir.z),
|
||||
acos(sky_dir.y));
|
||||
|
||||
if (st.x < 0.0)
|
||||
st.x += PI * 2.0;
|
||||
|
||||
st /= vec2(PI * 2.0, PI);
|
||||
|
||||
light = textureLod(sampler2D(environment, linear_sampler), st, 0.0).rgb;
|
||||
}
|
||||
|
||||
light_average += light;
|
||||
|
||||
#ifdef USE_SH_LIGHTMAPS
|
||||
|
||||
float c[4] = float[](
|
||||
0.282095, //l0
|
||||
0.488603 * ray_dir.y, //l1n1
|
||||
0.488603 * ray_dir.z, //l1n0
|
||||
0.488603 * ray_dir.x //l1p1
|
||||
);
|
||||
|
||||
for (uint j = 0; j < 4; j++) {
|
||||
sh_accum[j].rgb += light * c[j] * (8.0 / float(params.ray_count));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
vec3 light_total;
|
||||
if (params.ray_from == 0) {
|
||||
light_total = vec3(0.0);
|
||||
} else {
|
||||
light_total = imageLoad(bounce_accum, ivec3(atlas_pos, params.atlas_slice)).rgb;
|
||||
}
|
||||
|
||||
light_total += light_average;
|
||||
|
||||
#ifdef USE_SH_LIGHTMAPS
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
vec4 accum = imageLoad(accum_light, ivec3(atlas_pos, params.atlas_slice * 4 + i));
|
||||
accum.rgb += sh_accum[i].rgb;
|
||||
imageStore(accum_light, ivec3(atlas_pos, params.atlas_slice * 4 + i), accum);
|
||||
}
|
||||
|
||||
#endif
|
||||
if (params.ray_to == params.ray_count) {
|
||||
light_total /= float(params.ray_count);
|
||||
imageStore(dest_light, ivec3(atlas_pos, params.atlas_slice), vec4(light_total, 1.0));
|
||||
#ifndef USE_SH_LIGHTMAPS
|
||||
vec4 accum = imageLoad(accum_light, ivec3(atlas_pos, params.atlas_slice));
|
||||
accum.rgb += light_total;
|
||||
imageStore(accum_light, ivec3(atlas_pos, params.atlas_slice), accum);
|
||||
#endif
|
||||
} else {
|
||||
imageStore(bounce_accum, ivec3(atlas_pos, params.atlas_slice), vec4(light_total, 1.0));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MODE_UNOCCLUDE
|
||||
|
||||
//texel_size = 0.5;
|
||||
//compute tangents
|
||||
|
||||
vec4 position_alpha = imageLoad(position, ivec3(atlas_pos, params.atlas_slice));
|
||||
if (position_alpha.a < 0.5) {
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 vertex_pos = position_alpha.xyz;
|
||||
vec4 normal_tsize = imageLoad(unocclude, ivec3(atlas_pos, params.atlas_slice));
|
||||
|
||||
vec3 face_normal = normal_tsize.xyz;
|
||||
float texel_size = normal_tsize.w;
|
||||
|
||||
vec3 v0 = abs(face_normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
|
||||
vec3 tangent = normalize(cross(v0, face_normal));
|
||||
vec3 bitangent = normalize(cross(tangent, face_normal));
|
||||
vec3 base_pos = vertex_pos + face_normal * params.bias; //raise a bit
|
||||
|
||||
vec3 rays[4] = vec3[](tangent, bitangent, -tangent, -bitangent);
|
||||
float min_d = 1e20;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
vec3 ray_to = base_pos + rays[i] * texel_size;
|
||||
float d;
|
||||
vec3 norm;
|
||||
|
||||
if (trace_ray(base_pos, ray_to, d, norm)) {
|
||||
|
||||
if (d < min_d) {
|
||||
vertex_pos = base_pos + rays[i] * d + norm * params.bias * 10.0; //this bias needs to be greater than the regular bias, because otherwise later, rays will go the other side when pointing back.
|
||||
min_d = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
position_alpha.xyz = vertex_pos;
|
||||
|
||||
imageStore(position, ivec3(atlas_pos, params.atlas_slice), position_alpha);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MODE_LIGHT_PROBES
|
||||
|
||||
vec3 position = probe_positions.data[probe_index].xyz;
|
||||
|
||||
vec4 probe_sh_accum[9] = vec4[](
|
||||
vec4(0.0),
|
||||
vec4(0.0),
|
||||
vec4(0.0),
|
||||
vec4(0.0),
|
||||
vec4(0.0),
|
||||
vec4(0.0),
|
||||
vec4(0.0),
|
||||
vec4(0.0),
|
||||
vec4(0.0));
|
||||
|
||||
for (uint i = params.ray_from; i < params.ray_to; i++) {
|
||||
vec3 ray_dir = vogel_hemisphere(i, params.ray_count, quick_hash(vec2(float(probe_index), 0.0)));
|
||||
if (bool(i & 1)) {
|
||||
//throw to both sides, so alternate them
|
||||
ray_dir.z *= -1.0;
|
||||
}
|
||||
|
||||
uint tidx;
|
||||
vec3 barycentric;
|
||||
vec3 light;
|
||||
|
||||
if (trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric)) {
|
||||
vec2 uv0 = vertices.data[triangles.data[tidx].indices.x].uv;
|
||||
vec2 uv1 = vertices.data[triangles.data[tidx].indices.y].uv;
|
||||
vec2 uv2 = vertices.data[triangles.data[tidx].indices.z].uv;
|
||||
vec3 uvw = vec3(barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2, float(triangles.data[tidx].slice));
|
||||
|
||||
light = textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb;
|
||||
light += textureLod(sampler2DArray(source_direct_light, linear_sampler), uvw, 0.0).rgb;
|
||||
} else {
|
||||
|
||||
//did not hit a triangle, reach out for the sky
|
||||
vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir);
|
||||
|
||||
vec2 st = vec2(
|
||||
atan(sky_dir.x, sky_dir.z),
|
||||
acos(sky_dir.y));
|
||||
|
||||
if (st.x < 0.0)
|
||||
st.x += PI * 2.0;
|
||||
|
||||
st /= vec2(PI * 2.0, PI);
|
||||
|
||||
light = textureLod(sampler2D(environment, linear_sampler), st, 0.0).rgb;
|
||||
}
|
||||
|
||||
{
|
||||
float c[9] = float[](
|
||||
0.282095, //l0
|
||||
0.488603 * ray_dir.y, //l1n1
|
||||
0.488603 * ray_dir.z, //l1n0
|
||||
0.488603 * ray_dir.x, //l1p1
|
||||
1.092548 * ray_dir.x * ray_dir.y, //l2n2
|
||||
1.092548 * ray_dir.y * ray_dir.z, //l2n1
|
||||
//0.315392 * (ray_dir.x * ray_dir.x + ray_dir.y * ray_dir.y + 2.0 * ray_dir.z * ray_dir.z), //l20
|
||||
0.315392 * (3.0 * ray_dir.z * ray_dir.z - 1.0), //l20
|
||||
1.092548 * ray_dir.x * ray_dir.z, //l2p1
|
||||
0.546274 * (ray_dir.x * ray_dir.x - ray_dir.y * ray_dir.y) //l2p2
|
||||
);
|
||||
|
||||
for (uint j = 0; j < 9; j++) {
|
||||
probe_sh_accum[j].rgb += light * c[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (params.ray_from > 0) {
|
||||
for (uint j = 0; j < 9; j++) { //accum from existing
|
||||
probe_sh_accum[j] += light_probes.data[probe_index * 9 + j];
|
||||
}
|
||||
}
|
||||
|
||||
if (params.ray_to == params.ray_count) {
|
||||
for (uint j = 0; j < 9; j++) { //accum from existing
|
||||
probe_sh_accum[j] *= 4.0 / float(params.ray_count);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint j = 0; j < 9; j++) { //accum from existing
|
||||
light_probes.data[probe_index * 9 + j] = probe_sh_accum[j];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MODE_DILATE
|
||||
|
||||
vec4 c = texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos, params.atlas_slice), 0);
|
||||
//sides first, as they are closer
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(-1, 0), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(0, 1), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(1, 0), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(0, -1), params.atlas_slice), 0);
|
||||
//endpoints second
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(-1, -1), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(-1, 1), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(1, -1), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(1, 1), params.atlas_slice), 0);
|
||||
|
||||
//far sides third
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(-2, 0), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(0, 2), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(2, 0), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(0, -2), params.atlas_slice), 0);
|
||||
|
||||
//far-mid endpoints
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(-2, -1), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(-2, 1), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(2, -1), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(2, 1), params.atlas_slice), 0);
|
||||
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(-1, -2), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(-1, 2), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(1, -2), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(1, 2), params.atlas_slice), 0);
|
||||
//far endpoints
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(-2, -2), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(-2, 2), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(2, -2), params.atlas_slice), 0);
|
||||
c = c.a > 0.5 ? c : texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos + ivec2(2, 2), params.atlas_slice), 0);
|
||||
|
||||
imageStore(dest_light, ivec3(atlas_pos, params.atlas_slice), c);
|
||||
|
||||
#endif
|
||||
}
|
||||
170
modules/lightmapper_rd/lm_raster.glsl
Normal file
170
modules/lightmapper_rd/lm_raster.glsl
Normal file
@@ -0,0 +1,170 @@
|
||||
/* clang-format off */
|
||||
[vertex]
|
||||
|
||||
#version 450
|
||||
|
||||
VERSION_DEFINES
|
||||
|
||||
#include "lm_common_inc.glsl"
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
layout(location = 0) out vec3 vertex_interp;
|
||||
layout(location = 1) out vec3 normal_interp;
|
||||
layout(location = 2) out vec2 uv_interp;
|
||||
layout(location = 3) out vec3 barycentric;
|
||||
layout(location = 4) flat out uvec3 vertex_indices;
|
||||
layout(location = 5) flat out vec3 face_normal;
|
||||
|
||||
layout(push_constant, binding = 0, std430) uniform Params {
|
||||
vec2 atlas_size;
|
||||
vec2 uv_offset;
|
||||
vec3 to_cell_size;
|
||||
uint base_triangle;
|
||||
vec3 to_cell_offset;
|
||||
float bias;
|
||||
ivec3 grid_size;
|
||||
uint pad2;
|
||||
}
|
||||
params;
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
void main() {
|
||||
|
||||
uint triangle_idx = params.base_triangle + gl_VertexIndex / 3;
|
||||
uint triangle_subidx = gl_VertexIndex % 3;
|
||||
|
||||
vertex_indices = triangles.data[triangle_idx].indices;
|
||||
|
||||
uint vertex_idx;
|
||||
if (triangle_subidx == 0) {
|
||||
vertex_idx = vertex_indices.x;
|
||||
barycentric = vec3(1, 0, 0);
|
||||
} else if (triangle_subidx == 1) {
|
||||
vertex_idx = vertex_indices.y;
|
||||
barycentric = vec3(0, 1, 0);
|
||||
} else {
|
||||
vertex_idx = vertex_indices.z;
|
||||
barycentric = vec3(0, 0, 1);
|
||||
}
|
||||
|
||||
vertex_interp = vertices.data[vertex_idx].position;
|
||||
uv_interp = vertices.data[vertex_idx].uv;
|
||||
normal_interp = vec3(vertices.data[vertex_idx].normal_xy, vertices.data[vertex_idx].normal_z);
|
||||
|
||||
face_normal = -normalize(cross((vertices.data[vertex_indices.x].position - vertices.data[vertex_indices.y].position), (vertices.data[vertex_indices.x].position - vertices.data[vertex_indices.z].position)));
|
||||
|
||||
gl_Position = vec4((uv_interp + params.uv_offset) * 2.0 - 1.0, 0.0001, 1.0);
|
||||
;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
[fragment]
|
||||
|
||||
#version 450
|
||||
|
||||
VERSION_DEFINES
|
||||
|
||||
#include "lm_common_inc.glsl"
|
||||
|
||||
|
||||
layout(push_constant, binding = 0, std430) uniform Params {
|
||||
vec2 atlas_size;
|
||||
vec2 uv_offset;
|
||||
vec3 to_cell_size;
|
||||
uint base_triangle;
|
||||
vec3 to_cell_offset;
|
||||
float bias;
|
||||
ivec3 grid_size;
|
||||
uint pad2;
|
||||
} params;
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
layout(location = 0) in vec3 vertex_interp;
|
||||
layout(location = 1) in vec3 normal_interp;
|
||||
layout(location = 2) in vec2 uv_interp;
|
||||
layout(location = 3) in vec3 barycentric;
|
||||
layout(location = 4) in flat uvec3 vertex_indices;
|
||||
layout(location = 5) in flat vec3 face_normal;
|
||||
|
||||
layout(location = 0) out vec4 position;
|
||||
layout(location = 1) out vec4 normal;
|
||||
layout(location = 2) out vec4 unocclude;
|
||||
|
||||
void main() {
|
||||
|
||||
vec3 vertex_pos = vertex_interp;
|
||||
|
||||
{
|
||||
// smooth out vertex position by interpolating its projection in the 3 normal planes (normal plane is created by vertex pos and normal)
|
||||
// because we don't want to interpolate inwards, normals found pointing inwards are pushed out.
|
||||
|
||||
vec3 pos_a = vertices.data[vertex_indices.x].position;
|
||||
vec3 pos_b = vertices.data[vertex_indices.y].position;
|
||||
vec3 pos_c = vertices.data[vertex_indices.z].position;
|
||||
vec3 center = (pos_a + pos_b + pos_c) * 0.3333333;
|
||||
vec3 norm_a = vec3(vertices.data[vertex_indices.x].normal_xy, vertices.data[vertex_indices.x].normal_z);
|
||||
vec3 norm_b = vec3(vertices.data[vertex_indices.y].normal_xy, vertices.data[vertex_indices.y].normal_z);
|
||||
vec3 norm_c = vec3(vertices.data[vertex_indices.z].normal_xy, vertices.data[vertex_indices.z].normal_z);
|
||||
|
||||
{
|
||||
vec3 dir_a = normalize(pos_a - center);
|
||||
float d_a = dot(dir_a, norm_a);
|
||||
if (d_a < 0) {
|
||||
//pointing inwards
|
||||
norm_a = normalize(norm_a - dir_a * d_a);
|
||||
}
|
||||
}
|
||||
{
|
||||
vec3 dir_b = normalize(pos_b - center);
|
||||
float d_b = dot(dir_b, norm_b);
|
||||
if (d_b < 0) {
|
||||
//pointing inwards
|
||||
norm_b = normalize(norm_b - dir_b * d_b);
|
||||
}
|
||||
}
|
||||
{
|
||||
vec3 dir_c = normalize(pos_c - center);
|
||||
float d_c = dot(dir_c, norm_c);
|
||||
if (d_c < 0) {
|
||||
//pointing inwards
|
||||
norm_c = normalize(norm_c - dir_c * d_c);
|
||||
}
|
||||
}
|
||||
|
||||
float d_a = dot(norm_a, pos_a);
|
||||
float d_b = dot(norm_b, pos_b);
|
||||
float d_c = dot(norm_c, pos_c);
|
||||
|
||||
vec3 proj_a = vertex_pos - norm_a * (dot(norm_a, vertex_pos) - d_a);
|
||||
vec3 proj_b = vertex_pos - norm_b * (dot(norm_b, vertex_pos) - d_b);
|
||||
vec3 proj_c = vertex_pos - norm_c * (dot(norm_c, vertex_pos) - d_c);
|
||||
|
||||
vec3 smooth_position = proj_a * barycentric.x + proj_b * barycentric.y + proj_c * barycentric.z;
|
||||
|
||||
if (dot(face_normal, smooth_position) > dot(face_normal, vertex_pos)) { //only project outwards
|
||||
vertex_pos = smooth_position;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// unocclusion technique based on:
|
||||
// https://ndotl.wordpress.com/2018/08/29/baking-artifact-free-lightmaps/
|
||||
|
||||
/* compute texel size */
|
||||
vec3 delta_uv = max(abs(dFdx(vertex_interp)), abs(dFdy(vertex_interp)));
|
||||
float texel_size = max(delta_uv.x, max(delta_uv.y, delta_uv.z));
|
||||
texel_size *= sqrt(2.0); //expand to unit box edge length (again, worst case)
|
||||
|
||||
unocclude.xyz = face_normal;
|
||||
unocclude.w = texel_size;
|
||||
|
||||
//continued on lm_compute.glsl
|
||||
}
|
||||
|
||||
position = vec4(vertex_pos, 1.0);
|
||||
normal = vec4(normalize(normal_interp), 1.0);
|
||||
}
|
||||
64
modules/lightmapper_rd/register_types.cpp
Normal file
64
modules/lightmapper_rd/register_types.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "register_types.h"
|
||||
|
||||
#include "core/project_settings.h"
|
||||
#include "lightmapper_rd.h"
|
||||
#include "scene/3d/lightmapper.h"
|
||||
|
||||
#ifndef _3D_DISABLED
|
||||
static Lightmapper *create_lightmapper_rd() {
|
||||
return memnew(LightmapperRD);
|
||||
}
|
||||
#endif
|
||||
|
||||
void register_lightmapper_rd_types() {
|
||||
|
||||
GLOBAL_DEF("rendering/gpu_lightmapper/quality/low_quality_ray_count", 16);
|
||||
GLOBAL_DEF("rendering/gpu_lightmapper/quality/medium_quality_ray_count", 64);
|
||||
GLOBAL_DEF("rendering/gpu_lightmapper/quality/high_quality_ray_count", 256);
|
||||
GLOBAL_DEF("rendering/gpu_lightmapper/quality/ultra_quality_ray_count", 1024);
|
||||
GLOBAL_DEF("rendering/gpu_lightmapper/performance/max_rays_per_pass", 32);
|
||||
GLOBAL_DEF("rendering/gpu_lightmapper/performance/region_size", 512);
|
||||
|
||||
GLOBAL_DEF("rendering/gpu_lightmapper/quality/low_quality_probe_ray_count", 64);
|
||||
GLOBAL_DEF("rendering/gpu_lightmapper/quality/medium_quality_probe_ray_count", 256);
|
||||
GLOBAL_DEF("rendering/gpu_lightmapper/quality/high_quality_probe_ray_count", 512);
|
||||
GLOBAL_DEF("rendering/gpu_lightmapper/quality/ultra_quality_probe_ray_count", 2048);
|
||||
GLOBAL_DEF("rendering/gpu_lightmapper/performance/max_rays_per_probe_pass", 64);
|
||||
#ifndef _3D_DISABLED
|
||||
ClassDB::register_class<LightmapperRD>();
|
||||
Lightmapper::create_gpu = create_lightmapper_rd;
|
||||
#endif
|
||||
}
|
||||
|
||||
void unregister_lightmapper_rd_types() {
|
||||
}
|
||||
37
modules/lightmapper_rd/register_types.h
Normal file
37
modules/lightmapper_rd/register_types.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef LIGHTMAPPER_RD_REGISTER_TYPES_H
|
||||
#define LIGHTMAPPER_RD_REGISTER_TYPES_H
|
||||
|
||||
void register_lightmapper_rd_types();
|
||||
void unregister_lightmapper_rd_types();
|
||||
|
||||
#endif // XATLAS_UNWRAP_REGISTER_TYPES_H
|
||||
@@ -267,13 +267,21 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
|
||||
header.channels = channel_infos;
|
||||
header.pixel_types = pixel_types;
|
||||
header.requested_pixel_types = requested_pixel_types;
|
||||
header.compression_type = TINYEXR_COMPRESSIONTYPE_PIZ;
|
||||
|
||||
CharString utf8_filename = p_path.utf8();
|
||||
const char *err;
|
||||
int ret = SaveEXRImageToFile(&image, &header, utf8_filename.ptr(), &err);
|
||||
if (ret != TINYEXR_SUCCESS) {
|
||||
unsigned char *mem = nullptr;
|
||||
const char *err = nullptr;
|
||||
|
||||
size_t bytes = SaveEXRImageToMemory(&image, &header, &mem, &err);
|
||||
|
||||
if (bytes == 0) {
|
||||
print_error(String("Saving EXR failed. Error: {0}").format(varray(err)));
|
||||
return ERR_FILE_CANT_WRITE;
|
||||
} else {
|
||||
FileAccessRef ref = FileAccess::open(p_path, FileAccess::WRITE);
|
||||
ERR_FAIL_COND_V(!ref, ERR_FILE_CANT_WRITE);
|
||||
ref->store_buffer(mem, bytes);
|
||||
free(mem);
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
@@ -137,6 +137,7 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
|
||||
|
||||
pack_options.maxChartSize = 4096;
|
||||
pack_options.blockAlign = true;
|
||||
pack_options.padding = 1;
|
||||
pack_options.texelsPerUnit = 1.0 / p_texel_size;
|
||||
|
||||
xatlas::Atlas *atlas = xatlas::Create();
|
||||
|
||||
Reference in New Issue
Block a user