@@ -514,7 +514,7 @@ VertexOutput VS_Model(ModelInput input, uint particleIndex : SV_InstanceID)
|
||||
output.Position = mul(float4(output.WorldPosition, 1), ViewProjectionMatrix);
|
||||
|
||||
// Pass vertex attributes
|
||||
output.TexCoord = input.TexCoord;
|
||||
output.TexCoord = input.TexCoord0;
|
||||
output.ParticleIndex = particleIndex;
|
||||
#if USE_VERTEX_COLOR
|
||||
output.VertexColor = input.Color;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Version: @0
|
||||
|
||||
#define MATERIAL 1
|
||||
#define MATERIAL_TEXCOORDS 4
|
||||
#define USE_PER_VIEW_CONSTANTS 1
|
||||
#define USE_PER_DRAW_CONSTANTS 1
|
||||
@3
|
||||
@@ -24,17 +25,19 @@ Buffer<float4> BoneMatrices : register(t1);
|
||||
Buffer<float4> PrevBoneMatrices : register(t2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Geometry data passed though the graphics rendering stages up to the pixel shader
|
||||
struct GeometryData
|
||||
{
|
||||
float3 WorldPosition : TEXCOORD0;
|
||||
float2 TexCoord : TEXCOORD1;
|
||||
float2 LightmapUV : TEXCOORD2;
|
||||
float4 TexCoords01 : TEXCOORD1;
|
||||
float4 TexCoords23 : TEXCOORD2;
|
||||
float2 LightmapUV : TEXCOORD3;
|
||||
#if USE_VERTEX_COLOR
|
||||
half4 VertexColor : COLOR;
|
||||
#endif
|
||||
float3 WorldNormal : TEXCOORD3;
|
||||
float4 WorldTangent : TEXCOORD4;
|
||||
float3 WorldNormal : TEXCOORD4;
|
||||
float4 WorldTangent : TEXCOORD5;
|
||||
float3 PrevWorldPosition : TEXCOORD7;
|
||||
nointerpolation uint ObjectIndex : TEXCOORD8;
|
||||
};
|
||||
@@ -68,7 +71,7 @@ struct MaterialInput
|
||||
{
|
||||
float3 WorldPosition;
|
||||
float TwoSidedSign;
|
||||
float2 TexCoord;
|
||||
float2 TexCoords[MATERIAL_TEXCOORDS];
|
||||
#if USE_LIGHTMAP
|
||||
float2 LightmapUV;
|
||||
#endif
|
||||
@@ -86,12 +89,18 @@ struct MaterialInput
|
||||
#endif
|
||||
};
|
||||
|
||||
// Map access to the main texure coordinate channel as UV0
|
||||
#define TexCoord TexCoords[0]
|
||||
|
||||
// Extracts geometry data to the material input
|
||||
MaterialInput GetGeometryMaterialInput(GeometryData geometry)
|
||||
{
|
||||
MaterialInput output = (MaterialInput)0;
|
||||
output.WorldPosition = geometry.WorldPosition;
|
||||
output.TexCoord = geometry.TexCoord;
|
||||
output.TexCoords[0] = geometry.TexCoords01.xy;
|
||||
output.TexCoords[1] = geometry.TexCoords01.zw;
|
||||
output.TexCoords[2] = geometry.TexCoords23.xy;
|
||||
output.TexCoords[3] = geometry.TexCoords23.zw;
|
||||
#if USE_LIGHTMAP
|
||||
output.LightmapUV = geometry.LightmapUV;
|
||||
#endif
|
||||
@@ -126,8 +135,8 @@ MaterialInput GetGeometryMaterialInput(GeometryData geometry)
|
||||
GeometryData InterpolateGeometry(GeometryData p0, float w0, GeometryData p1, float w1, GeometryData p2, float w2)
|
||||
{
|
||||
GeometryData output = (GeometryData)0;
|
||||
output.TexCoord = p0.TexCoord * w0 + p1.TexCoord * w1 + p2.TexCoord * w2;
|
||||
output.LightmapUV = p0.LightmapUV * w0 + p1.LightmapUV * w1 + p2.LightmapUV * w2;
|
||||
output.TexCoords01 = p0.TexCoords01 * w0 + p1.TexCoords01 * w1 + p2.TexCoords01 * w2;
|
||||
output.TexCoords23 = p0.TexCoords23 * w0 + p1.TexCoords23 * w1 + p2.TexCoords23 * w2;
|
||||
#if USE_VERTEX_COLOR
|
||||
output.VertexColor = p0.VertexColor * w0 + p1.VertexColor * w1 + p2.VertexColor * w2;
|
||||
#endif
|
||||
@@ -312,14 +321,15 @@ VertexOutput VS(ModelInput input)
|
||||
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
|
||||
|
||||
// Pass vertex attributes
|
||||
output.Geometry.TexCoord = input.TexCoord;
|
||||
output.Geometry.TexCoords01 = float4(input.TexCoord0, input.TexCoord1);
|
||||
output.Geometry.TexCoords23 = float4(input.TexCoord2, input.TexCoord3);
|
||||
#if USE_VERTEX_COLOR
|
||||
output.Geometry.VertexColor = input.Color;
|
||||
#endif
|
||||
#if CAN_USE_LIGHTMAP
|
||||
output.Geometry.LightmapUV = input.LightmapUV * object.LightmapArea.zw + object.LightmapArea.xy;
|
||||
#else
|
||||
output.Geometry.LightmapUV = input.LightmapUV;
|
||||
output.Geometry.LightmapUV = float2(0, 0);
|
||||
#endif
|
||||
|
||||
// Calculate tanget space to world space transformation matrix for unit vectors
|
||||
@@ -486,9 +496,10 @@ VertexOutput VS_Skinned(ModelInput_Skinned input)
|
||||
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
|
||||
|
||||
// Pass vertex attributes
|
||||
output.Geometry.TexCoord = input.TexCoord;
|
||||
output.Geometry.TexCoords01 = float4(input.TexCoord0, input.TexCoord1);
|
||||
output.Geometry.TexCoords23 = float4(input.TexCoord2, input.TexCoord3);
|
||||
#if USE_VERTEX_COLOR
|
||||
output.Geometry.VertexColor = float4(0, 0, 0, 1);
|
||||
output.Geometry.VertexColor = input.Color;
|
||||
#endif
|
||||
output.Geometry.LightmapUV = float2(0, 0);
|
||||
|
||||
|
||||
@@ -123,9 +123,15 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
AlternativeTitles = new string[] { "UV", "UVs" },
|
||||
Description = "Texture coordinates",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(110, 30),
|
||||
Size = new Float2(150, 30),
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
0u
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Text(0, 1, "Channel:"),
|
||||
NodeElementArchetype.Factory.UnsignedInteger(50, 0, 0, -1, 0, 3),
|
||||
NodeElementArchetype.Factory.Output(0, "UVs", typeof(Float2), 0)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -93,6 +93,118 @@ namespace FlaxEditor.Windows.Assets
|
||||
}
|
||||
}
|
||||
|
||||
protected class UVsPropertiesProxyBase : PropertiesProxyBase
|
||||
{
|
||||
public enum UVChannel
|
||||
{
|
||||
None,
|
||||
TexCoord0,
|
||||
TexCoord1,
|
||||
TexCoord2,
|
||||
TexCoord3,
|
||||
LightmapUVs,
|
||||
};
|
||||
|
||||
private UVChannel _uvChannel = UVChannel.None;
|
||||
|
||||
[EditorOrder(0), EditorDisplay(null, "Preview UV Channel"), EnumDisplay(EnumDisplayAttribute.FormatMode.None)]
|
||||
[Tooltip("Set UV channel to preview.")]
|
||||
public UVChannel Channel
|
||||
{
|
||||
get => _uvChannel;
|
||||
set
|
||||
{
|
||||
if (_uvChannel == value)
|
||||
return;
|
||||
_uvChannel = value;
|
||||
Window._meshData?.RequestMeshData(Window._asset);
|
||||
}
|
||||
}
|
||||
|
||||
[EditorOrder(1), EditorDisplay(null, "LOD"), Limit(0, Model.MaxLODs), VisibleIf("ShowUVs")]
|
||||
[Tooltip("Level Of Detail index to preview UVs layout.")]
|
||||
public int LOD = 0;
|
||||
|
||||
[EditorOrder(2), EditorDisplay(null, "Mesh"), Limit(-1, 1000000), VisibleIf("ShowUVs")]
|
||||
[Tooltip("Mesh index to preview UVs layout. Use -1 for all meshes")]
|
||||
public int Mesh = -1;
|
||||
|
||||
private bool ShowUVs => _uvChannel != UVChannel.None;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnClean()
|
||||
{
|
||||
Channel = UVChannel.None;
|
||||
|
||||
base.OnClean();
|
||||
}
|
||||
|
||||
protected class ProxyEditor : ProxyEditorBase
|
||||
{
|
||||
private UVsLayoutPreviewControl _uvsPreview;
|
||||
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var proxy = (UVsPropertiesProxyBase)Values[0];
|
||||
if (Utilities.Utils.OnAssetProperties(layout, proxy.Asset))
|
||||
return;
|
||||
|
||||
base.Initialize(layout);
|
||||
|
||||
_uvsPreview = layout.Custom<UVsLayoutPreviewControl>().CustomControl;
|
||||
_uvsPreview.Window = proxy.Window;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
if (_uvsPreview != null)
|
||||
{
|
||||
var proxy = (UVsPropertiesProxyBase)Values[0];
|
||||
switch (proxy._uvChannel)
|
||||
{
|
||||
case UVChannel.TexCoord0: _uvsPreview.Channel = 0; break;
|
||||
case UVChannel.TexCoord1: _uvsPreview.Channel = 1; break;
|
||||
case UVChannel.TexCoord2: _uvsPreview.Channel = 2; break;
|
||||
case UVChannel.TexCoord3: _uvsPreview.Channel = 3; break;
|
||||
case UVChannel.LightmapUVs:
|
||||
{
|
||||
_uvsPreview.Channel = -1;
|
||||
if (proxy.Window.Asset && proxy.Window.Asset.IsLoaded)
|
||||
{
|
||||
// Pick UVs channel index from the first mesh
|
||||
proxy.Window.Asset.GetMeshes(out var meshes);
|
||||
foreach (var mesh in meshes)
|
||||
{
|
||||
if (mesh is Mesh m && m.HasLightmapUVs)
|
||||
{
|
||||
_uvsPreview.Channel = m.LightmapUVsIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: _uvsPreview.Channel = -1; break;
|
||||
}
|
||||
_uvsPreview.LOD = proxy.LOD;
|
||||
_uvsPreview.Mesh = proxy.Mesh;
|
||||
_uvsPreview.HighlightIndex = proxy.Window._highlightIndex;
|
||||
_uvsPreview.IsolateIndex = proxy.Window._isolateIndex;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
_uvsPreview = null;
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected sealed class UVsLayoutPreviewControl : RenderToTextureControl
|
||||
{
|
||||
private int _channel = -1;
|
||||
@@ -168,15 +280,21 @@ namespace FlaxEditor.Windows.Assets
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMeshUVs(int meshIndex, ref MeshDataCache.MeshData meshData)
|
||||
private void DrawMeshUVs(int meshIndex, ref MeshDataCache.MeshData meshData, ref Rectangle bounds)
|
||||
{
|
||||
var uvScale = Size;
|
||||
if (meshData.IndexBuffer == null || meshData.VertexAccessor == null)
|
||||
{
|
||||
Render2D.DrawText(Style.Current.FontMedium, "Missing mesh data", bounds, Color.Red, TextAlignment.Center, TextAlignment.Center);
|
||||
return;
|
||||
}
|
||||
var linesColor = _highlightIndex != -1 && _highlightIndex == meshIndex ? Style.Current.BackgroundSelected : Color.White;
|
||||
var texCoordStream = meshData.VertexAccessor.TexCoord(_channel);
|
||||
if (!texCoordStream.IsValid)
|
||||
{
|
||||
Render2D.DrawText(Style.Current.FontMedium, "Missing texcoords channel", bounds, Color.Yellow, TextAlignment.Center, TextAlignment.Center);
|
||||
return;
|
||||
}
|
||||
var uvScale = bounds.Size;
|
||||
for (int i = 0; i < meshData.IndexBuffer.Length; i += 3)
|
||||
{
|
||||
// Cache triangle indices
|
||||
@@ -206,19 +324,19 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
base.DrawSelf();
|
||||
|
||||
var size = Size;
|
||||
if (_channel < 0 || size.MaxValue < 5.0f)
|
||||
var bounds = new Rectangle(Float2.Zero, Size);
|
||||
if (_channel < 0 || bounds.Size.MaxValue < 5.0f)
|
||||
return;
|
||||
if (Window._meshData == null)
|
||||
Window._meshData = new MeshDataCache();
|
||||
if (!Window._meshData.RequestMeshData(Window._asset))
|
||||
{
|
||||
Invalidate();
|
||||
Render2D.DrawText(Style.Current.FontMedium, "Loading...", new Rectangle(Float2.Zero, size), Color.White, TextAlignment.Center, TextAlignment.Center);
|
||||
Render2D.DrawText(Style.Current.FontMedium, "Loading...", bounds, Color.White, TextAlignment.Center, TextAlignment.Center);
|
||||
return;
|
||||
}
|
||||
|
||||
Render2D.PushClip(new Rectangle(Float2.Zero, size));
|
||||
Render2D.PushClip(bounds);
|
||||
|
||||
var meshDatas = Window._meshData.MeshDatas;
|
||||
var lodIndex = Mathf.Clamp(_lod, 0, meshDatas.Length - 1);
|
||||
@@ -230,12 +348,12 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
if (_isolateIndex != -1 && _isolateIndex != meshIndex)
|
||||
continue;
|
||||
DrawMeshUVs(meshIndex, ref lod[meshIndex]);
|
||||
DrawMeshUVs(meshIndex, ref lod[meshIndex], ref bounds);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawMeshUVs(mesh, ref lod[mesh]);
|
||||
DrawMeshUVs(mesh, ref lod[mesh], ref bounds);
|
||||
}
|
||||
|
||||
Render2D.PopClip();
|
||||
|
||||
@@ -438,93 +438,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(ProxyEditor))]
|
||||
private sealed class UVsPropertiesProxy : PropertiesProxyBase
|
||||
private sealed class UVsPropertiesProxy : UVsPropertiesProxyBase
|
||||
{
|
||||
public enum UVChannel
|
||||
{
|
||||
None,
|
||||
TexCoord,
|
||||
LightmapUVs,
|
||||
};
|
||||
|
||||
private UVChannel _uvChannel = UVChannel.None;
|
||||
|
||||
[EditorOrder(0), EditorDisplay(null, "Preview UV Channel"), EnumDisplay(EnumDisplayAttribute.FormatMode.None)]
|
||||
[Tooltip("Set UV channel to preview.")]
|
||||
public UVChannel Channel
|
||||
{
|
||||
get => _uvChannel;
|
||||
set
|
||||
{
|
||||
if (_uvChannel == value)
|
||||
return;
|
||||
_uvChannel = value;
|
||||
Window._meshData?.RequestMeshData(Window._asset);
|
||||
}
|
||||
}
|
||||
|
||||
[EditorOrder(1), EditorDisplay(null, "LOD"), Limit(0, Model.MaxLODs), VisibleIf("ShowUVs")]
|
||||
[Tooltip("Level Of Detail index to preview UVs layout.")]
|
||||
public int LOD = 0;
|
||||
|
||||
[EditorOrder(2), EditorDisplay(null, "Mesh"), Limit(-1, 1000000), VisibleIf("ShowUVs")]
|
||||
[Tooltip("Mesh index to preview UVs layout. Use -1 for all meshes")]
|
||||
public int Mesh = -1;
|
||||
|
||||
private bool ShowUVs => _uvChannel != UVChannel.None;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnClean()
|
||||
{
|
||||
Channel = UVChannel.None;
|
||||
|
||||
base.OnClean();
|
||||
}
|
||||
|
||||
private class ProxyEditor : ProxyEditorBase
|
||||
{
|
||||
private UVsLayoutPreviewControl _uvsPreview;
|
||||
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var proxy = (UVsPropertiesProxy)Values[0];
|
||||
if (Utilities.Utils.OnAssetProperties(layout, proxy.Asset))
|
||||
return;
|
||||
|
||||
base.Initialize(layout);
|
||||
|
||||
_uvsPreview = layout.Custom<UVsLayoutPreviewControl>().CustomControl;
|
||||
_uvsPreview.Window = proxy.Window;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
if (_uvsPreview != null)
|
||||
{
|
||||
var proxy = (UVsPropertiesProxy)Values[0];
|
||||
switch (proxy._uvChannel)
|
||||
{
|
||||
case UVChannel.TexCoord: _uvsPreview.Channel = 0; break;
|
||||
case UVChannel.LightmapUVs: _uvsPreview.Channel = 1; break;
|
||||
default: _uvsPreview.Channel = -1; break;
|
||||
}
|
||||
_uvsPreview.LOD = proxy.LOD;
|
||||
_uvsPreview.Mesh = proxy.Mesh;
|
||||
_uvsPreview.HighlightIndex = proxy.Window._highlightIndex;
|
||||
_uvsPreview.IsolateIndex = proxy.Window._isolateIndex;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
_uvsPreview = null;
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(ProxyEditor))]
|
||||
|
||||
@@ -497,87 +497,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(ProxyEditor))]
|
||||
private sealed class UVsPropertiesProxy : PropertiesProxyBase
|
||||
private sealed class UVsPropertiesProxy : UVsPropertiesProxyBase
|
||||
{
|
||||
public enum UVChannel
|
||||
{
|
||||
None,
|
||||
TexCoord,
|
||||
};
|
||||
|
||||
private UVChannel _uvChannel = UVChannel.None;
|
||||
|
||||
[EditorOrder(0), EditorDisplay(null, "Preview UV Channel"), EnumDisplay(EnumDisplayAttribute.FormatMode.None)]
|
||||
[Tooltip("Set UV channel to preview.")]
|
||||
public UVChannel Channel
|
||||
{
|
||||
get => _uvChannel;
|
||||
set
|
||||
{
|
||||
if (_uvChannel == value)
|
||||
return;
|
||||
_uvChannel = value;
|
||||
Window._meshData?.RequestMeshData(Window._asset);
|
||||
}
|
||||
}
|
||||
|
||||
[EditorOrder(1), EditorDisplay(null, "LOD"), Limit(0, Model.MaxLODs), VisibleIf("ShowUVs")]
|
||||
[Tooltip("Level Of Detail index to preview UVs layout.")]
|
||||
public int LOD = 0;
|
||||
|
||||
[EditorOrder(2), EditorDisplay(null, "Mesh"), Limit(-1, 1000000), VisibleIf("ShowUVs")]
|
||||
[Tooltip("Mesh index to preview UVs layout. Use -1 for all meshes")]
|
||||
public int Mesh = -1;
|
||||
|
||||
private bool ShowUVs => _uvChannel != UVChannel.None;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnClean()
|
||||
{
|
||||
Channel = UVChannel.None;
|
||||
|
||||
base.OnClean();
|
||||
}
|
||||
|
||||
private class ProxyEditor : ProxyEditorBase
|
||||
{
|
||||
private UVsLayoutPreviewControl _uvsPreview;
|
||||
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var proxy = (UVsPropertiesProxy)Values[0];
|
||||
if (Utilities.Utils.OnAssetProperties(layout, proxy.Asset))
|
||||
return;
|
||||
|
||||
base.Initialize(layout);
|
||||
|
||||
_uvsPreview = layout.Custom<UVsLayoutPreviewControl>().CustomControl;
|
||||
_uvsPreview.Window = proxy.Window;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
if (_uvsPreview != null)
|
||||
{
|
||||
var proxy = (UVsPropertiesProxy)Values[0];
|
||||
_uvsPreview.Channel = proxy._uvChannel == UVChannel.TexCoord ? 0 : -1;
|
||||
_uvsPreview.LOD = proxy.LOD;
|
||||
_uvsPreview.Mesh = proxy.Mesh;
|
||||
_uvsPreview.HighlightIndex = proxy.Window._highlightIndex;
|
||||
_uvsPreview.IsolateIndex = proxy.Window._isolateIndex;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
_uvsPreview = null;
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(ProxyEditor))]
|
||||
|
||||
@@ -167,23 +167,22 @@ void RawData::ToModelData(ModelData& modelData) const
|
||||
auto& surface = slot->Surfaces[i];
|
||||
vertexCount += surface.Vertices.Count();
|
||||
}
|
||||
mesh->EnsureCapacity(vertexCount, vertexCount, false, false);
|
||||
mesh->EnsureCapacity(vertexCount, vertexCount, false, false, false, 2);
|
||||
|
||||
// Write surfaces into vertex and index buffers
|
||||
int32 index = 0;
|
||||
for (int32 i = 0; i < slot->Surfaces.Count(); i++)
|
||||
{
|
||||
auto& surface = slot->Surfaces[i];
|
||||
|
||||
auto& surface = slot->Surfaces.Get()[i];
|
||||
for (int32 vIndex = 0; vIndex < surface.Vertices.Count(); vIndex++)
|
||||
{
|
||||
auto& v = surface.Vertices[vIndex];
|
||||
auto& v = surface.Vertices.Get()[vIndex];
|
||||
|
||||
mesh->Positions.Add(v.Position);
|
||||
mesh->UVs.Add(v.TexCoord);
|
||||
mesh->UVs.Get()[0].Add(v.TexCoord);
|
||||
mesh->UVs.Get()[1].Add(v.LightmapUVs * surface.UVsArea.Size + surface.UVsArea.Location);
|
||||
mesh->Normals.Add(v.Normal);
|
||||
mesh->Tangents.Add(v.Tangent);
|
||||
mesh->LightmapUVs.Add(v.LightmapUVs * surface.UVsArea.Size + surface.UVsArea.Location);
|
||||
|
||||
mesh->Indices.Add(index++);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Config.h"
|
||||
#include "Engine/Core/Math/Vector2.h"
|
||||
#include "Engine/Core/Math/Vector3.h"
|
||||
#include "Engine/Level/Actors/BrushMode.h"
|
||||
|
||||
namespace CSG
|
||||
|
||||
@@ -562,11 +562,13 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
LOG(Warning, "Cannot save model with empty meshes.");
|
||||
return true;
|
||||
}
|
||||
bool hasUVs = mesh.UVs.HasItems();
|
||||
if (hasUVs && (uint32)mesh.UVs.Count() != vertices)
|
||||
for (auto& channel : mesh.UVs)
|
||||
{
|
||||
LOG(Error, "Invalid size of {0} stream.", TEXT("UVs"));
|
||||
return true;
|
||||
if ((uint32)channel.Count() != vertices)
|
||||
{
|
||||
LOG(Error, "Invalid size of {0} stream.", TEXT("UVs"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool hasNormals = mesh.Normals.HasItems();
|
||||
if (hasNormals && (uint32)mesh.Normals.Count() != vertices)
|
||||
@@ -586,12 +588,6 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
LOG(Error, "Invalid size of {0} stream.", TEXT("BitangentSigns"));
|
||||
return true;
|
||||
}
|
||||
bool hasLightmapUVs = mesh.LightmapUVs.HasItems();
|
||||
if (hasLightmapUVs && (uint32)mesh.LightmapUVs.Count() != vertices)
|
||||
{
|
||||
LOG(Error, "Invalid size of {0} stream.", TEXT("LightmapUVs"));
|
||||
return true;
|
||||
}
|
||||
bool hasColors = mesh.Colors.HasItems();
|
||||
if (hasColors && (uint32)mesh.Colors.Count() != vertices)
|
||||
{
|
||||
@@ -626,7 +622,6 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
byte vbIndex = 0;
|
||||
// TODO: add option to quantize vertex positions (eg. 16-bit)
|
||||
// TODO: add option to quantize vertex attributes (eg. 8-bit blend weights, 8-bit texcoords)
|
||||
// TODO: add support for 16-bit blend indices (up to 65535 bones)
|
||||
|
||||
// Position
|
||||
if (useSeparatePositions)
|
||||
@@ -641,10 +636,14 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
auto& vb = vbElements.AddOne();
|
||||
if (!useSeparatePositions)
|
||||
vb.Add({ VertexElement::Types::Position, vbIndex, 0, 0, PixelFormat::R32G32B32_Float });
|
||||
if (hasUVs)
|
||||
vb.Add({ VertexElement::Types::TexCoord, vbIndex, 0, 0, PixelFormat::R16G16_Float });
|
||||
if (hasLightmapUVs)
|
||||
vb.Add({ VertexElement::Types::TexCoord1, vbIndex, 0, 0, PixelFormat::R16G16_Float });
|
||||
for (int32 channelIdx = 0; channelIdx < mesh.UVs.Count(); channelIdx++)
|
||||
{
|
||||
auto& channel = mesh.UVs.Get()[channelIdx];
|
||||
if (channel.HasItems())
|
||||
{
|
||||
vb.Add({ (VertexElement::Types)((int32)VertexElement::Types::TexCoord0 + channelIdx), vbIndex, 0, 0, PixelFormat::R16G16_Float });
|
||||
}
|
||||
}
|
||||
vb.Add({ VertexElement::Types::Normal, vbIndex, 0, 0, PixelFormat::R10G10B10A2_UNorm });
|
||||
vb.Add({ VertexElement::Types::Tangent, vbIndex, 0, 0, PixelFormat::R10G10B10A2_UNorm });
|
||||
if (isSkinned)
|
||||
@@ -745,20 +744,16 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
break;
|
||||
}
|
||||
case VertexElement::Types::TexCoord0:
|
||||
case VertexElement::Types::TexCoord1:
|
||||
case VertexElement::Types::TexCoord2:
|
||||
case VertexElement::Types::TexCoord3:
|
||||
{
|
||||
const Float2 uv = hasUVs ? mesh.UVs.Get()[vertex] : Float2::Zero;
|
||||
const int32 channelIdx = (int32)element.Type - (int32)VertexElement::Types::TexCoord0;
|
||||
const Float2 uv = mesh.UVs.Get()[channelIdx].Get()[vertex];
|
||||
const Half2 uvEnc(uv);
|
||||
stream.Write(uvEnc);
|
||||
break;
|
||||
}
|
||||
case VertexElement::Types::TexCoord1:
|
||||
{
|
||||
// TODO: refactor LightmapUVs into a generic TexCoord channel and support up to 4 UVs
|
||||
const Float2 lightmapUV = hasLightmapUVs ? mesh.LightmapUVs.Get()[vertex] : Float2::Zero;
|
||||
const Half2 lightmapUVEnc(lightmapUV);
|
||||
stream.Write(lightmapUVEnc);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG(Error, "Unsupported vertex element: {}", element.ToString());
|
||||
return true;
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
#include "Engine/Engine/Engine.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Streaming/StreamingGroup.h"
|
||||
#include "Engine/Threading/ThreadPoolTask.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Graphics/RenderTools.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Graphics/Models/ModelInstanceEntry.h"
|
||||
#include "Engine/Graphics/Models/Config.h"
|
||||
#include "Engine/Graphics/Models/MeshDeformation.h"
|
||||
#include "Engine/Graphics/Models/ModelInstanceEntry.h"
|
||||
#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
#include "Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h"
|
||||
#include "Engine/Debug/Exceptions/ArgumentOutOfRangeException.h"
|
||||
#include "Engine/Graphics/Models/MeshDeformation.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
#if USE_EDITOR
|
||||
|
||||
@@ -132,7 +132,10 @@ void RepackMeshLightmapUVs(ModelData& data)
|
||||
{
|
||||
Float2 uvOffset(entry.Slot->X * atlasSizeInv, entry.Slot->Y * atlasSizeInv);
|
||||
Float2 uvScale(entry.Slot->Width * atlasSizeInv, entry.Slot->Height * atlasSizeInv);
|
||||
for (auto& uv : entry.Mesh->LightmapUVs)
|
||||
if (entry.Mesh->LightmapUVsIndex == -1)
|
||||
continue;
|
||||
auto& lightmapUVs = entry.Mesh->UVs[entry.Mesh->LightmapUVsIndex];
|
||||
for (auto& uv : lightmapUVs)
|
||||
{
|
||||
uv = uv * uvScale + uvOffset;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
/// <summary>
|
||||
/// Current materials shader version.
|
||||
/// </summary>
|
||||
#define MATERIAL_GRAPH_VERSION 170
|
||||
#define MATERIAL_GRAPH_VERSION 171
|
||||
|
||||
class Material;
|
||||
class GPUShader;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -325,6 +325,8 @@ LPCSTR RenderToolsDX::GetVertexInputSemantic(VertexElement::Types type, UINT& se
|
||||
case VertexElement::Types::Attribute3:
|
||||
semanticIndex = 3;
|
||||
return "ATTRIBUTE";
|
||||
case VertexElement::Types::Lightmap:
|
||||
return "LIGHTMAP";
|
||||
default:
|
||||
LOG(Fatal, "Invalid vertex shader element semantic type");
|
||||
return "";
|
||||
|
||||
@@ -488,6 +488,8 @@ VertexElement::Types ShaderCompiler::ParseVertexElementType(StringAnsiView seman
|
||||
return VertexElement::Types::Tangent;
|
||||
if (semantic == "BLENDINDICES")
|
||||
return VertexElement::Types::BlendIndices;
|
||||
if (semantic == "LIGHTMAP")
|
||||
return VertexElement::Types::Lightmap;
|
||||
if (semantic == "BLENDWEIGHTS" ||
|
||||
semantic == "BLENDWEIGHT") // [Deprecated in v1.10]
|
||||
return VertexElement::Types::BlendWeights;
|
||||
|
||||
@@ -189,8 +189,20 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
|
||||
}
|
||||
// TexCoord
|
||||
case 2:
|
||||
value = getUVs;
|
||||
{
|
||||
const auto layer = GetRootLayer();
|
||||
if (layer && layer->Domain == MaterialDomain::Surface)
|
||||
{
|
||||
const uint32 channel = node->Values.HasItems() ? Math::Min((uint32)node->Values[0], 3u) : 0u;
|
||||
value = Value(VariantType::Float2, String::Format(TEXT("input.TexCoords[{}]"), channel));
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: migrate all material domain templates to TexCoords array (of size MATERIAL_TEXCOORDS=1)
|
||||
value = getUVs;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Cube Texture
|
||||
case 3:
|
||||
{
|
||||
|
||||
@@ -15,7 +15,6 @@ MaterialLayer::MaterialLayer(const Guid& id)
|
||||
, ShadingModel(MaterialShadingModel::Lit)
|
||||
, MaskThreshold(0.3f)
|
||||
, OpacityThreshold(0.12f)
|
||||
, ParamIdsMappings(8)
|
||||
{
|
||||
ASSERT(ID.IsValid());
|
||||
}
|
||||
|
||||
@@ -246,13 +246,15 @@ bool ProcessMesh(ModelData& result, AssimpImporterData& data, const aiMesh* aMes
|
||||
mesh.Positions.Set((const Float3*)aMesh->mVertices, aMesh->mNumVertices);
|
||||
|
||||
// Texture coordinates
|
||||
if (aMesh->mTextureCoords[0])
|
||||
for (int32 channelIndex = 0; channelIndex < MODEL_MAX_UV && aMesh->mTextureCoords[channelIndex]; channelIndex++)
|
||||
{
|
||||
mesh.UVs.Resize(aMesh->mNumVertices, false);
|
||||
aiVector3D* a = aMesh->mTextureCoords[0];
|
||||
mesh.UVs.Resize(channelIndex + 1);
|
||||
auto& channel = mesh.UVs[channelIndex];
|
||||
channel.Resize(aMesh->mNumVertices, false);
|
||||
aiVector3D* a = aMesh->mTextureCoords[channelIndex];
|
||||
for (uint32 v = 0; v < aMesh->mNumVertices; v++)
|
||||
{
|
||||
mesh.UVs[v] = *(Float2*)a;
|
||||
channel.Get()[v] = *(Float2*)a;
|
||||
a++;
|
||||
}
|
||||
}
|
||||
@@ -265,7 +267,7 @@ bool ProcessMesh(ModelData& result, AssimpImporterData& data, const aiMesh* aMes
|
||||
const auto face = &aMesh->mFaces[faceIndex];
|
||||
if (face->mNumIndices != 3)
|
||||
{
|
||||
errorMsg = TEXT("All faces in a mesh must be trangles!");
|
||||
errorMsg = TEXT("All faces in a mesh must be triangles!");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -296,57 +298,7 @@ bool ProcessMesh(ModelData& result, AssimpImporterData& data, const aiMesh* aMes
|
||||
}
|
||||
|
||||
// Lightmap UVs
|
||||
if (data.Options.LightmapUVsSource == ModelLightmapUVsSource::Disable)
|
||||
{
|
||||
// No lightmap UVs
|
||||
}
|
||||
else if (data.Options.LightmapUVsSource == ModelLightmapUVsSource::Generate)
|
||||
{
|
||||
// Generate lightmap UVs
|
||||
if (mesh.GenerateLightmapUVs())
|
||||
{
|
||||
LOG(Error, "Failed to generate lightmap uvs");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Select input channel index
|
||||
int32 inputChannelIndex;
|
||||
switch (data.Options.LightmapUVsSource)
|
||||
{
|
||||
case ModelLightmapUVsSource::Channel0:
|
||||
inputChannelIndex = 0;
|
||||
break;
|
||||
case ModelLightmapUVsSource::Channel1:
|
||||
inputChannelIndex = 1;
|
||||
break;
|
||||
case ModelLightmapUVsSource::Channel2:
|
||||
inputChannelIndex = 2;
|
||||
break;
|
||||
case ModelLightmapUVsSource::Channel3:
|
||||
inputChannelIndex = 3;
|
||||
break;
|
||||
default:
|
||||
inputChannelIndex = INVALID_INDEX;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if has that channel texcoords
|
||||
if (inputChannelIndex >= 0 && inputChannelIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS && aMesh->mTextureCoords[inputChannelIndex])
|
||||
{
|
||||
mesh.LightmapUVs.Resize(aMesh->mNumVertices, false);
|
||||
aiVector3D* a = aMesh->mTextureCoords[inputChannelIndex];
|
||||
for (uint32 v = 0; v < aMesh->mNumVertices; v++)
|
||||
{
|
||||
mesh.LightmapUVs[v] = *(Float2*)a;
|
||||
a++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Warning, "Cannot import result lightmap uvs. Missing texcoords channel {0}.", inputChannelIndex);
|
||||
}
|
||||
}
|
||||
mesh.SetLightmapUVsSource(data.Options.LightmapUVsSource);
|
||||
|
||||
// Vertex Colors
|
||||
if (data.Options.ImportVertexColors && aMesh->mColors[0])
|
||||
|
||||
@@ -386,10 +386,12 @@ bool ProcessMesh(ImporterData& data, FbxMesh* fbxMesh, MeshData& mesh, String& e
|
||||
}
|
||||
|
||||
// Texture coordinates
|
||||
FbxGeometryElementUV* texcoords = fbxMesh->GetElementUV(0);
|
||||
if (texcoords)
|
||||
for (int32 channelIndex = 0; channelIndex < MODEL_MAX_UV && fbxMesh->GetElementUV(channelIndex); channelIndex++)
|
||||
{
|
||||
ReadLayerData(fbxMesh, *texcoords, mesh.UVs);
|
||||
FbxGeometryElementUV* texcoords = fbxMesh->GetElementUV(0);
|
||||
mesh.UVs.Resize(channelIndex + 1);
|
||||
auto& channel = mesh.UVs[channelIndex];
|
||||
ReadLayerData(fbxMesh, *texcoords, channel);
|
||||
}
|
||||
|
||||
// Normals
|
||||
@@ -405,53 +407,7 @@ bool ProcessMesh(ImporterData& data, FbxMesh* fbxMesh, MeshData& mesh, String& e
|
||||
}
|
||||
|
||||
// Lightmap UVs
|
||||
if (data.Options.LightmapUVsSource == ModelLightmapUVsSource::Disable)
|
||||
{
|
||||
// No lightmap UVs
|
||||
}
|
||||
else if (data.Options.LightmapUVsSource == ModelLightmapUVsSource::Generate)
|
||||
{
|
||||
// Generate lightmap UVs
|
||||
if (mesh.GenerateLightmapUVs())
|
||||
{
|
||||
// TODO: we could propagate this message to Debug Console in editor? or create interface to gather some msgs from importing service
|
||||
LOG(Warning, "Failed to generate lightmap uvs");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Select input channel index
|
||||
int32 inputChannelIndex;
|
||||
switch (data.Options.LightmapUVsSource)
|
||||
{
|
||||
case ModelLightmapUVsSource::Channel0:
|
||||
inputChannelIndex = 0;
|
||||
break;
|
||||
case ModelLightmapUVsSource::Channel1:
|
||||
inputChannelIndex = 1;
|
||||
break;
|
||||
case ModelLightmapUVsSource::Channel2:
|
||||
inputChannelIndex = 2;
|
||||
break;
|
||||
case ModelLightmapUVsSource::Channel3:
|
||||
inputChannelIndex = 3;
|
||||
break;
|
||||
default:
|
||||
inputChannelIndex = INVALID_INDEX;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if has that channel texcoords
|
||||
if (inputChannelIndex >= 0 && inputChannelIndex < fbxMesh->GetElementUVCount() && fbxMesh->GetElementUV(inputChannelIndex))
|
||||
{
|
||||
ReadLayerData(fbxMesh, *fbxMesh->GetElementUV(inputChannelIndex), mesh.LightmapUVs);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: we could propagate this message to Debug Console in editor? or create interface to gather some msgs from importing service
|
||||
LOG(Warning, "Cannot import model lightmap uvs. Missing texcoords channel {0}.", inputChannelIndex);
|
||||
}
|
||||
}
|
||||
mesh.SetLightmapUVsSource(data.Options.LightmapUVsSource);
|
||||
|
||||
// Vertex Colors
|
||||
if (data.Options.ImportVertexColors && fbxMesh->GetElementVertexColorCount() > 0)
|
||||
@@ -609,10 +565,11 @@ bool ProcessMesh(ImporterData& data, FbxMesh* fbxMesh, MeshData& mesh, String& e
|
||||
}
|
||||
|
||||
// Flip the Y in texcoords
|
||||
for (int32 i = 0; i < mesh.UVs.Count(); i++)
|
||||
mesh.UVs[i].Y = 1.0f - mesh.UVs[i].Y;
|
||||
for (int32 i = 0; i < mesh.LightmapUVs.Count(); i++)
|
||||
mesh.LightmapUVs[i].Y = 1.0f - mesh.LightmapUVs[i].Y;
|
||||
for (auto& channel : mesh.UVs)
|
||||
{
|
||||
for (int32 i = 0; i < channel.Count(); i++)
|
||||
channel[i].Y = 1.0f - channel[i].Y;
|
||||
}
|
||||
|
||||
// Handle missing material case (could never happen but it's better to be sure it will work)
|
||||
if (mesh.MaterialSlotIndex == -1)
|
||||
|
||||
@@ -690,7 +690,6 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
||||
const ofbx::GeometryPartition& partition = geometryData.getPartition(partitionIndex);
|
||||
const int vertexCount = partition.triangles_count * 3;
|
||||
const ofbx::Vec3Attributes& positions = geometryData.getPositions();
|
||||
const ofbx::Vec2Attributes& uvs = geometryData.getUVs();
|
||||
const ofbx::Vec3Attributes& normals = geometryData.getNormals();
|
||||
const ofbx::Vec3Attributes& tangents = geometryData.getTangents();
|
||||
const ofbx::Vec4Attributes& colors = geometryData.getColors();
|
||||
@@ -723,15 +722,18 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
||||
mesh.Indices.Get()[i] = i;
|
||||
|
||||
// Texture coordinates
|
||||
if (uvs.values)
|
||||
for (int32 channelIndex = 0; channelIndex < MODEL_MAX_UV && geometryData.getUVs(channelIndex).values; channelIndex++)
|
||||
{
|
||||
mesh.UVs.Resize(vertexCount, false);
|
||||
const ofbx::Vec2Attributes& uvs = geometryData.getUVs(channelIndex);
|
||||
mesh.UVs.Resize(channelIndex + 1);
|
||||
auto& channel = mesh.UVs[channelIndex];
|
||||
channel.Resize(vertexCount, false);
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
mesh.UVs.Get()[i] = ToFloat2(uvs.get(triangulatedIndices[i]));
|
||||
channel.Get()[i] = ToFloat2(uvs.get(triangulatedIndices[i]));
|
||||
if (data.ConvertRH)
|
||||
{
|
||||
for (int32 v = 0; v < vertexCount; v++)
|
||||
mesh.UVs[v].Y = 1.0f - mesh.UVs[v].Y;
|
||||
for (int v = 0; v < vertexCount; v++)
|
||||
channel.Get()[v].Y = 1.0f - channel.Get()[v].Y;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -776,59 +778,7 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
||||
}
|
||||
|
||||
// Lightmap UVs
|
||||
if (data.Options.LightmapUVsSource == ModelLightmapUVsSource::Disable)
|
||||
{
|
||||
// No lightmap UVs
|
||||
}
|
||||
else if (data.Options.LightmapUVsSource == ModelLightmapUVsSource::Generate)
|
||||
{
|
||||
// Generate lightmap UVs
|
||||
if (mesh.GenerateLightmapUVs())
|
||||
{
|
||||
LOG(Error, "Failed to generate lightmap uvs");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Select input channel index
|
||||
int32 inputChannelIndex;
|
||||
switch (data.Options.LightmapUVsSource)
|
||||
{
|
||||
case ModelLightmapUVsSource::Channel0:
|
||||
inputChannelIndex = 0;
|
||||
break;
|
||||
case ModelLightmapUVsSource::Channel1:
|
||||
inputChannelIndex = 1;
|
||||
break;
|
||||
case ModelLightmapUVsSource::Channel2:
|
||||
inputChannelIndex = 2;
|
||||
break;
|
||||
case ModelLightmapUVsSource::Channel3:
|
||||
inputChannelIndex = 3;
|
||||
break;
|
||||
default:
|
||||
inputChannelIndex = INVALID_INDEX;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if has that channel texcoords
|
||||
const auto lightmapUVs = geometryData.getUVs(inputChannelIndex);
|
||||
if (lightmapUVs.values)
|
||||
{
|
||||
mesh.LightmapUVs.Resize(vertexCount, false);
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
mesh.LightmapUVs.Get()[i] = ToFloat2(lightmapUVs.get(triangulatedIndices[i]));
|
||||
if (data.ConvertRH)
|
||||
{
|
||||
for (int32 v = 0; v < vertexCount; v++)
|
||||
mesh.LightmapUVs[v].Y = 1.0f - mesh.LightmapUVs[v].Y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Warning, "Cannot import model lightmap uvs. Missing texcoords channel {0}.", inputChannelIndex);
|
||||
}
|
||||
}
|
||||
mesh.SetLightmapUVsSource(data.Options.LightmapUVsSource);
|
||||
|
||||
// Vertex Colors
|
||||
if (data.Options.ImportVertexColors && colors.values)
|
||||
|
||||
@@ -2027,11 +2027,14 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
|
||||
meshopt_remapVertexBuffer(dstMesh->name.Get(), srcMesh->name.Get(), srcMeshVertexCount, sizeof(type), remap.Get()); \
|
||||
}
|
||||
REMAP_VERTEX_BUFFER(Positions, Float3);
|
||||
REMAP_VERTEX_BUFFER(UVs, Float2);
|
||||
dstMesh->UVs.Resize(srcMesh->UVs.Count());
|
||||
for (int32 channelIdx = 0; channelIdx < srcMesh->UVs.Count(); channelIdx++)
|
||||
{
|
||||
REMAP_VERTEX_BUFFER(UVs[channelIdx], Float2);
|
||||
}
|
||||
REMAP_VERTEX_BUFFER(Normals, Float3);
|
||||
REMAP_VERTEX_BUFFER(Tangents, Float3);
|
||||
REMAP_VERTEX_BUFFER(Tangents, Float3);
|
||||
REMAP_VERTEX_BUFFER(LightmapUVs, Float2);
|
||||
REMAP_VERTEX_BUFFER(Colors, Color);
|
||||
REMAP_VERTEX_BUFFER(BlendIndices, Int4);
|
||||
REMAP_VERTEX_BUFFER(BlendWeights, Float4);
|
||||
|
||||
@@ -126,8 +126,7 @@ RenderCacheVSOutput VS_RenderCacheTerrain(TerrainVertexInput input)
|
||||
output.WorldNormal = tangentToWorld[2];
|
||||
|
||||
// Transform lightmap UV to clip-space
|
||||
float2 texCoord = input.TexCoord;
|
||||
float2 lightmapUV = texCoord * LightmapArea.zw + LightmapArea.xy;
|
||||
float2 lightmapUV = input.TexCoord * LightmapArea.zw + LightmapArea.xy;
|
||||
lightmapUV.y = 1.0 - lightmapUV.y;
|
||||
lightmapUV.xy = lightmapUV.xy * 2.0 - 1.0;
|
||||
output.Position = float4(lightmapUV, 0, 1);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
#define MATERIAL 1
|
||||
#define MATERIAL_TEXCOORDS 4
|
||||
|
||||
#include "./Flax/Common.hlsl"
|
||||
#include "./Flax/MaterialCommon.hlsl"
|
||||
@@ -19,20 +20,18 @@ Texture2D GridTexture : register(t0);
|
||||
|
||||
struct VertexOutput
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float3 WorldPosition : TEXCOORD0;
|
||||
float2 TexCoord : TEXCOORD1;
|
||||
float2 LightmapUV : TEXCOORD2;
|
||||
float3 WorldNormal : TEXCOORD3;
|
||||
float4 Position : SV_Position;
|
||||
float3 WorldPosition : TEXCOORD0;
|
||||
float2 LightmapUV : TEXCOORD1;
|
||||
float3 WorldNormal : TEXCOORD2;
|
||||
};
|
||||
|
||||
struct PixelInput
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float3 WorldPosition : TEXCOORD0;
|
||||
float2 TexCoord : TEXCOORD1;
|
||||
float2 LightmapUV : TEXCOORD2;
|
||||
float3 WorldNormal : TEXCOORD3;
|
||||
float4 Position : SV_Position;
|
||||
float3 WorldPosition : TEXCOORD0;
|
||||
float2 LightmapUV : TEXCOORD1;
|
||||
float3 WorldNormal : TEXCOORD2;
|
||||
};
|
||||
|
||||
float3x3 RemoveScaleFromLocalToWorld(float3x3 localToWorld)
|
||||
@@ -67,7 +66,6 @@ VertexOutput VS(ModelInput input)
|
||||
VertexOutput output;
|
||||
output.WorldPosition = mul(float4(input.Position.xyz, 1), WorldMatrix).xyz;
|
||||
output.Position = mul(float4(output.WorldPosition.xyz, 1), ViewProjectionMatrix);
|
||||
output.TexCoord = input.TexCoord;
|
||||
output.LightmapUV = input.LightmapUV * LightmapArea.zw + LightmapArea.xy;
|
||||
output.WorldNormal = tangentToWorld[2];
|
||||
return output;
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
#ifndef MATERIAL_SHADING_MODEL
|
||||
#define MATERIAL_SHADING_MODEL SHADING_MODEL_LIT
|
||||
#endif
|
||||
#ifndef MATERIAL_TEXCOORDS
|
||||
#define MATERIAL_TEXCOORDS 1
|
||||
#endif
|
||||
#ifndef USE_INSTANCING
|
||||
#define USE_INSTANCING 0
|
||||
#endif
|
||||
@@ -186,10 +189,21 @@ cbuffer DrawData : register(b2)
|
||||
struct ModelInput
|
||||
{
|
||||
float3 Position : POSITION;
|
||||
float2 TexCoord : TEXCOORD0;
|
||||
#if MATERIAL_TEXCOORDS > 0
|
||||
float2 TexCoord0 : TEXCOORD0;
|
||||
#endif
|
||||
#if MATERIAL_TEXCOORDS > 1
|
||||
float2 TexCoord1 : TEXCOORD1;
|
||||
#endif
|
||||
#if MATERIAL_TEXCOORDS > 2
|
||||
float2 TexCoord2 : TEXCOORD2;
|
||||
#endif
|
||||
#if MATERIAL_TEXCOORDS > 3
|
||||
float2 TexCoord3 : TEXCOORD3;
|
||||
#endif
|
||||
float2 LightmapUV : LIGHTMAP;
|
||||
float4 Normal : NORMAL;
|
||||
float4 Tangent : TANGENT;
|
||||
float2 LightmapUV : TEXCOORD1;
|
||||
#if USE_VERTEX_COLOR
|
||||
half4 Color : COLOR;
|
||||
#endif
|
||||
@@ -209,7 +223,18 @@ struct ModelInput_PosOnly
|
||||
struct ModelInput_Skinned
|
||||
{
|
||||
float3 Position : POSITION;
|
||||
float2 TexCoord : TEXCOORD0;
|
||||
#if MATERIAL_TEXCOORDS > 0
|
||||
float2 TexCoord0 : TEXCOORD0;
|
||||
#endif
|
||||
#if MATERIAL_TEXCOORDS > 1
|
||||
float2 TexCoord1 : TEXCOORD1;
|
||||
#endif
|
||||
#if MATERIAL_TEXCOORDS > 2
|
||||
float2 TexCoord2 : TEXCOORD2;
|
||||
#endif
|
||||
#if MATERIAL_TEXCOORDS > 3
|
||||
float2 TexCoord3 : TEXCOORD3;
|
||||
#endif
|
||||
float4 Normal : NORMAL;
|
||||
float4 Tangent : TANGENT;
|
||||
uint4 BlendIndices : BLENDINDICES;
|
||||
|
||||
Reference in New Issue
Block a user