diff options
Diffstat (limited to 'scene/3d')
-rw-r--r-- | scene/3d/arvr_nodes.cpp | 10 | ||||
-rw-r--r-- | scene/3d/baked_lightmap.cpp | 84 | ||||
-rw-r--r-- | scene/3d/baked_lightmap.h | 22 | ||||
-rw-r--r-- | scene/3d/camera.cpp | 12 | ||||
-rw-r--r-- | scene/3d/camera.h | 2 | ||||
-rw-r--r-- | scene/3d/skeleton.cpp | 7 | ||||
-rw-r--r-- | scene/3d/voxel_light_baker.cpp | 170 | ||||
-rw-r--r-- | scene/3d/voxel_light_baker.h | 35 |
8 files changed, 240 insertions, 102 deletions
diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp index e1e0b9b1ce..2bb41bf49e 100644 --- a/scene/3d/arvr_nodes.cpp +++ b/scene/3d/arvr_nodes.cpp @@ -231,7 +231,7 @@ void ARVRController::_notification(int p_what) { void ARVRController::_bind_methods() { ClassDB::bind_method(D_METHOD("set_controller_id", "controller_id"), &ARVRController::set_controller_id); ClassDB::bind_method(D_METHOD("get_controller_id"), &ARVRController::get_controller_id); - ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_id", PROPERTY_HINT_RANGE, "1,32,1"), "set_controller_id", "get_controller_id"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_controller_id", "get_controller_id"); ClassDB::bind_method(D_METHOD("get_controller_name"), &ARVRController::get_controller_name); // passthroughs to information about our related joystick @@ -251,7 +251,8 @@ void ARVRController::_bind_methods() { }; void ARVRController::set_controller_id(int p_controller_id) { - // we don't check any bounds here, this controller may not yet be active and just be a place holder until it is. + // We don't check any bounds here, this controller may not yet be active and just be a place holder until it is. + // Note that setting this to 0 means this node is not bound to a controller yet. controller_id = p_controller_id; }; @@ -420,7 +421,7 @@ void ARVRAnchor::_bind_methods() { ClassDB::bind_method(D_METHOD("set_anchor_id", "anchor_id"), &ARVRAnchor::set_anchor_id); ClassDB::bind_method(D_METHOD("get_anchor_id"), &ARVRAnchor::get_anchor_id); - ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_id"), "set_anchor_id", "get_anchor_id"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_anchor_id", "get_anchor_id"); ClassDB::bind_method(D_METHOD("get_anchor_name"), &ARVRAnchor::get_anchor_name); ClassDB::bind_method(D_METHOD("get_is_active"), &ARVRAnchor::get_is_active); @@ -430,7 +431,8 @@ void ARVRAnchor::_bind_methods() { }; void ARVRAnchor::set_anchor_id(int p_anchor_id) { - // we don't check any bounds here, this anchor may not yet be active and just be a place holder until it is. + // We don't check any bounds here, this anchor may not yet be active and just be a place holder until it is. + // Note that setting this to 0 means this node is not bound to an anchor yet. anchor_id = p_anchor_id; }; diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index 754dcd9a6c..9a77626296 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -165,20 +165,20 @@ BakedLightmap::BakeBeginFunc BakedLightmap::bake_begin_function = NULL; BakedLightmap::BakeStepFunc BakedLightmap::bake_step_function = NULL; BakedLightmap::BakeEndFunc BakedLightmap::bake_end_function = NULL; -void BakedLightmap::set_bake_subdiv(Subdiv p_subdiv) { - bake_subdiv = p_subdiv; +void BakedLightmap::set_bake_cell_size(float p_cell_size) { + bake_cell_size = p_cell_size; } -BakedLightmap::Subdiv BakedLightmap::get_bake_subdiv() const { - return bake_subdiv; +float BakedLightmap::get_bake_cell_size() const { + return bake_cell_size; } -void BakedLightmap::set_capture_subdiv(Subdiv p_subdiv) { - capture_subdiv = p_subdiv; +void BakedLightmap::set_capture_cell_size(float p_cell_size) { + capture_cell_size = p_cell_size; } -BakedLightmap::Subdiv BakedLightmap::get_capture_subdiv() const { - return capture_subdiv; +float BakedLightmap::get_capture_cell_size() const { + return capture_cell_size; } void BakedLightmap::set_extents(const Vector3 &p_extents) { @@ -327,11 +327,29 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi Ref<BakedLightmapData> new_light_data; new_light_data.instance(); - static const int subdiv_value[SUBDIV_MAX] = { 8, 9, 10, 11 }; - VoxelLightBaker baker; - baker.begin_bake(subdiv_value[bake_subdiv], AABB(-extents, extents * 2.0)); + int bake_subdiv; + int capture_subdiv; + AABB bake_bounds; + { + bake_bounds = AABB(-extents, extents * 2.0); + int subdiv = nearest_power_of_2_templated(int(bake_bounds.get_longest_axis_size() / bake_cell_size)); + bake_bounds.size[bake_bounds.get_longest_axis_size()] = subdiv * bake_cell_size; + bake_subdiv = nearest_shift(subdiv) + 1; + + capture_subdiv = bake_subdiv; + float css = bake_cell_size; + while (css < capture_cell_size && capture_subdiv > 2) { + capture_subdiv--; + css *= 2.0; + } + + print_line("bake subdiv: " + itos(bake_subdiv)); + print_line("capture subdiv: " + itos(capture_subdiv)); + } + + baker.begin_bake(bake_subdiv, bake_bounds); List<PlotMesh> mesh_list; List<PlotLight> light_list; @@ -510,19 +528,19 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi } } - int csubdiv = subdiv_value[capture_subdiv]; AABB bounds = AABB(-extents, extents * 2); - new_light_data->set_cell_subdiv(csubdiv); + new_light_data->set_cell_subdiv(capture_subdiv); new_light_data->set_bounds(bounds); - new_light_data->set_octree(baker.create_capture_octree(csubdiv)); + new_light_data->set_octree(baker.create_capture_octree(capture_subdiv)); { + float bake_bound_size = bake_bounds.get_longest_axis_size(); Transform to_bounds; - to_bounds.basis.scale(Vector3(bounds.get_longest_axis_size(), bounds.get_longest_axis_size(), bounds.get_longest_axis_size())); + to_bounds.basis.scale(Vector3(bake_bound_size, bake_bound_size, bake_bound_size)); to_bounds.origin = bounds.position; Transform to_grid; - to_grid.basis.scale(Vector3(1 << (csubdiv - 1), 1 << (csubdiv - 1), 1 << (csubdiv - 1))); + to_grid.basis.scale(Vector3(1 << (capture_subdiv - 1), 1 << (capture_subdiv - 1), 1 << (capture_subdiv - 1))); Transform to_cell_space = to_grid * to_bounds.affine_inverse(); new_light_data->set_cell_space_transform(to_cell_space); @@ -693,11 +711,11 @@ void BakedLightmap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_light_data", "data"), &BakedLightmap::set_light_data); ClassDB::bind_method(D_METHOD("get_light_data"), &BakedLightmap::get_light_data); - ClassDB::bind_method(D_METHOD("set_bake_subdiv", "bake_subdiv"), &BakedLightmap::set_bake_subdiv); - ClassDB::bind_method(D_METHOD("get_bake_subdiv"), &BakedLightmap::get_bake_subdiv); + ClassDB::bind_method(D_METHOD("set_bake_cell_size", "bake_cell_size"), &BakedLightmap::set_bake_cell_size); + ClassDB::bind_method(D_METHOD("get_bake_cell_size"), &BakedLightmap::get_bake_cell_size); - ClassDB::bind_method(D_METHOD("set_capture_subdiv", "capture_subdiv"), &BakedLightmap::set_capture_subdiv); - ClassDB::bind_method(D_METHOD("get_capture_subdiv"), &BakedLightmap::get_capture_subdiv); + ClassDB::bind_method(D_METHOD("set_capture_cell_size", "capture_cell_size"), &BakedLightmap::set_capture_cell_size); + ClassDB::bind_method(D_METHOD("get_capture_cell_size"), &BakedLightmap::get_capture_cell_size); ClassDB::bind_method(D_METHOD("set_bake_quality", "bake_quality"), &BakedLightmap::set_bake_quality); ClassDB::bind_method(D_METHOD("get_bake_quality"), &BakedLightmap::get_bake_quality); @@ -724,23 +742,20 @@ void BakedLightmap::_bind_methods() { ClassDB::bind_method(D_METHOD("debug_bake"), &BakedLightmap::_debug_bake); ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); - ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_subdiv", PROPERTY_HINT_ENUM, "128,256,512,1024"), "set_bake_subdiv", "get_bake_subdiv"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "capture_subdiv", PROPERTY_HINT_ENUM, "128,256,512"), "set_capture_subdiv", "get_capture_subdiv"); + ADD_GROUP("Bake", "bake_"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_bake_cell_size", "get_bake_cell_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), "set_bake_quality", "get_bake_quality"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mode", PROPERTY_HINT_ENUM, "ConeTrace,RayTrace"), "set_bake_mode", "get_bake_mode"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_energy", "get_energy"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hdr"), "set_hdr", "is_hdr"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_energy", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_hdr"), "set_hdr", "is_hdr"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "bake_extents"), "set_extents", "get_extents"); + ADD_GROUP("Capture", "capture_"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "capture_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_capture_cell_size", "get_capture_cell_size"); + ADD_GROUP("Data", ""); ADD_PROPERTY(PropertyInfo(Variant::STRING, "image_path", PROPERTY_HINT_DIR), "set_image_path", "get_image_path"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "BakedIndirectLightData"), "set_light_data", "get_light_data"); - BIND_ENUM_CONSTANT(SUBDIV_128); - BIND_ENUM_CONSTANT(SUBDIV_256); - BIND_ENUM_CONSTANT(SUBDIV_512); - BIND_ENUM_CONSTANT(SUBDIV_1024); - BIND_ENUM_CONSTANT(SUBDIV_MAX); - BIND_ENUM_CONSTANT(BAKE_QUALITY_LOW); BIND_ENUM_CONSTANT(BAKE_QUALITY_MEDIUM); BIND_ENUM_CONSTANT(BAKE_QUALITY_HIGH); @@ -757,8 +772,9 @@ void BakedLightmap::_bind_methods() { BakedLightmap::BakedLightmap() { extents = Vector3(10, 10, 10); - bake_subdiv = SUBDIV_256; - capture_subdiv = SUBDIV_128; + bake_cell_size = 0.1; + capture_cell_size = 0.25; + bake_quality = BAKE_QUALITY_MEDIUM; bake_mode = BAKE_MODE_CONE_TRACE; energy = 1; diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h index 9e15f1bb10..9b53e41d73 100644 --- a/scene/3d/baked_lightmap.h +++ b/scene/3d/baked_lightmap.h @@ -61,15 +61,6 @@ class BakedLightmap : public VisualInstance { GDCLASS(BakedLightmap, VisualInstance); public: - enum Subdiv { - SUBDIV_128, - SUBDIV_256, - SUBDIV_512, - SUBDIV_1024, - SUBDIV_MAX - - }; - enum BakeQuality { BAKE_QUALITY_LOW, BAKE_QUALITY_MEDIUM, @@ -95,8 +86,8 @@ public: typedef void (*BakeEndFunc)(); private: - Subdiv bake_subdiv; - Subdiv capture_subdiv; + float bake_cell_size; + float capture_cell_size; Vector3 extents; float propagation; float energy; @@ -148,11 +139,11 @@ public: void set_light_data(const Ref<BakedLightmapData> &p_data); Ref<BakedLightmapData> get_light_data() const; - void set_bake_subdiv(Subdiv p_subdiv); - Subdiv get_bake_subdiv() const; + void set_bake_cell_size(float p_cell_size); + float get_bake_cell_size() const; - void set_capture_subdiv(Subdiv p_subdiv); - Subdiv get_capture_subdiv() const; + void set_capture_cell_size(float p_cell_size); + float get_capture_cell_size() const; void set_extents(const Vector3 &p_extents); Vector3 get_extents() const; @@ -182,7 +173,6 @@ public: BakedLightmap(); }; -VARIANT_ENUM_CAST(BakedLightmap::Subdiv); VARIANT_ENUM_CAST(BakedLightmap::BakeQuality); VARIANT_ENUM_CAST(BakedLightmap::BakeMode); VARIANT_ENUM_CAST(BakedLightmap::BakeError); diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 72c0b979af..c74abb7e2d 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -407,15 +407,6 @@ Camera::KeepAspect Camera::get_keep_aspect_mode() const { return keep_aspect; } -void Camera::set_vaspect(bool p_vaspect) { - set_keep_aspect_mode(p_vaspect ? KEEP_WIDTH : KEEP_HEIGHT); - _update_camera_mode(); -} - -bool Camera::get_vaspect() const { - return keep_aspect == KEEP_HEIGHT; -} - void Camera::set_doppler_tracking(DopplerTracking p_tracking) { if (doppler_tracking == p_tracking) @@ -468,14 +459,11 @@ void Camera::_bind_methods() { ClassDB::bind_method(D_METHOD("get_environment"), &Camera::get_environment); ClassDB::bind_method(D_METHOD("set_keep_aspect_mode", "mode"), &Camera::set_keep_aspect_mode); ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera::get_keep_aspect_mode); - ClassDB::bind_method(D_METHOD("set_vaspect"), &Camera::set_vaspect); - ClassDB::bind_method(D_METHOD("get_vaspect"), &Camera::get_vaspect); ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera::set_doppler_tracking); ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking); //ClassDB::bind_method(D_METHOD("_camera_make_current"),&Camera::_camera_make_current ); ADD_PROPERTY(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"), "set_keep_aspect_mode", "get_keep_aspect_mode"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vaspect"), "set_vaspect", "get_vaspect"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset"); diff --git a/scene/3d/camera.h b/scene/3d/camera.h index 520afb962b..d69a02afeb 100644 --- a/scene/3d/camera.h +++ b/scene/3d/camera.h @@ -148,8 +148,6 @@ public: void set_keep_aspect_mode(KeepAspect p_aspect); KeepAspect get_keep_aspect_mode() const; - void set_vaspect(bool p_vaspect); - bool get_vaspect() const; void set_v_offset(float p_offset); float get_v_offset() const; diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index d0e0937eca..3d40bb299a 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -180,6 +180,9 @@ void Skeleton::_notification(int p_what) { rest_global_inverse_dirty = false; } + Transform global_transform = get_global_transform(); + Transform global_transform_inverse = global_transform.affine_inverse(); + for (int i = 0; i < len; i++) { Bone &b = bonesptr[i]; @@ -239,7 +242,9 @@ void Skeleton::_notification(int p_what) { } } - vs->skeleton_bone_set_transform(skeleton, i, b.pose_global * b.rest_global_inverse); + Transform transform = b.pose_global * b.rest_global_inverse; + + vs->skeleton_bone_set_transform(skeleton, i, global_transform * (transform * global_transform_inverse)); for (List<uint32_t>::Element *E = b.nodes_bound.front(); E; E = E->next()) { diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp index 96ac5e8a05..bf0f801e32 100644 --- a/scene/3d/voxel_light_baker.cpp +++ b/scene/3d/voxel_light_baker.cpp @@ -1,5 +1,41 @@ +/*************************************************************************/ +/* voxel_light_baker.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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 "voxel_light_baker.h" #include "os/os.h" + +#include <stdlib.h> +#ifdef _OPENMP +#include <omp.h> +#endif + #define FINDMINMAX(x0, x1, x2, min, max) \ min = max = x0; \ if (x1 < min) min = x1; \ @@ -183,14 +219,23 @@ static bool fast_tri_box_overlap(const Vector3 &boxcenter, const Vector3 boxhalf return true; /* box and triangle overlaps */ } -static _FORCE_INLINE_ Vector2 get_uv(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv) { +static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv, const Vector3 *p_normal, Vector2 &r_uv, Vector3 &r_normal) { - if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) - return p_uv[0]; - if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) - return p_uv[1]; - if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) - return p_uv[2]; + if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) { + r_uv = p_uv[0]; + r_normal = p_normal[0]; + return; + } + if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) { + r_uv = p_uv[1]; + r_normal = p_normal[1]; + return; + } + if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) { + r_uv = p_uv[2]; + r_normal = p_normal[2]; + return; + } Vector3 v0 = p_vtx[1] - p_vtx[0]; Vector3 v1 = p_vtx[2] - p_vtx[0]; @@ -202,16 +247,20 @@ static _FORCE_INLINE_ Vector2 get_uv(const Vector3 &p_pos, const Vector3 *p_vtx, float d20 = v2.dot(v0); float d21 = v2.dot(v1); float denom = (d00 * d11 - d01 * d01); - if (denom == 0) - return p_uv[0]; + if (denom == 0) { + r_uv = p_uv[0]; + r_normal = p_normal[0]; + return; + } float v = (d11 * d20 - d01 * d21) / denom; float w = (d00 * d21 - d01 * d20) / denom; float u = 1.0f - v - w; - return p_uv[0] * u + p_uv[1] * v + p_uv[2] * w; + r_uv = p_uv[0] * u + p_uv[1] * v + p_uv[2] * w; + r_normal = (p_normal[0] * u + p_normal[1] * v + p_normal[2] * w).normalized(); } -void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) { +void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) { if (p_level == cell_subdiv - 1) { //plot the face by guessing it's albedo and emission value @@ -289,7 +338,11 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p intersection = Face3(p_vtx[0], p_vtx[1], p_vtx[2]).get_closest_point_to(intersection); - Vector2 uv = get_uv(intersection, p_vtx, p_uv); + Vector2 uv; + Vector3 lnormal; + get_uv_and_normal(intersection, p_vtx, p_uv, p_normal, uv, lnormal); + if (lnormal == Vector3()) //just in case normal as nor provided + lnormal = normal; int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); @@ -304,7 +357,7 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p emission_accum.g += p_material.emission[ofs].g; emission_accum.b += p_material.emission[ofs].b; - normal_accum += normal; + normal_accum += lnormal; alpha += 1.0; } @@ -316,7 +369,11 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]); Vector3 inters = f.get_closest_point_to(p_aabb.position + p_aabb.size * 0.5); - Vector2 uv = get_uv(inters, p_vtx, p_uv); + Vector3 lnormal; + Vector2 uv; + get_uv_and_normal(inters, p_vtx, p_uv, p_normal, uv, normal); + if (lnormal == Vector3()) //just in case normal as nor provided + lnormal = normal; int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); @@ -334,7 +391,7 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p emission_accum.g = p_material.emission[ofs].g * alpha; emission_accum.b = p_material.emission[ofs].b * alpha; - normal_accum *= alpha; + normal_accum = lnormal * alpha; } else { @@ -415,7 +472,7 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p bake_cells[child_idx].level = p_level + 1; } - _plot_face(bake_cells[p_idx].childs[i], p_level + 1, nx, ny, nz, p_vtx, p_uv, p_material, aabb); + _plot_face(bake_cells[p_idx].childs[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb); } } } @@ -539,9 +596,12 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con PoolVector<Vector3>::Read vr = vertices.read(); PoolVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV]; PoolVector<Vector2>::Read uvr; + PoolVector<Vector3> normals = a[Mesh::ARRAY_NORMAL]; + PoolVector<Vector3>::Read nr; PoolVector<int> index = a[Mesh::ARRAY_INDEX]; bool read_uv = false; + bool read_normals = false; if (uv.size()) { @@ -549,6 +609,11 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con read_uv = true; } + if (normals.size()) { + read_normals = true; + nr = normals.read(); + } + if (index.size()) { int facecount = index.size() / 3; @@ -558,6 +623,7 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con Vector3 vtxs[3]; Vector2 uvs[3]; + Vector3 normal[3]; for (int k = 0; k < 3; k++) { vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]); @@ -569,11 +635,17 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con } } + if (read_normals) { + for (int k = 0; k < 3; k++) { + normal[k] = nr[ir[j * 3 + k]]; + } + } + //test against original bounds if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) continue; //plot - _plot_face(0, 0, 0, 0, 0, vtxs, uvs, material, po2_bounds); + _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds); } } else { @@ -584,6 +656,7 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con Vector3 vtxs[3]; Vector2 uvs[3]; + Vector3 normal[3]; for (int k = 0; k < 3; k++) { vtxs[k] = p_xform.xform(vr[j * 3 + k]); @@ -595,11 +668,17 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con } } + if (read_normals) { + for (int k = 0; k < 3; k++) { + normal[k] = nr[j * 3 + k]; + } + } + //test against original bounds if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) continue; //plot face - _plot_face(0, 0, 0, 0, 0, vtxs, uvs, material, po2_bounds); + _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds); } } } @@ -1600,19 +1679,17 @@ Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const return accum; } -uint32_t xorshiftstate[] = { 123 }; // anything non-zero will do here - -_ALWAYS_INLINE_ uint32_t xorshift32() { +_ALWAYS_INLINE_ uint32_t xorshift32(uint32_t *state) { /* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */ - uint32_t x = xorshiftstate[0]; + uint32_t x = *state; x ^= x << 13; x ^= x >> 17; x ^= x << 5; - xorshiftstate[0] = x; + *state = x; return x; } -Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal) { +Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal, uint32_t *rng_state) { int samples_per_quality[3] = { 48, 128, 512 }; @@ -1634,20 +1711,23 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V const Light *light = bake_light.ptr(); const Cell *cells = bake_cells.ptr(); + // Prevent false sharing when running on OpenMP + uint32_t local_rng_state = *rng_state; + for (int i = 0; i < samples; i++) { - float random_angle1 = (((xorshift32() % 65535) / 65535.0) * 2.0 - 1.0) * spread; + float random_angle1 = (((xorshift32(&local_rng_state) % 65535) / 65535.0) * 2.0 - 1.0) * spread; Vector3 axis(0, sin(random_angle1), cos(random_angle1)); - float random_angle2 = ((xorshift32() % 65535) / 65535.0) * Math_PI * 2.0; + float random_angle2 = ((xorshift32(&local_rng_state) % 65535) / 65535.0) * Math_PI * 2.0; Basis rot(Vector3(0, 0, 1), random_angle2); axis = rot.xform(axis); Vector3 direction = normal_xform.xform(axis).normalized(); - Vector3 pos = p_pos + Vector3(0.5, 0.5, 0.5) + direction * bias; - Vector3 advance = direction * _get_normal_advance(direction); + Vector3 pos = p_pos /*+ Vector3(0.5, 0.5, 0.5)*/ + advance * bias; + uint32_t cell = CHILD_EMPTY; while (cell == CHILD_EMPTY) { @@ -1709,9 +1789,14 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V accum.y += light[cell].accum[i][1] * amount; accum.z += light[cell].accum[i][2] * amount; } + accum.x += cells[cell].emission[0]; + accum.y += cells[cell].emission[1]; + accum.z += cells[cell].emission[2]; } } + // Make sure we don't reset this thread's RNG state + *rng_state = local_rng_state; return accum / samples; } @@ -1758,6 +1843,7 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh Vector3 vertex[3]; Vector3 normal[3]; Vector2 uv[3]; + for (int j = 0; j < 3; j++) { int idx = ic ? ir[i * 3 + j] : i * 3 + j; vertex[j] = xform.xform(vr[idx]); @@ -1768,21 +1854,43 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh _plot_triangle(uv, vertex, normal, lightmap.ptrw(), width, height); } } - //step 3 perform voxel cone trace on lightmap pixels + //step 3 perform voxel cone trace on lightmap pixels { LightMap *lightmap_ptr = lightmap.ptrw(); uint64_t begin_time = OS::get_singleton()->get_ticks_usec(); volatile int lines = 0; + // make sure our OS-level rng is seeded + srand(OS::get_singleton()->get_ticks_usec()); + + // setup an RNG state for each OpenMP thread + uint32_t threadcount = 1; + uint32_t threadnum = 0; +#ifdef _OPENMP + threadcount = omp_get_max_threads(); +#endif + Vector<uint32_t> rng_states; + rng_states.resize(threadcount); + for (uint32_t i = 0; i < threadcount; i++) { + do { + rng_states[i] = rand(); + } while (rng_states[i] == 0); + } + uint32_t *rng_states_p = rng_states.ptrw(); + for (int i = 0; i < height; i++) { //print_line("bake line " + itos(i) + " / " + itos(height)); #ifdef _OPENMP -#pragma omp parallel for schedule(dynamic, 1) +#pragma omp parallel for schedule(dynamic, 1) private(threadnum) #endif for (int j = 0; j < width; j++) { +#ifdef _OPENMP + threadnum = omp_get_thread_num(); +#endif + //if (i == 125 && j == 280) { LightMap *pixel = &lightmap_ptr[i * width + j]; @@ -1795,7 +1903,7 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy; } break; case BAKE_MODE_RAY_TRACE: { - pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal) * energy; + pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal, &rng_states_p[threadnum]) * energy; } break; // pixel->light = Vector3(1, 1, 1); //} diff --git a/scene/3d/voxel_light_baker.h b/scene/3d/voxel_light_baker.h index 6dee2ee69b..7db31f8a67 100644 --- a/scene/3d/voxel_light_baker.h +++ b/scene/3d/voxel_light_baker.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* voxel_light_baker.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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 VOXEL_LIGHT_BAKER_H #define VOXEL_LIGHT_BAKER_H @@ -99,7 +129,8 @@ private: Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add); MaterialCache _get_material_cache(Ref<Material> p_material); - void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb); + + void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb); void _fixup_plot(int p_idx, int p_level); void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, DebugMode p_mode); void _check_init_light(); @@ -117,7 +148,7 @@ private: _FORCE_INLINE_ void _sample_baked_octree_filtered_and_anisotropic(const Vector3 &p_posf, const Vector3 &p_direction, float p_level, Vector3 &r_color, float &r_alpha); _FORCE_INLINE_ Vector3 _voxel_cone_trace(const Vector3 &p_pos, const Vector3 &p_normal, float p_aperture); _FORCE_INLINE_ Vector3 _compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 &p_normal); - _FORCE_INLINE_ Vector3 _compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal); + _FORCE_INLINE_ Vector3 _compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal, uint32_t *rng_state); public: void begin_bake(int p_subdiv, const AABB &p_bounds); |