Add support for up to 4 texture channels when importing meshes

#2667
This commit is contained in:
Wojtek Figat
2025-01-11 22:40:20 +01:00
parent 756ba0a533
commit a1c46d2e6e
31 changed files with 427 additions and 475 deletions

View File

@@ -10,7 +10,7 @@
/// <summary>
/// Current materials shader version.
/// </summary>
#define MATERIAL_GRAPH_VERSION 170
#define MATERIAL_GRAPH_VERSION 171
class Material;
class GPUShader;

View File

@@ -385,8 +385,33 @@ void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& in
renderContextBatch.GetMainContext().List->AddDrawCall(renderContextBatch, drawModes, info.Flags, shadowsMode, info.Bounds, drawCall, entry.ReceiveDecals, info.SortOrder);
}
bool Mesh::Init(uint32 vertices, uint32 triangles, const Array<const void*, FixedAllocation<3>>& vbData, const void* ibData, bool use16BitIndexBuffer, const Array<GPUVertexLayout*, FixedAllocation<3>>& vbLayout)
bool Mesh::Init(uint32 vertices, uint32 triangles, const Array<const void*, FixedAllocation<3>>& vbData, const void* ibData, bool use16BitIndexBuffer, Array<GPUVertexLayout*, FixedAllocation<3>> vbLayout)
{
// Inject lightmap uv coordinate index into the vertex layout of one of the buffers
if (LightmapUVsIndex != -1)
{
const auto vertexElementType = (VertexElement::Types)((int32)VertexElement::Types::TexCoord0 + LightmapUVsIndex);
for (int32 vbIndex = 0; vbIndex < vbLayout.Count(); vbIndex++)
{
// Check if layout contains lightmap uvs texcoords channel
GPUVertexLayout* layout = vbLayout[vbIndex];
VertexElement element = layout->FindElement(vertexElementType);
if (element.Type == vertexElementType)
{
// Ensure element doesn't exist in this layout
if (layout->FindElement(VertexElement::Types::Lightmap).Format == PixelFormat::Unknown)
{
GPUVertexLayout::Elements elements = layout->GetElements();
element.Type = VertexElement::Types::Lightmap;
elements.Add(element);
layout = GPUVertexLayout::Get(elements, true);
vbLayout[vbIndex] = layout;
}
break;
}
}
}
if (MeshBase::Init(vertices, triangles, vbData, ibData, use16BitIndexBuffer, vbLayout))
return true;

View File

@@ -172,7 +172,7 @@ public:
public:
// [MeshBase]
bool Init(uint32 vertices, uint32 triangles, const Array<const void*, FixedAllocation<3>>& vbData, const void* ibData, bool use16BitIndexBuffer, const Array<GPUVertexLayout*, FixedAllocation<3>>& vbLayout) override;
bool Init(uint32 vertices, uint32 triangles, const Array<const void*, FixedAllocation<3>>& vbData, const void* ibData, bool use16BitIndexBuffer, Array<GPUVertexLayout*, FixedAllocation<3>> vbLayout) override;
void Release() override;
private:

View File

@@ -330,7 +330,7 @@ GPUVertexLayout* MeshBase::GetVertexLayout() const
return GPUVertexLayout::Get(Span<GPUBuffer*>(_vertexBuffers, MODEL_MAX_VB));
}
bool MeshBase::Init(uint32 vertices, uint32 triangles, const Array<const void*, FixedAllocation<MODEL_MAX_VB>>& vbData, const void* ibData, bool use16BitIndexBuffer, const Array<GPUVertexLayout*, FixedAllocation<MODEL_MAX_VB>>& vbLayout)
bool MeshBase::Init(uint32 vertices, uint32 triangles, const Array<const void*, FixedAllocation<MODEL_MAX_VB>>& vbData, const void* ibData, bool use16BitIndexBuffer, Array<GPUVertexLayout*, FixedAllocation<MODEL_MAX_VB>> vbLayout)
{
CHECK_RETURN(vbData.HasItems() && vertices, true);
CHECK_RETURN(ibData, true);

View File

@@ -221,7 +221,7 @@ public:
/// <param name="use16BitIndexBuffer">True to use 16-bit indices for the index buffer (true: uint16, false: uint32).</param>
/// <param name="vbLayout">Layout descriptors for the vertex buffers attributes (one for each vertex buffer).</param>
/// <returns>True if failed, otherwise false.</returns>
API_FUNCTION(Sealed) virtual bool Init(uint32 vertices, uint32 triangles, const Array<const void*, FixedAllocation<MODEL_MAX_VB>>& vbData, const void* ibData, bool use16BitIndexBuffer, const Array<GPUVertexLayout*, FixedAllocation<MODEL_MAX_VB>>& vbLayout);
API_FUNCTION(Sealed) virtual bool Init(uint32 vertices, uint32 triangles, const Array<const void*, FixedAllocation<MODEL_MAX_VB>>& vbData, const void* ibData, bool use16BitIndexBuffer, Array<GPUVertexLayout*, FixedAllocation<MODEL_MAX_VB>> vbLayout);
/// <summary>
/// Releases the mesh data (GPU buffers and local cache).

View File

@@ -6,7 +6,7 @@
#include "Engine/Core/Log.h"
#include "Engine/Core/Utilities.h"
#include "Engine/Core/Types/DateTime.h"
#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Core/Types/Stopwatch.h"
#include "Engine/Core/Collections/BitArray.h"
#include "Engine/Tools/ModelTool/ModelTool.h"
#include "Engine/Tools/ModelTool/VertexTriangleAdjacency.h"
@@ -77,8 +77,39 @@ void RemapArrayHelper(Array<T>& target, const std::vector<uint32_t>& remap)
}
}
void MeshData::SetLightmapUVsSource(ModelLightmapUVsSource source)
{
if (source == ModelLightmapUVsSource::Disable)
{
// No lightmap UVs
}
else if (source == ModelLightmapUVsSource::Generate)
{
// Generate lightmap UVs
if (GenerateLightmapUVs())
{
LOG(Error, "Failed to generate lightmap uvs");
}
}
else
{
// Select input channel index
const int32 inputChannelIndex = (int32)source - (int32)ModelLightmapUVsSource::Channel0;
if (inputChannelIndex >= 0 && inputChannelIndex < UVs.Count() && UVs[inputChannelIndex].HasItems())
{
LightmapUVsIndex = inputChannelIndex;
}
else
{
LOG(Warning, "Cannot import result lightmap uvs. Missing texcoords channel {0}.", inputChannelIndex);
}
}
}
bool MeshData::GenerateLightmapUVs()
{
if (Positions.IsEmpty() || Indices.IsEmpty())
return true;
PROFILE_CPU();
#if PLATFORM_WINDOWS
// Prepare
@@ -87,8 +118,7 @@ bool MeshData::GenerateLightmapUVs()
int32 facesCount = Indices.Count() / 3;
DirectX::XMFLOAT3* positions = (DirectX::XMFLOAT3*)Positions.Get();
LOG(Info, "Generating lightmaps UVs ({0} vertices, {1} triangles)...", verticesCount, facesCount);
DateTime startTime = DateTime::Now();
Stopwatch stopwatch;
// Generate adjacency data
const float adjacencyEpsilon = 0.001f;
@@ -126,27 +156,30 @@ bool MeshData::GenerateLightmapUVs()
return true;
}
const DateTime endTime = DateTime::Now();
// Log info
const int32 nTotalVerts = (int32)vb.size();
const int32 msTime = Math::CeilToInt((float)(endTime - startTime).GetTotalMilliseconds());
LOG(Info, "Lightmap UVs generated! Charts: {0}, stretching: {1}, {2} vertices. Time: {3}ms", outCharts, outStretch, nTotalVerts, msTime);
stopwatch.Stop();
LOG(Info, "Lightmap UVs generated! Charts: {0}, stretching: {1}, {2} vertices. Time: {3}ms", outCharts, outStretch, (int32)vb.size(), stopwatch.GetMilliseconds());
// Update mesh data (remap vertices due to vertex buffer and index buffer change)
RemapArrayHelper(Positions, vertexRemapArray);
RemapArrayHelper(UVs, vertexRemapArray);
LightmapUVsIndex = Math::Min(UVs.Count(), MODEL_MAX_UV - 1);
for (int32 channel = 0; channel < LightmapUVsIndex; channel++)
RemapArrayHelper(UVs[channel], vertexRemapArray);
RemapArrayHelper(Normals, vertexRemapArray);
RemapArrayHelper(Tangents, vertexRemapArray);
RemapArrayHelper(Colors, vertexRemapArray);
RemapArrayHelper(BlendIndices, vertexRemapArray);
RemapArrayHelper(BlendWeights, vertexRemapArray);
LightmapUVs.Resize(nTotalVerts, false);
for (int32 i = 0; i < nTotalVerts; i++)
LightmapUVs[i] = *(Float2*)&vb[i].uv;
uint32* ibP = (uint32*)ib.data();
for (int32 i = 0; i < Indices.Count(); i++)
Indices[i] = *ibP++;
// Add generated data
UVs.Resize(LightmapUVsIndex + 1);
auto& lightmapChannel = UVs[LightmapUVsIndex];
lightmapChannel.Resize((int32)vb.size(), false);
for (int32 i = 0; i < (int32)vb.size(); i++)
lightmapChannel.Get()[i] = *(Float2*)&vb[i].uv;
#else
LOG(Error, "Model lightmap UVs generation is not supported on this platform.");
#endif
@@ -162,6 +195,10 @@ int32 FindVertex(const MeshData& mesh, int32 vertexIndex, int32 startIndex, int3
)
{
const float uvEpsSqr = (1.0f / 250.0f) * (1.0f / 250.0f);
const Float2* uv0 = mesh.UVs.Count() > 0 && mesh.UVs[0].HasItems() ? mesh.UVs[0].Get() : nullptr;
const Float2* uv1 = mesh.UVs.Count() > 1 && mesh.UVs[1].HasItems() ? mesh.UVs[1].Get() : nullptr;
const Float2* uv2 = mesh.UVs.Count() > 2 && mesh.UVs[2].HasItems() ? mesh.UVs[2].Get() : nullptr;
const Float2* uv3 = mesh.UVs.Count() > 3 && mesh.UVs[3].HasItems() ? mesh.UVs[3].Get() : nullptr;
#if USE_SPATIAL_SORT
const Float3 vPosition = mesh.Positions[vertexIndex];
@@ -169,10 +206,12 @@ int32 FindVertex(const MeshData& mesh, int32 vertexIndex, int32 startIndex, int3
if (spatialSortCache.empty())
return INVALID_INDEX;
const Float2 vUV = mesh.UVs.HasItems() ? mesh.UVs[vertexIndex] : Float2::Zero;
const Float2 vUV0 = uv0 ? uv0[vertexIndex] : Float2::Zero;
const Float2 vUV1 = uv1 ? uv1[vertexIndex] : Float2::Zero;
const Float2 vUV2 = uv2 ? uv2[vertexIndex] : Float2::Zero;
const Float2 vUV3 = uv3 ? uv3[vertexIndex] : Float2::Zero;
const Float3 vNormal = mesh.Normals.HasItems() ? mesh.Normals[vertexIndex] : Float3::Zero;
const Float3 vTangent = mesh.Tangents.HasItems() ? mesh.Tangents[vertexIndex] : Float3::Zero;
const Float2 vLightmapUV = mesh.LightmapUVs.HasItems() ? mesh.LightmapUVs[vertexIndex] : Float2::Zero;
const Color vColor = mesh.Colors.HasItems() ? mesh.Colors[vertexIndex] : Color::Black; // Assuming Color::Black as a default color
const int32 end = startIndex + searchRange;
@@ -184,10 +223,12 @@ int32 FindVertex(const MeshData& mesh, int32 vertexIndex, int32 startIndex, int3
continue;
#else
const Float3 vPosition = mesh.Positions[vertexIndex];
const Float2 vUV = mesh.UVs.HasItems() ? mesh.UVs[vertexIndex] : Float2::Zero;
const Float2 vUV0 = uv0 ? uv0[vertexIndex] : Float2::Zero;
const Float2 vUV1 = uv1 ? uv1[vertexIndex] : Float2::Zero;
const Float2 vUV2 = uv2 ? uv2[vertexIndex] : Float2::Zero;
const Float2 vUV3 = uv3 ? uv3[vertexIndex] : Float2::Zero;
const Float3 vNormal = mesh.Normals.HasItems() ? mesh.Normals[vertexIndex] : Float3::Zero;
const Float3 vTangent = mesh.Tangents.HasItems() ? mesh.Tangents[vertexIndex] : Float3::Zero;
const Float2 vLightmapUV = mesh.LightmapUVs.HasItems() ? mesh.LightmapUVs[vertexIndex] : Float2::Zero;
const Color vColor = mesh.Colors.HasItems() ? mesh.Colors[vertexIndex] : Color::Black; // Assuming Color::Black as a default color
const int32 end = startIndex + searchRange;
@@ -199,17 +240,20 @@ int32 FindVertex(const MeshData& mesh, int32 vertexIndex, int32 startIndex, int3
#endif
if (mapping[v] == INVALID_INDEX)
continue;
if (mesh.UVs.HasItems() && (vUV - mesh.UVs[v]).LengthSquared() > uvEpsSqr)
if (uv0 && (vUV0 - uv0[v]).LengthSquared() > uvEpsSqr)
continue;
if (uv1 && (vUV1 - uv1[v]).LengthSquared() > uvEpsSqr)
continue;
if (uv2 && (vUV2 - uv2[v]).LengthSquared() > uvEpsSqr)
continue;
if (uv3 && (vUV3 - uv3[v]).LengthSquared() > uvEpsSqr)
continue;
if (mesh.Normals.HasItems() && Float3::Dot(vNormal, mesh.Normals[v]) < 0.98f)
continue;
if (mesh.Tangents.HasItems() && Float3::Dot(vTangent, mesh.Tangents[v]) < 0.98f)
continue;
if (mesh.LightmapUVs.HasItems() && (vLightmapUV - mesh.LightmapUVs[v]).LengthSquared() > uvEpsSqr)
continue;
if (mesh.Colors.HasItems() && vColor != mesh.Colors[v])
continue;
// TODO: check more components?
return v;
}
@@ -238,7 +282,7 @@ void RemapBuffer(Array<T>& src, Array<T>& dst, const Array<int32>& mapping, int3
void MeshData::BuildIndexBuffer()
{
PROFILE_CPU();
const auto startTime = Platform::GetTimeSeconds();
Stopwatch stopwatch;
const int32 vertexCount = Positions.Count();
MeshData newMesh;
@@ -287,14 +331,15 @@ void MeshData::BuildIndexBuffer()
newMesh.SwapBuffers(*this);
#define REMAP_BUFFER(name) RemapBuffer(newMesh.name, name, mapping, newVertexCounter)
REMAP_BUFFER(Positions);
REMAP_BUFFER(UVs);
REMAP_BUFFER(Normals);
REMAP_BUFFER(Tangents);
REMAP_BUFFER(BitangentSigns);
REMAP_BUFFER(LightmapUVs);
REMAP_BUFFER(Colors);
REMAP_BUFFER(BlendIndices);
REMAP_BUFFER(BlendWeights);
UVs.Resize(newMesh.UVs.Count());
for (int32 channelIdx = 0; channelIdx < UVs.Count(); channelIdx++)
REMAP_BUFFER(UVs[channelIdx]);
#undef REMAP_BUFFER
BlendShapes.Resize(newMesh.BlendShapes.Count());
for (int32 blendShapeIndex = 0; blendShapeIndex < newMesh.BlendShapes.Count(); blendShapeIndex++)
@@ -317,8 +362,8 @@ void MeshData::BuildIndexBuffer()
}
}
const auto endTime = Platform::GetTimeSeconds();
const double time = Utilities::RoundTo2DecimalPlaces(endTime - startTime);
stopwatch.Stop();
const double time = Utilities::RoundTo2DecimalPlaces(stopwatch.GetTotalSeconds());
if (time > 0.5f) // Don't log if generation was fast enough
LOG(Info, "Generated {3} for mesh in {0}s ({1} vertices, {2} indices)", time, vertexCount, Indices.Count(), TEXT("indices"));
}
@@ -494,7 +539,7 @@ namespace
void GetTexCoord(const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert)
{
const auto meshData = (MeshData*)pContext->m_pUserData;
const auto e = meshData->UVs[meshData->Indices[iFace * 3 + iVert]];
const auto e = meshData->UVs[0][meshData->Indices[iFace * 3 + iVert]];
fvTexcOut[0] = e.X;
fvTexcOut[1] = e.Y;
}
@@ -518,7 +563,7 @@ bool MeshData::GenerateTangents(float smoothingAngle)
}
if (Normals.IsEmpty() || UVs.IsEmpty())
{
LOG(Warning, "Missing normals or texcoors data to generate tangents.");
LOG(Warning, "Missing normals or texcoords data to generate tangents.");
return true;
}
PROFILE_CPU();
@@ -549,7 +594,7 @@ bool MeshData::GenerateTangents(float smoothingAngle)
vertexDone.SetAll(false);
const Float3* meshNorm = Normals.Get();
const Float2* meshTex = UVs.Get();
const Float2* meshTex = UVs[0].Get();
Float3* meshTang = Tangents.Get();
// Calculate the tangent per-triangle

View File

@@ -17,21 +17,21 @@ void MeshData::Clear()
Normals.Clear();
Tangents.Clear();
BitangentSigns.Clear();
LightmapUVs.Clear();
Colors.Clear();
BlendIndices.Clear();
BlendWeights.Clear();
BlendShapes.Clear();
}
void MeshData::EnsureCapacity(int32 vertices, int32 indices, bool preserveContents, bool withColors, bool withSkin)
void MeshData::EnsureCapacity(int32 vertices, int32 indices, bool preserveContents, bool withColors, bool withSkin, int32 texcoords)
{
Positions.EnsureCapacity(vertices, preserveContents);
Indices.EnsureCapacity(indices, preserveContents);
UVs.EnsureCapacity(vertices, preserveContents);
UVs.Resize(texcoords);
for (auto& channel : UVs)
channel.EnsureCapacity(vertices, preserveContents);
Normals.EnsureCapacity(vertices, preserveContents);
Tangents.EnsureCapacity(vertices, preserveContents);
LightmapUVs.EnsureCapacity(vertices, preserveContents);
Colors.EnsureCapacity(withColors ? vertices : 0, preserveContents);
BlendIndices.EnsureCapacity(withSkin ? vertices : 0, preserveContents);
BlendWeights.EnsureCapacity(withSkin ? vertices : 0, preserveContents);
@@ -45,7 +45,6 @@ void MeshData::SwapBuffers(MeshData& other)
Normals.Swap(other.Normals);
Tangents.Swap(other.Tangents);
BitangentSigns.Swap(other.BitangentSigns);
LightmapUVs.Swap(other.LightmapUVs);
Colors.Swap(other.Colors);
BlendIndices.Swap(other.BlendIndices);
BlendWeights.Swap(other.BlendWeights);
@@ -61,7 +60,6 @@ void MeshData::Release()
Normals.Resize(0);
Tangents.Resize(0);
BitangentSigns.Resize(0);
LightmapUVs.Resize(0);
Colors.Resize(0);
BlendIndices.Resize(0);
BlendWeights.Resize(0);
@@ -72,11 +70,12 @@ PRAGMA_DISABLE_DEPRECATION_WARNINGS
void MeshData::InitFromModelVertices(ModelVertex19* vertices, uint32 verticesCount)
{
Positions.Resize(verticesCount, false);
UVs.Resize(verticesCount, false);
UVs.Resize(2);
UVs[0].Resize(verticesCount, false);
UVs[1].Resize(verticesCount, false);
Normals.Resize(verticesCount, false);
Tangents.Resize(verticesCount, false);
BitangentSigns.Resize(0);
LightmapUVs.Resize(verticesCount, false);
Colors.Resize(0);
BlendIndices.Resize(0);
BlendWeights.Resize(0);
@@ -85,10 +84,10 @@ void MeshData::InitFromModelVertices(ModelVertex19* vertices, uint32 verticesCou
for (uint32 i = 0; i < verticesCount; i++)
{
Positions[i] = vertices->Position;
UVs[i] = vertices->TexCoord.ToFloat2();
UVs[0][i] = vertices->TexCoord.ToFloat2();
UVs[1][i] = vertices->LightmapUVs.ToFloat2();
Normals[i] = vertices->Normal.ToFloat3() * 2.0f - 1.0f;
Tangents[i] = vertices->Tangent.ToFloat3() * 2.0f - 1.0f;
LightmapUVs[i] = vertices->LightmapUVs.ToFloat2();
Colors[i] = Color(vertices->Color);
vertices++;
@@ -98,11 +97,12 @@ void MeshData::InitFromModelVertices(ModelVertex19* vertices, uint32 verticesCou
void MeshData::InitFromModelVertices(VB0ElementType18* vb0, VB1ElementType18* vb1, uint32 verticesCount)
{
Positions.Resize(verticesCount, false);
UVs.Resize(verticesCount, false);
UVs.Resize(2);
UVs[0].Resize(verticesCount, false);
UVs[1].Resize(verticesCount, false);
Normals.Resize(verticesCount, false);
Tangents.Resize(verticesCount, false);
BitangentSigns.Resize(0);
LightmapUVs.Resize(verticesCount, false);
Colors.Resize(0);
BlendIndices.Resize(0);
BlendWeights.Resize(0);
@@ -111,10 +111,10 @@ void MeshData::InitFromModelVertices(VB0ElementType18* vb0, VB1ElementType18* vb
for (uint32 i = 0; i < verticesCount; i++)
{
Positions[i] = vb0->Position;
UVs[i] = vb1->TexCoord.ToFloat2();
UVs[0][i] = vb1->TexCoord.ToFloat2();
UVs[1][i] = vb1->LightmapUVs.ToFloat2();
Normals[i] = vb1->Normal.ToFloat3() * 2.0f - 1.0f;
Tangents[i] = vb1->Tangent.ToFloat3() * 2.0f - 1.0f;
LightmapUVs[i] = vb1->LightmapUVs.ToFloat2();
vb0++;
vb1++;
@@ -124,19 +124,16 @@ void MeshData::InitFromModelVertices(VB0ElementType18* vb0, VB1ElementType18* vb
void MeshData::InitFromModelVertices(VB0ElementType18* vb0, VB1ElementType18* vb1, VB2ElementType18* vb2, uint32 verticesCount)
{
Positions.Resize(verticesCount, false);
UVs.Resize(verticesCount, false);
UVs.Resize(2);
UVs[0].Resize(verticesCount, false);
UVs[1].Resize(verticesCount, false);
Normals.Resize(verticesCount, false);
Tangents.Resize(verticesCount, false);
BitangentSigns.Resize(0);
LightmapUVs.Resize(verticesCount, false);
if (vb2)
{
Colors.Resize(verticesCount, false);
}
else
{
Colors.Resize(0);
}
BlendIndices.Resize(0);
BlendWeights.Resize(0);
BlendShapes.Resize(0);
@@ -144,10 +141,10 @@ void MeshData::InitFromModelVertices(VB0ElementType18* vb0, VB1ElementType18* vb
for (uint32 i = 0; i < verticesCount; i++)
{
Positions[i] = vb0->Position;
UVs[i] = vb1->TexCoord.ToFloat2();
UVs[0][i] = vb1->TexCoord.ToFloat2();
UVs[1][i] = vb1->LightmapUVs.ToFloat2();
Normals[i] = vb1->Normal.ToFloat3() * 2.0f - 1.0f;
Tangents[i] = vb1->Tangent.ToFloat3() * 2.0f - 1.0f;
LightmapUVs[i] = vb1->LightmapUVs.ToFloat2();
if (vb2)
{
Colors[i] = Color(vb2->Color);
@@ -310,22 +307,32 @@ void MeshData::Merge(MeshData& other)
}
// Merge vertex buffer
#define MERGE(item, defautValue) \
#define MERGE(item, defaultValue) \
if (item.HasItems() && other.item.HasItems()) \
item.Add(other.item); \
else if (item.HasItems() && !other.item.HasItems()) \
for (int32 i = 0; i < other.Positions.Count(); i++) item.Add(defautValue); \
for (int32 i = 0; i < other.Positions.Count(); i++) item.Add(defaultValue); \
else if (!item.HasItems() && other.item.HasItems()) \
for (int32 i = 0; i < Positions.Count(); i++) item.Add(defautValue)
for (int32 i = 0; i < Positions.Count(); i++) item.Add(defaultValue)
MERGE(Positions, Float3::Zero);
MERGE(UVs, Float2::Zero);
MERGE(Normals, Float3::Forward);
MERGE(Tangents, Float3::Right);
MERGE(BitangentSigns, 1.0f);
MERGE(LightmapUVs, Float2::Zero);
MERGE(Colors, Color::Black);
MERGE(BlendIndices, Int4::Zero);
MERGE(BlendWeights, Float4::Zero);
if (other.UVs.Count() > UVs.Count())
UVs.Resize(other.UVs.Count());
for (int32 channelIdx = 0; channelIdx < UVs.Count(); channelIdx++)
{
if (other.UVs.Count() <= channelIdx)
{
for (int32 i = 0; i < other.Positions.Count(); i++)
UVs[channelIdx].Add(Float2::Zero);
continue;
}
MERGE(UVs[channelIdx], Float2::Zero);
}
#undef MERGE
// Merge blend shapes

View File

@@ -41,9 +41,7 @@ public:
/// <summary>
/// Texture coordinates (list of channels)
/// </summary>
// TODO: multiple UVs
Array<Float2> UVs;
Array<Float2> LightmapUVs; // TODO: remove this and move to UVs
Array<Array<Float2>, FixedAllocation<MODEL_MAX_UV>> UVs;
/// <summary>
/// Normals vector
@@ -121,7 +119,8 @@ public:
/// <param name="preserveContents">Failed if clear data otherwise will try to preserve the buffers contents.</param>
/// <param name="withColors">True if use vertex colors buffer.</param>
/// <param name="withSkin">True if use vertex blend indices and weights buffer.</param>
void EnsureCapacity(int32 vertices, int32 indices, bool preserveContents = false, bool withColors = true, bool withSkin = true);
/// <param name="texcoords">Amount of texture coordinate channels to use.</param>
void EnsureCapacity(int32 vertices, int32 indices, bool preserveContents = false, bool withColors = true, bool withSkin = true, int32 texcoords = 1);
/// <summary>
/// Swaps the vertex and index buffers contents (without a data copy) with the other mesh.
@@ -189,6 +188,11 @@ public:
void CalculateBounds(BoundingBox& box, BoundingSphere& sphere) const;
#if COMPILE_WITH_MODEL_TOOL
/// <summary>
/// Setups Lightmap UVs based on the option.
/// </summary>
void SetLightmapUVsSource(ModelLightmapUVsSource source);
/// <summary>
/// Generate lightmap uvs for the mesh entry
/// </summary>

View File

@@ -55,6 +55,8 @@ PACK_BEGIN() struct FLAXENGINE_API VertexElement
Attribute2 = 17,
// General purpose attribute (at index 3). Maps to 'ATTRIBUTE3' semantic in the shader.
Attribute3 = 18,
// Lightmap UVs that usually map one of the texture coordinate channels. Maps to 'LIGHTMAP' semantic in the shader.
Lightmap = 30,
// Texture coordinate. Maps to 'TEXCOORD' semantic in the shader.
TexCoord = TexCoord0,
// General purpose attribute. Maps to 'ATTRIBUTE0' semantic in the shader.