initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
This commit is contained in:
14
modules/lightmapper_rd/SCsub
Normal file
14
modules/lightmapper_rd/SCsub
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
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")
|
||||
env_lightmapper_rd.Depends(Glob("*.glsl.gen.h"), ["lm_common_inc.glsl", "#glsl_builders.py"])
|
||||
|
||||
# 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 env.editor_build
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
2418
modules/lightmapper_rd/lightmapper_rd.cpp
Normal file
2418
modules/lightmapper_rd/lightmapper_rd.cpp
Normal file
File diff suppressed because it is too large
Load Diff
320
modules/lightmapper_rd/lightmapper_rd.h
Normal file
320
modules/lightmapper_rd/lightmapper_rd.h
Normal file
@@ -0,0 +1,320 @@
|
||||
/**************************************************************************/
|
||||
/* lightmapper_rd.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/templates/local_vector.h"
|
||||
#include "scene/3d/lightmapper.h"
|
||||
#include "scene/resources/mesh.h"
|
||||
#include "servers/rendering/rendering_device.h"
|
||||
|
||||
class RDShaderFile;
|
||||
class LightmapperRD : public Lightmapper {
|
||||
GDCLASS(LightmapperRD, Lightmapper)
|
||||
|
||||
struct BakeParameters {
|
||||
float world_size[3] = {};
|
||||
float bias = 0.0;
|
||||
|
||||
float to_cell_offset[3] = {};
|
||||
int32_t grid_size = 0;
|
||||
|
||||
float to_cell_size[3] = {};
|
||||
uint32_t light_count = 0;
|
||||
|
||||
float env_transform[12] = {};
|
||||
|
||||
int32_t atlas_size[2] = {};
|
||||
float exposure_normalization = 0.0f;
|
||||
uint32_t bounces = 0;
|
||||
|
||||
float bounce_indirect_energy = 0.0f;
|
||||
uint32_t shadowmask_light_idx = 0;
|
||||
uint32_t transparency_rays = 0;
|
||||
float supersampling_factor = 0.0f;
|
||||
};
|
||||
|
||||
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 = 0.0;
|
||||
float color[3] = {};
|
||||
float size = 0.0;
|
||||
float range = 0.0;
|
||||
float attenuation = 0.0;
|
||||
float cos_spot_angle = 0.0;
|
||||
float inv_spot_attenuation = 0.0;
|
||||
float indirect_energy = 0.0;
|
||||
float shadow_blur = 0.0;
|
||||
uint32_t static_bake = 0;
|
||||
uint32_t pad = 0;
|
||||
|
||||
bool operator<(const Light &p_light) const {
|
||||
return type < p_light.type;
|
||||
}
|
||||
};
|
||||
|
||||
struct LightMetadata {
|
||||
String name;
|
||||
uint32_t type = LIGHT_TYPE_DIRECTIONAL;
|
||||
|
||||
bool operator<(const LightMetadata &p_light) const {
|
||||
return type < p_light.type;
|
||||
}
|
||||
};
|
||||
|
||||
struct Vertex {
|
||||
float position[3] = {};
|
||||
float normal_z = 0.0;
|
||||
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_murmur3_one_float(p_edge.a.x);
|
||||
h = hash_murmur3_one_float(p_edge.a.y, h);
|
||||
h = hash_murmur3_one_float(p_edge.a.z, h);
|
||||
h = hash_murmur3_one_float(p_edge.b.x, h);
|
||||
h = hash_murmur3_one_float(p_edge.b.y, h);
|
||||
h = hash_murmur3_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_murmur3_one_float(p_vtx.position[0]);
|
||||
h = hash_murmur3_one_float(p_vtx.position[1], h);
|
||||
h = hash_murmur3_one_float(p_vtx.position[2], h);
|
||||
h = hash_murmur3_one_float(p_vtx.uv[0], h);
|
||||
h = hash_murmur3_one_float(p_vtx.uv[1], h);
|
||||
h = hash_murmur3_one_float(p_vtx.normal_xy[0], h);
|
||||
h = hash_murmur3_one_float(p_vtx.normal_xy[1], h);
|
||||
h = hash_murmur3_one_float(p_vtx.normal_z, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
};
|
||||
|
||||
struct Triangle {
|
||||
uint32_t indices[3] = {};
|
||||
uint32_t slice = 0;
|
||||
float min_bounds[3] = {};
|
||||
uint32_t cull_mode = 0;
|
||||
float max_bounds[3] = {};
|
||||
float pad1 = 0.0;
|
||||
bool operator<(const Triangle &p_triangle) const {
|
||||
return slice < p_triangle.slice;
|
||||
}
|
||||
};
|
||||
|
||||
struct ClusterAABB {
|
||||
float min_bounds[3];
|
||||
float pad0 = 0.0f;
|
||||
float max_bounds[3];
|
||||
float pad1 = 0.0f;
|
||||
};
|
||||
|
||||
Vector<MeshInstance> mesh_instances;
|
||||
|
||||
Vector<Light> lights;
|
||||
Vector<LightMetadata> light_metadata;
|
||||
|
||||
struct TriangleSort {
|
||||
uint32_t cell_index = 0;
|
||||
uint32_t triangle_index = 0;
|
||||
AABB triangle_aabb;
|
||||
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
template <int T>
|
||||
struct TriangleSortAxis {
|
||||
bool operator()(const TriangleSort &p_a, const TriangleSort &p_b) const {
|
||||
return p_a.triangle_aabb.get_center()[T] < p_b.triangle_aabb.get_center()[T];
|
||||
}
|
||||
};
|
||||
|
||||
void _plot_triangle_into_triangle_index_list(int p_size, const Vector3i &p_ofs, const AABB &p_bounds, const Vector3 p_points[3], uint32_t p_triangle_index, LocalVector<TriangleSort> &triangles, uint32_t p_grid_size);
|
||||
void _sort_triangle_clusters(uint32_t p_cluster_size, uint32_t p_cluster_index, uint32_t p_index_start, uint32_t p_count, LocalVector<TriangleSort> &p_triangle_sort, LocalVector<ClusterAABB> &p_cluster_aabb);
|
||||
|
||||
struct RasterPushConstant {
|
||||
float atlas_size[2] = {};
|
||||
float uv_offset[2] = {};
|
||||
float to_cell_size[3] = {};
|
||||
uint32_t base_triangle = 0;
|
||||
float to_cell_offset[3] = {};
|
||||
float bias = 0.0;
|
||||
int32_t grid_size[3] = {};
|
||||
uint32_t pad2 = 0;
|
||||
};
|
||||
|
||||
struct RasterSeamsPushConstant {
|
||||
uint32_t base_index = 0;
|
||||
uint32_t slice = 0;
|
||||
float uv_offset[2] = {};
|
||||
uint32_t debug = 0;
|
||||
float blend = 0.0;
|
||||
uint32_t pad[2] = {};
|
||||
};
|
||||
|
||||
struct PushConstant {
|
||||
uint32_t atlas_slice = 0;
|
||||
uint32_t ray_count = 0;
|
||||
uint32_t ray_from = 0;
|
||||
uint32_t ray_to = 0;
|
||||
uint32_t region_ofs[2] = {};
|
||||
uint32_t probe_count = 0;
|
||||
uint32_t denoiser_range = 0;
|
||||
};
|
||||
|
||||
Vector<Ref<Image>> lightmap_textures;
|
||||
Vector<Ref<Image>> shadowmask_textures;
|
||||
Vector<Color> probe_values;
|
||||
|
||||
struct DilateParams {
|
||||
uint32_t radius;
|
||||
uint32_t pad[3];
|
||||
};
|
||||
|
||||
struct DenoiseParams {
|
||||
float spatial_bandwidth;
|
||||
float light_bandwidth;
|
||||
float albedo_bandwidth;
|
||||
float normal_bandwidth;
|
||||
|
||||
int half_search_window;
|
||||
float filter_strength;
|
||||
float pad[2];
|
||||
};
|
||||
|
||||
BakeError _blit_meshes_into_atlas(int p_max_texture_size, int p_denoiser_range, Vector<Ref<Image>> &albedo_images, Vector<Ref<Image>> &emission_images, AABB &bounds, Size2i &atlas_size, int &atlas_slices, float p_supersampling_factor, 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, uint32_t p_cluster_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 &lights_buffer, RID &r_triangle_indices_buffer, RID &r_cluster_indices_buffer, RID &r_cluster_aabbs_buffer, RID &probe_positions_buffer, RID &grid_texture, 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);
|
||||
|
||||
BakeError _dilate(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices);
|
||||
BakeError _denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, RID p_unocclude_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function, void *p_bake_userdata);
|
||||
BakeError _pack_l1(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices);
|
||||
|
||||
Error _store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name, bool p_shadowmask);
|
||||
Ref<Image> _read_pfm(const String &p_name, bool p_shadowmask);
|
||||
BakeError _denoise_oidn(RenderingDevice *p_rd, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, bool p_shadowmask, const String &p_exe);
|
||||
|
||||
public:
|
||||
virtual void add_mesh(const MeshData &p_mesh) override;
|
||||
virtual void add_directional_light(const String &p_name, bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_angular_distance, float p_shadow_blur) override;
|
||||
virtual void add_omni_light(const String &p_name, bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) override;
|
||||
virtual void add_spot_light(const String &p_name, bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) override;
|
||||
virtual void add_probe(const Vector3 &p_position) override;
|
||||
virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_denoiser_range, int p_bounces, float p_bounce_indirect_energy, float p_bias, int p_max_texture_size, bool p_bake_sh, bool p_bake_shadowmask, bool p_texture_for_bounces, 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, float p_exposure_normalization = 1.0, float p_supersampling_factor = 1.0f) override;
|
||||
|
||||
int get_bake_texture_count() const override;
|
||||
Ref<Image> get_bake_texture(int p_index) const override;
|
||||
int get_shadowmask_texture_count() const override;
|
||||
Ref<Image> get_shadowmask_texture(int p_index) const override;
|
||||
int get_bake_mesh_count() const override;
|
||||
Variant get_bake_mesh_userdata(int p_index) const override;
|
||||
Rect2 get_bake_mesh_uv_scale(int p_index) const override;
|
||||
int get_bake_mesh_texture_slice(int p_index) const override;
|
||||
int get_bake_probe_count() const override;
|
||||
Vector3 get_bake_probe_point(int p_probe) const override;
|
||||
Vector<Color> get_bake_probe_sh(int p_probe) const override;
|
||||
|
||||
LightmapperRD();
|
||||
};
|
108
modules/lightmapper_rd/lm_blendseams.glsl
Normal file
108
modules/lightmapper_rd/lm_blendseams.glsl
Normal file
@@ -0,0 +1,108 @@
|
||||
#[versions]
|
||||
|
||||
lines = "#define MODE_LINES";
|
||||
triangles = "#define MODE_TRIANGLES";
|
||||
|
||||
#[vertex]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "lm_common_inc.glsl"
|
||||
|
||||
layout(push_constant, 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
|
||||
}
|
||||
|
||||
#[fragment]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "lm_common_inc.glsl"
|
||||
|
||||
layout(push_constant, 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
|
||||
}
|
||||
}
|
131
modules/lightmapper_rd/lm_common_inc.glsl
Normal file
131
modules/lightmapper_rd/lm_common_inc.glsl
Normal file
@@ -0,0 +1,131 @@
|
||||
|
||||
layout(set = 0, binding = 0) uniform BakeParameters {
|
||||
vec3 world_size;
|
||||
float bias;
|
||||
|
||||
vec3 to_cell_offset;
|
||||
int grid_size;
|
||||
|
||||
vec3 to_cell_size;
|
||||
uint light_count;
|
||||
|
||||
mat3x4 env_transform;
|
||||
|
||||
ivec2 atlas_size;
|
||||
float exposure_normalization;
|
||||
uint bounces;
|
||||
|
||||
float bounce_indirect_energy;
|
||||
int shadowmask_light_idx;
|
||||
uint transparency_rays;
|
||||
float supersampling_factor;
|
||||
}
|
||||
bake_params;
|
||||
|
||||
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;
|
||||
|
||||
#define CULL_DISABLED 0
|
||||
#define CULL_FRONT 1
|
||||
#define CULL_BACK 2
|
||||
|
||||
struct Triangle {
|
||||
uvec3 indices;
|
||||
uint slice;
|
||||
vec3 min_bounds;
|
||||
uint cull_mode;
|
||||
vec3 max_bounds;
|
||||
uint pad1;
|
||||
};
|
||||
|
||||
struct ClusterAABB {
|
||||
vec3 min_bounds;
|
||||
uint pad0;
|
||||
vec3 max_bounds;
|
||||
uint pad1;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 2, std430) restrict readonly buffer Triangles {
|
||||
Triangle data[];
|
||||
}
|
||||
triangles;
|
||||
|
||||
layout(set = 0, binding = 3, std430) restrict readonly buffer TriangleIndices {
|
||||
uint data[];
|
||||
}
|
||||
triangle_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 cos_spot_angle;
|
||||
float inv_spot_attenuation;
|
||||
|
||||
float indirect_energy;
|
||||
float shadow_blur;
|
||||
bool static_bake;
|
||||
uint pad;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 4, std430) restrict readonly buffer Lights {
|
||||
Light data[];
|
||||
}
|
||||
lights;
|
||||
|
||||
struct Seam {
|
||||
uvec2 a;
|
||||
uvec2 b;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 5, std430) restrict readonly buffer Seams {
|
||||
Seam data[];
|
||||
}
|
||||
seams;
|
||||
|
||||
layout(set = 0, binding = 6, std430) restrict readonly buffer Probes {
|
||||
vec4 data[];
|
||||
}
|
||||
probe_positions;
|
||||
|
||||
layout(set = 0, binding = 7) uniform utexture3D grid;
|
||||
|
||||
layout(set = 0, binding = 8) uniform texture2DArray albedo_tex;
|
||||
layout(set = 0, binding = 9) uniform texture2DArray emission_tex;
|
||||
|
||||
layout(set = 0, binding = 10) uniform sampler linear_sampler;
|
||||
|
||||
layout(set = 0, binding = 11, std430) restrict readonly buffer ClusterIndices {
|
||||
uint data[];
|
||||
}
|
||||
cluster_indices;
|
||||
|
||||
layout(set = 0, binding = 12, std430) restrict readonly buffer ClusterAABBs {
|
||||
ClusterAABB data[];
|
||||
}
|
||||
cluster_aabbs;
|
||||
|
||||
// Fragment action constants
|
||||
const uint FA_NONE = 0;
|
||||
const uint FA_SMOOTHEN_POSITION = 1;
|
1304
modules/lightmapper_rd/lm_compute.glsl
Normal file
1304
modules/lightmapper_rd/lm_compute.glsl
Normal file
File diff suppressed because it is too large
Load Diff
167
modules/lightmapper_rd/lm_raster.glsl
Normal file
167
modules/lightmapper_rd/lm_raster.glsl
Normal file
@@ -0,0 +1,167 @@
|
||||
#[vertex]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "lm_common_inc.glsl"
|
||||
|
||||
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(location = 6) flat out uint fragment_action;
|
||||
|
||||
layout(push_constant, 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;
|
||||
|
||||
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)));
|
||||
|
||||
{
|
||||
const float FLAT_THRESHOLD = 0.99;
|
||||
const vec3 norm_a = vec3(vertices.data[vertex_indices.x].normal_xy, vertices.data[vertex_indices.x].normal_z);
|
||||
const vec3 norm_b = vec3(vertices.data[vertex_indices.y].normal_xy, vertices.data[vertex_indices.y].normal_z);
|
||||
const vec3 norm_c = vec3(vertices.data[vertex_indices.z].normal_xy, vertices.data[vertex_indices.z].normal_z);
|
||||
fragment_action = (dot(norm_a, norm_b) < FLAT_THRESHOLD || dot(norm_a, norm_c) < FLAT_THRESHOLD || dot(norm_b, norm_c) < FLAT_THRESHOLD) ? FA_SMOOTHEN_POSITION : FA_NONE;
|
||||
}
|
||||
|
||||
gl_Position = vec4((uv_interp + params.uv_offset) * 2.0 - 1.0, 0.0001, 1.0);
|
||||
}
|
||||
|
||||
#[fragment]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "lm_common_inc.glsl"
|
||||
|
||||
layout(push_constant, 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;
|
||||
|
||||
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 = 6) in flat uint fragment_action;
|
||||
|
||||
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;
|
||||
|
||||
if (fragment_action == FA_SMOOTHEN_POSITION) {
|
||||
// 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);
|
||||
}
|
74
modules/lightmapper_rd/register_types.cpp
Normal file
74
modules/lightmapper_rd/register_types.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/**************************************************************************/
|
||||
/* register_types.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "lightmapper_rd.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "scene/3d/lightmapper.h"
|
||||
|
||||
#ifndef _3D_DISABLED
|
||||
static Lightmapper *create_lightmapper_rd() {
|
||||
return memnew(LightmapperRD);
|
||||
}
|
||||
#endif
|
||||
|
||||
void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level) {
|
||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/low_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 32);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/medium_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 128);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/high_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 512);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/ultra_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 2048);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/max_rays_per_pass", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 4);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/region_size", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 512);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/max_transparency_rays", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 8);
|
||||
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/low_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 64);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/medium_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 256);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/high_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 512);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/ultra_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 2048);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/max_rays_per_probe_pass", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
|
||||
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/denoising/denoiser", PROPERTY_HINT_ENUM, "JNLM,OIDN"), 0);
|
||||
#ifndef _3D_DISABLED
|
||||
GDREGISTER_CLASS(LightmapperRD);
|
||||
Lightmapper::create_gpu = create_lightmapper_rd;
|
||||
#endif
|
||||
}
|
||||
|
||||
void uninitialize_lightmapper_rd_module(ModuleInitializationLevel p_level) {
|
||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||
return;
|
||||
}
|
||||
}
|
36
modules/lightmapper_rd/register_types.h
Normal file
36
modules/lightmapper_rd/register_types.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/**************************************************************************/
|
||||
/* register_types.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level);
|
||||
void uninitialize_lightmapper_rd_module(ModuleInitializationLevel p_level);
|
Reference in New Issue
Block a user