Skip to content

Commit

Permalink
[Rendering] Added ModelTransformUsage to decide how the original mode…
Browse files Browse the repository at this point in the history
…l transformation is used
  • Loading branch information
tebjan committed Jul 16, 2020
1 parent 6c9894e commit 560a78d
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 17 deletions.
11 changes: 11 additions & 0 deletions sources/engine/Stride.Engine/Engine/IInstancing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,21 @@

namespace Stride.Engine
{
public enum ModelTransformUsage
{
Replace,
PreMultiply,
PostMultiply
}

public interface IInstancing
{
int InstanceCount { get; }

BoundingBox BoundingBox { get; }

ModelTransformUsage ModelTransformUsage { get; }

void Update();
}
}
3 changes: 2 additions & 1 deletion sources/engine/Stride.Engine/Engine/InstanceComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ public sealed class InstanceComponent : ActivableEntityComponent
[Display("Instancing", Expand = ExpandRule.Always)]
public InstancingComponent Master
{
get => master;
get => master;
set
{
if (value != master)
{
// Reject instancing that isn't set
if (value != null && value.Type == null)
return;

Expand Down
4 changes: 4 additions & 0 deletions sources/engine/Stride.Engine/Engine/InstancingBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ public abstract class InstancingBase : IInstancing
[DataMemberIgnore]
public virtual BoundingBox BoundingBox { get; set; } = BoundingBox.Empty;

[DataMember(10)]
[Display("Model Transformation Usage")]
public virtual ModelTransformUsage ModelTransformUsage { get; set; }

public virtual void Update()
{

Expand Down
2 changes: 1 addition & 1 deletion sources/engine/Stride.Engine/Engine/InstancingComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ public sealed class InstancingComponent : ActivableEntityComponent
[DataMember(10)]
[NotNull]
[Display("Instancing Type", Expand = ExpandRule.Always)]
public IInstancing Type { get; set; }
public IInstancing Type { get; set; } = new InstancingEntityTransform();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ namespace Stride.Engine
[Display("EntityTransform")]
public class InstancingEntityTransform : InstancingUserArray
{
[DataMemberIgnore]
public override ModelTransformUsage ModelTransformUsage
{
get => ModelTransformUsage.Replace;
}

private readonly List<InstanceComponent> instances = new List<InstanceComponent>();

internal InstanceComponent GetInstanceAt(int instanceId)
Expand Down
2 changes: 1 addition & 1 deletion sources/engine/Stride.Engine/Engine/InstancingUserArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public override void Update()
{
if (WorldMatrices != null)
{
// Make sure inverse matrices are big enough
// Make sure inverse matrices array is big enough
if (WorldInverseMatrices.Length < InstanceCount)
{
WorldInverseMatrices = new Matrix[InstanceCount];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace Stride.Engine.Processors
public class InstancingProcessor : EntityProcessor<InstancingComponent, InstancingProcessor.InstancingData>, IEntityComponentRenderProcessor
{
private readonly Dictionary<ModelComponent, InstancingComponent> modelInstancingMap = new Dictionary<ModelComponent, InstancingComponent>();
private ModelRenderProcessor ModelRenderProcessor;

public class InstancingData
{
Expand Down Expand Up @@ -61,25 +62,70 @@ private void UpdateInstancing(InstancingComponent instancingComponent, Instancin
var meshInfo = instancingData.ModelComponent.MeshInfos[i];

// This must reflect the transformations in the shaders
var ibb = new BoundingBoxExt(instancing.BoundingBox);
var mbb = new BoundingBoxExt(meshInfo.BoundingBox);

// We need to remove the world transformation component
//if (mesh.Skinning != null && instancingData.ModelComponent.Skeleton != null)
// This is currently not entirely correct, it ignores cases with extreme scalings
switch (instancing.ModelTransformUsage)
{
Matrix.Invert(ref instancingData.ModelComponent.Skeleton.NodeTransformations[0].LocalMatrix, out var invWorld);
mbb.Transform(invWorld);
case ModelTransformUsage.Replace:
BoundingBoxReplaceWorld(instancingData, instancing, meshInfo, mesh);
break;
case ModelTransformUsage.PreMultiply:
BoundingBoxPreMultiplyWorld(instancingData, instancing, meshInfo, mesh);
break;
case ModelTransformUsage.PostMultiply:
BoundingBoxPostMultiplyWorld(instancingData, instancing, meshInfo, mesh);
break;
default:
break;
}

// ibb.Transform(instancingData.TransformComponent.WorldMatrix);
var center = ibb.Center;// - instancingData.TransformComponent.WorldMatrix.TranslationVector;
var extend = mbb.Extent + ibb.Extent;
meshInfo.BoundingBox = new BoundingBox(center - extend, center + extend);
}
}
}
}
}

private static void BoundingBoxReplaceWorld(InstancingData instancingData, IInstancing instancing, ModelComponent.MeshInfo meshInfo, Mesh mesh)
{
// We need to remove the world transformation component
if (instancingData.ModelComponent.Skeleton != null)
{
var ibb = instancing.BoundingBox;
var mbb = new BoundingBoxExt(meshInfo.BoundingBox);

Matrix.Invert(ref instancingData.ModelComponent.Skeleton.NodeTransformations[0].LocalMatrix, out var invWorld);
mbb.Transform(invWorld);

var center = ibb.Center;
var extend = ibb.Extent + mbb.Extent;
meshInfo.BoundingBox = new BoundingBox(center - extend, center + extend);
}
else // Just take the original mesh one
{
var ibb = instancing.BoundingBox;

var center = ibb.Center;
var extend = ibb.Extent + mesh.BoundingBox.Extent;
meshInfo.BoundingBox = new BoundingBox(center - extend, center + extend);
}
}

private static void BoundingBoxPreMultiplyWorld(InstancingData instancingData, IInstancing instancing, ModelComponent.MeshInfo meshInfo, Mesh mesh)
{

var ibb = instancing.BoundingBox;

var center = meshInfo.BoundingBox.Center;
var extend = ibb.Extent + meshInfo.BoundingBox.Extent;
meshInfo.BoundingBox = new BoundingBox(center - extend, center + extend);
}

private static void BoundingBoxPostMultiplyWorld(InstancingData instancingData, IInstancing instancing, ModelComponent.MeshInfo meshInfo, Mesh mesh)
{
var ibb = new BoundingBoxExt(instancing.BoundingBox);
ibb.Transform(instancingData.TransformComponent.WorldMatrix);
var center = meshInfo.BoundingBox.Center + ibb.Center - instancingData.TransformComponent.WorldMatrix.TranslationVector; // World translation was applied twice now
var extend = meshInfo.BoundingBox.Extent + ibb.Extent;
meshInfo.BoundingBox = new BoundingBox(center - extend, center + extend);
}

protected override void OnEntityComponentAdding(Entity entity, [NotNull] InstancingComponent component, [NotNull] InstancingData data)
{
data.TransformComponent = component.Entity.Get<TransformComponent>();
Expand Down Expand Up @@ -110,6 +156,8 @@ protected internal override void OnSystemAdd()
{
base.OnSystemAdd();
VisibilityGroup.Tags.Set(InstancingRenderFeature.ModelToInstancingMap, modelInstancingMap);

ModelRenderProcessor = EntityManager.GetProcessor<ModelRenderProcessor>();
}

protected internal override void OnSystemRemove()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public struct InstancingData
public bool BuffersManagedByUser;
public Buffer<Matrix> InstanceWorldBuffer;
public Buffer<Matrix> InstanceWorldInverseBuffer;
public int ModelTransformUsage;
}

public class InstancingRenderFeature : SubRenderFeature
Expand Down Expand Up @@ -79,6 +80,7 @@ public override void Extract()
if (instancingComponent.Enabled && instancingBase.InstanceCount > 0)
{
instancingData.InstanceCount = instancingBase.InstanceCount;
instancingData.ModelTransformUsage = (int)instancingBase.ModelTransformUsage;

if (instancingBase is InstancingUserBuffer instancingUserBuffer)
{
Expand Down Expand Up @@ -146,6 +148,7 @@ public override void PrepareEffectPermutations(RenderDrawContext context)
if (renderEffect != null)
{
renderEffect.EffectValidator.ValidateParameter(StrideEffectBaseKeys.ModelTransformUsage, instancingData.ModelTransformUsage);
renderEffect.EffectValidator.ValidateParameter(StrideEffectBaseKeys.HasInstancing, instancingData.InstanceCount > 0);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace Stride.Rendering

if (StrideEffectBaseKeys.HasInstancing)
{
mixin macro StrideEffectBaseKeys.ModelTransformUsage;
mixin TransformationWAndVPInstanced;
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public void Generate(ShaderMixinSource mixin, ShaderMixinContext context)
context.Mixin(mixin, "NormalStream");
if (context.GetParam(StrideEffectBaseKeys.HasInstancing))
{
mixin.AddMacro("ModelTransformUsage", context.GetParam(StrideEffectBaseKeys.ModelTransformUsage));
context.Mixin(mixin, "TransformationWAndVPInstanced");
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ public static class StrideEffectBaseKeys
public static readonly PermutationParameterKey<ShaderSource> RenderTargetExtensions = ParameterKeys.NewPermutation<ShaderSource>();

public static readonly PermutationParameterKey<bool> HasInstancing = ParameterKeys.NewPermutation<bool>();

public static readonly PermutationParameterKey<int> ModelTransformUsage = ParameterKeys.NewPermutation<int>();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
shader TransformationInstancing : TransformationBase
#ifndef ModelTransformUsage
# define ModelTransformUsage 0
#endif

shader TransformationInstancing : TransformationBase, Transformation
{
struct InstanceTransform
{
Expand All @@ -13,11 +17,23 @@ shader TransformationInstancing : TransformationBase

float4x4 GetInstanceWorld()
{
#if ModelTransformUsage == 0
return InstanceWorld[streams.InstanceID].Matrix;
#elif ModelTransformUsage == 1
return mul(Transformation.World, InstanceWorld[streams.InstanceID].Matrix);
#else
return mul(InstanceWorld[streams.InstanceID].Matrix, Transformation.World);
#endif
}

float4x4 GetInstanceWorldInverse()
{
#if ModelTransformUsage == 0
return InstanceWorldInverse[streams.InstanceID].Matrix;
#elif ModelTransformUsage == 1
return mul(InstanceWorldInverse[streams.InstanceID].Matrix, Transformation.WorldInverse);
#else
return mul(Transformation.WorldInverse, InstanceWorldInverse[streams.InstanceID].Matrix);
#endif
}
};

0 comments on commit 560a78d

Please sign in to comment.