Merge remote-tracking branch 'origin/master' into 1.10
# Conflicts: # Source/Editor/SceneGraph/Actors/StaticModelNode.cs # Source/Engine/Graphics/Models/Mesh.cs # Source/Engine/Graphics/Models/ModelData.h
This commit is contained in:
@@ -65,6 +65,7 @@ namespace ALC
|
||||
struct SourceData
|
||||
{
|
||||
AudioDataInfo Format;
|
||||
float Pan;
|
||||
bool Spatial;
|
||||
};
|
||||
|
||||
@@ -106,6 +107,26 @@ namespace ALC
|
||||
|
||||
namespace Source
|
||||
{
|
||||
void SetupSpatial(uint32 sourceID, float pan, bool spatial)
|
||||
{
|
||||
alSourcei(sourceID, AL_SOURCE_RELATIVE, !spatial); // Non-spatial sounds use AL_POSITION for panning
|
||||
#ifdef AL_SOFT_source_spatialize
|
||||
alSourcei(sourceID, AL_SOURCE_SPATIALIZE_SOFT, spatial || Math::Abs(pan) > ZeroTolerance ? AL_TRUE : AL_FALSE); // Fix multi-channel sources played as spatial or non-spatial sources played with panning
|
||||
#endif
|
||||
if (spatial)
|
||||
{
|
||||
#ifdef AL_EXT_STEREO_ANGLES
|
||||
const float panAngle = pan * PI_HALF;
|
||||
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
|
||||
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
alSource3f(sourceID, AL_POSITION, pan, 0, -sqrtf(1.0f - pan * pan));
|
||||
}
|
||||
}
|
||||
|
||||
void Rebuild(uint32& sourceID, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler)
|
||||
{
|
||||
ASSERT_LOW_LAYER(sourceID == 0);
|
||||
@@ -116,11 +137,8 @@ namespace ALC
|
||||
alSourcef(sourceID, AL_PITCH, pitch);
|
||||
alSourcef(sourceID, AL_SEC_OFFSET, 0.0f);
|
||||
alSourcei(sourceID, AL_LOOPING, loop);
|
||||
alSourcei(sourceID, AL_SOURCE_RELATIVE, !spatial); // Non-spatial sounds use AL_POSITION for panning
|
||||
alSourcei(sourceID, AL_BUFFER, 0);
|
||||
#ifdef AL_SOFT_source_spatialize
|
||||
alSourcei(sourceID, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE); // Always spatialize, fixes multi-channel played as spatial
|
||||
#endif
|
||||
SetupSpatial(sourceID, pan, spatial);
|
||||
if (spatial)
|
||||
{
|
||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, attenuation);
|
||||
@@ -128,18 +146,12 @@ namespace ALC
|
||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(minDistance));
|
||||
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
|
||||
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(Vector3::Zero));
|
||||
#ifdef AL_EXT_STEREO_ANGLES
|
||||
const float panAngle = pan * PI_HALF;
|
||||
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
|
||||
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, 0.0f);
|
||||
alSourcef(sourceID, AL_DOPPLER_FACTOR, 1.0f);
|
||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, 0.0f);
|
||||
alSource3f(sourceID, AL_POSITION, pan, 0, -sqrtf(1.0f - pan * pan));
|
||||
alSource3f(sourceID, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
@@ -160,12 +172,11 @@ namespace ALC
|
||||
if (Device == nullptr)
|
||||
return;
|
||||
|
||||
ALCint attrsHrtf[] = { ALC_HRTF_SOFT, ALC_TRUE };
|
||||
const ALCint* attrList = nullptr;
|
||||
ALCint attrList[] = { ALC_HRTF_SOFT, ALC_FALSE };
|
||||
if (Audio::GetEnableHRTF())
|
||||
{
|
||||
LOG(Info, "Enabling OpenAL HRTF");
|
||||
attrList = attrsHrtf;
|
||||
attrList[1] = ALC_TRUE;
|
||||
}
|
||||
|
||||
Context = alcCreateContext(Device, attrList);
|
||||
@@ -318,6 +329,7 @@ uint32 AudioBackendOAL::Source_Add(const AudioDataInfo& format, const Vector3& p
|
||||
auto& data = ALC::SourcesData[sourceID];
|
||||
data.Format = format;
|
||||
data.Spatial = spatial;
|
||||
data.Pan = pan;
|
||||
ALC::Locker.Unlock();
|
||||
|
||||
return sourceID;
|
||||
@@ -370,20 +382,11 @@ void AudioBackendOAL::Source_PitchChanged(uint32 sourceID, float pitch)
|
||||
void AudioBackendOAL::Source_PanChanged(uint32 sourceID, float pan)
|
||||
{
|
||||
ALC::Locker.Lock();
|
||||
const bool spatial = ALC::SourcesData[sourceID].Spatial;
|
||||
auto& e = ALC::SourcesData[sourceID];
|
||||
e.Pan = pan;
|
||||
const bool spatial = e.Spatial;
|
||||
ALC::Locker.Unlock();
|
||||
if (spatial)
|
||||
{
|
||||
#ifdef AL_EXT_STEREO_ANGLES
|
||||
const float panAngle = pan * PI_HALF;
|
||||
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
|
||||
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
alSource3f(sourceID, AL_POSITION, pan, 0, -sqrtf(1.0f - pan * pan));
|
||||
}
|
||||
ALC::Source::SetupSpatial(sourceID, pan, spatial);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_IsLoopingChanged(uint32 sourceID, bool loop)
|
||||
@@ -393,6 +396,9 @@ void AudioBackendOAL::Source_IsLoopingChanged(uint32 sourceID, bool loop)
|
||||
|
||||
void AudioBackendOAL::Source_SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler)
|
||||
{
|
||||
ALC::Locker.Lock();
|
||||
const bool pan = ALC::SourcesData[sourceID].Spatial;
|
||||
ALC::Locker.Unlock();
|
||||
if (spatial)
|
||||
{
|
||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, attenuation);
|
||||
@@ -405,6 +411,7 @@ void AudioBackendOAL::Source_SpatialSetupChanged(uint32 sourceID, bool spatial,
|
||||
alSourcef(sourceID, AL_DOPPLER_FACTOR, 1.0f);
|
||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, 0.0f);
|
||||
}
|
||||
ALC::Source::SetupSpatial(sourceID, pan, spatial);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_Play(uint32 sourceID)
|
||||
@@ -602,7 +609,7 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferID, byte* samples, const AudioDa
|
||||
|
||||
if (!format)
|
||||
{
|
||||
LOG(Error, "Not suppported audio data format for OpenAL device: BitDepth={}, NumChannels={}", info.BitDepth, info.NumChannels);
|
||||
LOG(Error, "Not supported audio data format for OpenAL device: BitDepth={}, NumChannels={}", info.BitDepth, info.NumChannels);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -159,19 +159,19 @@ CreateAssetResult ImportAudio::Import(CreateAssetContext& context, AudioDecoder&
|
||||
else
|
||||
{
|
||||
// Split audio data into a several chunks (uniform data spread)
|
||||
const int32 minChunkSize = 1 * 1024 * 1024; // 1 MB
|
||||
const int32 dataAlignment = info.NumChannels * bytesPerSample; // Ensure to never split samples in-between (eg. 24-bit that uses 3 bytes)
|
||||
const int32 chunkSize = Math::Max<int32>(minChunkSize, (int32)Math::AlignUp<uint32>(bufferSize / ASSET_FILE_DATA_CHUNKS, dataAlignment));
|
||||
const int32 chunksCount = Math::CeilToInt((float)bufferSize / chunkSize);
|
||||
const uint32 minChunkSize = 1 * 1024 * 1024; // 1 MB
|
||||
const uint32 dataAlignment = info.NumChannels * bytesPerSample * ASSET_FILE_DATA_CHUNKS; // Ensure to never split samples in-between (eg. 24-bit that uses 3 bytes)
|
||||
const uint32 chunkSize = Math::AlignUp(Math::Max(minChunkSize, bufferSize / ASSET_FILE_DATA_CHUNKS), dataAlignment);
|
||||
const int32 chunksCount = Math::CeilToInt((float)bufferSize / (float)chunkSize);
|
||||
ASSERT(chunksCount > 0 && chunksCount <= ASSET_FILE_DATA_CHUNKS);
|
||||
|
||||
byte* ptr = sampleBuffer.Get();
|
||||
int32 size = bufferSize;
|
||||
uint32 size = bufferSize;
|
||||
for (int32 chunkIndex = 0; chunkIndex < chunksCount; chunkIndex++)
|
||||
{
|
||||
if (context.AllocateChunk(chunkIndex))
|
||||
return CreateAssetResult::CannotAllocateChunk;
|
||||
const int32 t = Math::Min(size, chunkSize);
|
||||
const uint32 t = Math::Min(size, chunkSize);
|
||||
|
||||
WRITE_DATA(chunkIndex, ptr, t);
|
||||
|
||||
|
||||
@@ -520,4 +520,24 @@ PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
return result;
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
Array<Vector3> Mesh::GetCollisionProxyPoints() const
|
||||
{
|
||||
PROFILE_CPU();
|
||||
Array<Vector3> result;
|
||||
#if USE_PRECISE_MESH_INTERSECTS
|
||||
for (int32 i = 0; i < _collisionProxy.Triangles.Count(); i++)
|
||||
{
|
||||
auto triangle = _collisionProxy.Triangles.Get()[i];
|
||||
result.Add(triangle.V0);
|
||||
result.Add(triangle.V1);
|
||||
result.Add(triangle.V2);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -536,5 +536,16 @@ namespace FlaxEngine
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
/// <summary>
|
||||
/// Gets the collision proxy points for the mesh.
|
||||
/// </summary>
|
||||
/// <returns>The triangle points in the collision proxy.</returns>
|
||||
internal Vector3[] GetCollisionProxyPoints()
|
||||
{
|
||||
return Internal_GetCollisionProxyPoints(__unmanagedPtr, out _);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,5 +171,8 @@ private:
|
||||
API_FUNCTION(NoProxy) bool UpdateMeshUInt(int32 vertexCount, int32 triangleCount, const MArray* verticesObj, const MArray* trianglesObj, const MArray* normalsObj, const MArray* tangentsObj, const MArray* uvObj, const MArray* colorsObj);
|
||||
API_FUNCTION(NoProxy) bool UpdateMeshUShort(int32 vertexCount, int32 triangleCount, const MArray* verticesObj, const MArray* trianglesObj, const MArray* normalsObj, const MArray* tangentsObj, const MArray* uvObj, const MArray* colorsObj);
|
||||
API_FUNCTION(NoProxy) MArray* DownloadBuffer(bool forceGpu, MTypeObject* resultType, int32 typeI);
|
||||
#if USE_EDITOR
|
||||
API_FUNCTION(NoProxy) Array<Vector3> GetCollisionProxyPoints() const;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
int32 LightmapUVsIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Global translation for this mesh to be at its local origin.
|
||||
/// Local translation for this mesh to be at it's local origin.
|
||||
/// </summary>
|
||||
Vector3 OriginTranslation = Vector3::Zero;
|
||||
|
||||
|
||||
@@ -9,6 +9,11 @@ ModelInstanceActor::ModelInstanceActor(const SpawnParams& params)
|
||||
{
|
||||
}
|
||||
|
||||
String ModelInstanceActor::MeshReference::ToString() const
|
||||
{
|
||||
return String::Format(TEXT("Actor={},LOD={},Mesh={}"), Actor ? Actor->GetNamePath() : String::Empty, LODIndex, MeshIndex);
|
||||
}
|
||||
|
||||
void ModelInstanceActor::SetEntries(const Array<ModelInstanceEntry>& value)
|
||||
{
|
||||
WaitForModelLoad();
|
||||
|
||||
@@ -27,6 +27,8 @@ API_CLASS(Abstract) class FLAXENGINE_API ModelInstanceActor : public Actor
|
||||
API_FIELD() int32 LODIndex = 0;
|
||||
// Index of the mesh (within the LOD).
|
||||
API_FIELD() int32 MeshIndex = 0;
|
||||
|
||||
String ToString() const;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
@@ -647,6 +647,7 @@ void Cloth::CalculateInvMasses(Array<float>& invMasses)
|
||||
if (_paint.Count() != verticesCount)
|
||||
{
|
||||
// Fix incorrect paint data
|
||||
LOG(Warning, "Incorrect cloth '{}' paint size {} for mesh '{}' that has {} vertices", GetNamePath(), _paint.Count(), mesh.ToString(), verticesCount);
|
||||
int32 countBefore = _paint.Count();
|
||||
_paint.Resize(verticesCount);
|
||||
for (int32 i = countBefore; i < verticesCount; i++)
|
||||
@@ -795,7 +796,10 @@ bool Cloth::OnPreUpdate()
|
||||
if (!positionStream.IsValid() || !blendIndicesStream.IsValid() || !blendWeightsStream.IsValid())
|
||||
return false;
|
||||
if (verticesCount != _paint.Count())
|
||||
{
|
||||
LOG(Warning, "Incorrect cloth '{}' paint size {} for mesh '{}' that has {} vertices", GetNamePath(), _paint.Count(), mesh.ToString(), verticesCount);
|
||||
return false;
|
||||
}
|
||||
PROFILE_CPU_NAMED("Skinned Pose");
|
||||
PhysicsBackend::LockClothParticles(_cloth);
|
||||
const Span<const Float4> particles = PhysicsBackend::GetClothParticles(_cloth);
|
||||
|
||||
@@ -399,7 +399,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="text">The input text to test.</param>
|
||||
/// <param name="layout">The layout properties.</param>
|
||||
/// <returns>The minimum size for that text and fot to render properly.</returns>
|
||||
/// <returns>The minimum size for that text and font to render properly.</returns>
|
||||
API_FUNCTION() Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout);
|
||||
|
||||
/// <summary>
|
||||
@@ -408,7 +408,7 @@ public:
|
||||
/// <param name="text">The input text to test.</param>
|
||||
/// <param name="textRange">The input text range (substring range of the input text parameter).</param>
|
||||
/// <param name="layout">The layout properties.</param>
|
||||
/// <returns>The minimum size for that text and fot to render properly.</returns>
|
||||
/// <returns>The minimum size for that text and font to render properly.</returns>
|
||||
API_FUNCTION() Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout)
|
||||
{
|
||||
return MeasureText(textRange.Substring(text), layout);
|
||||
@@ -418,7 +418,7 @@ public:
|
||||
/// Measures minimum size of the rectangle that will be needed to draw given text
|
||||
/// </summary>.
|
||||
/// <param name="text">The input text to test.</param>
|
||||
/// <returns>The minimum size for that text and fot to render properly.</returns>
|
||||
/// <returns>The minimum size for that text and font to render properly.</returns>
|
||||
API_FUNCTION() FORCE_INLINE Float2 MeasureText(const StringView& text)
|
||||
{
|
||||
return MeasureText(text, TextLayoutOptions());
|
||||
@@ -429,7 +429,7 @@ public:
|
||||
/// </summary>.
|
||||
/// <param name="text">The input text to test.</param>
|
||||
/// <param name="textRange">The input text range (substring range of the input text parameter).</param>
|
||||
/// <returns>The minimum size for that text and fot to render properly.</returns>
|
||||
/// <returns>The minimum size for that text and font to render properly.</returns>
|
||||
API_FUNCTION() FORCE_INLINE Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextRange& textRange)
|
||||
{
|
||||
return MeasureText(textRange.Substring(text), TextLayoutOptions());
|
||||
|
||||
@@ -732,7 +732,12 @@ Array<ScriptingObject*, HeapAllocation> Scripting::GetObjects()
|
||||
{
|
||||
Array<ScriptingObject*> objects;
|
||||
_objectsLocker.Lock();
|
||||
#if USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING
|
||||
for (const auto& e : _objectsDictionary)
|
||||
objects.Add(e.Value.Ptr);
|
||||
#else
|
||||
_objectsDictionary.GetValues(objects);
|
||||
#endif
|
||||
_objectsLocker.Unlock();
|
||||
return objects;
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ Ray JsonTools::GetRay(const Value& value)
|
||||
{
|
||||
return Ray(
|
||||
GetVector3(value, "Position", Vector3::Zero),
|
||||
GetVector3(value, "Direction", Vector3::One)
|
||||
GetVector3(value, "Direction", Vector3::Forward)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "AudioTool.h"
|
||||
#include "Engine/Core/Core.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include "Engine/Core/Memory/Allocation.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
@@ -307,8 +308,9 @@ void AudioTool::ConvertFromFloat(const float* input, int32* output, uint32 numSa
|
||||
{
|
||||
for (uint32 i = 0; i < numSamples; i++)
|
||||
{
|
||||
const float sample = *(float*)input;
|
||||
output[i] = static_cast<int32>(sample * 2147483647.0f);
|
||||
float sample = *(float*)input;
|
||||
sample = Math::Clamp(sample, -1.0f + ZeroTolerance, +1.0f - ZeroTolerance);
|
||||
output[i] = static_cast<int32>(sample * 2147483648.0f);
|
||||
input++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,24 +597,10 @@ bool ImportMesh(int32 index, ModelData& result, AssimpImporterData& data, String
|
||||
// Link mesh
|
||||
meshData->NodeIndex = nodeIndex;
|
||||
AssimpNode* curNode = &data.Nodes[meshData->NodeIndex];
|
||||
Vector3 translation = Vector3::Zero;
|
||||
Vector3 scale = Vector3::One;
|
||||
Quaternion rotation = Quaternion::Identity;
|
||||
|
||||
while (true)
|
||||
{
|
||||
translation += curNode->LocalTransform.Translation;
|
||||
scale *= curNode->LocalTransform.Scale;
|
||||
rotation *= curNode->LocalTransform.Orientation;
|
||||
|
||||
if (curNode->ParentIndex == -1)
|
||||
break;
|
||||
curNode = &data.Nodes[curNode->ParentIndex];
|
||||
}
|
||||
|
||||
meshData->OriginTranslation = translation;
|
||||
meshData->OriginOrientation = rotation;
|
||||
meshData->Scaling = scale;
|
||||
|
||||
meshData->OriginTranslation = curNode->LocalTransform.Translation;
|
||||
meshData->OriginOrientation = curNode->LocalTransform.Orientation;
|
||||
meshData->Scaling = curNode->LocalTransform.Scale;
|
||||
|
||||
if (result.LODs.Count() <= lodIndex)
|
||||
result.LODs.Resize(lodIndex + 1);
|
||||
|
||||
@@ -992,7 +992,8 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
||||
}*/
|
||||
|
||||
// Get local transform for origin shifting translation
|
||||
auto translation = ToMatrix(aMesh->getGlobalTransform()).GetTranslation();
|
||||
|
||||
auto translation = Float3((float)aMesh->getLocalTranslation().x, (float)aMesh->getLocalTranslation().y, (float)aMesh->getLocalTranslation().z);
|
||||
auto scale = data.GlobalSettings.UnitScaleFactor;
|
||||
if (data.GlobalSettings.CoordAxis == ofbx::CoordSystem_RightHanded)
|
||||
mesh.OriginTranslation = scale * Vector3(translation.X, translation.Y, -translation.Z);
|
||||
|
||||
@@ -1549,23 +1549,25 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
|
||||
|
||||
// Prepare import transformation
|
||||
Transform importTransform(options.Translation, options.Rotation, Float3(options.Scale));
|
||||
if (options.UseLocalOrigin && data.LODs.HasItems() && data.LODs[0].Meshes.HasItems())
|
||||
{
|
||||
importTransform.Translation -= importTransform.Orientation * data.LODs[0].Meshes[0]->OriginTranslation * importTransform.Scale;
|
||||
}
|
||||
if (options.CenterGeometry && data.LODs.HasItems() && data.LODs[0].Meshes.HasItems())
|
||||
{
|
||||
// Calculate the bounding box (use LOD0 as a reference)
|
||||
BoundingBox box = data.LODs[0].GetBox();
|
||||
auto center = data.LODs[0].Meshes[0]->OriginOrientation * importTransform.Orientation * box.GetCenter() * importTransform.Scale * data.LODs[0].Meshes[0]->Scaling;
|
||||
importTransform.Translation -= center;
|
||||
}
|
||||
|
||||
// Apply the import transformation
|
||||
if (!importTransform.IsIdentity() && data.Nodes.HasItems())
|
||||
if ((!importTransform.IsIdentity() || options.UseLocalOrigin || options.CenterGeometry) && data.Nodes.HasItems())
|
||||
{
|
||||
if (options.Type == ModelType::SkinnedModel)
|
||||
{
|
||||
// Setup other transform options
|
||||
if (options.UseLocalOrigin && data.LODs.HasItems() && data.LODs[0].Meshes.HasItems())
|
||||
{
|
||||
importTransform.Translation -= importTransform.Orientation * data.LODs[0].Meshes[0]->OriginTranslation * importTransform.Scale;
|
||||
}
|
||||
if (options.CenterGeometry && data.LODs.HasItems() && data.LODs[0].Meshes.HasItems())
|
||||
{
|
||||
// Calculate the bounding box (use LOD0 as a reference)
|
||||
BoundingBox box = data.LODs[0].GetBox();
|
||||
auto center = data.LODs[0].Meshes[0]->OriginOrientation * importTransform.Orientation * box.GetCenter() * importTransform.Scale * data.LODs[0].Meshes[0]->Scaling;
|
||||
importTransform.Translation -= center;
|
||||
}
|
||||
|
||||
// Transform the root node using the import transformation
|
||||
auto& root = data.Skeleton.RootNode();
|
||||
Transform meshTransform = root.LocalTransform.WorldToLocal(importTransform).LocalToWorld(root.LocalTransform);
|
||||
@@ -1596,9 +1598,31 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transform the root node using the import transformation
|
||||
auto& root = data.Nodes[0];
|
||||
root.LocalTransform = importTransform.LocalToWorld(root.LocalTransform);
|
||||
// Transform the nodes using the import transformation
|
||||
if (data.LODs.HasItems() && data.LODs[0].Meshes.HasItems())
|
||||
{
|
||||
for (int i = 0; i < data.LODs[0].Meshes.Count(); ++i)
|
||||
{
|
||||
auto* meshData = data.LODs[0].Meshes[i];
|
||||
Transform transform = importTransform;
|
||||
if (options.UseLocalOrigin)
|
||||
{
|
||||
transform.Translation -= transform.Orientation * meshData->OriginTranslation * transform.Scale;
|
||||
}
|
||||
if (options.CenterGeometry)
|
||||
{
|
||||
// Calculate the bounding box (use LOD0 as a reference)
|
||||
BoundingBox box = data.LODs[0].GetBox();
|
||||
auto center = meshData->OriginOrientation * transform.Orientation * box.GetCenter() * transform.Scale * meshData->Scaling;
|
||||
transform.Translation -= center;
|
||||
}
|
||||
|
||||
int32 nodeIndex = meshData->NodeIndex;
|
||||
|
||||
auto& node = data.Nodes[nodeIndex];
|
||||
node.LocalTransform = transform.LocalToWorld(node.LocalTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user