You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2026-01-05 19:31:35 +00:00
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:
@@ -878,3 +878,114 @@ Basis Basis::slerp(const Basis &target, const real_t &t) const {
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void Basis::rotate_sh(real_t *p_values) {
|
||||
|
||||
// code by John Hable
|
||||
// http://filmicworlds.com/blog/simple-and-fast-spherical-harmonic-rotation/
|
||||
// this code is Public Domain
|
||||
|
||||
const static real_t s_c3 = 0.94617469575; // (3*sqrt(5))/(4*sqrt(pi))
|
||||
const static real_t s_c4 = -0.31539156525; // (-sqrt(5))/(4*sqrt(pi))
|
||||
const static real_t s_c5 = 0.54627421529; // (sqrt(15))/(4*sqrt(pi))
|
||||
|
||||
const static real_t s_c_scale = 1.0 / 0.91529123286551084;
|
||||
const static real_t s_c_scale_inv = 0.91529123286551084;
|
||||
|
||||
const static real_t s_rc2 = 1.5853309190550713 * s_c_scale;
|
||||
const static real_t s_c4_div_c3 = s_c4 / s_c3;
|
||||
const static real_t s_c4_div_c3_x2 = (s_c4 / s_c3) * 2.0;
|
||||
|
||||
const static real_t s_scale_dst2 = s_c3 * s_c_scale_inv;
|
||||
const static real_t s_scale_dst4 = s_c5 * s_c_scale_inv;
|
||||
|
||||
real_t src[9] = { p_values[0], p_values[1], p_values[2], p_values[3], p_values[4], p_values[5], p_values[6], p_values[7], p_values[8] };
|
||||
|
||||
real_t m00 = elements[0][0];
|
||||
real_t m01 = elements[0][1];
|
||||
real_t m02 = elements[0][2];
|
||||
real_t m10 = elements[1][0];
|
||||
real_t m11 = elements[1][1];
|
||||
real_t m12 = elements[1][2];
|
||||
real_t m20 = elements[2][0];
|
||||
real_t m21 = elements[2][1];
|
||||
real_t m22 = elements[2][2];
|
||||
|
||||
p_values[0] = src[0];
|
||||
p_values[1] = m11 * src[1] - m12 * src[2] + m10 * src[3];
|
||||
p_values[2] = -m21 * src[1] + m22 * src[2] - m20 * src[3];
|
||||
p_values[3] = m01 * src[1] - m02 * src[2] + m00 * src[3];
|
||||
|
||||
real_t sh0 = src[7] + src[8] + src[8] - src[5];
|
||||
real_t sh1 = src[4] + s_rc2 * src[6] + src[7] + src[8];
|
||||
real_t sh2 = src[4];
|
||||
real_t sh3 = -src[7];
|
||||
real_t sh4 = -src[5];
|
||||
|
||||
// Rotations. R0 and R1 just use the raw matrix columns
|
||||
real_t r2x = m00 + m01;
|
||||
real_t r2y = m10 + m11;
|
||||
real_t r2z = m20 + m21;
|
||||
|
||||
real_t r3x = m00 + m02;
|
||||
real_t r3y = m10 + m12;
|
||||
real_t r3z = m20 + m22;
|
||||
|
||||
real_t r4x = m01 + m02;
|
||||
real_t r4y = m11 + m12;
|
||||
real_t r4z = m21 + m22;
|
||||
|
||||
// dense matrix multiplication one column at a time
|
||||
|
||||
// column 0
|
||||
real_t sh0_x = sh0 * m00;
|
||||
real_t sh0_y = sh0 * m10;
|
||||
real_t d0 = sh0_x * m10;
|
||||
real_t d1 = sh0_y * m20;
|
||||
real_t d2 = sh0 * (m20 * m20 + s_c4_div_c3);
|
||||
real_t d3 = sh0_x * m20;
|
||||
real_t d4 = sh0_x * m00 - sh0_y * m10;
|
||||
|
||||
// column 1
|
||||
real_t sh1_x = sh1 * m02;
|
||||
real_t sh1_y = sh1 * m12;
|
||||
d0 += sh1_x * m12;
|
||||
d1 += sh1_y * m22;
|
||||
d2 += sh1 * (m22 * m22 + s_c4_div_c3);
|
||||
d3 += sh1_x * m22;
|
||||
d4 += sh1_x * m02 - sh1_y * m12;
|
||||
|
||||
// column 2
|
||||
real_t sh2_x = sh2 * r2x;
|
||||
real_t sh2_y = sh2 * r2y;
|
||||
d0 += sh2_x * r2y;
|
||||
d1 += sh2_y * r2z;
|
||||
d2 += sh2 * (r2z * r2z + s_c4_div_c3_x2);
|
||||
d3 += sh2_x * r2z;
|
||||
d4 += sh2_x * r2x - sh2_y * r2y;
|
||||
|
||||
// column 3
|
||||
real_t sh3_x = sh3 * r3x;
|
||||
real_t sh3_y = sh3 * r3y;
|
||||
d0 += sh3_x * r3y;
|
||||
d1 += sh3_y * r3z;
|
||||
d2 += sh3 * (r3z * r3z + s_c4_div_c3_x2);
|
||||
d3 += sh3_x * r3z;
|
||||
d4 += sh3_x * r3x - sh3_y * r3y;
|
||||
|
||||
// column 4
|
||||
real_t sh4_x = sh4 * r4x;
|
||||
real_t sh4_y = sh4 * r4y;
|
||||
d0 += sh4_x * r4y;
|
||||
d1 += sh4_y * r4z;
|
||||
d2 += sh4 * (r4z * r4z + s_c4_div_c3_x2);
|
||||
d3 += sh4_x * r4z;
|
||||
d4 += sh4_x * r4x - sh4_y * r4y;
|
||||
|
||||
// extra multipliers
|
||||
p_values[4] = d0;
|
||||
p_values[5] = -d1;
|
||||
p_values[6] = d2 * s_scale_dst2;
|
||||
p_values[7] = -d3;
|
||||
p_values[8] = d4 * s_scale_dst4;
|
||||
}
|
||||
|
||||
@@ -159,6 +159,7 @@ public:
|
||||
bool is_rotation() const;
|
||||
|
||||
Basis slerp(const Basis &target, const real_t &t) const;
|
||||
void rotate_sh(real_t *p_values);
|
||||
|
||||
operator String() const;
|
||||
|
||||
|
||||
@@ -33,6 +33,22 @@
|
||||
#include "core/math/math_funcs.h"
|
||||
#include "core/print_string.h"
|
||||
|
||||
float CameraMatrix::determinant() const {
|
||||
|
||||
return matrix[0][3] * matrix[1][2] * matrix[2][1] * matrix[3][0] - matrix[0][2] * matrix[1][3] * matrix[2][1] * matrix[3][0] -
|
||||
matrix[0][3] * matrix[1][1] * matrix[2][2] * matrix[3][0] + matrix[0][1] * matrix[1][3] * matrix[2][2] * matrix[3][0] +
|
||||
matrix[0][2] * matrix[1][1] * matrix[2][3] * matrix[3][0] - matrix[0][1] * matrix[1][2] * matrix[2][3] * matrix[3][0] -
|
||||
matrix[0][3] * matrix[1][2] * matrix[2][0] * matrix[3][1] + matrix[0][2] * matrix[1][3] * matrix[2][0] * matrix[3][1] +
|
||||
matrix[0][3] * matrix[1][0] * matrix[2][2] * matrix[3][1] - matrix[0][0] * matrix[1][3] * matrix[2][2] * matrix[3][1] -
|
||||
matrix[0][2] * matrix[1][0] * matrix[2][3] * matrix[3][1] + matrix[0][0] * matrix[1][2] * matrix[2][3] * matrix[3][1] +
|
||||
matrix[0][3] * matrix[1][1] * matrix[2][0] * matrix[3][2] - matrix[0][1] * matrix[1][3] * matrix[2][0] * matrix[3][2] -
|
||||
matrix[0][3] * matrix[1][0] * matrix[2][1] * matrix[3][2] + matrix[0][0] * matrix[1][3] * matrix[2][1] * matrix[3][2] +
|
||||
matrix[0][1] * matrix[1][0] * matrix[2][3] * matrix[3][2] - matrix[0][0] * matrix[1][1] * matrix[2][3] * matrix[3][2] -
|
||||
matrix[0][2] * matrix[1][1] * matrix[2][0] * matrix[3][3] + matrix[0][1] * matrix[1][2] * matrix[2][0] * matrix[3][3] +
|
||||
matrix[0][2] * matrix[1][0] * matrix[2][1] * matrix[3][3] - matrix[0][0] * matrix[1][2] * matrix[2][1] * matrix[3][3] -
|
||||
matrix[0][1] * matrix[1][0] * matrix[2][2] * matrix[3][3] + matrix[0][0] * matrix[1][1] * matrix[2][2] * matrix[3][3];
|
||||
}
|
||||
|
||||
void CameraMatrix::set_identity() {
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
||||
@@ -47,6 +47,7 @@ struct CameraMatrix {
|
||||
|
||||
real_t matrix[4][4];
|
||||
|
||||
float determinant() const;
|
||||
void set_identity();
|
||||
void set_zero();
|
||||
void set_light_bias();
|
||||
|
||||
@@ -115,8 +115,6 @@ public:
|
||||
triangles.push_back(Triangle(p_points.size() + 0, p_points.size() + 1, p_points.size() + 2));
|
||||
|
||||
for (int i = 0; i < p_points.size(); i++) {
|
||||
//std::cout << "Traitement du point " << *p << std::endl;
|
||||
//std::cout << "_triangles contains " << _triangles.size() << " elements" << std::endl;
|
||||
|
||||
Vector<Edge> polygon;
|
||||
|
||||
|
||||
386
core/math/delaunay_3d.h
Normal file
386
core/math/delaunay_3d.h
Normal file
@@ -0,0 +1,386 @@
|
||||
#ifndef DELAUNAY_3D_H
|
||||
#define DELAUNAY_3D_H
|
||||
|
||||
#include "core/local_vector.h"
|
||||
#include "core/math/aabb.h"
|
||||
#include "core/math/camera_matrix.h"
|
||||
#include "core/math/vector3.h"
|
||||
#include "core/oa_hash_map.h"
|
||||
#include "core/os/file_access.h"
|
||||
#include "core/print_string.h"
|
||||
#include "core/variant.h"
|
||||
#include "core/vector.h"
|
||||
#include "thirdparty/r128/r128.h"
|
||||
|
||||
class Delaunay3D {
|
||||
struct Simplex;
|
||||
|
||||
enum {
|
||||
ACCEL_GRID_SIZE = 16
|
||||
};
|
||||
struct GridPos {
|
||||
Vector3i pos;
|
||||
List<Simplex *>::Element *E = nullptr;
|
||||
};
|
||||
|
||||
struct Simplex {
|
||||
|
||||
uint32_t points[4];
|
||||
R128 circum_center_x;
|
||||
R128 circum_center_y;
|
||||
R128 circum_center_z;
|
||||
R128 circum_r2;
|
||||
LocalVector<GridPos> grid_positions;
|
||||
List<Simplex *>::Element *SE = nullptr;
|
||||
|
||||
_FORCE_INLINE_ Simplex() {}
|
||||
_FORCE_INLINE_ Simplex(uint32_t p_a, uint32_t p_b, uint32_t p_c, uint32_t p_d) {
|
||||
points[0] = p_a;
|
||||
points[1] = p_b;
|
||||
points[2] = p_c;
|
||||
points[3] = p_d;
|
||||
}
|
||||
};
|
||||
|
||||
struct Triangle {
|
||||
uint32_t triangle[3];
|
||||
bool bad;
|
||||
_FORCE_INLINE_ bool operator==(const Triangle &p_triangle) const {
|
||||
return triangle[0] == p_triangle.triangle[0] && triangle[1] == p_triangle.triangle[1] && triangle[2] == p_triangle.triangle[2];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Triangle() { bad = false; }
|
||||
_FORCE_INLINE_ Triangle(uint32_t p_a, uint32_t p_b, uint32_t p_c) {
|
||||
if (p_a > p_b)
|
||||
SWAP(p_a, p_b);
|
||||
if (p_b > p_c)
|
||||
SWAP(p_b, p_c);
|
||||
if (p_a > p_b)
|
||||
SWAP(p_a, p_b);
|
||||
|
||||
bad = false;
|
||||
triangle[0] = p_a;
|
||||
triangle[1] = p_b;
|
||||
triangle[2] = p_c;
|
||||
}
|
||||
};
|
||||
|
||||
struct TriangleHasher {
|
||||
_FORCE_INLINE_ static uint32_t hash(const Triangle &p_triangle) {
|
||||
uint32_t h = hash_djb2_one_32(p_triangle.triangle[0]);
|
||||
h = hash_djb2_one_32(p_triangle.triangle[1], h);
|
||||
return hash_djb2_one_32(p_triangle.triangle[2], h);
|
||||
}
|
||||
};
|
||||
|
||||
struct FPVal {
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ static void circum_sphere_compute(const Vector3 *p_points, Simplex *p_simplex) {
|
||||
|
||||
// the only part in the algorithm where there may be precision errors is this one, so ensure that
|
||||
// we do it as maximum precision as possible
|
||||
|
||||
R128 v0_x = p_points[p_simplex->points[0]].x;
|
||||
R128 v0_y = p_points[p_simplex->points[0]].y;
|
||||
R128 v0_z = p_points[p_simplex->points[0]].z;
|
||||
R128 v1_x = p_points[p_simplex->points[1]].x;
|
||||
R128 v1_y = p_points[p_simplex->points[1]].y;
|
||||
R128 v1_z = p_points[p_simplex->points[1]].z;
|
||||
R128 v2_x = p_points[p_simplex->points[2]].x;
|
||||
R128 v2_y = p_points[p_simplex->points[2]].y;
|
||||
R128 v2_z = p_points[p_simplex->points[2]].z;
|
||||
R128 v3_x = p_points[p_simplex->points[3]].x;
|
||||
R128 v3_y = p_points[p_simplex->points[3]].y;
|
||||
R128 v3_z = p_points[p_simplex->points[3]].z;
|
||||
|
||||
//Create the rows of our "unrolled" 3x3 matrix
|
||||
R128 row1_x = v1_x - v0_x;
|
||||
R128 row1_y = v1_y - v0_y;
|
||||
R128 row1_z = v1_z - v0_z;
|
||||
|
||||
R128 row2_x = v2_x - v0_x;
|
||||
R128 row2_y = v2_y - v0_y;
|
||||
R128 row2_z = v2_z - v0_z;
|
||||
|
||||
R128 row3_x = v3_x - v0_x;
|
||||
R128 row3_y = v3_y - v0_y;
|
||||
R128 row3_z = v3_z - v0_z;
|
||||
|
||||
R128 sq_lenght1 = row1_x * row1_x + row1_y * row1_y + row1_z * row1_z;
|
||||
R128 sq_lenght2 = row2_x * row2_x + row2_y * row2_y + row2_z * row2_z;
|
||||
R128 sq_lenght3 = row3_x * row3_x + row3_y * row3_y + row3_z * row3_z;
|
||||
|
||||
//Compute the determinant of said matrix
|
||||
R128 determinant = row1_x * (row2_y * row3_z - row3_y * row2_z) - row2_x * (row1_y * row3_z - row3_y * row1_z) + row3_x * (row1_y * row2_z - row2_y * row1_z);
|
||||
|
||||
// Compute the volume of the tetrahedron, and precompute a scalar quantity for re-use in the formula
|
||||
R128 volume = determinant / R128(6.f);
|
||||
R128 i12volume = R128(1.f) / (volume * R128(12.f));
|
||||
|
||||
R128 center_x = v0_x + i12volume * ((row2_y * row3_z - row3_y * row2_z) * sq_lenght1 - (row1_y * row3_z - row3_y * row1_z) * sq_lenght2 + (row1_y * row2_z - row2_y * row1_z) * sq_lenght3);
|
||||
R128 center_y = v0_y + i12volume * (-(row2_x * row3_z - row3_x * row2_z) * sq_lenght1 + (row1_x * row3_z - row3_x * row1_z) * sq_lenght2 - (row1_x * row2_z - row2_x * row1_z) * sq_lenght3);
|
||||
R128 center_z = v0_z + i12volume * ((row2_x * row3_y - row3_x * row2_y) * sq_lenght1 - (row1_x * row3_y - row3_x * row1_y) * sq_lenght2 + (row1_x * row2_y - row2_x * row1_y) * sq_lenght3);
|
||||
|
||||
//Once we know the center, the radius is clearly the distance to any vertex
|
||||
|
||||
R128 rel1_x = center_x - v0_x;
|
||||
R128 rel1_y = center_y - v0_y;
|
||||
R128 rel1_z = center_z - v0_z;
|
||||
|
||||
R128 radius1 = rel1_x * rel1_x + rel1_y * rel1_y + rel1_z * rel1_z;
|
||||
|
||||
p_simplex->circum_center_x = center_x;
|
||||
p_simplex->circum_center_y = center_y;
|
||||
p_simplex->circum_center_z = center_z;
|
||||
p_simplex->circum_r2 = radius1;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ static bool simplex_contains(const Vector3 *p_points, const Simplex &p_simplex, uint32_t p_vertex) {
|
||||
|
||||
R128 v_x = p_points[p_vertex].x;
|
||||
R128 v_y = p_points[p_vertex].y;
|
||||
R128 v_z = p_points[p_vertex].z;
|
||||
|
||||
R128 rel2_x = p_simplex.circum_center_x - v_x;
|
||||
R128 rel2_y = p_simplex.circum_center_y - v_y;
|
||||
R128 rel2_z = p_simplex.circum_center_z - v_z;
|
||||
|
||||
R128 radius2 = rel2_x * rel2_x + rel2_y * rel2_y + rel2_z * rel2_z;
|
||||
|
||||
return radius2 < (p_simplex.circum_r2 - R128(0.00001));
|
||||
}
|
||||
|
||||
static bool simplex_is_coplanar(const Vector3 *p_points, const Simplex &p_simplex) {
|
||||
|
||||
Plane p(p_points[p_simplex.points[0]], p_points[p_simplex.points[1]], p_points[p_simplex.points[2]]);
|
||||
if (ABS(p.distance_to(p_points[p_simplex.points[3]])) < CMP_EPSILON) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CameraMatrix cm;
|
||||
|
||||
cm.matrix[0][0] = p_points[p_simplex.points[0]].x;
|
||||
cm.matrix[0][1] = p_points[p_simplex.points[1]].x;
|
||||
cm.matrix[0][2] = p_points[p_simplex.points[2]].x;
|
||||
cm.matrix[0][3] = p_points[p_simplex.points[3]].x;
|
||||
|
||||
cm.matrix[1][0] = p_points[p_simplex.points[0]].y;
|
||||
cm.matrix[1][1] = p_points[p_simplex.points[1]].y;
|
||||
cm.matrix[1][2] = p_points[p_simplex.points[2]].y;
|
||||
cm.matrix[1][3] = p_points[p_simplex.points[3]].y;
|
||||
|
||||
cm.matrix[2][0] = p_points[p_simplex.points[0]].z;
|
||||
cm.matrix[2][1] = p_points[p_simplex.points[1]].z;
|
||||
cm.matrix[2][2] = p_points[p_simplex.points[2]].z;
|
||||
cm.matrix[2][3] = p_points[p_simplex.points[3]].z;
|
||||
|
||||
cm.matrix[3][0] = 1.0;
|
||||
cm.matrix[3][1] = 1.0;
|
||||
cm.matrix[3][2] = 1.0;
|
||||
cm.matrix[3][3] = 1.0;
|
||||
|
||||
return ABS(cm.determinant()) <= CMP_EPSILON;
|
||||
}
|
||||
|
||||
public:
|
||||
struct OutputSimplex {
|
||||
uint32_t points[4];
|
||||
};
|
||||
|
||||
static Vector<OutputSimplex> tetrahedralize(const Vector<Vector3> &p_points) {
|
||||
|
||||
uint32_t point_count = p_points.size();
|
||||
Vector3 *points = (Vector3 *)memalloc(sizeof(Vector3) * (point_count + 4));
|
||||
|
||||
{
|
||||
const Vector3 *src_points = p_points.ptr();
|
||||
AABB rect;
|
||||
for (uint32_t i = 0; i < point_count; i++) {
|
||||
Vector3 point = src_points[i];
|
||||
if (i == 0) {
|
||||
rect.position = point;
|
||||
} else {
|
||||
rect.expand_to(point);
|
||||
}
|
||||
points[i] = point;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < point_count; i++) {
|
||||
points[i] = (points[i] - rect.position) / rect.size;
|
||||
}
|
||||
|
||||
float delta_max = Math::sqrt(2.0) * 20.0;
|
||||
Vector3 center = Vector3(0.5, 0.5, 0.5);
|
||||
|
||||
// any simplex that contains everything is good
|
||||
points[point_count + 0] = center + Vector3(0, 1, 0) * delta_max;
|
||||
points[point_count + 1] = center + Vector3(0, -1, 1) * delta_max;
|
||||
points[point_count + 2] = center + Vector3(1, -1, -1) * delta_max;
|
||||
points[point_count + 3] = center + Vector3(-1, -1, -1) * delta_max;
|
||||
}
|
||||
|
||||
List<Simplex *> acceleration_grid[ACCEL_GRID_SIZE][ACCEL_GRID_SIZE][ACCEL_GRID_SIZE];
|
||||
|
||||
List<Simplex *> simplex_list;
|
||||
{
|
||||
//create root simplex
|
||||
Simplex *root = memnew(Simplex(point_count + 0, point_count + 1, point_count + 2, point_count + 3));
|
||||
root->SE = simplex_list.push_back(root);
|
||||
|
||||
for (uint32_t i = 0; i < ACCEL_GRID_SIZE; i++) {
|
||||
for (uint32_t j = 0; j < ACCEL_GRID_SIZE; j++) {
|
||||
for (uint32_t k = 0; k < ACCEL_GRID_SIZE; k++) {
|
||||
GridPos gp;
|
||||
gp.E = acceleration_grid[i][j][k].push_back(root);
|
||||
gp.pos = Vector3i(i, j, k);
|
||||
root->grid_positions.push_back(gp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
circum_sphere_compute(points, root);
|
||||
}
|
||||
|
||||
OAHashMap<Triangle, uint32_t, TriangleHasher> triangles_inserted;
|
||||
LocalVector<Triangle> triangles;
|
||||
|
||||
for (uint32_t i = 0; i < point_count; i++) {
|
||||
|
||||
bool unique = true;
|
||||
for (uint32_t j = i + 1; j < point_count; j++) {
|
||||
if (points[i].is_equal_approx(points[j])) {
|
||||
unique = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!unique) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector3i grid_pos = Vector3i(points[i] * ACCEL_GRID_SIZE);
|
||||
grid_pos.x = CLAMP(grid_pos.x, 0, ACCEL_GRID_SIZE - 1);
|
||||
grid_pos.y = CLAMP(grid_pos.y, 0, ACCEL_GRID_SIZE - 1);
|
||||
grid_pos.z = CLAMP(grid_pos.z, 0, ACCEL_GRID_SIZE - 1);
|
||||
|
||||
for (List<Simplex *>::Element *E = acceleration_grid[grid_pos.x][grid_pos.y][grid_pos.z].front(); E;) {
|
||||
List<Simplex *>::Element *N = E->next(); //may be deleted
|
||||
|
||||
Simplex *simplex = E->get();
|
||||
|
||||
if (simplex_contains(points, *simplex, i)) {
|
||||
|
||||
static const uint32_t triangle_order[4][3] = {
|
||||
{ 0, 1, 2 },
|
||||
{ 0, 1, 3 },
|
||||
{ 0, 2, 3 },
|
||||
{ 1, 2, 3 },
|
||||
};
|
||||
|
||||
for (uint32_t k = 0; k < 4; k++) {
|
||||
Triangle t = Triangle(simplex->points[triangle_order[k][0]], simplex->points[triangle_order[k][1]], simplex->points[triangle_order[k][2]]);
|
||||
uint32_t *p = triangles_inserted.lookup_ptr(t);
|
||||
if (p) {
|
||||
triangles[*p].bad = true;
|
||||
} else {
|
||||
triangles_inserted.insert(t, triangles.size());
|
||||
triangles.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
//remove simplex and continue
|
||||
simplex_list.erase(simplex->SE);
|
||||
|
||||
for (uint32_t k = 0; k < simplex->grid_positions.size(); k++) {
|
||||
Vector3i p = simplex->grid_positions[k].pos;
|
||||
acceleration_grid[p.x][p.y][p.z].erase(simplex->grid_positions[k].E);
|
||||
}
|
||||
memdelete(simplex);
|
||||
}
|
||||
E = N;
|
||||
}
|
||||
|
||||
uint32_t good_triangles = 0;
|
||||
for (uint32_t j = 0; j < triangles.size(); j++) {
|
||||
|
||||
if (triangles[j].bad) {
|
||||
continue;
|
||||
}
|
||||
Simplex *new_simplex = memnew(Simplex(triangles[j].triangle[0], triangles[j].triangle[1], triangles[j].triangle[2], i));
|
||||
circum_sphere_compute(points, new_simplex);
|
||||
new_simplex->SE = simplex_list.push_back(new_simplex);
|
||||
{
|
||||
Vector3 center;
|
||||
center.x = double(new_simplex->circum_center_x);
|
||||
center.y = double(new_simplex->circum_center_y);
|
||||
center.z = double(new_simplex->circum_center_z);
|
||||
|
||||
float radius2 = Math::sqrt(double(new_simplex->circum_r2));
|
||||
radius2 += 0.0001; //
|
||||
Vector3 extents = Vector3(radius2, radius2, radius2);
|
||||
Vector3i from = Vector3i((center - extents) * ACCEL_GRID_SIZE);
|
||||
Vector3i to = Vector3i((center + extents) * ACCEL_GRID_SIZE);
|
||||
from.x = CLAMP(from.x, 0, ACCEL_GRID_SIZE - 1);
|
||||
from.y = CLAMP(from.y, 0, ACCEL_GRID_SIZE - 1);
|
||||
from.z = CLAMP(from.z, 0, ACCEL_GRID_SIZE - 1);
|
||||
to.x = CLAMP(to.x, 0, ACCEL_GRID_SIZE - 1);
|
||||
to.y = CLAMP(to.y, 0, ACCEL_GRID_SIZE - 1);
|
||||
to.z = CLAMP(to.z, 0, ACCEL_GRID_SIZE - 1);
|
||||
|
||||
for (int32_t x = from.x; x <= to.x; x++) {
|
||||
for (int32_t y = from.y; y <= to.y; y++) {
|
||||
for (int32_t z = from.z; z <= to.z; z++) {
|
||||
GridPos gp;
|
||||
gp.pos = Vector3(x, y, z);
|
||||
gp.E = acceleration_grid[x][y][z].push_back(new_simplex);
|
||||
new_simplex->grid_positions.push_back(gp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
good_triangles++;
|
||||
}
|
||||
|
||||
//print_line("at point " + itos(i) + "/" + itos(point_count) + " simplices added " + itos(good_triangles) + "/" + itos(simplex_list.size()) + " - triangles: " + itos(triangles.size()));
|
||||
triangles.clear();
|
||||
triangles_inserted.clear();
|
||||
}
|
||||
|
||||
//print_line("end with simplices: " + itos(simplex_list.size()));
|
||||
Vector<OutputSimplex> ret_simplices;
|
||||
ret_simplices.resize(simplex_list.size());
|
||||
OutputSimplex *ret_simplicesw = ret_simplices.ptrw();
|
||||
uint32_t simplices_written = 0;
|
||||
|
||||
for (List<Simplex *>::Element *E = simplex_list.front(); E; E = E->next()) {
|
||||
Simplex *simplex = E->get();
|
||||
bool invalid = false;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (simplex->points[j] >= point_count) {
|
||||
invalid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (invalid || simplex_is_coplanar(points, *simplex)) {
|
||||
memdelete(simplex);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret_simplicesw[simplices_written].points[0] = simplex->points[0];
|
||||
ret_simplicesw[simplices_written].points[1] = simplex->points[1];
|
||||
ret_simplicesw[simplices_written].points[2] = simplex->points[2];
|
||||
ret_simplicesw[simplices_written].points[3] = simplex->points[3];
|
||||
simplices_written++;
|
||||
memdelete(simplex);
|
||||
}
|
||||
|
||||
ret_simplices.resize(simplices_written);
|
||||
|
||||
memfree(points);
|
||||
|
||||
return ret_simplices;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // DELAUNAY_3D_H
|
||||
@@ -33,6 +33,8 @@
|
||||
#include "core/print_string.h"
|
||||
#include "thirdparty/misc/clipper.hpp"
|
||||
#include "thirdparty/misc/triangulator.h"
|
||||
#define STB_RECT_PACK_IMPLEMENTATION
|
||||
#include "thirdparty/stb_rect_pack/stb_rect_pack.h"
|
||||
|
||||
#define SCALE_FACTOR 100000.0 // Based on CMP_EPSILON.
|
||||
|
||||
@@ -1242,3 +1244,195 @@ Vector<Vector3> Geometry::compute_convex_mesh_points(const Plane *p_planes, int
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
Vector<Point2i> Geometry::pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size) {
|
||||
|
||||
Vector<stbrp_node> nodes;
|
||||
nodes.resize(p_atlas_size.width);
|
||||
|
||||
stbrp_context context;
|
||||
stbrp_init_target(&context, p_atlas_size.width, p_atlas_size.height, nodes.ptrw(), p_atlas_size.width);
|
||||
|
||||
Vector<stbrp_rect> rects;
|
||||
rects.resize(p_sizes.size());
|
||||
|
||||
for (int i = 0; i < p_sizes.size(); i++) {
|
||||
rects.write[i].id = 0;
|
||||
rects.write[i].w = p_sizes[i].width;
|
||||
rects.write[i].h = p_sizes[i].height;
|
||||
rects.write[i].x = 0;
|
||||
rects.write[i].y = 0;
|
||||
rects.write[i].was_packed = 0;
|
||||
}
|
||||
|
||||
int res = stbrp_pack_rects(&context, rects.ptrw(), rects.size());
|
||||
if (res == 0) { //pack failed
|
||||
return Vector<Point2i>();
|
||||
}
|
||||
|
||||
Vector<Point2i> ret;
|
||||
ret.resize(p_sizes.size());
|
||||
|
||||
for (int i = 0; i < p_sizes.size(); i++) {
|
||||
Point2i r(rects[i].x, rects[i].y);
|
||||
ret.write[i] = r;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Vector<Vector3i> Geometry::partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size) {
|
||||
|
||||
Vector<stbrp_node> nodes;
|
||||
nodes.resize(p_atlas_size.width);
|
||||
zeromem(nodes.ptrw(), sizeof(stbrp_node) * nodes.size());
|
||||
|
||||
stbrp_context context;
|
||||
stbrp_init_target(&context, p_atlas_size.width, p_atlas_size.height, nodes.ptrw(), p_atlas_size.width);
|
||||
|
||||
Vector<stbrp_rect> rects;
|
||||
rects.resize(p_sizes.size());
|
||||
|
||||
for (int i = 0; i < p_sizes.size(); i++) {
|
||||
rects.write[i].id = i;
|
||||
rects.write[i].w = p_sizes[i].width;
|
||||
rects.write[i].h = p_sizes[i].height;
|
||||
rects.write[i].x = 0;
|
||||
rects.write[i].y = 0;
|
||||
rects.write[i].was_packed = 0;
|
||||
}
|
||||
|
||||
stbrp_pack_rects(&context, rects.ptrw(), rects.size());
|
||||
|
||||
Vector<Vector3i> ret;
|
||||
ret.resize(p_sizes.size());
|
||||
|
||||
for (int i = 0; i < p_sizes.size(); i++) {
|
||||
ret.write[rects[i].id] = Vector3i(rects[i].x, rects[i].y, rects[i].was_packed != 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define square(m_s) ((m_s) * (m_s))
|
||||
#define INF 1e20
|
||||
|
||||
/* dt of 1d function using squared distance */
|
||||
static void edt(float *f, int stride, int n) {
|
||||
|
||||
float *d = (float *)alloca(sizeof(float) * n + sizeof(int) * n + sizeof(float) * (n + 1));
|
||||
int *v = (int *)&(d[n]);
|
||||
float *z = (float *)&v[n];
|
||||
|
||||
int k = 0;
|
||||
v[0] = 0;
|
||||
z[0] = -INF;
|
||||
z[1] = +INF;
|
||||
for (int q = 1; q <= n - 1; q++) {
|
||||
float s = ((f[q * stride] + square(q)) - (f[v[k] * stride] + square(v[k]))) / (2 * q - 2 * v[k]);
|
||||
while (s <= z[k]) {
|
||||
k--;
|
||||
s = ((f[q * stride] + square(q)) - (f[v[k] * stride] + square(v[k]))) / (2 * q - 2 * v[k]);
|
||||
}
|
||||
k++;
|
||||
v[k] = q;
|
||||
|
||||
z[k] = s;
|
||||
z[k + 1] = +INF;
|
||||
}
|
||||
|
||||
k = 0;
|
||||
for (int q = 0; q <= n - 1; q++) {
|
||||
while (z[k + 1] < q)
|
||||
k++;
|
||||
d[q] = square(q - v[k]) + f[v[k] * stride];
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
f[i * stride] = d[i];
|
||||
}
|
||||
}
|
||||
|
||||
#undef square
|
||||
|
||||
Vector<uint32_t> Geometry::generate_edf(const Vector<bool> &p_voxels, const Vector3i &p_size, bool p_negative) {
|
||||
|
||||
uint32_t float_count = p_size.x * p_size.y * p_size.z;
|
||||
|
||||
ERR_FAIL_COND_V((uint32_t)p_voxels.size() != float_count, Vector<uint32_t>());
|
||||
|
||||
float *work_memory = memnew_arr(float, float_count);
|
||||
for (uint32_t i = 0; i < float_count; i++) {
|
||||
work_memory[i] = INF;
|
||||
}
|
||||
|
||||
uint32_t y_mult = p_size.x;
|
||||
uint32_t z_mult = y_mult * p_size.y;
|
||||
|
||||
//plot solid cells
|
||||
{
|
||||
const bool *voxr = p_voxels.ptr();
|
||||
for (uint32_t i = 0; i < float_count; i++) {
|
||||
|
||||
bool plot = voxr[i];
|
||||
if (p_negative) {
|
||||
plot = !plot;
|
||||
}
|
||||
if (plot) {
|
||||
work_memory[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//process in each direction
|
||||
|
||||
//xy->z
|
||||
|
||||
for (int i = 0; i < p_size.x; i++) {
|
||||
for (int j = 0; j < p_size.y; j++) {
|
||||
edt(&work_memory[i + j * y_mult], z_mult, p_size.z);
|
||||
}
|
||||
}
|
||||
|
||||
//xz->y
|
||||
|
||||
for (int i = 0; i < p_size.x; i++) {
|
||||
for (int j = 0; j < p_size.z; j++) {
|
||||
edt(&work_memory[i + j * z_mult], y_mult, p_size.y);
|
||||
}
|
||||
}
|
||||
|
||||
//yz->x
|
||||
for (int i = 0; i < p_size.y; i++) {
|
||||
for (int j = 0; j < p_size.z; j++) {
|
||||
edt(&work_memory[i * y_mult + j * z_mult], 1, p_size.x);
|
||||
}
|
||||
}
|
||||
|
||||
Vector<uint32_t> ret;
|
||||
ret.resize(float_count);
|
||||
{
|
||||
uint32_t *w = ret.ptrw();
|
||||
for (uint32_t i = 0; i < float_count; i++) {
|
||||
w[i] = uint32_t(Math::sqrt(work_memory[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Vector<int8_t> Geometry::generate_sdf8(const Vector<uint32_t> &p_positive, const Vector<uint32_t> &p_negative) {
|
||||
ERR_FAIL_COND_V(p_positive.size() != p_negative.size(), Vector<int8_t>());
|
||||
Vector<int8_t> sdf8;
|
||||
int s = p_positive.size();
|
||||
sdf8.resize(s);
|
||||
|
||||
const uint32_t *rpos = p_positive.ptr();
|
||||
const uint32_t *rneg = p_negative.ptr();
|
||||
int8_t *wsdf = sdf8.ptrw();
|
||||
for (int i = 0; i < s; i++) {
|
||||
int32_t diff = int32_t(rpos[i]) - int32_t(rneg[i]);
|
||||
wsdf[i] = CLAMP(diff, -128, 127);
|
||||
}
|
||||
return sdf8;
|
||||
}
|
||||
|
||||
@@ -1024,6 +1024,249 @@ public:
|
||||
|
||||
static Vector<Vector3> compute_convex_mesh_points(const Plane *p_planes, int p_plane_count);
|
||||
|
||||
#define FINDMINMAX(x0, x1, x2, min, max) \
|
||||
min = max = x0; \
|
||||
if (x1 < min) \
|
||||
min = x1; \
|
||||
if (x1 > max) \
|
||||
max = x1; \
|
||||
if (x2 < min) \
|
||||
min = x2; \
|
||||
if (x2 > max) \
|
||||
max = x2;
|
||||
|
||||
_FORCE_INLINE_ static bool planeBoxOverlap(Vector3 normal, float d, Vector3 maxbox) {
|
||||
int q;
|
||||
Vector3 vmin, vmax;
|
||||
for (q = 0; q <= 2; q++) {
|
||||
if (normal[q] > 0.0f) {
|
||||
vmin[q] = -maxbox[q];
|
||||
vmax[q] = maxbox[q];
|
||||
} else {
|
||||
vmin[q] = maxbox[q];
|
||||
vmax[q] = -maxbox[q];
|
||||
}
|
||||
}
|
||||
if (normal.dot(vmin) + d > 0.0f)
|
||||
return false;
|
||||
if (normal.dot(vmax) + d >= 0.0f)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*======================== X-tests ========================*/
|
||||
#define AXISTEST_X01(a, b, fa, fb) \
|
||||
p0 = a * v0.y - b * v0.z; \
|
||||
p2 = a * v2.y - b * v2.z; \
|
||||
if (p0 < p2) { \
|
||||
min = p0; \
|
||||
max = p2; \
|
||||
} else { \
|
||||
min = p2; \
|
||||
max = p0; \
|
||||
} \
|
||||
rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
|
||||
if (min > rad || max < -rad) \
|
||||
return false;
|
||||
|
||||
#define AXISTEST_X2(a, b, fa, fb) \
|
||||
p0 = a * v0.y - b * v0.z; \
|
||||
p1 = a * v1.y - b * v1.z; \
|
||||
if (p0 < p1) { \
|
||||
min = p0; \
|
||||
max = p1; \
|
||||
} else { \
|
||||
min = p1; \
|
||||
max = p0; \
|
||||
} \
|
||||
rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
|
||||
if (min > rad || max < -rad) \
|
||||
return false;
|
||||
|
||||
/*======================== Y-tests ========================*/
|
||||
#define AXISTEST_Y02(a, b, fa, fb) \
|
||||
p0 = -a * v0.x + b * v0.z; \
|
||||
p2 = -a * v2.x + b * v2.z; \
|
||||
if (p0 < p2) { \
|
||||
min = p0; \
|
||||
max = p2; \
|
||||
} else { \
|
||||
min = p2; \
|
||||
max = p0; \
|
||||
} \
|
||||
rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
|
||||
if (min > rad || max < -rad) \
|
||||
return false;
|
||||
|
||||
#define AXISTEST_Y1(a, b, fa, fb) \
|
||||
p0 = -a * v0.x + b * v0.z; \
|
||||
p1 = -a * v1.x + b * v1.z; \
|
||||
if (p0 < p1) { \
|
||||
min = p0; \
|
||||
max = p1; \
|
||||
} else { \
|
||||
min = p1; \
|
||||
max = p0; \
|
||||
} \
|
||||
rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
|
||||
if (min > rad || max < -rad) \
|
||||
return false;
|
||||
|
||||
/*======================== Z-tests ========================*/
|
||||
|
||||
#define AXISTEST_Z12(a, b, fa, fb) \
|
||||
p1 = a * v1.x - b * v1.y; \
|
||||
p2 = a * v2.x - b * v2.y; \
|
||||
if (p2 < p1) { \
|
||||
min = p2; \
|
||||
max = p1; \
|
||||
} else { \
|
||||
min = p1; \
|
||||
max = p2; \
|
||||
} \
|
||||
rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
|
||||
if (min > rad || max < -rad) \
|
||||
return false;
|
||||
|
||||
#define AXISTEST_Z0(a, b, fa, fb) \
|
||||
p0 = a * v0.x - b * v0.y; \
|
||||
p1 = a * v1.x - b * v1.y; \
|
||||
if (p0 < p1) { \
|
||||
min = p0; \
|
||||
max = p1; \
|
||||
} else { \
|
||||
min = p1; \
|
||||
max = p0; \
|
||||
} \
|
||||
rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
|
||||
if (min > rad || max < -rad) \
|
||||
return false;
|
||||
|
||||
_FORCE_INLINE_ static bool triangle_box_overlap(const Vector3 &boxcenter, const Vector3 boxhalfsize, const Vector3 *triverts) {
|
||||
|
||||
/* use separating axis theorem to test overlap between triangle and box */
|
||||
/* need to test for overlap in these directions: */
|
||||
/* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
|
||||
/* we do not even need to test these) */
|
||||
/* 2) normal of the triangle */
|
||||
/* 3) crossproduct(edge from tri, {x,y,z}-directin) */
|
||||
/* this gives 3x3=9 more tests */
|
||||
Vector3 v0, v1, v2;
|
||||
float min, max, d, p0, p1, p2, rad, fex, fey, fez;
|
||||
Vector3 normal, e0, e1, e2;
|
||||
|
||||
/* This is the fastest branch on Sun */
|
||||
/* move everything so that the boxcenter is in (0,0,0) */
|
||||
|
||||
v0 = triverts[0] - boxcenter;
|
||||
v1 = triverts[1] - boxcenter;
|
||||
v2 = triverts[2] - boxcenter;
|
||||
|
||||
/* compute triangle edges */
|
||||
e0 = v1 - v0; /* tri edge 0 */
|
||||
e1 = v2 - v1; /* tri edge 1 */
|
||||
e2 = v0 - v2; /* tri edge 2 */
|
||||
|
||||
/* Bullet 3: */
|
||||
/* test the 9 tests first (this was faster) */
|
||||
fex = Math::abs(e0.x);
|
||||
fey = Math::abs(e0.y);
|
||||
fez = Math::abs(e0.z);
|
||||
AXISTEST_X01(e0.z, e0.y, fez, fey);
|
||||
AXISTEST_Y02(e0.z, e0.x, fez, fex);
|
||||
AXISTEST_Z12(e0.y, e0.x, fey, fex);
|
||||
|
||||
fex = Math::abs(e1.x);
|
||||
fey = Math::abs(e1.y);
|
||||
fez = Math::abs(e1.z);
|
||||
AXISTEST_X01(e1.z, e1.y, fez, fey);
|
||||
AXISTEST_Y02(e1.z, e1.x, fez, fex);
|
||||
AXISTEST_Z0(e1.y, e1.x, fey, fex);
|
||||
|
||||
fex = Math::abs(e2.x);
|
||||
fey = Math::abs(e2.y);
|
||||
fez = Math::abs(e2.z);
|
||||
AXISTEST_X2(e2.z, e2.y, fez, fey);
|
||||
AXISTEST_Y1(e2.z, e2.x, fez, fex);
|
||||
AXISTEST_Z12(e2.y, e2.x, fey, fex);
|
||||
|
||||
/* Bullet 1: */
|
||||
/* first test overlap in the {x,y,z}-directions */
|
||||
/* find min, max of the triangle each direction, and test for overlap in */
|
||||
/* that direction -- this is equivalent to testing a minimal AABB around */
|
||||
/* the triangle against the AABB */
|
||||
|
||||
/* test in X-direction */
|
||||
FINDMINMAX(v0.x, v1.x, v2.x, min, max);
|
||||
if (min > boxhalfsize.x || max < -boxhalfsize.x)
|
||||
return false;
|
||||
|
||||
/* test in Y-direction */
|
||||
FINDMINMAX(v0.y, v1.y, v2.y, min, max);
|
||||
if (min > boxhalfsize.y || max < -boxhalfsize.y)
|
||||
return false;
|
||||
|
||||
/* test in Z-direction */
|
||||
FINDMINMAX(v0.z, v1.z, v2.z, min, max);
|
||||
if (min > boxhalfsize.z || max < -boxhalfsize.z)
|
||||
return false;
|
||||
|
||||
/* Bullet 2: */
|
||||
/* test if the box intersects the plane of the triangle */
|
||||
/* compute plane equation of triangle: normal*x+d=0 */
|
||||
normal = e0.cross(e1);
|
||||
d = -normal.dot(v0); /* plane eq: normal.x+d=0 */
|
||||
return planeBoxOverlap(normal, d, boxhalfsize); /* if true, box and triangle overlaps */
|
||||
}
|
||||
|
||||
static Vector<Point2i> pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size);
|
||||
static Vector<Vector3i> partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size);
|
||||
|
||||
static Vector<uint32_t> generate_edf(const Vector<bool> &p_voxels, const Vector3i &p_size, bool p_negative);
|
||||
static Vector<int8_t> generate_sdf8(const Vector<uint32_t> &p_positive, const Vector<uint32_t> &p_negative);
|
||||
|
||||
static Vector3 triangle_get_barycentric_coords(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c, const Vector3 &p_pos) {
|
||||
Vector3 v0 = p_b - p_a;
|
||||
Vector3 v1 = p_c - p_a;
|
||||
Vector3 v2 = p_pos - p_a;
|
||||
|
||||
float d00 = v0.dot(v0);
|
||||
float d01 = v0.dot(v1);
|
||||
float d11 = v1.dot(v1);
|
||||
float d20 = v2.dot(v0);
|
||||
float d21 = v2.dot(v1);
|
||||
float denom = (d00 * d11 - d01 * d01);
|
||||
if (denom == 0) {
|
||||
return Vector3(); //invalid triangle, return empty
|
||||
}
|
||||
float v = (d11 * d20 - d01 * d21) / denom;
|
||||
float w = (d00 * d21 - d01 * d20) / denom;
|
||||
float u = 1.0f - v - w;
|
||||
return Vector3(u, v, w);
|
||||
}
|
||||
|
||||
static Color tetrahedron_get_barycentric_coords(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c, const Vector3 &p_d, const Vector3 &p_pos) {
|
||||
Vector3 vap = p_pos - p_a;
|
||||
Vector3 vbp = p_pos - p_b;
|
||||
|
||||
Vector3 vab = p_b - p_a;
|
||||
Vector3 vac = p_c - p_a;
|
||||
Vector3 vad = p_d - p_a;
|
||||
|
||||
Vector3 vbc = p_c - p_b;
|
||||
Vector3 vbd = p_d - p_b;
|
||||
// ScTP computes the scalar triple product
|
||||
#define STP(m_a, m_b, m_c) ((m_a).dot((m_b).cross((m_c))))
|
||||
float va6 = STP(vbp, vbd, vbc);
|
||||
float vb6 = STP(vap, vac, vad);
|
||||
float vc6 = STP(vap, vad, vab);
|
||||
float vd6 = STP(vap, vab, vac);
|
||||
float v6 = 1 / STP(vab, vac, vad);
|
||||
return Color(va6 * v6, vb6 * v6, vc6 * v6, vd6 * v6);
|
||||
#undef STP
|
||||
}
|
||||
|
||||
private:
|
||||
static Vector<Vector<Point2>> _polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open = false);
|
||||
static Vector<Vector<Point2>> _polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type);
|
||||
|
||||
@@ -153,6 +153,10 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
|
||||
|
||||
/* misc */
|
||||
|
||||
bool Plane::is_equal_approx_any_side(const Plane &p_plane) const {
|
||||
return (normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d)) || (normal.is_equal_approx(-p_plane.normal) && Math::is_equal_approx(d, -p_plane.d));
|
||||
}
|
||||
|
||||
bool Plane::is_equal_approx(const Plane &p_plane) const {
|
||||
|
||||
return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d);
|
||||
|
||||
@@ -69,6 +69,7 @@ public:
|
||||
|
||||
Plane operator-() const { return Plane(-normal, -d); }
|
||||
bool is_equal_approx(const Plane &p_plane) const;
|
||||
bool is_equal_approx_any_side(const Plane &p_plane) const;
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
|
||||
_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;
|
||||
|
||||
2
core/math/r128.cpp
Normal file
2
core/math/r128.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#define R128_IMPLEMENTATION
|
||||
#include "thirdparty/r128/r128.h"
|
||||
Reference in New Issue
Block a user