Merge pull request #23743 from BastiaanOlij/csg_mikkt_tangent
Adding mikkt tangent support to CSG objects
This commit is contained in:
commit
6ed1be9637
|
@ -159,6 +159,74 @@ CSGBrush *CSGShape::_get_brush() {
|
||||||
return brush;
|
return brush;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CSGShape::mikktGetNumFaces(const SMikkTSpaceContext *pContext) {
|
||||||
|
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
|
||||||
|
|
||||||
|
return surface.vertices.size() / 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CSGShape::mikktGetNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace) {
|
||||||
|
// always 3
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSGShape::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert) {
|
||||||
|
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
|
||||||
|
|
||||||
|
Vector3 v = surface.verticesw[iFace * 3 + iVert];
|
||||||
|
fvPosOut[0] = v.x;
|
||||||
|
fvPosOut[1] = v.y;
|
||||||
|
fvPosOut[2] = v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSGShape::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert) {
|
||||||
|
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
|
||||||
|
|
||||||
|
Vector3 n = surface.normalsw[iFace * 3 + iVert];
|
||||||
|
fvNormOut[0] = n.x;
|
||||||
|
fvNormOut[1] = n.y;
|
||||||
|
fvNormOut[2] = n.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSGShape::mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert) {
|
||||||
|
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
|
||||||
|
|
||||||
|
Vector2 t = surface.uvsw[iFace * 3 + iVert];
|
||||||
|
fvTexcOut[0] = t.x;
|
||||||
|
fvTexcOut[1] = t.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSGShape::mikktSetTSpaceBasic(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert) {
|
||||||
|
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
|
||||||
|
|
||||||
|
int i = (iFace * 3 + iVert) * 4;
|
||||||
|
|
||||||
|
// Godot seems to want the tangent flipped because our handedness is reversed..
|
||||||
|
surface.tansw[i++] = -fvTangent[0];
|
||||||
|
surface.tansw[i++] = -fvTangent[1];
|
||||||
|
surface.tansw[i++] = -fvTangent[2];
|
||||||
|
surface.tansw[i++] = fSign;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSGShape::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
|
||||||
|
const tbool bIsOrientationPreserving, const int iFace, const int iVert) {
|
||||||
|
|
||||||
|
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
|
||||||
|
|
||||||
|
int i = iFace * 3 + iVert;
|
||||||
|
Vector3 normal = surface.normalsw[i];
|
||||||
|
Vector3 tangent = Vector3(fvTangent[0], fvTangent[1], fvTangent[2]);
|
||||||
|
Vector3 bitangent = Vector3(fvBiTangent[0], fvBiTangent[1], fvBiTangent[2]);
|
||||||
|
float d = bitangent.dot(normal.cross(tangent));
|
||||||
|
|
||||||
|
// Godot seems to want the tangent flipped because our handedness is reversed..
|
||||||
|
i *= 4;
|
||||||
|
surface.tansw[i++] = -tangent.x;
|
||||||
|
surface.tansw[i++] = -tangent.y;
|
||||||
|
surface.tansw[i++] = -tangent.z;
|
||||||
|
surface.tansw[i++] = d < 0 ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
void CSGShape::_update_shape() {
|
void CSGShape::_update_shape() {
|
||||||
|
|
||||||
if (parent)
|
if (parent)
|
||||||
|
@ -211,6 +279,9 @@ void CSGShape::_update_shape() {
|
||||||
surfaces.write[i].vertices.resize(face_count[i] * 3);
|
surfaces.write[i].vertices.resize(face_count[i] * 3);
|
||||||
surfaces.write[i].normals.resize(face_count[i] * 3);
|
surfaces.write[i].normals.resize(face_count[i] * 3);
|
||||||
surfaces.write[i].uvs.resize(face_count[i] * 3);
|
surfaces.write[i].uvs.resize(face_count[i] * 3);
|
||||||
|
if (calculate_tangents) {
|
||||||
|
surfaces.write[i].tans.resize(face_count[i] * 3 * 4);
|
||||||
|
}
|
||||||
surfaces.write[i].last_added = 0;
|
surfaces.write[i].last_added = 0;
|
||||||
|
|
||||||
if (i != surfaces.size() - 1) {
|
if (i != surfaces.size() - 1) {
|
||||||
|
@ -220,6 +291,9 @@ void CSGShape::_update_shape() {
|
||||||
surfaces.write[i].verticesw = surfaces.write[i].vertices.write();
|
surfaces.write[i].verticesw = surfaces.write[i].vertices.write();
|
||||||
surfaces.write[i].normalsw = surfaces.write[i].normals.write();
|
surfaces.write[i].normalsw = surfaces.write[i].normals.write();
|
||||||
surfaces.write[i].uvsw = surfaces.write[i].uvs.write();
|
surfaces.write[i].uvsw = surfaces.write[i].uvs.write();
|
||||||
|
if (calculate_tangents) {
|
||||||
|
surfaces.write[i].tansw = surfaces.write[i].tans.write();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//fill arrays
|
//fill arrays
|
||||||
|
@ -274,9 +348,19 @@ void CSGShape::_update_shape() {
|
||||||
normal = -normal;
|
normal = -normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
surfaces[idx].verticesw[last + order[j]] = v;
|
int k = last + order[j];
|
||||||
surfaces[idx].uvsw[last + order[j]] = n->faces[i].uvs[j];
|
surfaces[idx].verticesw[k] = v;
|
||||||
surfaces[idx].normalsw[last + order[j]] = normal;
|
surfaces[idx].uvsw[k] = n->faces[i].uvs[j];
|
||||||
|
surfaces[idx].normalsw[k] = normal;
|
||||||
|
|
||||||
|
if (calculate_tangents) {
|
||||||
|
// zero out our tangents for now
|
||||||
|
k *= 4;
|
||||||
|
surfaces[idx].tansw[k++] = 0.0;
|
||||||
|
surfaces[idx].tansw[k++] = 0.0;
|
||||||
|
surfaces[idx].tansw[k++] = 0.0;
|
||||||
|
surfaces[idx].tansw[k++] = 0.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
surfaces.write[idx].last_added += 3;
|
surfaces.write[idx].last_added += 3;
|
||||||
|
@ -287,20 +371,43 @@ void CSGShape::_update_shape() {
|
||||||
//create surfaces
|
//create surfaces
|
||||||
|
|
||||||
for (int i = 0; i < surfaces.size(); i++) {
|
for (int i = 0; i < surfaces.size(); i++) {
|
||||||
|
// calculate tangents for this surface
|
||||||
|
bool have_tangents = calculate_tangents;
|
||||||
|
if (have_tangents) {
|
||||||
|
SMikkTSpaceInterface mkif;
|
||||||
|
mkif.m_getNormal = mikktGetNormal;
|
||||||
|
mkif.m_getNumFaces = mikktGetNumFaces;
|
||||||
|
mkif.m_getNumVerticesOfFace = mikktGetNumVerticesOfFace;
|
||||||
|
mkif.m_getPosition = mikktGetPosition;
|
||||||
|
mkif.m_getTexCoord = mikktGetTexCoord;
|
||||||
|
mkif.m_setTSpace = mikktSetTSpaceDefault;
|
||||||
|
mkif.m_setTSpaceBasic = NULL;
|
||||||
|
|
||||||
|
SMikkTSpaceContext msc;
|
||||||
|
msc.m_pInterface = &mkif;
|
||||||
|
msc.m_pUserData = &surfaces.write[i];
|
||||||
|
have_tangents = genTangSpaceDefault(&msc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unset write access
|
||||||
surfaces.write[i].verticesw = PoolVector<Vector3>::Write();
|
surfaces.write[i].verticesw = PoolVector<Vector3>::Write();
|
||||||
surfaces.write[i].normalsw = PoolVector<Vector3>::Write();
|
surfaces.write[i].normalsw = PoolVector<Vector3>::Write();
|
||||||
surfaces.write[i].uvsw = PoolVector<Vector2>::Write();
|
surfaces.write[i].uvsw = PoolVector<Vector2>::Write();
|
||||||
|
surfaces.write[i].tansw = PoolVector<float>::Write();
|
||||||
|
|
||||||
if (surfaces[i].last_added == 0)
|
if (surfaces[i].last_added == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// and convert to surface array
|
||||||
Array array;
|
Array array;
|
||||||
array.resize(Mesh::ARRAY_MAX);
|
array.resize(Mesh::ARRAY_MAX);
|
||||||
|
|
||||||
array[Mesh::ARRAY_VERTEX] = surfaces[i].vertices;
|
array[Mesh::ARRAY_VERTEX] = surfaces[i].vertices;
|
||||||
array[Mesh::ARRAY_NORMAL] = surfaces[i].normals;
|
array[Mesh::ARRAY_NORMAL] = surfaces[i].normals;
|
||||||
array[Mesh::ARRAY_TEX_UV] = surfaces[i].uvs;
|
array[Mesh::ARRAY_TEX_UV] = surfaces[i].uvs;
|
||||||
|
if (have_tangents) {
|
||||||
|
array[Mesh::ARRAY_TANGENT] = surfaces[i].tans;
|
||||||
|
}
|
||||||
|
|
||||||
int idx = root_mesh->get_surface_count();
|
int idx = root_mesh->get_surface_count();
|
||||||
root_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, array);
|
root_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, array);
|
||||||
|
@ -400,6 +507,15 @@ CSGShape::Operation CSGShape::get_operation() const {
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSGShape::set_calculate_tangents(bool p_calculate_tangents) {
|
||||||
|
calculate_tangents = p_calculate_tangents;
|
||||||
|
_make_dirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSGShape::is_calculating_tangents() const {
|
||||||
|
return calculate_tangents;
|
||||||
|
}
|
||||||
|
|
||||||
void CSGShape::_validate_property(PropertyInfo &property) const {
|
void CSGShape::_validate_property(PropertyInfo &property) const {
|
||||||
if (is_inside_tree() && property.name.begins_with("use_collision") && !is_root_shape()) {
|
if (is_inside_tree() && property.name.begins_with("use_collision") && !is_root_shape()) {
|
||||||
//hide collision if not root
|
//hide collision if not root
|
||||||
|
@ -421,9 +537,13 @@ void CSGShape::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGShape::set_snap);
|
ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGShape::set_snap);
|
||||||
ClassDB::bind_method(D_METHOD("get_snap"), &CSGShape::get_snap);
|
ClassDB::bind_method(D_METHOD("get_snap"), &CSGShape::get_snap);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_calculate_tangents", "enabled"), &CSGShape::set_calculate_tangents);
|
||||||
|
ClassDB::bind_method(D_METHOD("is_calculating_tangents"), &CSGShape::is_calculating_tangents);
|
||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_collision"), "set_use_collision", "is_using_collision");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_collision"), "set_use_collision", "is_using_collision");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "snap", PROPERTY_HINT_RANGE, "0.0001,1,0.001"), "set_snap", "get_snap");
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "snap", PROPERTY_HINT_RANGE, "0.0001,1,0.001"), "set_snap", "get_snap");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "calculate_tangents"), "set_calculate_tangents", "is_calculating_tangents");
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(OPERATION_UNION);
|
BIND_ENUM_CONSTANT(OPERATION_UNION);
|
||||||
BIND_ENUM_CONSTANT(OPERATION_INTERSECTION);
|
BIND_ENUM_CONSTANT(OPERATION_INTERSECTION);
|
||||||
|
@ -438,6 +558,7 @@ CSGShape::CSGShape() {
|
||||||
use_collision = false;
|
use_collision = false;
|
||||||
operation = OPERATION_UNION;
|
operation = OPERATION_UNION;
|
||||||
snap = 0.001;
|
snap = 0.001;
|
||||||
|
calculate_tangents = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSGShape::~CSGShape() {
|
CSGShape::~CSGShape() {
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "csg.h"
|
#include "csg.h"
|
||||||
#include "scene/3d/visual_instance.h"
|
#include "scene/3d/visual_instance.h"
|
||||||
#include "scene/resources/concave_polygon_shape.h"
|
#include "scene/resources/concave_polygon_shape.h"
|
||||||
|
#include "thirdparty/misc/mikktspace.h"
|
||||||
|
|
||||||
class CSGShape : public VisualInstance {
|
class CSGShape : public VisualInstance {
|
||||||
GDCLASS(CSGShape, VisualInstance);
|
GDCLASS(CSGShape, VisualInstance);
|
||||||
|
@ -63,6 +64,8 @@ private:
|
||||||
Ref<ConcavePolygonShape> root_collision_shape;
|
Ref<ConcavePolygonShape> root_collision_shape;
|
||||||
RID root_collision_instance;
|
RID root_collision_instance;
|
||||||
|
|
||||||
|
bool calculate_tangents;
|
||||||
|
|
||||||
Ref<ArrayMesh> root_mesh;
|
Ref<ArrayMesh> root_mesh;
|
||||||
|
|
||||||
struct Vector3Hasher {
|
struct Vector3Hasher {
|
||||||
|
@ -78,14 +81,26 @@ private:
|
||||||
PoolVector<Vector3> vertices;
|
PoolVector<Vector3> vertices;
|
||||||
PoolVector<Vector3> normals;
|
PoolVector<Vector3> normals;
|
||||||
PoolVector<Vector2> uvs;
|
PoolVector<Vector2> uvs;
|
||||||
|
PoolVector<float> tans;
|
||||||
Ref<Material> material;
|
Ref<Material> material;
|
||||||
int last_added;
|
int last_added;
|
||||||
|
|
||||||
PoolVector<Vector3>::Write verticesw;
|
PoolVector<Vector3>::Write verticesw;
|
||||||
PoolVector<Vector3>::Write normalsw;
|
PoolVector<Vector3>::Write normalsw;
|
||||||
PoolVector<Vector2>::Write uvsw;
|
PoolVector<Vector2>::Write uvsw;
|
||||||
|
PoolVector<float>::Write tansw;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//mikktspace callbacks
|
||||||
|
static int mikktGetNumFaces(const SMikkTSpaceContext *pContext);
|
||||||
|
static int mikktGetNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace);
|
||||||
|
static void mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert);
|
||||||
|
static void mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert);
|
||||||
|
static void mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert);
|
||||||
|
static void mikktSetTSpaceBasic(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert);
|
||||||
|
static void mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
|
||||||
|
const tbool bIsOrientationPreserving, const int iFace, const int iVert);
|
||||||
|
|
||||||
void _update_shape();
|
void _update_shape();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -115,6 +130,9 @@ public:
|
||||||
void set_snap(float p_snap);
|
void set_snap(float p_snap);
|
||||||
float get_snap() const;
|
float get_snap() const;
|
||||||
|
|
||||||
|
void set_calculate_tangents(bool p_calculate_tangents);
|
||||||
|
bool is_calculating_tangents() const;
|
||||||
|
|
||||||
bool is_root_shape() const;
|
bool is_root_shape() const;
|
||||||
CSGShape();
|
CSGShape();
|
||||||
~CSGShape();
|
~CSGShape();
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
</method>
|
</method>
|
||||||
</methods>
|
</methods>
|
||||||
<members>
|
<members>
|
||||||
|
<member name="calculate_tangents" type="bool" setter="set_calculate_tangents" getter="is_calculating_tangents">
|
||||||
|
Calculate tangents for the CSG shape which allows the use of normal maps. This is only applied on the root shape, this setting is ignored on any child.
|
||||||
|
</member>
|
||||||
<member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape.Operation">
|
<member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape.Operation">
|
||||||
The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent.
|
The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent.
|
||||||
</member>
|
</member>
|
||||||
|
|
Loading…
Reference in New Issue