Add various improvements to MeshAccessor such as ComputeNormals and ComputeTangents
https://forum.flaxengine.com/t/how-to-create-procedural-generated-geometry-using-meshaccessor/2420
This commit is contained in:
@@ -428,6 +428,20 @@ namespace FlaxEngine
|
||||
|
||||
partial struct VertexElement : IEquatable<VertexElement>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates the vertex element description.
|
||||
/// </summary>
|
||||
/// <param name="type">Element type.</param>
|
||||
/// <param name="format">Data format.</param>
|
||||
public VertexElement(Types type, PixelFormat format)
|
||||
{
|
||||
Type = type;
|
||||
Slot = 0;
|
||||
Offset = 0;
|
||||
PerInstance = 0;
|
||||
Format = format;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the vertex element description.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace FlaxEngine
|
||||
@@ -466,6 +467,17 @@ namespace FlaxEngine
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if stream is valid.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to check.</param>
|
||||
/// <returns>True if stream is valid, otherwise false.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator bool(Stream stream)
|
||||
{
|
||||
return stream.IsValid;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[][] _data = new byte[(int)MeshBufferType.MAX][];
|
||||
@@ -586,19 +598,19 @@ namespace FlaxEngine
|
||||
bool use16BitIndexBuffer = false;
|
||||
IntPtr[] vbData = new IntPtr[3];
|
||||
GPUVertexLayout[] vbLayout = new GPUVertexLayout[3];
|
||||
if (_data[VB0] != null)
|
||||
if (_data[VB0] != null && _data[VB0].Length != 0)
|
||||
{
|
||||
vbData[0] = dataPtr[VB0];
|
||||
vbLayout[0] = _layouts[VB0];
|
||||
vertices = (uint)_data[VB0].Length / _layouts[VB0].Stride;
|
||||
}
|
||||
if (_data[VB1] != null)
|
||||
if (_data[VB1] != null && _data[VB1].Length != 0)
|
||||
{
|
||||
vbData[1] = dataPtr[VB1];
|
||||
vbLayout[1] = _layouts[VB1];
|
||||
vertices = (uint)_data[VB1].Length / _layouts[VB1].Stride;
|
||||
}
|
||||
if (_data[VB2] != null)
|
||||
if (_data[VB2] != null && _data[VB2].Length != 0)
|
||||
{
|
||||
vbData[2] = dataPtr[VB2];
|
||||
vbLayout[2] = _layouts[VB2];
|
||||
@@ -798,6 +810,16 @@ namespace FlaxEngine
|
||||
set => SetStreamFloat3(VertexElement.Types.Normal, value, PackNormal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the vertex tangent vectors (unpacked, normalized). Null if <see cref="VertexElement.Types.Tangent"/> does not exist in vertex buffers of the mesh.
|
||||
/// </summary>
|
||||
/// <remarks>Uses <see cref="Tangent"/> stream to read or write data to the vertex buffer.</remarks>
|
||||
public Float3[] Tangents
|
||||
{
|
||||
get => GetStreamFloat3(VertexElement.Types.Tangent, UnpackNormal);
|
||||
set => SetStreamFloat3(VertexElement.Types.Tangent, value, PackNormal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the vertex UVs (texcoord channel 0). Null if <see cref="VertexElement.Types.TexCoord"/> does not exist in vertex buffers of the mesh.
|
||||
/// </summary>
|
||||
@@ -808,6 +830,70 @@ namespace FlaxEngine
|
||||
set => SetStreamFloat2(VertexElement.Types.TexCoord, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recalculates normal vectors for all vertices.
|
||||
/// </summary>
|
||||
public void ComputeNormals()
|
||||
{
|
||||
var positions = Position();
|
||||
var indices = Index();
|
||||
if (!positions)
|
||||
throw new Exception("Cannot compute tangents without positions.");
|
||||
if (!indices)
|
||||
throw new Exception("Cannot compute tangents without indices.");
|
||||
if (!Normal())
|
||||
throw new Exception("Cannot compute tangents without Normal vertex element.");
|
||||
var vertexCount = positions.Count;
|
||||
if (vertexCount == 0)
|
||||
return;
|
||||
var indexCount = indices.Count;
|
||||
|
||||
// Compute per-face normals but store them per-vertex
|
||||
var normals = new Float3[vertexCount];
|
||||
for (int i = 0; i < indexCount; i += 3)
|
||||
{
|
||||
var i1 = indices.GetInt(i + 0);
|
||||
var i2 = indices.GetInt(i + 1);
|
||||
var i3 = indices.GetInt(i + 2);
|
||||
Float3 v1 = positions.GetFloat3(i1);
|
||||
Float3 v2 = positions.GetFloat3(i2);
|
||||
Float3 v3 = positions.GetFloat3(i3);
|
||||
Float3 n = Float3.Cross((v2 - v1), (v3 - v1)).Normalized;
|
||||
|
||||
normals[i1] += n;
|
||||
normals[i2] += n;
|
||||
normals[i3] += n;
|
||||
}
|
||||
|
||||
// Average normals
|
||||
for (int i = 0; i < normals.Length; i++)
|
||||
normals[i] = normals[i].Normalized;
|
||||
|
||||
// Write back to the buffer
|
||||
Normals = normals;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recalculates tangent vectors for all vertices based on normals.
|
||||
/// </summary>
|
||||
public void ComputeTangents()
|
||||
{
|
||||
var normals = Normal();
|
||||
var tangents = Tangent();
|
||||
if (!normals)
|
||||
throw new Exception("Cannot compute tangents without normals.");
|
||||
if (!tangents)
|
||||
throw new Exception("Cannot compute tangents without Tangent vertex element.");
|
||||
var count = normals.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Float3 normal = normals.GetFloat3(i);
|
||||
UnpackNormal(ref normal);
|
||||
RenderTools.CalculateTangentFrame(out var n, out var t, ref normal);
|
||||
tangents.SetFloat4(i, t);
|
||||
}
|
||||
}
|
||||
|
||||
private uint[] GetStreamUInt(Stream stream)
|
||||
{
|
||||
uint[] result = null;
|
||||
|
||||
@@ -38,6 +38,11 @@ public:
|
||||
bool IsValid() const;
|
||||
bool IsLinear(PixelFormat expectedFormat) const;
|
||||
|
||||
FORCE_INLINE operator bool() const
|
||||
{
|
||||
return IsValid();
|
||||
}
|
||||
|
||||
FORCE_INLINE int32 GetInt(int32 index) const
|
||||
{
|
||||
ASSERT_LOW_LAYER(index * _stride < _data.Length());
|
||||
|
||||
@@ -548,6 +548,13 @@ void RenderTools::ComputeCascadeUpdateFrequency(int32 cascadeIndex, int32 cascad
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderTools::ShouldUpdateCascade(int32 frameIndex, int32 cascadeIndex, int32 cascadeCount, int32 updateMaxCountPerFrame, bool updateForce)
|
||||
{
|
||||
int32 updateFrequency, updatePhrase;
|
||||
ComputeCascadeUpdateFrequency(cascadeIndex, cascadeCount, updateFrequency, updatePhrase, updateMaxCountPerFrame);
|
||||
return (frameIndex % updateFrequency == updatePhrase) || updateForce;
|
||||
}
|
||||
|
||||
float RenderTools::ComputeTemporalTime()
|
||||
{
|
||||
const float time = Time::Draw.UnscaledTime.GetTotalSeconds();
|
||||
|
||||
@@ -119,12 +119,7 @@ public:
|
||||
static void ComputeCascadeUpdateFrequency(int32 cascadeIndex, int32 cascadeCount, int32& updateFrequency, int32& updatePhrase, int32 updateMaxCountPerFrame = 1);
|
||||
|
||||
// Checks if cached data should be updated during the given frame.
|
||||
FORCE_INLINE static bool ShouldUpdateCascade(int32 frameIndex, int32 cascadeIndex, int32 cascadeCount, int32 updateMaxCountPerFrame = 1, bool updateForce = false)
|
||||
{
|
||||
int32 updateFrequency, updatePhrase;
|
||||
ComputeCascadeUpdateFrequency(cascadeIndex, cascadeCount, updateFrequency, updatePhrase, updateMaxCountPerFrame);
|
||||
return (frameIndex % updateFrequency == updatePhrase) || updateForce;
|
||||
}
|
||||
static bool ShouldUpdateCascade(int32 frameIndex, int32 cascadeIndex, int32 cascadeCount, int32 updateMaxCountPerFrame = 1, bool updateForce = false);
|
||||
|
||||
// Calculates temporal offset in the dithering factor that gets cleaned out by TAA.
|
||||
// Returns 0-1 value based on unscaled draw time for temporal effects to reduce artifacts from screen-space dithering when using Temporal Anti-Aliasing.
|
||||
@@ -136,8 +131,9 @@ public:
|
||||
DEPRECATED("Use CalculateTangentFrame with unpacked Float3/Float4.") static void CalculateTangentFrame(FloatR10G10B10A2& resultNormal, FloatR10G10B10A2& resultTangent, const Float3& normal, const Float3& tangent);
|
||||
|
||||
// Result normal/tangent are already packed into [0;1] range.
|
||||
static void CalculateTangentFrame(Float3& resultNormal, Float4& resultTangent, const Float3& normal);
|
||||
static void CalculateTangentFrame(Float3& resultNormal, Float4& resultTangent, const Float3& normal, const Float3& tangent);
|
||||
API_FUNCTION() static void CalculateTangentFrame(API_PARAM(Out) Float3& resultNormal, API_PARAM(Out) Float4& resultTangent, API_PARAM(Ref) const Float3& normal);
|
||||
// Result normal/tangent are already packed into [0;1] range.
|
||||
API_FUNCTION() static void CalculateTangentFrame(API_PARAM(Out) Float3& resultNormal, API_PARAM(Out) Float4& resultTangent, API_PARAM(Ref) const Float3& normal, API_PARAM(Ref) const Float3& tangent);
|
||||
|
||||
static void ComputeSphereModelDrawMatrix(const RenderView& view, const Float3& position, float radius, Matrix& resultWorld, bool& resultIsViewInside);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user