Merge pull request #49314 from madmiraal/fix-48408-3.x
[3.x] Fix multiple issues with CSGPolygon
This commit is contained in:
commit
bf383a31cb
|
@ -29,7 +29,6 @@
|
|||
/*************************************************************************/
|
||||
|
||||
#include "csg_shape.h"
|
||||
#include "scene/3d/path.h"
|
||||
|
||||
void CSGShape::set_use_collision(bool p_enable) {
|
||||
if (use_collision == p_enable) {
|
||||
|
@ -1745,109 +1744,80 @@ CSGTorus::CSGTorus() {
|
|||
///////////////
|
||||
|
||||
CSGBrush *CSGPolygon::_build_brush() {
|
||||
// set our bounding box
|
||||
|
||||
if (polygon.size() < 3) {
|
||||
return memnew(CSGBrush);
|
||||
}
|
||||
|
||||
Vector<Point2> final_polygon = polygon;
|
||||
|
||||
if (Triangulate::get_area(final_polygon) > 0) {
|
||||
final_polygon.invert();
|
||||
}
|
||||
|
||||
Vector<int> triangles = Geometry::triangulate_polygon(final_polygon);
|
||||
|
||||
if (triangles.size() < 3) {
|
||||
return memnew(CSGBrush);
|
||||
}
|
||||
|
||||
Path *path = nullptr;
|
||||
Ref<Curve3D> curve;
|
||||
|
||||
// get bounds for our polygon
|
||||
Vector2 final_polygon_min;
|
||||
Vector2 final_polygon_max;
|
||||
for (int i = 0; i < final_polygon.size(); i++) {
|
||||
Vector2 p = final_polygon[i];
|
||||
if (i == 0) {
|
||||
final_polygon_min = p;
|
||||
final_polygon_max = final_polygon_min;
|
||||
} else {
|
||||
if (p.x < final_polygon_min.x) {
|
||||
final_polygon_min.x = p.x;
|
||||
}
|
||||
if (p.y < final_polygon_min.y) {
|
||||
final_polygon_min.y = p.y;
|
||||
}
|
||||
|
||||
if (p.x > final_polygon_max.x) {
|
||||
final_polygon_max.x = p.x;
|
||||
}
|
||||
if (p.y > final_polygon_max.y) {
|
||||
final_polygon_max.y = p.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
Vector2 final_polygon_size = final_polygon_max - final_polygon_min;
|
||||
|
||||
if (mode == MODE_PATH) {
|
||||
if (!has_node(path_node)) {
|
||||
return memnew(CSGBrush);
|
||||
}
|
||||
Node *n = get_node(path_node);
|
||||
if (!n) {
|
||||
return memnew(CSGBrush);
|
||||
}
|
||||
path = Object::cast_to<Path>(n);
|
||||
if (!path) {
|
||||
return memnew(CSGBrush);
|
||||
}
|
||||
|
||||
if (path != path_cache) {
|
||||
if (path_cache) {
|
||||
path_cache->disconnect("tree_exited", this, "_path_exited");
|
||||
path_cache->disconnect("curve_changed", this, "_path_changed");
|
||||
path_cache = nullptr;
|
||||
}
|
||||
|
||||
path_cache = path;
|
||||
|
||||
path_cache->connect("tree_exited", this, "_path_exited");
|
||||
path_cache->connect("curve_changed", this, "_path_changed");
|
||||
}
|
||||
curve = path->get_curve();
|
||||
if (curve.is_null()) {
|
||||
return memnew(CSGBrush);
|
||||
}
|
||||
if (curve->get_baked_length() <= 0) {
|
||||
return memnew(CSGBrush);
|
||||
}
|
||||
}
|
||||
CSGBrush *brush = memnew(CSGBrush);
|
||||
|
||||
int face_count = 0;
|
||||
if (polygon.size() < 3) {
|
||||
return brush;
|
||||
}
|
||||
|
||||
// Triangulate polygon shape.
|
||||
Vector<Point2> shape_polygon = polygon;
|
||||
if (Triangulate::get_area(shape_polygon) > 0) {
|
||||
shape_polygon.invert();
|
||||
}
|
||||
int shape_sides = shape_polygon.size();
|
||||
Vector<int> shape_faces = Geometry::triangulate_polygon(shape_polygon);
|
||||
ERR_FAIL_COND_V_MSG(shape_faces.size() < 3, brush, "Failed to triangulate CSGPolygon");
|
||||
|
||||
// Get polygon enclosing Rect2.
|
||||
Rect2 shape_rect(shape_polygon[0], Vector2());
|
||||
for (int i = 1; i < shape_sides; i++) {
|
||||
shape_rect.expand_to(shape_polygon[i]);
|
||||
}
|
||||
|
||||
// If MODE_PATH, check if curve has changed.
|
||||
Ref<Curve3D> curve;
|
||||
if (mode == MODE_PATH) {
|
||||
Path *current_path = Object::cast_to<Path>(get_node_or_null(path_node));
|
||||
if (path != current_path) {
|
||||
if (path) {
|
||||
path->disconnect("tree_exited", this, "_path_exited");
|
||||
path->disconnect("curve_changed", this, "_path_changed");
|
||||
}
|
||||
path = current_path;
|
||||
if (path) {
|
||||
path->connect("tree_exited", this, "_path_exited");
|
||||
path->connect("curve_changed", this, "_path_changed");
|
||||
}
|
||||
}
|
||||
|
||||
if (!path) {
|
||||
return brush;
|
||||
}
|
||||
|
||||
curve = path->get_curve();
|
||||
if (curve.is_null() || curve->get_point_count() < 2) {
|
||||
return brush;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the number of extrusions, ends and faces.
|
||||
int extrusions = 0;
|
||||
int extrusion_face_count = shape_sides * 2;
|
||||
int end_count = 0;
|
||||
int shape_face_count = shape_faces.size() / 3;
|
||||
switch (mode) {
|
||||
case MODE_DEPTH:
|
||||
face_count = triangles.size() * 2 / 3 + (final_polygon.size()) * 2;
|
||||
extrusions = 1;
|
||||
end_count = 2;
|
||||
break;
|
||||
case MODE_SPIN:
|
||||
face_count = (spin_degrees < 360 ? triangles.size() * 2 / 3 : 0) + (final_polygon.size()) * 2 * spin_sides;
|
||||
extrusions = spin_sides;
|
||||
if (spin_degrees < 360) {
|
||||
end_count = 2;
|
||||
}
|
||||
break;
|
||||
case MODE_PATH: {
|
||||
float bl = curve->get_baked_length();
|
||||
int splits = MAX(2, Math::ceil(bl / path_interval));
|
||||
if (path_joined) {
|
||||
face_count = splits * final_polygon.size() * 2;
|
||||
} else {
|
||||
face_count = triangles.size() * 2 / 3 + splits * final_polygon.size() * 2;
|
||||
extrusions = Math::ceil(1.0 * curve->get_point_count() / path_interval);
|
||||
if (!path_joined) {
|
||||
end_count = 2;
|
||||
extrusions -= 1;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
int face_count = extrusions * extrusion_face_count + end_count * shape_face_count;
|
||||
|
||||
bool invert_val = is_inverting_faces();
|
||||
// Initialize variables used to create the mesh.
|
||||
Ref<Material> material = get_material();
|
||||
|
||||
PoolVector<Vector3> faces;
|
||||
|
@ -1858,362 +1828,216 @@ CSGBrush *CSGPolygon::_build_brush() {
|
|||
|
||||
faces.resize(face_count * 3);
|
||||
uvs.resize(face_count * 3);
|
||||
|
||||
smooth.resize(face_count);
|
||||
materials.resize(face_count);
|
||||
invert.resize(face_count);
|
||||
|
||||
AABB aabb; //must be computed
|
||||
{
|
||||
PoolVector<Vector3>::Write facesw = faces.write();
|
||||
PoolVector<Vector2>::Write uvsw = uvs.write();
|
||||
PoolVector<bool>::Write smoothw = smooth.write();
|
||||
PoolVector<Ref<Material>>::Write materialsw = materials.write();
|
||||
PoolVector<bool>::Write invertw = invert.write();
|
||||
PoolVector<Vector3>::Write facesw = faces.write();
|
||||
PoolVector<Vector2>::Write uvsw = uvs.write();
|
||||
PoolVector<bool>::Write smoothw = smooth.write();
|
||||
PoolVector<Ref<Material>>::Write materialsw = materials.write();
|
||||
PoolVector<bool>::Write invertw = invert.write();
|
||||
|
||||
int face = 0;
|
||||
int face = 0;
|
||||
Transform base_xform;
|
||||
Transform current_xform;
|
||||
Transform previous_xform;
|
||||
double u_step = 1.0 / extrusions;
|
||||
double v_step = 1.0 / shape_sides;
|
||||
double spin_step = Math::deg2rad(spin_degrees / spin_sides);
|
||||
double extrusion_step = 1.0 / extrusions;
|
||||
if (mode == MODE_PATH) {
|
||||
if (path_joined) {
|
||||
extrusion_step = 1.0 / (extrusions - 1);
|
||||
}
|
||||
extrusion_step *= curve->get_baked_length();
|
||||
}
|
||||
|
||||
if (mode == MODE_PATH) {
|
||||
if (!path_local) {
|
||||
base_xform = path->get_global_transform();
|
||||
}
|
||||
|
||||
Vector3 current_point = curve->interpolate_baked(0);
|
||||
Vector3 next_point = curve->interpolate_baked(extrusion_step);
|
||||
Vector3 current_up = Vector3(0, 1, 0);
|
||||
Vector3 direction = next_point - current_point;
|
||||
|
||||
if (path_joined) {
|
||||
Vector3 last_point = curve->interpolate_baked(curve->get_baked_length());
|
||||
direction = next_point - last_point;
|
||||
}
|
||||
|
||||
switch (path_rotation) {
|
||||
case PATH_ROTATION_POLYGON:
|
||||
direction = Vector3(0, 0, -1);
|
||||
break;
|
||||
case PATH_ROTATION_PATH:
|
||||
break;
|
||||
case PATH_ROTATION_PATH_FOLLOW:
|
||||
current_up = curve->interpolate_baked_up_vector(0);
|
||||
break;
|
||||
}
|
||||
|
||||
Transform facing = Transform().looking_at(direction, current_up);
|
||||
current_xform = base_xform.translated(current_point) * facing;
|
||||
}
|
||||
|
||||
// Create the mesh.
|
||||
if (end_count > 0) {
|
||||
// Add front end face.
|
||||
for (int face_idx = 0; face_idx < shape_face_count; face_idx++) {
|
||||
for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) {
|
||||
// We need to reverse the rotation of the shape face vertices.
|
||||
int index = shape_faces[face_idx * 3 + 2 - face_vertex_idx];
|
||||
Point2 p = shape_polygon[index];
|
||||
Point2 uv = (p - shape_rect.position) / shape_rect.size;
|
||||
|
||||
// Use the left side of the bottom half of the y-inverted texture.
|
||||
uv.x = uv.x / 2;
|
||||
uv.y = 1 - (uv.y / 2);
|
||||
|
||||
facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0));
|
||||
uvsw[face * 3 + face_vertex_idx] = uv;
|
||||
}
|
||||
|
||||
smoothw[face] = false;
|
||||
materialsw[face] = material;
|
||||
invertw[face] = invert_faces;
|
||||
face++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add extrusion faces.
|
||||
for (int x0 = 0; x0 < extrusions; x0++) {
|
||||
previous_xform = current_xform;
|
||||
|
||||
switch (mode) {
|
||||
case MODE_DEPTH: {
|
||||
//add triangles, front and back
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < triangles.size(); j += 3) {
|
||||
for (int k = 0; k < 3; k++) {
|
||||
int src[3] = { 0, i == 0 ? 1 : 2, i == 0 ? 2 : 1 };
|
||||
Vector2 p = final_polygon[triangles[j + src[k]]];
|
||||
Vector3 v = Vector3(p.x, p.y, 0);
|
||||
if (i == 0) {
|
||||
v.z -= depth;
|
||||
}
|
||||
facesw[face * 3 + k] = v;
|
||||
uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
|
||||
if (i == 0) {
|
||||
uvsw[face * 3 + k].x = 1.0 - uvsw[face * 3 + k].x; /* flip x */
|
||||
}
|
||||
}
|
||||
|
||||
smoothw[face] = false;
|
||||
materialsw[face] = material;
|
||||
invertw[face] = invert_val;
|
||||
face++;
|
||||
}
|
||||
}
|
||||
|
||||
//add triangles for depth
|
||||
for (int i = 0; i < final_polygon.size(); i++) {
|
||||
int i_n = (i + 1) % final_polygon.size();
|
||||
|
||||
Vector3 v[4] = {
|
||||
Vector3(final_polygon[i].x, final_polygon[i].y, -depth),
|
||||
Vector3(final_polygon[i_n].x, final_polygon[i_n].y, -depth),
|
||||
Vector3(final_polygon[i_n].x, final_polygon[i_n].y, 0),
|
||||
Vector3(final_polygon[i].x, final_polygon[i].y, 0),
|
||||
};
|
||||
|
||||
Vector2 u[4] = {
|
||||
Vector2(0, 0),
|
||||
Vector2(0, 1),
|
||||
Vector2(1, 1),
|
||||
Vector2(1, 0)
|
||||
};
|
||||
|
||||
// face 1
|
||||
facesw[face * 3 + 0] = v[0];
|
||||
facesw[face * 3 + 1] = v[1];
|
||||
facesw[face * 3 + 2] = v[2];
|
||||
|
||||
uvsw[face * 3 + 0] = u[0];
|
||||
uvsw[face * 3 + 1] = u[1];
|
||||
uvsw[face * 3 + 2] = u[2];
|
||||
|
||||
smoothw[face] = smooth_faces;
|
||||
invertw[face] = invert_val;
|
||||
materialsw[face] = material;
|
||||
|
||||
face++;
|
||||
|
||||
// face 2
|
||||
facesw[face * 3 + 0] = v[2];
|
||||
facesw[face * 3 + 1] = v[3];
|
||||
facesw[face * 3 + 2] = v[0];
|
||||
|
||||
uvsw[face * 3 + 0] = u[2];
|
||||
uvsw[face * 3 + 1] = u[3];
|
||||
uvsw[face * 3 + 2] = u[0];
|
||||
|
||||
smoothw[face] = smooth_faces;
|
||||
invertw[face] = invert_val;
|
||||
materialsw[face] = material;
|
||||
|
||||
face++;
|
||||
}
|
||||
|
||||
current_xform.translate(Vector3(0, 0, -depth));
|
||||
} break;
|
||||
case MODE_SPIN: {
|
||||
for (int i = 0; i < spin_sides; i++) {
|
||||
float inci = float(i) / spin_sides;
|
||||
float inci_n = float((i + 1)) / spin_sides;
|
||||
|
||||
float angi = -(inci * spin_degrees / 360.0) * Math_PI * 2.0;
|
||||
float angi_n = -(inci_n * spin_degrees / 360.0) * Math_PI * 2.0;
|
||||
|
||||
Vector3 normali = Vector3(Math::cos(angi), 0, Math::sin(angi));
|
||||
Vector3 normali_n = Vector3(Math::cos(angi_n), 0, Math::sin(angi_n));
|
||||
|
||||
//add triangles for depth
|
||||
for (int j = 0; j < final_polygon.size(); j++) {
|
||||
int j_n = (j + 1) % final_polygon.size();
|
||||
|
||||
Vector3 v[4] = {
|
||||
Vector3(normali.x * final_polygon[j].x, final_polygon[j].y, normali.z * final_polygon[j].x),
|
||||
Vector3(normali.x * final_polygon[j_n].x, final_polygon[j_n].y, normali.z * final_polygon[j_n].x),
|
||||
Vector3(normali_n.x * final_polygon[j_n].x, final_polygon[j_n].y, normali_n.z * final_polygon[j_n].x),
|
||||
Vector3(normali_n.x * final_polygon[j].x, final_polygon[j].y, normali_n.z * final_polygon[j].x),
|
||||
};
|
||||
|
||||
Vector2 u[4] = {
|
||||
Vector2(0, 0),
|
||||
Vector2(0, 1),
|
||||
Vector2(1, 1),
|
||||
Vector2(1, 0)
|
||||
};
|
||||
|
||||
// face 1
|
||||
facesw[face * 3 + 0] = v[0];
|
||||
facesw[face * 3 + 1] = v[2];
|
||||
facesw[face * 3 + 2] = v[1];
|
||||
|
||||
uvsw[face * 3 + 0] = u[0];
|
||||
uvsw[face * 3 + 1] = u[2];
|
||||
uvsw[face * 3 + 2] = u[1];
|
||||
|
||||
smoothw[face] = smooth_faces;
|
||||
invertw[face] = invert_val;
|
||||
materialsw[face] = material;
|
||||
|
||||
face++;
|
||||
|
||||
// face 2
|
||||
facesw[face * 3 + 0] = v[2];
|
||||
facesw[face * 3 + 1] = v[0];
|
||||
facesw[face * 3 + 2] = v[3];
|
||||
|
||||
uvsw[face * 3 + 0] = u[2];
|
||||
uvsw[face * 3 + 1] = u[0];
|
||||
uvsw[face * 3 + 2] = u[3];
|
||||
|
||||
smoothw[face] = smooth_faces;
|
||||
invertw[face] = invert_val;
|
||||
materialsw[face] = material;
|
||||
|
||||
face++;
|
||||
}
|
||||
|
||||
if (i == 0 && spin_degrees < 360) {
|
||||
for (int j = 0; j < triangles.size(); j += 3) {
|
||||
for (int k = 0; k < 3; k++) {
|
||||
int src[3] = { 0, 2, 1 };
|
||||
Vector2 p = final_polygon[triangles[j + src[k]]];
|
||||
Vector3 v = Vector3(p.x, p.y, 0);
|
||||
facesw[face * 3 + k] = v;
|
||||
uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
|
||||
}
|
||||
|
||||
smoothw[face] = false;
|
||||
materialsw[face] = material;
|
||||
invertw[face] = invert_val;
|
||||
face++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == spin_sides - 1 && spin_degrees < 360) {
|
||||
for (int j = 0; j < triangles.size(); j += 3) {
|
||||
for (int k = 0; k < 3; k++) {
|
||||
int src[3] = { 0, 1, 2 };
|
||||
Vector2 p = final_polygon[triangles[j + src[k]]];
|
||||
Vector3 v = Vector3(normali_n.x * p.x, p.y, normali_n.z * p.x);
|
||||
facesw[face * 3 + k] = v;
|
||||
uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
|
||||
uvsw[face * 3 + k].x = 1.0 - uvsw[face * 3 + k].x; /* flip x */
|
||||
}
|
||||
|
||||
smoothw[face] = false;
|
||||
materialsw[face] = material;
|
||||
invertw[face] = invert_val;
|
||||
face++;
|
||||
}
|
||||
}
|
||||
}
|
||||
current_xform.rotate(Vector3(0, 1, 0), spin_step);
|
||||
} break;
|
||||
case MODE_PATH: {
|
||||
float bl = curve->get_baked_length();
|
||||
int splits = MAX(2, Math::ceil(bl / path_interval));
|
||||
float u1 = 0.0;
|
||||
float u2 = path_continuous_u ? 0.0 : 1.0;
|
||||
|
||||
Transform path_to_this;
|
||||
if (!path_local) {
|
||||
// center on paths origin
|
||||
path_to_this = get_global_transform().affine_inverse() * path->get_global_transform();
|
||||
}
|
||||
|
||||
Transform prev_xf;
|
||||
|
||||
Vector3 lookat_dir;
|
||||
|
||||
if (path_rotation == PATH_ROTATION_POLYGON) {
|
||||
lookat_dir = (path->get_global_transform().affine_inverse() * get_global_transform()).xform(Vector3(0, 0, -1));
|
||||
} else {
|
||||
Vector3 p1, p2;
|
||||
p1 = curve->interpolate_baked(0);
|
||||
p2 = curve->interpolate_baked(0.1);
|
||||
lookat_dir = (p2 - p1).normalized();
|
||||
}
|
||||
|
||||
for (int i = 0; i <= splits; i++) {
|
||||
float ofs = i * path_interval;
|
||||
if (ofs > bl) {
|
||||
ofs = bl;
|
||||
}
|
||||
if (i == splits && path_joined) {
|
||||
ofs = 0.0;
|
||||
}
|
||||
|
||||
Transform xf;
|
||||
xf.origin = curve->interpolate_baked(ofs);
|
||||
|
||||
Vector3 local_dir;
|
||||
|
||||
if (path_rotation == PATH_ROTATION_PATH_FOLLOW && ofs > 0) {
|
||||
//before end
|
||||
Vector3 p1 = curve->interpolate_baked(ofs - 0.1);
|
||||
Vector3 p2 = curve->interpolate_baked(ofs);
|
||||
local_dir = (p2 - p1).normalized();
|
||||
|
||||
double previous_offset = x0 * extrusion_step;
|
||||
double current_offset = (x0 + 1) * extrusion_step;
|
||||
double next_offset = (x0 + 2) * extrusion_step;
|
||||
if (x0 == extrusions - 1) {
|
||||
if (path_joined) {
|
||||
current_offset = 0;
|
||||
next_offset = extrusion_step;
|
||||
} else {
|
||||
local_dir = lookat_dir;
|
||||
next_offset = current_offset;
|
||||
}
|
||||
|
||||
xf = xf.looking_at(xf.origin + local_dir, Vector3(0, 1, 0));
|
||||
Basis rot(Vector3(0, 0, 1), curve->interpolate_baked_tilt(ofs));
|
||||
|
||||
xf = xf * rot; //post mult
|
||||
|
||||
xf = path_to_this * xf;
|
||||
|
||||
if (i > 0) {
|
||||
if (path_continuous_u) {
|
||||
u1 = u2;
|
||||
u2 += (prev_xf.origin - xf.origin).length();
|
||||
};
|
||||
|
||||
//put triangles where they belong
|
||||
//add triangles for depth
|
||||
for (int j = 0; j < final_polygon.size(); j++) {
|
||||
int j_n = (j + 1) % final_polygon.size();
|
||||
|
||||
Vector3 v[4] = {
|
||||
prev_xf.xform(Vector3(final_polygon[j].x, final_polygon[j].y, 0)),
|
||||
prev_xf.xform(Vector3(final_polygon[j_n].x, final_polygon[j_n].y, 0)),
|
||||
xf.xform(Vector3(final_polygon[j_n].x, final_polygon[j_n].y, 0)),
|
||||
xf.xform(Vector3(final_polygon[j].x, final_polygon[j].y, 0)),
|
||||
};
|
||||
|
||||
Vector2 u[4] = {
|
||||
Vector2(u1, 1),
|
||||
Vector2(u1, 0),
|
||||
Vector2(u2, 0),
|
||||
Vector2(u2, 1)
|
||||
};
|
||||
|
||||
// face 1
|
||||
facesw[face * 3 + 0] = v[0];
|
||||
facesw[face * 3 + 1] = v[1];
|
||||
facesw[face * 3 + 2] = v[2];
|
||||
|
||||
uvsw[face * 3 + 0] = u[0];
|
||||
uvsw[face * 3 + 1] = u[1];
|
||||
uvsw[face * 3 + 2] = u[2];
|
||||
|
||||
smoothw[face] = smooth_faces;
|
||||
invertw[face] = invert_val;
|
||||
materialsw[face] = material;
|
||||
|
||||
face++;
|
||||
|
||||
// face 2
|
||||
facesw[face * 3 + 0] = v[2];
|
||||
facesw[face * 3 + 1] = v[3];
|
||||
facesw[face * 3 + 2] = v[0];
|
||||
|
||||
uvsw[face * 3 + 0] = u[2];
|
||||
uvsw[face * 3 + 1] = u[3];
|
||||
uvsw[face * 3 + 2] = u[0];
|
||||
|
||||
smoothw[face] = smooth_faces;
|
||||
invertw[face] = invert_val;
|
||||
materialsw[face] = material;
|
||||
|
||||
face++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 0 && !path_joined) {
|
||||
for (int j = 0; j < triangles.size(); j += 3) {
|
||||
for (int k = 0; k < 3; k++) {
|
||||
int src[3] = { 0, 1, 2 };
|
||||
Vector2 p = final_polygon[triangles[j + src[k]]];
|
||||
Vector3 v = Vector3(p.x, p.y, 0);
|
||||
facesw[face * 3 + k] = xf.xform(v);
|
||||
uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
|
||||
}
|
||||
|
||||
smoothw[face] = false;
|
||||
materialsw[face] = material;
|
||||
invertw[face] = invert_val;
|
||||
face++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == splits && !path_joined) {
|
||||
for (int j = 0; j < triangles.size(); j += 3) {
|
||||
for (int k = 0; k < 3; k++) {
|
||||
int src[3] = { 0, 2, 1 };
|
||||
Vector2 p = final_polygon[triangles[j + src[k]]];
|
||||
Vector3 v = Vector3(p.x, p.y, 0);
|
||||
facesw[face * 3 + k] = xf.xform(v);
|
||||
uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
|
||||
uvsw[face * 3 + k].x = 1.0 - uvsw[face * 3 + k].x; /* flip x */
|
||||
}
|
||||
|
||||
smoothw[face] = false;
|
||||
materialsw[face] = material;
|
||||
invertw[face] = invert_val;
|
||||
face++;
|
||||
}
|
||||
}
|
||||
|
||||
prev_xf = xf;
|
||||
}
|
||||
|
||||
Vector3 previous_point = curve->interpolate_baked(previous_offset);
|
||||
Vector3 current_point = curve->interpolate_baked(current_offset);
|
||||
Vector3 next_point = curve->interpolate_baked(next_offset);
|
||||
Vector3 current_up = Vector3(0, 1, 0);
|
||||
Vector3 direction = next_point - previous_point;
|
||||
|
||||
switch (path_rotation) {
|
||||
case PATH_ROTATION_POLYGON:
|
||||
direction = Vector3(0, 0, -1);
|
||||
break;
|
||||
case PATH_ROTATION_PATH:
|
||||
break;
|
||||
case PATH_ROTATION_PATH_FOLLOW:
|
||||
current_up = curve->interpolate_baked_up_vector(current_offset);
|
||||
break;
|
||||
}
|
||||
|
||||
Transform facing = Transform().looking_at(direction, current_up);
|
||||
current_xform = base_xform.translated(current_point) * facing;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (face != face_count) {
|
||||
ERR_PRINT("Face mismatch bug! fix code");
|
||||
double u0 = x0 * u_step;
|
||||
double u1 = ((x0 + 1) * u_step);
|
||||
if (mode == MODE_PATH && !path_continuous_u) {
|
||||
u0 = 0.0;
|
||||
u1 = 1.0;
|
||||
}
|
||||
for (int i = 0; i < face_count * 3; i++) {
|
||||
if (i == 0) {
|
||||
aabb.position = facesw[i];
|
||||
} else {
|
||||
aabb.expand_to(facesw[i]);
|
||||
}
|
||||
|
||||
// invert UVs on the Y-axis OpenGL = upside down
|
||||
uvsw[i].y = 1.0 - uvsw[i].y;
|
||||
for (int y0 = 0; y0 < shape_sides; y0++) {
|
||||
int y1 = (y0 + 1) % shape_sides;
|
||||
// Use the top half of the texture.
|
||||
double v0 = (y0 * v_step) / 2;
|
||||
double v1 = ((y0 + 1) * v_step) / 2;
|
||||
|
||||
Vector3 v[4] = {
|
||||
previous_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)),
|
||||
current_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)),
|
||||
current_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)),
|
||||
previous_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)),
|
||||
};
|
||||
|
||||
Vector2 u[4] = {
|
||||
Vector2(u0, v0),
|
||||
Vector2(u1, v0),
|
||||
Vector2(u1, v1),
|
||||
Vector2(u0, v1),
|
||||
};
|
||||
|
||||
// Face 1
|
||||
facesw[face * 3 + 0] = v[0];
|
||||
facesw[face * 3 + 1] = v[1];
|
||||
facesw[face * 3 + 2] = v[2];
|
||||
|
||||
uvsw[face * 3 + 0] = u[0];
|
||||
uvsw[face * 3 + 1] = u[1];
|
||||
uvsw[face * 3 + 2] = u[2];
|
||||
|
||||
smoothw[face] = smooth_faces;
|
||||
invertw[face] = invert_faces;
|
||||
materialsw[face] = material;
|
||||
|
||||
face++;
|
||||
|
||||
// Face 2
|
||||
facesw[face * 3 + 0] = v[2];
|
||||
facesw[face * 3 + 1] = v[3];
|
||||
facesw[face * 3 + 2] = v[0];
|
||||
|
||||
uvsw[face * 3 + 0] = u[2];
|
||||
uvsw[face * 3 + 1] = u[3];
|
||||
uvsw[face * 3 + 2] = u[0];
|
||||
|
||||
smoothw[face] = smooth_faces;
|
||||
invertw[face] = invert_faces;
|
||||
materialsw[face] = material;
|
||||
|
||||
face++;
|
||||
}
|
||||
}
|
||||
|
||||
if (end_count > 1) {
|
||||
// Add back end face.
|
||||
for (int face_idx = 0; face_idx < shape_face_count; face_idx++) {
|
||||
for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) {
|
||||
int index = shape_faces[face_idx * 3 + face_vertex_idx];
|
||||
Point2 p = shape_polygon[index];
|
||||
Point2 uv = (p - shape_rect.position) / shape_rect.size;
|
||||
|
||||
// Use the x-inverted ride side of the bottom half of the y-inverted texture.
|
||||
uv.x = 1 - uv.x / 2;
|
||||
uv.y = 1 - (uv.y / 2);
|
||||
|
||||
facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0));
|
||||
uvsw[face * 3 + face_vertex_idx] = uv;
|
||||
}
|
||||
|
||||
smoothw[face] = false;
|
||||
materialsw[face] = material;
|
||||
invertw[face] = invert_faces;
|
||||
face++;
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(face != face_count, brush, "Bug: Failed to create the CSGPolygon mesh correctly.");
|
||||
|
||||
brush->build_from_faces(faces, uvs, smooth, materials, invert);
|
||||
|
||||
return brush;
|
||||
|
@ -2221,10 +2045,10 @@ CSGBrush *CSGPolygon::_build_brush() {
|
|||
|
||||
void CSGPolygon::_notification(int p_what) {
|
||||
if (p_what == NOTIFICATION_EXIT_TREE) {
|
||||
if (path_cache) {
|
||||
path_cache->disconnect("tree_exited", this, "_path_exited");
|
||||
path_cache->disconnect("curve_changed", this, "_path_changed");
|
||||
path_cache = nullptr;
|
||||
if (path) {
|
||||
path->disconnect("tree_exited", this, "_path_exited");
|
||||
path->disconnect("curve_changed", this, "_path_changed");
|
||||
path = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2249,7 +2073,7 @@ void CSGPolygon::_path_changed() {
|
|||
}
|
||||
|
||||
void CSGPolygon::_path_exited() {
|
||||
path_cache = nullptr;
|
||||
path = nullptr;
|
||||
}
|
||||
|
||||
void CSGPolygon::_bind_methods() {
|
||||
|
@ -2271,10 +2095,10 @@ void CSGPolygon::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_path_node", "path"), &CSGPolygon::set_path_node);
|
||||
ClassDB::bind_method(D_METHOD("get_path_node"), &CSGPolygon::get_path_node);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_path_interval", "distance"), &CSGPolygon::set_path_interval);
|
||||
ClassDB::bind_method(D_METHOD("set_path_interval", "path_interval"), &CSGPolygon::set_path_interval);
|
||||
ClassDB::bind_method(D_METHOD("get_path_interval"), &CSGPolygon::get_path_interval);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_path_rotation", "mode"), &CSGPolygon::set_path_rotation);
|
||||
ClassDB::bind_method(D_METHOD("set_path_rotation", "path_rotation"), &CSGPolygon::set_path_rotation);
|
||||
ClassDB::bind_method(D_METHOD("get_path_rotation"), &CSGPolygon::get_path_rotation);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_path_local", "enable"), &CSGPolygon::set_path_local);
|
||||
|
@ -2300,11 +2124,11 @@ void CSGPolygon::_bind_methods() {
|
|||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Depth,Spin,Path"), "set_mode", "get_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth", PROPERTY_HINT_EXP_RANGE, "0.01,100.0,0.01,or_greater"), "set_depth", "get_depth");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "spin_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_spin_sides", "get_spin_sides");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path"), "set_path_node", "get_path_node");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "path_interval", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_path_interval", "get_path_interval");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "path_interval", PROPERTY_HINT_RANGE, "0.1,1.0,0.05"), "set_path_interval", "get_path_interval");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_local"), "set_path_local", "is_path_local");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_continuous_u"), "set_path_continuous_u", "is_path_continuous_u");
|
||||
|
@ -2373,7 +2197,7 @@ float CSGPolygon::get_spin_degrees() const {
|
|||
return spin_degrees;
|
||||
}
|
||||
|
||||
void CSGPolygon::set_spin_sides(const int p_spin_sides) {
|
||||
void CSGPolygon::set_spin_sides(int p_spin_sides) {
|
||||
ERR_FAIL_COND(p_spin_sides < 3);
|
||||
spin_sides = p_spin_sides;
|
||||
_make_dirty();
|
||||
|
@ -2395,11 +2219,12 @@ NodePath CSGPolygon::get_path_node() const {
|
|||
}
|
||||
|
||||
void CSGPolygon::set_path_interval(float p_interval) {
|
||||
ERR_FAIL_COND_MSG(p_interval < 0.001, "Path interval cannot be smaller than 0.001.");
|
||||
ERR_FAIL_COND_MSG(p_interval <= 0 || p_interval > 1, "Path interval must be greater than 0 and less than or equal to 1.0.");
|
||||
path_interval = p_interval;
|
||||
_make_dirty();
|
||||
update_gizmo();
|
||||
}
|
||||
|
||||
float CSGPolygon::get_path_interval() const {
|
||||
return path_interval;
|
||||
}
|
||||
|
@ -2471,10 +2296,10 @@ CSGPolygon::CSGPolygon() {
|
|||
spin_degrees = 360;
|
||||
spin_sides = 8;
|
||||
smooth_faces = false;
|
||||
path_interval = 1;
|
||||
path_rotation = PATH_ROTATION_PATH;
|
||||
path_interval = 1.0;
|
||||
path_rotation = PATH_ROTATION_PATH_FOLLOW;
|
||||
path_local = false;
|
||||
path_continuous_u = false;
|
||||
path_continuous_u = true;
|
||||
path_joined = false;
|
||||
path_cache = nullptr;
|
||||
path = nullptr;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#define CSGJS_HEADER_ONLY
|
||||
|
||||
#include "csg.h"
|
||||
#include "scene/3d/path.h"
|
||||
#include "scene/3d/visual_instance.h"
|
||||
#include "scene/resources/concave_polygon_shape.h"
|
||||
#include "thirdparty/misc/mikktspace.h"
|
||||
|
@ -170,10 +171,8 @@ public:
|
|||
class CSGPrimitive : public CSGShape {
|
||||
GDCLASS(CSGPrimitive, CSGShape);
|
||||
|
||||
private:
|
||||
bool invert_faces;
|
||||
|
||||
protected:
|
||||
bool invert_faces;
|
||||
CSGBrush *_create_brush_from_arrays(const PoolVector<Vector3> &p_vertices, const PoolVector<Vector2> &p_uv, const PoolVector<bool> &p_smooth, const PoolVector<Ref<Material>> &p_materials);
|
||||
static void _bind_methods();
|
||||
|
||||
|
@ -371,7 +370,7 @@ private:
|
|||
PathRotation path_rotation;
|
||||
bool path_local;
|
||||
|
||||
Node *path_cache;
|
||||
Path *path;
|
||||
|
||||
bool smooth_faces;
|
||||
bool path_continuous_u;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
Extrudes a 2D polygon shape to create a 3D mesh.
|
||||
</brief_description>
|
||||
<description>
|
||||
This node takes a 2D polygon shape and extrudes it to create a 3D mesh.
|
||||
An array of 2D points is extruded to quickly and easily create a variety of 3D meshes.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
|
@ -12,63 +12,65 @@
|
|||
</methods>
|
||||
<members>
|
||||
<member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0">
|
||||
Extrusion depth when [member mode] is [constant MODE_DEPTH].
|
||||
When [member mode] is [constant MODE_DEPTH], the depth of the extrusion.
|
||||
</member>
|
||||
<member name="material" type="Material" setter="set_material" getter="get_material">
|
||||
Material to use for the resulting mesh.
|
||||
Material to use for the resulting mesh. The UV maps the top half of the material to the extruded shape (U along the the length of the extrusions and V around the outline of the [member polygon]), the bottom-left quarter to the front end face, and the bottom-right quarter to the back end face.
|
||||
</member>
|
||||
<member name="mode" type="int" setter="set_mode" getter="get_mode" enum="CSGPolygon.Mode" default="0">
|
||||
Extrusion mode.
|
||||
The [member mode] used to extrude the [member polygon].
|
||||
</member>
|
||||
<member name="path_continuous_u" type="bool" setter="set_path_continuous_u" getter="is_path_continuous_u">
|
||||
If [code]true[/code] the u component of our uv will continuously increase in unison with the distance traveled along our path when [member mode] is [constant MODE_PATH].
|
||||
When [member mode] is [constant MODE_PATH], by default, the top half of the [member material] is stretched along the entire length of the extruded shape. If [code]false[/code] the top half of the material is repeated every step of the extrusion.
|
||||
</member>
|
||||
<member name="path_interval" type="float" setter="set_path_interval" getter="get_path_interval">
|
||||
Interval at which a new extrusion slice is added along the path when [member mode] is [constant MODE_PATH].
|
||||
When [member mode] is [constant MODE_PATH], the path interval or ratio of path points to extrusions.
|
||||
</member>
|
||||
<member name="path_joined" type="bool" setter="set_path_joined" getter="is_path_joined">
|
||||
If [code]true[/code] the start and end of our path are joined together ensuring there is no seam when [member mode] is [constant MODE_PATH].
|
||||
When [member mode] is [constant MODE_PATH], if [code]true[/code] the ends of the path are joined, by adding an extrusion between the last and first points of the path.
|
||||
</member>
|
||||
<member name="path_local" type="bool" setter="set_path_local" getter="is_path_local">
|
||||
If [code]false[/code] we extrude centered on our path, if [code]true[/code] we extrude in relation to the position of our CSGPolygon when [member mode] is [constant MODE_PATH].
|
||||
When [member mode] is [constant MODE_PATH], if [code]true[/code] the [Transform] of the [CSGPolygon] is used as the starting point for the extrusions, not the [Transform] of the [member path_node].
|
||||
</member>
|
||||
<member name="path_node" type="NodePath" setter="set_path_node" getter="get_path_node">
|
||||
The [Shape] object containing the path along which we extrude when [member mode] is [constant MODE_PATH].
|
||||
When [member mode] is [constant MODE_PATH], the location of the [Path] object used to extrude the [member polygon].
|
||||
</member>
|
||||
<member name="path_rotation" type="int" setter="set_path_rotation" getter="get_path_rotation" enum="CSGPolygon.PathRotation">
|
||||
The method by which each slice is rotated along the path when [member mode] is [constant MODE_PATH].
|
||||
When [member mode] is [constant MODE_PATH], the [enum PathRotation] method used to rotate the [member polygon] as it is extruded.
|
||||
</member>
|
||||
<member name="polygon" type="PoolVector2Array" setter="set_polygon" getter="get_polygon" default="PoolVector2Array( 0, 0, 0, 1, 1, 1, 1, 0 )">
|
||||
Point array that defines the shape that we'll extrude.
|
||||
The point array that defines the 2D polygon that is extruded.
|
||||
</member>
|
||||
<member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="false">
|
||||
Generates smooth normals so smooth shading is applied to our mesh.
|
||||
If [code]true[/code], applies smooth shading to the extrusions.
|
||||
</member>
|
||||
<member name="spin_degrees" type="float" setter="set_spin_degrees" getter="get_spin_degrees">
|
||||
Degrees to rotate our extrusion for each slice when [member mode] is [constant MODE_SPIN].
|
||||
When [member mode] is [constant MODE_SPIN], the total number of degrees the [member polygon] is rotated when extruding.
|
||||
</member>
|
||||
<member name="spin_sides" type="int" setter="set_spin_sides" getter="get_spin_sides">
|
||||
Number of extrusion when [member mode] is [constant MODE_SPIN].
|
||||
When [member mode] is [constant MODE_SPIN], the number of extrusions made.
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
<constant name="MODE_DEPTH" value="0" enum="Mode">
|
||||
Shape is extruded to [member depth].
|
||||
The [member polygon] shape is extruded along the negative Z axis.
|
||||
</constant>
|
||||
<constant name="MODE_SPIN" value="1" enum="Mode">
|
||||
Shape is extruded by rotating it around an axis.
|
||||
The [member polygon] shape is extruded by rotating it around the Y axis.
|
||||
</constant>
|
||||
<constant name="MODE_PATH" value="2" enum="Mode">
|
||||
Shape is extruded along a path set by a [Shape] set in [member path_node].
|
||||
The [member polygon] shape is extruded along the [Path] specified in [member path_node].
|
||||
</constant>
|
||||
<constant name="PATH_ROTATION_POLYGON" value="0" enum="PathRotation">
|
||||
Slice is not rotated.
|
||||
The [member polygon] shape is not rotated.
|
||||
[b]Note:[/b] Requires the path's Z coordinates to continually decrease to ensure viable shapes.
|
||||
</constant>
|
||||
<constant name="PATH_ROTATION_PATH" value="1" enum="PathRotation">
|
||||
Slice is rotated around the up vector of the path.
|
||||
The [member polygon] shape is rotated along the path, but it is not rotated around the path axis.
|
||||
[b]Note:[/b] Requires the path's Z coordinates to continually decrease to ensure viable shapes.
|
||||
</constant>
|
||||
<constant name="PATH_ROTATION_PATH_FOLLOW" value="2" enum="PathRotation">
|
||||
Slice is rotate to match the path exactly.
|
||||
The [member polygon] shape follows the path and its rotations around the path axis.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
|
|
Loading…
Reference in New Issue