several agonizing hours of dealing with more GCC v13 gremlins involving calculating tangents
This commit is contained in:
parent
6ae24419e7
commit
9e823645a4
@ -1,13 +1,13 @@
|
||||
{
|
||||
"engine": {
|
||||
"scenes": {
|
||||
"start": "StartMenu",
|
||||
"start": "SourceEngine",
|
||||
"matrix": { "reverseInfinite": true },
|
||||
"lights": { "enabled": true,
|
||||
"lightmaps": true,
|
||||
"lightmaps": false,
|
||||
"max": 32,
|
||||
"shadows": {
|
||||
"enabled": true,
|
||||
"enabled": false,
|
||||
"update": 4,
|
||||
"max": 16,
|
||||
"samples": 2
|
||||
|
||||
@ -62,7 +62,7 @@
|
||||
"renderer": {
|
||||
"front face": "auto",
|
||||
"cull mode": "back",
|
||||
"filter": "nearest",
|
||||
"filter": "linear",
|
||||
|
||||
"atlas": false,
|
||||
"invert": true,
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
{
|
||||
"import": "./base_sourceengine.json",
|
||||
"assets": [
|
||||
// { "filename": "./models/mds_mcdonalds.glb" }
|
||||
{ "filename": "./models/mds_mcdonalds/graph.json" }
|
||||
{ "filename": "./models/mds_mcdonalds.glb" }
|
||||
// { "filename": "./models/mds_mcdonalds/graph.json" }
|
||||
// ,{ "filename": "/ball.json", "delay": 1 }
|
||||
// ,{ "filename": "/ragdoll.json", "delay": 1 }
|
||||
// ,{ "filename": "/craeture.json", "delay": 2.0 }
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
{
|
||||
"import": "./base_sourceengine.json",
|
||||
"assets": [
|
||||
{ "filename": "./maps/cs_office.bsp" }
|
||||
// { "filename": "./maps/cs_office/graph.json" }
|
||||
// { "filename": "./maps/cs_office.bsp" }
|
||||
{ "filename": "./maps/cs_office/graph.json" }
|
||||
],
|
||||
"metadata": {
|
||||
"graph": {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
// "import": "./rp_downtown_v2.json"
|
||||
// "import": "./ss2_medsci1.json"
|
||||
// "import": "./mds_mcdonalds.json"
|
||||
"import": "./cs_office.json"
|
||||
"import": "./mds_mcdonalds.json"
|
||||
// "import": "./cs_office.json"
|
||||
// "import": "./gm_construct.json"
|
||||
}
|
||||
@ -400,11 +400,7 @@ void populateSurface( InstanceAddresses addresses, uvec3 indices ) {
|
||||
vec3 tangent_tri = (edge1 * deltaUV2.y - edge2 * deltaUV1.y) * r;
|
||||
|
||||
#pragma unroll 3
|
||||
for ( uint i = 0; i < 3; ++i ) {
|
||||
vec3 n = points[i].normal;
|
||||
// Gram-Schmidt orthogonalization
|
||||
points[i].tangent = normalize(tangent_tri - n * dot(n, tangent_tri));
|
||||
}
|
||||
for ( uint _ = 0; _ < 3; ++_ ) points[_].tangent = tangent_tri;
|
||||
}
|
||||
}
|
||||
|
||||
@ -456,6 +452,8 @@ void populateSurface( InstanceAddresses addresses, uvec3 indices ) {
|
||||
// bind tangent
|
||||
if ( triangle.point.tangent != vec3(0) ) {
|
||||
surface.tangent.world = normalize(vec3( surface.object.model * vec4(triangle.point.tangent, 0.0) ));
|
||||
surface.tangent.world = normalize(surface.tangent.world - dot(surface.tangent.world, surface.normal.world) * surface.normal.world);
|
||||
|
||||
vec3 bitangent = normalize(vec3( surface.object.model * vec4(cross( triangle.point.normal, triangle.point.tangent ), 0.0) ));
|
||||
surface.tbn = mat3(surface.tangent.world, bitangent, surface.normal.world);
|
||||
}
|
||||
|
||||
@ -99,13 +99,23 @@ namespace uf {
|
||||
|
||||
size_t primitiveID = partitioned.size();
|
||||
auto& slice = partitioned.emplace_back();
|
||||
slice.vertices.reserve( mlet.indices.size() );
|
||||
slice.indices.reserve( mlet.indices.size() );
|
||||
|
||||
uf::stl::unordered_map<U, U> indexMap;
|
||||
for ( U globalID : mlet.indices ) {
|
||||
if ( indexMap.find(globalID) == indexMap.end() ) {
|
||||
indexMap[globalID] = (U)(slice.vertices.size());
|
||||
slice.vertices.emplace_back(meshlet.vertices[globalID]);
|
||||
}
|
||||
slice.indices.emplace_back( indexMap[globalID] );
|
||||
}
|
||||
|
||||
if ( clip ) {
|
||||
node.effectiveExtents.min = node.extents.min;
|
||||
node.effectiveExtents.max = node.extents.max;
|
||||
uf::shapes::clip<T,U>( slice.vertices, slice.indices, pod::AABB{ node.extents.min, node.extents.max } );
|
||||
// blender outputs poopy tangents that don't get fixed here
|
||||
// better to recalculate them before slicing anyways
|
||||
// uf::mesh::tangents<T,U>( slice.vertices, slice.indices );
|
||||
}
|
||||
|
||||
slice.primitive.instance = meshlet.primitive.instance;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <uf/utils/string/hash.h>
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <uf/utils/memory/unordered_map.h>
|
||||
|
||||
#if UF_USE_VULKAN
|
||||
@ -603,54 +604,26 @@ namespace uf {
|
||||
};
|
||||
|
||||
namespace mesh {
|
||||
template <typename T, typename = void> struct has_tangent : std::false_type {};
|
||||
template <typename T> struct has_tangent<T, std::void_t<decltype(std::declval<T>().tangent)>> : std::true_type {};
|
||||
|
||||
template <typename T, typename = void> struct has_normal : std::false_type {};
|
||||
template <typename T> struct has_normal<T, std::void_t<decltype(std::declval<T>().normal)>> : std::true_type {};
|
||||
|
||||
size_t UF_API fetchIndex( const void* pointer, size_t stride, size_t index );
|
||||
pod::Vector3f UF_API fetchVertex( const uf::Mesh::View& view, const uf::Mesh::AttributeView& positions, size_t index );
|
||||
pod::Triangle UF_API fetchTriangle( const uf::Mesh::View& view, const uf::Mesh::AttributeView& indices, const uf::Mesh::AttributeView& positions, size_t triID );
|
||||
pod::TriangleWithNormal UF_API fetchTriangle( const uf::Mesh& mesh, size_t triID );
|
||||
|
||||
template<typename T>
|
||||
T fetchVertexAttribute( const uf::Mesh::View& view, const uf::Mesh::AttributeView& attributeView, size_t index ) {
|
||||
#define CAST_VERTEX(type) {\
|
||||
const type* vertices = (type*) attributeView.data(view.vertex.first + index);\
|
||||
for ( auto i = 0; i < T::size; ++i ) res[i] = vertices[i];\
|
||||
return res;\
|
||||
}
|
||||
#define DEQUANTIZE_VERTEX(type) {\
|
||||
const type* vertices = (type*) attributeView.data(view.vertex.first + index);\
|
||||
for ( auto i = 0; i < T::size; ++i ) res[i] = uf::quant::dequantize(vertices[i]);\
|
||||
return res;\
|
||||
}
|
||||
|
||||
// direct copy
|
||||
if ( uf::renderer::typeToEnum<typename T::type_t>() == attributeView.type() && T::size == attributeView.components() ) {
|
||||
return uf::vector::copy<typename T::type_t, T::size>( (typename T::type_t*) attributeView.data( view.vertex.first + index ) );
|
||||
}
|
||||
|
||||
// implicit copy
|
||||
T res;
|
||||
switch ( attributeView.type() ) {
|
||||
// dequantize
|
||||
case uf::renderer::enums::Type::USHORT:
|
||||
case uf::renderer::enums::Type::SHORT: {
|
||||
DEQUANTIZE_VERTEX(uint16_t);
|
||||
} break;
|
||||
case uf::renderer::enums::Type::FLOAT: {
|
||||
CAST_VERTEX(float);
|
||||
} break;
|
||||
#if UF_USE_FLOAT16
|
||||
case uf::renderer::enums::Type::HALF: {
|
||||
CAST_VERTEX(std::float16_t);
|
||||
} break;
|
||||
#endif
|
||||
#if UF_USE_BFLOAT16
|
||||
case uf::renderer::enums::Type::BFLOAT: {
|
||||
CAST_VERTEX(std::bfloat16_t);
|
||||
} break;
|
||||
#endif
|
||||
default: UF_EXCEPTION("unsupported attribute type: {}", attributeView.attribute.descriptor.type); break;
|
||||
}
|
||||
}
|
||||
template<typename T> size_t windingOrder( uf::stl::vector<T>& vertices );
|
||||
template<typename T, typename U> size_t windingOrder( uf::stl::vector<T>& vertices, uf::stl::vector<U>& indices );
|
||||
template<typename T> void normals( uf::stl::vector<T>& vertices );
|
||||
template<typename T, typename U = uint32_t> void normals( uf::stl::vector<T>& vertices, const uf::stl::vector<U>& indices );
|
||||
// specifically refuses to work properly
|
||||
template<typename T> void tangents( uf::stl::vector<T>& vertices );
|
||||
template<typename T, typename U = uint32_t> void tangents( uf::stl::vector<T>& vertices, const uf::stl::vector<U>& indices );
|
||||
|
||||
template<typename T> T fetchVertexAttribute( const uf::Mesh::View& view, const uf::Mesh::AttributeView& attributeView, size_t index );
|
||||
template<typename T>
|
||||
T& getVertexAttribute( const uf::Mesh::View& view, const uf::Mesh::AttributeView& attributeView, size_t index ) {
|
||||
UF_ASSERT( uf::renderer::typeToEnum<typename T::type_t>() == attributeView.type() && T::size == attributeView.components() );
|
||||
@ -711,6 +684,250 @@ namespace uf {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T uf::mesh::fetchVertexAttribute( const uf::Mesh::View& view, const uf::Mesh::AttributeView& attributeView, size_t index ) {
|
||||
#define CAST_VERTEX(type) {\
|
||||
const type* vertices = (type*) attributeView.data(view.vertex.first + index);\
|
||||
for ( auto i = 0; i < T::size; ++i ) res[i] = vertices[i];\
|
||||
return res;\
|
||||
}
|
||||
#define DEQUANTIZE_VERTEX(type) {\
|
||||
const type* vertices = (type*) attributeView.data(view.vertex.first + index);\
|
||||
for ( auto i = 0; i < T::size; ++i ) res[i] = uf::quant::dequantize(vertices[i]);\
|
||||
return res;\
|
||||
}
|
||||
|
||||
// direct copy
|
||||
if ( uf::renderer::typeToEnum<typename T::type_t>() == attributeView.type() && T::size == attributeView.components() ) {
|
||||
return uf::vector::copy<typename T::type_t, T::size>( (typename T::type_t*) attributeView.data( view.vertex.first + index ) );
|
||||
}
|
||||
|
||||
// implicit copy
|
||||
T res;
|
||||
switch ( attributeView.type() ) {
|
||||
// dequantize
|
||||
case uf::renderer::enums::Type::USHORT:
|
||||
case uf::renderer::enums::Type::SHORT: {
|
||||
DEQUANTIZE_VERTEX(uint16_t);
|
||||
} break;
|
||||
case uf::renderer::enums::Type::FLOAT: {
|
||||
CAST_VERTEX(float);
|
||||
} break;
|
||||
#if UF_USE_FLOAT16
|
||||
case uf::renderer::enums::Type::HALF: {
|
||||
CAST_VERTEX(std::float16_t);
|
||||
} break;
|
||||
#endif
|
||||
#if UF_USE_BFLOAT16
|
||||
case uf::renderer::enums::Type::BFLOAT: {
|
||||
CAST_VERTEX(std::bfloat16_t);
|
||||
} break;
|
||||
#endif
|
||||
default: UF_EXCEPTION("unsupported attribute type: {}", attributeView.attribute.descriptor.type); break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t uf::mesh::windingOrder( uf::stl::vector<T>& vertices ) {
|
||||
if constexpr ( !uf::mesh::has_normal<T>::value ) return 0;
|
||||
|
||||
size_t corrected = 0;
|
||||
for ( size_t i = 0; i < vertices.size() / 3; ++i ) {
|
||||
pod::Vector3f position[3] = {
|
||||
vertices[i * 3 + 0].position,
|
||||
vertices[i * 3 + 1].position,
|
||||
vertices[i * 3 + 2].position,
|
||||
};
|
||||
pod::Vector3f normal = uf::vector::normalize( uf::vector::cross((position[0] - position[1]), (position[1] - position[2])) );
|
||||
|
||||
if ( uf::vector::dot( vertices[i * 3 + 0].normal, normal ) < 0.0f ) {
|
||||
std::swap( vertices[i * 3 + 0], vertices[i * 3 + 2] );
|
||||
++corrected;
|
||||
}
|
||||
}
|
||||
return corrected;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
size_t uf::mesh::windingOrder( uf::stl::vector<T>& vertices, uf::stl::vector<U>& indices ) {
|
||||
if constexpr ( !uf::mesh::has_normal<T>::value ) return 0;
|
||||
if ( indices.empty() ) return uf::mesh::windingOrder( vertices );
|
||||
|
||||
size_t corrected = 0;
|
||||
for ( size_t i = 0; i < indices.size() / 3; ++i ) {
|
||||
size_t idx[3] = {
|
||||
indices[i * 3 + 0],
|
||||
indices[i * 3 + 1],
|
||||
indices[i * 3 + 2],
|
||||
};
|
||||
pod::Vector3f position[3] = {
|
||||
vertices[idx[0]].position,
|
||||
vertices[idx[1]].position,
|
||||
vertices[idx[2]].position,
|
||||
};
|
||||
pod::Vector3f normal = uf::vector::normalize( uf::vector::cross((position[0] - position[1]), (position[1] - position[2])) );
|
||||
|
||||
if ( uf::vector::dot( vertices[idx[0]].normal, normal ) < 0.0f ) {
|
||||
indices[i * 3 + 0] = idx[2];
|
||||
indices[i * 3 + 2] = idx[0];
|
||||
++corrected;
|
||||
}
|
||||
}
|
||||
return corrected;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void uf::mesh::tangents( uf::stl::vector<T>& vertices ) {
|
||||
if constexpr ( !uf::mesh::has_tangent<T>::value ) return;
|
||||
|
||||
for ( size_t i = 0; i < vertices.size(); i += 3 ) {
|
||||
size_t idx[3] = { i + 0, i + 1, i + 2 };
|
||||
|
||||
auto p0 = vertices[idx[0]].position;
|
||||
auto p1 = vertices[idx[1]].position;
|
||||
auto p2 = vertices[idx[2]].position;
|
||||
|
||||
auto uv0 = vertices[idx[0]].uv;
|
||||
auto uv1 = vertices[idx[1]].uv;
|
||||
auto uv2 = vertices[idx[2]].uv;
|
||||
|
||||
auto p10 = p1 - p0;
|
||||
auto p20 = p2 - p0;
|
||||
|
||||
auto uv10 = uv1 - uv0;
|
||||
auto uv20 = uv2 - uv0;
|
||||
|
||||
auto det = (uv10.x * uv20.y - uv10.y * uv20.x);
|
||||
float r = 1.0f / det;
|
||||
auto t = (p10 * uv20.y - p20 * uv10.y) * r;
|
||||
auto b = (p20 * uv10.x - p10 * uv20.x) * r;
|
||||
|
||||
for ( auto j = 0; j < 3; ++j ) {
|
||||
auto& n = vertices[idx[j]].normal;
|
||||
auto& tangent = vertices[idx[j]].tangent;
|
||||
tangent = uf::vector::normalize(t - n * uf::vector::dot(n, t));
|
||||
if ( uf::vector::dot( uf::vector::cross(n, tangent), b) < 0.0f ) tangent = -tangent;
|
||||
}
|
||||
/*
|
||||
pod::Vector3f position[3] = {
|
||||
vertices[idx[0]].position, vertices[idx[1]].position, vertices[idx[2]].position
|
||||
};
|
||||
pod::Vector2f uv[3] = {
|
||||
vertices[idx[0]].uv, vertices[idx[1]].uv, vertices[idx[2]].uv
|
||||
};
|
||||
|
||||
pod::Vector3f dPosition[2] = { position[1] - position[0], position[2] - position[0] };
|
||||
pod::Vector2f dUV[2] = { uv[1] - uv[0], uv[2] - uv[0] };
|
||||
|
||||
float det = (dUV[0].x * dUV[1].y - dUV[0].y * dUV[1].x);
|
||||
if ( det == 0.0f ) continue;
|
||||
float r = 1.0f / det;
|
||||
|
||||
auto t = (dPosition[0] * dUV[1].y - dPosition[1] * dUV[0].y) * r;
|
||||
auto b = (dPosition[1] * dUV[0].x - dPosition[0] * dUV[1].x) * r;
|
||||
|
||||
for ( auto j = 0; j < 3; ++j ) {
|
||||
auto& normal = vertices[idx[j]].normal;
|
||||
auto& tangent = vertices[idx[j]].tangent;
|
||||
tangent = uf::vector::normalize(t - normal * uf::vector::dot(normal, t));
|
||||
if ( uf::vector::dot(uf::vector::cross(normal, tangent), b) < 0.0f ) tangent = -tangent;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
void uf::mesh::tangents( uf::stl::vector<T>& vertices, const uf::stl::vector<U>& indices ) {
|
||||
if constexpr ( !uf::mesh::has_tangent<T>::value ) return;
|
||||
if ( indices.empty() ) return tangents( vertices );
|
||||
|
||||
for ( size_t i = 0; i < indices.size(); i += 3 ) {
|
||||
size_t idx[3] = { indices[i + 0], indices[i + 1], indices[i + 2] };
|
||||
|
||||
auto p0 = vertices[idx[0]].position;
|
||||
auto p1 = vertices[idx[1]].position;
|
||||
auto p2 = vertices[idx[2]].position;
|
||||
|
||||
auto uv0 = vertices[idx[0]].uv;
|
||||
auto uv1 = vertices[idx[1]].uv;
|
||||
auto uv2 = vertices[idx[2]].uv;
|
||||
|
||||
auto p10 = p1 - p0;
|
||||
auto p20 = p2 - p0;
|
||||
|
||||
auto uv10 = uv1 - uv0;
|
||||
auto uv20 = uv2 - uv0;
|
||||
|
||||
auto det = (uv10.x * uv20.y - uv10.y * uv20.x);
|
||||
float r = 1.0f / det;
|
||||
auto t = (p10 * uv20.y - p20 * uv10.y) * r;
|
||||
auto b = (p20 * uv10.x - p10 * uv20.x) * r;
|
||||
|
||||
for ( auto j = 0; j < 3; ++j ) {
|
||||
auto& n = vertices[idx[j]].normal;
|
||||
auto& tangent = vertices[idx[j]].tangent;
|
||||
tangent = uf::vector::normalize(t - n * uf::vector::dot(n, t));
|
||||
if ( uf::vector::dot( uf::vector::cross(n, tangent), b) < 0.0f ) tangent = -tangent;
|
||||
}
|
||||
/*
|
||||
pod::Vector3f position[3] = { vertices[idx[0]].position, vertices[idx[1]].position, vertices[idx[2]].position };
|
||||
pod::Vector2f uv[3] = { vertices[idx[0]].uv, vertices[idx[1]].uv, vertices[idx[2]].uv };
|
||||
pod::Vector3f dPosition[2] = { position[1] - position[0], position[2] - position[0] };
|
||||
pod::Vector2f dUV[2] = { uv[1] - uv[0], uv[2] - uv[0] };
|
||||
|
||||
float det = (dUV[0].x * dUV[1].y - dUV[0].y * dUV[1].x);
|
||||
if ( det == 0.0f ) continue;
|
||||
float r = 1.0f / det;
|
||||
|
||||
auto t = (dPosition[0] * dUV[1].y - dPosition[1] * dUV[0].y) * r;
|
||||
auto b = (dPosition[1] * dUV[0].x - dPosition[0] * dUV[1].x) * r;
|
||||
|
||||
for ( auto j = 0; j < 3; ++j ) {
|
||||
auto& normal = vertices[idx[j]].normal;
|
||||
auto& tangent = vertices[idx[j]].tangent;
|
||||
tangent = uf::vector::normalize(t - normal * uf::vector::dot(normal, t));
|
||||
if ( uf::vector::dot(uf::vector::cross(normal, tangent), b) < 0.0f ) tangent = -tangent;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void uf::mesh::normals( uf::stl::vector<T>& vertices ) {
|
||||
if constexpr ( !uf::mesh::has_normal<T>::value ) return;
|
||||
|
||||
for ( size_t i = 0; i < vertices.size(); i += 3 ) {
|
||||
auto& v0 = vertices[i + 0];
|
||||
auto& v1 = vertices[i + 1];
|
||||
auto& v2 = vertices[i + 2];
|
||||
|
||||
pod::Vector3f normal = uf::vector::normalize(uf::vector::cross(v1.position - v0.position, v2.position - v0.position));
|
||||
v0.normal = normal;
|
||||
v1.normal = normal;
|
||||
v2.normal = normal;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
void uf::mesh::normals( uf::stl::vector<T>& vertices, const uf::stl::vector<U>& indices ) {
|
||||
if constexpr ( !uf::mesh::has_normal<T>::value ) return;
|
||||
if ( indices.empty() ) return normals( vertices );
|
||||
|
||||
for ( auto& v : vertices ) v.normal = {};
|
||||
for ( size_t i = 0; i < indices.size(); i += 3 ) {
|
||||
auto& v0 = vertices[indices[i + 0]];
|
||||
auto& v1 = vertices[indices[i + 1]];
|
||||
auto& v2 = vertices[indices[i + 2]];
|
||||
|
||||
pod::Vector3f normal = uf::vector::cross(v1.position - v0.position, v2.position - v0.position);
|
||||
v0.normal += normal;
|
||||
v1.normal += normal;
|
||||
v2.normal += normal;
|
||||
}
|
||||
|
||||
for ( auto& v : vertices ) v.normal = uf::vector::normalize( v.normal );
|
||||
}
|
||||
|
||||
template<typename T> uf::stl::vector<pod::Primitive> uf::Mesh::compile( const uf::stl::vector<T>& meshlets ) {
|
||||
uf::stl::vector<pod::Primitive> primitives;
|
||||
uf::mesh::compile( *this, meshlets, primitives );
|
||||
|
||||
@ -539,8 +539,8 @@ UF_VERTEX_INTERPOLATE(uf::graph::mesh::Base, {
|
||||
uf::vector::lerp( p1.uv, p2.uv, t ),
|
||||
t < 0.5 ? p1.color : p2.color,
|
||||
uf::vector::lerp( p1.st, p2.st, t ),
|
||||
uf::vector::normalize( uf::vector::lerp( p1.normal, p2.normal, t ) ),
|
||||
uf::vector::normalize( uf::vector::lerp( p1.tangent, p2.tangent, t ) ),
|
||||
uf::vector::lerp( p1.normal, p2.normal, t ),
|
||||
uf::vector::lerp( p1.tangent, p2.tangent, t ),
|
||||
};
|
||||
})
|
||||
|
||||
@ -560,8 +560,8 @@ UF_VERTEX_INTERPOLATE(uf::graph::mesh::Skinned, {
|
||||
uf::vector::lerp( p1.uv, p2.uv, t ),
|
||||
t < 0.5 ? p1.color : p2.color,
|
||||
uf::vector::lerp( p1.st, p2.st, t ),
|
||||
uf::vector::normalize( uf::vector::lerp( p1.normal, p2.normal, t ) ),
|
||||
uf::vector::normalize( uf::vector::lerp( p1.tangent, p2.tangent, t ) ),
|
||||
uf::vector::lerp( p1.normal, p2.normal, t ),
|
||||
uf::vector::lerp( p1.tangent, p2.tangent, t ),
|
||||
t < 0.5 ? p1.joints : p2.joints,
|
||||
uf::vector::lerp( p1.weights, p2.weights, t ),
|
||||
};
|
||||
@ -1627,6 +1627,7 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) {
|
||||
}
|
||||
}
|
||||
|
||||
#if UF_USE_VULKAN
|
||||
if ( commands && !grouped.empty() ) {
|
||||
auto objectKeyName = std::to_string(grouped.front().objectID);
|
||||
if ( storage.entities.map.count(objectKeyName) > 0 ) {
|
||||
@ -1638,6 +1639,7 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for ( auto& key : storage.textures.keys ) textures.emplace_back( storage.textures.map[key] );
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include <uf/utils/image/atlas.h>
|
||||
#include <uf/utils/string/hash.h>
|
||||
#include <uf/utils/mesh/grid.h>
|
||||
#include <uf/utils/io/vfs.h>
|
||||
|
||||
#include <gltf/tiny_gltf.h>
|
||||
#include <uf/ext/gltf/gltf.h>
|
||||
@ -130,10 +131,18 @@ void ext::gltf::load( pod::Graph& graph, const uf::stl::string& filename, const
|
||||
tinygltf::TinyGLTF loader;
|
||||
|
||||
uf::stl::string warn, err;
|
||||
bool ret = extension == "glb" ? loader.LoadBinaryFromFile(&model, &err, &warn, filename) : loader.LoadASCIIFromFile(&model, &err, &warn, filename);
|
||||
//bool ret = extension == "glb" ? loader.LoadBinaryFromFile(&model, &err, &warn, filename) : loader.LoadASCIIFromFile(&model, &err, &warn, filename);
|
||||
|
||||
graph.name = filename;
|
||||
graph.metadata = metadata;
|
||||
bool ret = false;
|
||||
if ( extension == "glb" ) {
|
||||
// uf::stl::vector<uint8_t> buffer;
|
||||
// if ( !uf::io::readAsBuffer( buffer, filename ) ) return;
|
||||
// ret = loader.LoadBinaryFromMemory(&model, &err, &warn, buffer.data(), buffer.size());
|
||||
ret = loader.LoadBinaryFromFile(&model, &err, &warn, uf::vfs::resolveBase(filename));
|
||||
} else {
|
||||
// crunge
|
||||
ret = loader.LoadASCIIFromFile(&model, &err, &warn, uf::vfs::resolveBase(filename));
|
||||
}
|
||||
|
||||
if ( !warn.empty() ) UF_MSG_WARNING("glTF warning: {}", warn);
|
||||
if ( !err.empty() ) UF_MSG_ERROR("glTF error: {}", err);
|
||||
@ -141,10 +150,11 @@ void ext::gltf::load( pod::Graph& graph, const uf::stl::string& filename, const
|
||||
return;
|
||||
}
|
||||
|
||||
graph.name = filename;
|
||||
graph.metadata = metadata;
|
||||
|
||||
uf::stl::string key = graph.metadata["key"].as<uf::stl::string>("");
|
||||
if ( key != "" ) {
|
||||
key += ":";
|
||||
}
|
||||
if ( key != "" ) key += ":";
|
||||
|
||||
auto& storage = uf::graph::getStorage( graph );
|
||||
|
||||
|
||||
@ -4,6 +4,9 @@ struct {
|
||||
size_t corrected{};
|
||||
size_t total{};
|
||||
} windingOrder;
|
||||
struct {
|
||||
bool should = true;
|
||||
} normals;
|
||||
struct {
|
||||
bool should = true;
|
||||
} tangents;
|
||||
@ -12,6 +15,9 @@ struct {
|
||||
if ( graph.metadata["sanitizer"]["winding order"].as<bool>(true) || graph.metadata["renderer"]["invert"].as<bool>(true) ) {
|
||||
sanitizer.windingOrder.should = true;
|
||||
}
|
||||
if ( graph.metadata["sanitizer"]["normals"].as<bool>(false) ) {
|
||||
sanitizer.normals.should = true;
|
||||
}
|
||||
if ( graph.metadata["sanitizer"]["tangents"].as<bool>(false) ) {
|
||||
sanitizer.tangents.should = true;
|
||||
}
|
||||
@ -93,28 +99,27 @@ for ( auto& p : m.primitives ) {
|
||||
}
|
||||
|
||||
for ( size_t i = 0; i < meshlet.vertices.size(); ++i ) {
|
||||
#if 0
|
||||
#define ITERATE_ATTRIBUTE( name, member )\
|
||||
memcpy( &vertex.member[0], &attributes[name].buffer[i * attributes[name].components], attributes[name].stride );
|
||||
#else
|
||||
#define ITERATE_ATTRIBUTE( name, member, floatScale )\
|
||||
if ( !attributes[name].int8s.empty() ) { \
|
||||
for ( size_t j = 0; j < attributes[name].components; ++j )\
|
||||
vertex.member[j] = attributes[name].int8s[i * attributes[name].components + j];\
|
||||
} else if ( !attributes[name].int16s.empty() ) { \
|
||||
for ( size_t j = 0; j < attributes[name].components; ++j )\
|
||||
vertex.member[j] = attributes[name].int16s[i * attributes[name].components + j];\
|
||||
} else if ( !attributes[name].int32s.empty() ) { \
|
||||
for ( size_t j = 0; j < attributes[name].components; ++j )\
|
||||
vertex.member[j] = attributes[name].int32s[i * attributes[name].components + j];\
|
||||
} else if ( !attributes[name].floats.empty() ) { \
|
||||
for ( size_t j = 0; j < attributes[name].components; ++j )\
|
||||
vertex.member[j] = attributes[name].floats[i * attributes[name].components + j] * floatScale;\
|
||||
} else {\
|
||||
/*for some reason setting this breaks VXGI reflections*/\
|
||||
/*vertex.member = {};*/\
|
||||
}
|
||||
#endif
|
||||
#define ITERATE_ATTRIBUTE( name, member, floatScale )\
|
||||
if ( !attributes[name].int8s.empty() ) { \
|
||||
size_t limit = std::min<size_t>(attributes[name].components, vertex.member.size); \
|
||||
for ( size_t j = 0; j < limit; ++j )\
|
||||
vertex.member[j] = attributes[name].int8s[i * attributes[name].components + j];\
|
||||
} else if ( !attributes[name].int16s.empty() ) { \
|
||||
size_t limit = std::min<size_t>(attributes[name].components, vertex.member.size); \
|
||||
for ( size_t j = 0; j < limit; ++j )\
|
||||
vertex.member[j] = attributes[name].int16s[i * attributes[name].components + j];\
|
||||
} else if ( !attributes[name].int32s.empty() ) { \
|
||||
size_t limit = std::min<size_t>(attributes[name].components, vertex.member.size); \
|
||||
for ( size_t j = 0; j < limit; ++j )\
|
||||
vertex.member[j] = attributes[name].int32s[i * attributes[name].components + j];\
|
||||
} else if ( !attributes[name].floats.empty() ) { \
|
||||
size_t limit = std::min<size_t>(attributes[name].components, vertex.member.size); \
|
||||
for ( size_t j = 0; j < limit; ++j )\
|
||||
vertex.member[j] = attributes[name].floats[i * attributes[name].components + j] * floatScale;\
|
||||
} else {\
|
||||
/*for some reason setting this breaks VXGI reflections*/\
|
||||
/*vertex.member = {};*/\
|
||||
}
|
||||
|
||||
auto& vertex = meshlet.vertices[i];
|
||||
ITERATE_ATTRIBUTE("POSITION", position, 1);
|
||||
@ -182,55 +187,16 @@ for ( auto& p : m.primitives ) {
|
||||
meshlet.primitive.drawCommand.vertices = meshlet.vertices.size();
|
||||
|
||||
/* detect winding order */ if ( sanitizer.windingOrder.should ) {
|
||||
if ( !meshlet.indices.empty() ) {
|
||||
for ( size_t i = 0; i < meshlet.indices.size() / 3; ++i ) {
|
||||
size_t indices[3] = {
|
||||
meshlet.indices[i * 3 + 0],
|
||||
meshlet.indices[i * 3 + 1],
|
||||
meshlet.indices[i * 3 + 2],
|
||||
};
|
||||
pod::Vector3f triPosition[3] = {
|
||||
meshlet.vertices[indices[0]].position,
|
||||
meshlet.vertices[indices[1]].position,
|
||||
meshlet.vertices[indices[2]].position,
|
||||
};
|
||||
pod::Vector3f normal = meshlet.vertices[indices[0]].normal;
|
||||
pod::Vector3f geomNormal = uf::vector::normalize( uf::vector::cross((triPosition[0] - triPosition[1]), (triPosition[1] - triPosition[2])));
|
||||
|
||||
// negative dot = mismatched winding order
|
||||
if ( uf::vector::dot( normal, geomNormal ) < 0.0f ) {
|
||||
meshlet.indices[i * 3 + 0] = indices[2];
|
||||
meshlet.indices[i * 3 + 2] = indices[0];
|
||||
++sanitizer.windingOrder.corrected;
|
||||
}
|
||||
++sanitizer.windingOrder.total;
|
||||
}
|
||||
} else {
|
||||
for ( size_t i = 0; i < meshlet.vertices.size() / 3; ++i ) {
|
||||
size_t indices[3] = {
|
||||
i * 3 + 0,
|
||||
i * 3 + 1,
|
||||
i * 3 + 2,
|
||||
};
|
||||
pod::Vector3f triPosition[3] = {
|
||||
meshlet.vertices[indices[0]].position,
|
||||
meshlet.vertices[indices[1]].position,
|
||||
meshlet.vertices[indices[2]].position,
|
||||
};
|
||||
pod::Vector3f normal = meshlet.vertices[indices[0]].normal;
|
||||
pod::Vector3f geomNormal = uf::vector::normalize( uf::vector::cross((triPosition[0] - triPosition[1]), (triPosition[1] - triPosition[2])));
|
||||
|
||||
// negative dot = mismatched winding order
|
||||
if ( uf::vector::dot( normal, geomNormal ) < 0.0f ) {
|
||||
meshlet.indices[i * 3 + 0] = indices[2];
|
||||
meshlet.indices[i * 3 + 2] = indices[0];
|
||||
++sanitizer.windingOrder.corrected;
|
||||
}
|
||||
++sanitizer.windingOrder.total;
|
||||
}
|
||||
}
|
||||
sanitizer.windingOrder.corrected += uf::mesh::windingOrder( meshlet.vertices, meshlet.indices );
|
||||
sanitizer.windingOrder.total += meshlet.indices.empty() ? meshlet.vertices.size() : meshlet.indices.size();
|
||||
}
|
||||
/* calculate normals */ if ( sanitizer.normals.should ) {
|
||||
uf::mesh::normals( meshlet.vertices, meshlet.indices );
|
||||
}
|
||||
/* calculate tangents */ if ( sanitizer.tangents.should ) {
|
||||
#if 1
|
||||
uf::mesh::tangents( meshlet.vertices, meshlet.indices );
|
||||
#else
|
||||
if ( !meshlet.indices.empty() ) {
|
||||
for ( size_t i = 0; i < meshlet.indices.size() / 3; ++i ) {
|
||||
size_t indices[3] = {
|
||||
@ -312,6 +278,7 @@ for ( auto& p : m.primitives ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,7 +295,10 @@ if ( meshgrid.grid.divisions.x > 1 || meshgrid.grid.divisions.y > 1 || meshgrid.
|
||||
if ( meshgrid.print ) UF_MSG_DEBUG( "Draw commands: {}: {} -> {} | Partitions: {} -> {}", m.name, meshlets.size(), partitioned.size(),
|
||||
(meshgrid.grid.divisions.x * meshgrid.grid.divisions.y * meshgrid.grid.divisions.z), meshgrid.grid.nodes.size()
|
||||
);
|
||||
meshlets = std::move( partitioned );
|
||||
}
|
||||
|
||||
mesh.compile( meshlets, primitives );
|
||||
for ( auto& meshlet : partitioned ) {
|
||||
uf::mesh::tangents( meshlet.vertices, meshlet.indices );
|
||||
}
|
||||
mesh.compile( partitioned, primitives );
|
||||
} else {
|
||||
mesh.compile( meshlets, primitives );
|
||||
}
|
||||
@ -5,6 +5,8 @@
|
||||
#include <uf/ext/valve/common.h>
|
||||
#include <uf/ext/zlib/zlib.h>
|
||||
|
||||
#include <uf/utils/mesh/grid.h>
|
||||
|
||||
namespace impl {
|
||||
struct RGBE {
|
||||
uint8_t r, g, b;
|
||||
@ -753,6 +755,7 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co
|
||||
|
||||
if ( meshlets.empty() ) continue;
|
||||
|
||||
|
||||
auto meshName = ::fmt::format("model_{}", m);
|
||||
context.modelToMesh[m] = graph.meshes.size();
|
||||
|
||||
@ -762,7 +765,31 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co
|
||||
auto& mesh = storage.meshes[meshName];
|
||||
auto& primitives = storage.primitives[meshName];
|
||||
|
||||
mesh.compile( meshlets, primitives );
|
||||
// slice worldspawn
|
||||
if ( false && m == 0 ) {
|
||||
/*
|
||||
if ( ext::json::isObject( meshgrid.metadata ) ) {
|
||||
if ( meshgrid.metadata["size"].is<size_t>() ) {
|
||||
size_t d = meshgrid.metadata["size"].as<size_t>();
|
||||
meshgrid.grid.divisions = {d, d, d};
|
||||
} else {
|
||||
meshgrid.grid.divisions = uf::vector::decode( meshgrid.metadata["size"], meshgrid.grid.divisions );
|
||||
}
|
||||
|
||||
meshgrid.eps = meshgrid.metadata["epsilon"].as(meshgrid.eps);
|
||||
meshgrid.print = meshgrid.metadata["print"].as(meshgrid.print);
|
||||
meshgrid.clip = meshgrid.metadata["clip"].as(meshgrid.clip);
|
||||
meshgrid.cleanup = meshgrid.metadata["cleanup"].as(meshgrid.cleanup);
|
||||
}
|
||||
*/
|
||||
uf::meshgrid::Grid grid;
|
||||
grid.divisions = {8, 8, 8};
|
||||
auto mlets = uf::stl::values( meshlets );
|
||||
auto partitioned = uf::meshgrid::partition( grid, mlets, EPS, true, true );
|
||||
mesh.compile( partitioned, primitives );
|
||||
} else {
|
||||
mesh.compile( meshlets, primitives );
|
||||
}
|
||||
}
|
||||
|
||||
// read entities
|
||||
|
||||
@ -68,9 +68,9 @@ size_t ext::xatlas::unwrap( pod::Graph& graph ) {
|
||||
entry.commandID = viewIdx;
|
||||
|
||||
auto& decl = entry.decl;
|
||||
auto posView = view["position"];
|
||||
auto uvView = view["uv"];
|
||||
auto idxView = view["index"];
|
||||
auto posView = view["position"_hash];
|
||||
auto uvView = view["uv"_hash];
|
||||
auto idxView = view["index"_hash];
|
||||
|
||||
UF_ASSERT( posView.valid() && uvView.valid() );
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user