Add SortOrder to drawable object types for transparency sorting override
This commit is contained in:
@@ -275,12 +275,16 @@ namespace FlaxEditor.CustomEditors
|
||||
// Workaround for DefaultValueAttribute that doesn't support certain value types storage
|
||||
if (Type.Type == typeof(sbyte))
|
||||
_defaultValue = Convert.ToSByte(_defaultValue);
|
||||
else if (Type.Type == typeof(short))
|
||||
_defaultValue = Convert.ToInt16(_defaultValue);
|
||||
else if (Type.Type == typeof(ushort))
|
||||
_defaultValue = Convert.ToUInt16(_defaultValue);
|
||||
else if (Type.Type == typeof(uint))
|
||||
_defaultValue = Convert.ToUInt32(_defaultValue);
|
||||
else if (Type.Type == typeof(ulong))
|
||||
_defaultValue = Convert.ToUInt64(_defaultValue);
|
||||
else if (Type.Type == typeof(long))
|
||||
_defaultValue = Convert.ToInt64(_defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ void ViewportIconsRenderer::DrawIcons(RenderContext& renderContext, Actor* actor
|
||||
draw.PerInstanceRandom = 0;
|
||||
draw.LODBias = 0;
|
||||
draw.ForcedLOD = -1;
|
||||
draw.SortOrder = 0;
|
||||
draw.VertexColors = nullptr;
|
||||
|
||||
if (const auto scene = SceneObject::Cast<Scene>(actor))
|
||||
|
||||
@@ -1173,6 +1173,7 @@ void Foliage::Draw(RenderContext& renderContext)
|
||||
draw.Flags = GetStaticFlags();
|
||||
draw.LODBias = 0;
|
||||
draw.ForcedLOD = -1;
|
||||
draw.SortOrder = 0;
|
||||
draw.VertexColors = nullptr;
|
||||
draw.Lightmap = _scene->LightmapsData.GetReadyLightmap(instance.Lightmap.TextureIndex);
|
||||
draw.LightmapUVs = &instance.Lightmap.UVsArea;
|
||||
|
||||
@@ -408,7 +408,7 @@ void Mesh::Render(GPUContext* context) const
|
||||
context->DrawIndexedInstanced(_triangles * 3, 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, const Matrix& world, StaticFlags flags, bool receiveDecals, DrawPass drawModes, float perInstanceRandom) const
|
||||
void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, const Matrix& world, StaticFlags flags, bool receiveDecals, DrawPass drawModes, float perInstanceRandom, int16 sortOrder) const
|
||||
{
|
||||
if (!material || !material->IsSurface() || !IsInitialized())
|
||||
return;
|
||||
@@ -446,7 +446,7 @@ void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, cons
|
||||
#endif
|
||||
|
||||
// Push draw call to the render list
|
||||
renderContext.List->AddDrawCall(renderContext, drawModes, flags, drawCall, receiveDecals);
|
||||
renderContext.List->AddDrawCall(renderContext, drawModes, flags, drawCall, receiveDecals, sortOrder);
|
||||
}
|
||||
|
||||
void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float lodDitherFactor) const
|
||||
@@ -512,7 +512,7 @@ void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float
|
||||
#endif
|
||||
|
||||
// Push draw call to the render list
|
||||
renderContext.List->AddDrawCall(renderContext, drawModes, info.Flags, drawCall, entry.ReceiveDecals);
|
||||
renderContext.List->AddDrawCall(renderContext, drawModes, info.Flags, drawCall, entry.ReceiveDecals, info.SortOrder);
|
||||
}
|
||||
|
||||
void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& info, float lodDitherFactor) const
|
||||
|
||||
@@ -339,6 +339,11 @@ public:
|
||||
/// The forced LOD to use. Value -1 disables this feature.
|
||||
/// </summary>
|
||||
char ForcedLOD;
|
||||
|
||||
/// <summary>
|
||||
/// The object sorting key.
|
||||
/// </summary>
|
||||
int16 SortOrder;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -357,7 +362,8 @@ public:
|
||||
/// <param name="receiveDecals">True if rendered geometry can receive decals, otherwise false.</param>
|
||||
/// <param name="drawModes">The draw passes to use for rendering this object.</param>
|
||||
/// <param name="perInstanceRandom">The random per-instance value (normalized to range 0-1).</param>
|
||||
API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, DrawPass drawModes = DrawPass::Default, float perInstanceRandom = 0.0f) const;
|
||||
/// <param name="sortOrder">Object sorting key.</param>
|
||||
API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, DrawPass drawModes = DrawPass::Default, float perInstanceRandom = 0.0f, int16 sortOrder = 0) const;
|
||||
|
||||
/// <summary>
|
||||
/// Draws the mesh.
|
||||
|
||||
@@ -124,9 +124,7 @@ public:
|
||||
FORCE_INLINE void Render(GPUContext* context)
|
||||
{
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Meshes.Get()[i].Render(context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -139,12 +137,11 @@ public:
|
||||
/// <param name="receiveDecals">True if rendered geometry can receive decals, otherwise false.</param>
|
||||
/// <param name="drawModes">The draw passes to use for rendering this object.</param>
|
||||
/// <param name="perInstanceRandom">The random per-instance value (normalized to range 0-1).</param>
|
||||
API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, DrawPass drawModes = DrawPass::Default, float perInstanceRandom = 0.0f) const
|
||||
/// <param name="sortOrder">Object sorting key.</param>
|
||||
API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, DrawPass drawModes = DrawPass::Default, float perInstanceRandom = 0.0f, int16 sortOrder = 0) const
|
||||
{
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Meshes.Get()[i].Draw(renderContext, material, world, flags, receiveDecals, drawModes, perInstanceRandom);
|
||||
}
|
||||
Meshes.Get()[i].Draw(renderContext, material, world, flags, receiveDecals, drawModes, perInstanceRandom, sortOrder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -156,9 +153,7 @@ public:
|
||||
FORCE_INLINE void Draw(const RenderContext& renderContext, const Mesh::DrawInfo& info, float lodDitherFactor) const
|
||||
{
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Meshes.Get()[i].Draw(renderContext, info, lodDitherFactor);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -170,8 +165,6 @@ public:
|
||||
FORCE_INLINE void Draw(const RenderContextBatch& renderContextBatch, const Mesh::DrawInfo& info, float lodDitherFactor) const
|
||||
{
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Meshes.Get()[i].Draw(renderContextBatch, info, lodDitherFactor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -297,6 +297,7 @@ void Camera::Draw(RenderContext& renderContext)
|
||||
draw.PerInstanceRandom = GetPerInstanceRandom();
|
||||
draw.LODBias = 0;
|
||||
draw.ForcedLOD = -1;
|
||||
draw.SortOrder = 0;
|
||||
draw.VertexColors = nullptr;
|
||||
if (draw.DrawModes != DrawPass::None)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@ StaticModel::StaticModel(const SpawnParams& params)
|
||||
, _forcedLod(-1)
|
||||
, _vertexColorsDirty(false)
|
||||
, _vertexColorsCount(0)
|
||||
, _sortOrder(0)
|
||||
{
|
||||
_drawCategory = SceneRendering::SceneDrawAsync;
|
||||
Model.Changed.Bind<StaticModel, &StaticModel::OnModelChanged>(this);
|
||||
@@ -37,11 +38,21 @@ StaticModel::~StaticModel()
|
||||
SAFE_DELETE_GPU_RESOURCE(_vertexColorsBuffer[lodIndex]);
|
||||
}
|
||||
|
||||
float StaticModel::GetScaleInLightmap() const
|
||||
{
|
||||
return _scaleInLightmap;
|
||||
}
|
||||
|
||||
void StaticModel::SetScaleInLightmap(float value)
|
||||
{
|
||||
_scaleInLightmap = value;
|
||||
}
|
||||
|
||||
float StaticModel::GetBoundsScale() const
|
||||
{
|
||||
return _boundsScale;
|
||||
}
|
||||
|
||||
void StaticModel::SetBoundsScale(float value)
|
||||
{
|
||||
if (Math::NearEqual(_boundsScale, value))
|
||||
@@ -51,6 +62,46 @@ void StaticModel::SetBoundsScale(float value)
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
int32 StaticModel::GetLODBias() const
|
||||
{
|
||||
return _lodBias;
|
||||
}
|
||||
|
||||
void StaticModel::SetLODBias(int32 value)
|
||||
{
|
||||
_lodBias = static_cast<char>(Math::Clamp(value, -100, 100));
|
||||
}
|
||||
|
||||
int32 StaticModel::GetForcedLOD() const
|
||||
{
|
||||
return _forcedLod;
|
||||
}
|
||||
|
||||
void StaticModel::SetForcedLOD(int32 value)
|
||||
{
|
||||
_forcedLod = static_cast<char>(Math::Clamp(value, -1, 100));
|
||||
}
|
||||
|
||||
int32 StaticModel::GetSortOrder() const
|
||||
{
|
||||
return _sortOrder;
|
||||
}
|
||||
|
||||
void StaticModel::SetSortOrder(int32 value)
|
||||
{
|
||||
_sortOrder = (int16)Math::Clamp<int32>(value, MIN_int16, MAX_int16);
|
||||
}
|
||||
|
||||
bool StaticModel::HasLightmap() const
|
||||
{
|
||||
return Lightmap.TextureIndex != INVALID_INDEX;
|
||||
}
|
||||
|
||||
void StaticModel::RemoveLightmap()
|
||||
{
|
||||
Lightmap.TextureIndex = INVALID_INDEX;
|
||||
}
|
||||
|
||||
MaterialBase* StaticModel::GetMaterial(int32 meshIndex, int32 lodIndex) const
|
||||
{
|
||||
auto model = Model.Get();
|
||||
@@ -153,6 +204,11 @@ void StaticModel::SetVertexColor(int32 lodIndex, int32 meshIndex, int32 vertexIn
|
||||
LOG(Warning, "Specified model mesh index was out of range. LOD{0} mesh {1}.", lodIndex, meshIndex);
|
||||
}
|
||||
|
||||
bool StaticModel::HasVertexColors() const
|
||||
{
|
||||
return _vertexColorsCount != 0;
|
||||
}
|
||||
|
||||
void StaticModel::RemoveVertexColors()
|
||||
{
|
||||
for (int32 lodIndex = 0; lodIndex < _vertexColorsCount; lodIndex++)
|
||||
@@ -292,6 +348,7 @@ void StaticModel::Draw(RenderContext& renderContext)
|
||||
draw.PerInstanceRandom = GetPerInstanceRandom();
|
||||
draw.LODBias = _lodBias;
|
||||
draw.ForcedLOD = _forcedLod;
|
||||
draw.SortOrder = _sortOrder;
|
||||
draw.VertexColors = _vertexColorsCount ? _vertexColorsBuffer : nullptr;
|
||||
|
||||
Model->Draw(renderContext, draw);
|
||||
@@ -324,6 +381,7 @@ void StaticModel::Draw(RenderContextBatch& renderContextBatch)
|
||||
draw.PerInstanceRandom = GetPerInstanceRandom();
|
||||
draw.LODBias = _lodBias;
|
||||
draw.ForcedLOD = _forcedLod;
|
||||
draw.SortOrder = _sortOrder;
|
||||
draw.VertexColors = _vertexColorsCount ? _vertexColorsBuffer : nullptr;
|
||||
|
||||
Model->Draw(renderContextBatch, draw);
|
||||
@@ -356,6 +414,7 @@ void StaticModel::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
SERIALIZE(Model);
|
||||
SERIALIZE_MEMBER(LODBias, _lodBias);
|
||||
SERIALIZE_MEMBER(ForcedLOD, _forcedLod);
|
||||
SERIALIZE_MEMBER(SortOrder, _sortOrder);
|
||||
SERIALIZE(DrawModes);
|
||||
|
||||
if (HasLightmap()
|
||||
@@ -405,22 +464,9 @@ void StaticModel::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
|
||||
DESERIALIZE_MEMBER(ScaleInLightmap, _scaleInLightmap);
|
||||
DESERIALIZE_MEMBER(BoundsScale, _boundsScale);
|
||||
DESERIALIZE(Model);
|
||||
|
||||
{
|
||||
const auto member = stream.FindMember("LODBias");
|
||||
if (member != stream.MemberEnd() && member->value.IsInt())
|
||||
{
|
||||
SetLODBias(member->value.GetInt());
|
||||
}
|
||||
}
|
||||
{
|
||||
const auto member = stream.FindMember("ForcedLOD");
|
||||
if (member != stream.MemberEnd() && member->value.IsInt())
|
||||
{
|
||||
SetForcedLOD(member->value.GetInt());
|
||||
}
|
||||
}
|
||||
|
||||
DESERIALIZE_MEMBER(LODBias, _lodBias);
|
||||
DESERIALIZE_MEMBER(ForcedLOD, _forcedLod);
|
||||
DESERIALIZE_MEMBER(SortOrder, _sortOrder);
|
||||
DESERIALIZE(DrawModes);
|
||||
DESERIALIZE_MEMBER(LightmapIndex, Lightmap.TextureIndex);
|
||||
DESERIALIZE_MEMBER(LightmapArea, Lightmap.UVsArea);
|
||||
|
||||
@@ -21,6 +21,7 @@ private:
|
||||
char _forcedLod;
|
||||
bool _vertexColorsDirty;
|
||||
byte _vertexColorsCount;
|
||||
int16 _sortOrder;
|
||||
Array<Color32> _vertexColorsData[MODEL_MAX_LODS];
|
||||
GPUBuffer* _vertexColorsBuffer[MODEL_MAX_LODS];
|
||||
Model* _residencyChangedModel = nullptr;
|
||||
@@ -53,10 +54,7 @@ public:
|
||||
/// Gets the model scale in lightmap (applied to all the meshes).
|
||||
/// </summary>
|
||||
API_PROPERTY(Attributes="EditorOrder(10), DefaultValue(1.0f), EditorDisplay(\"Model\", \"Scale In Lightmap\"), Limit(0, 1000.0f, 0.1f)")
|
||||
FORCE_INLINE float GetScaleInLightmap() const
|
||||
{
|
||||
return _scaleInLightmap;
|
||||
}
|
||||
float GetScaleInLightmap() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the model scale in lightmap (applied to all the meshes).
|
||||
@@ -67,10 +65,7 @@ public:
|
||||
/// Gets the model bounds scale. It is useful when using Position Offset to animate the vertices of the object outside of its bounds. Increasing the bounds of an object will reduce performance.
|
||||
/// </summary>
|
||||
API_PROPERTY(Attributes="EditorOrder(12), DefaultValue(1.0f), EditorDisplay(\"Model\"), Limit(0, 10.0f, 0.1f)")
|
||||
FORCE_INLINE float GetBoundsScale() const
|
||||
{
|
||||
return _boundsScale;
|
||||
}
|
||||
float GetBoundsScale() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the model bounds scale. It is useful when using Position Offset to animate the vertices of the object outside of its bounds.
|
||||
@@ -81,51 +76,44 @@ public:
|
||||
/// Gets the model Level Of Detail bias value. Allows to increase or decrease rendered model quality.
|
||||
/// </summary>
|
||||
API_PROPERTY(Attributes="EditorOrder(40), DefaultValue(0), Limit(-100, 100, 0.1f), EditorDisplay(\"Model\", \"LOD Bias\")")
|
||||
FORCE_INLINE int32 GetLODBias() const
|
||||
{
|
||||
return static_cast<int32>(_lodBias);
|
||||
}
|
||||
int32 GetLODBias() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the model Level Of Detail bias value. Allows to increase or decrease rendered model quality.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetLODBias(int32 value)
|
||||
{
|
||||
_lodBias = static_cast<char>(Math::Clamp(value, -100, 100));
|
||||
}
|
||||
API_PROPERTY() void SetLODBias(int32 value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model forced Level Of Detail index. Allows to bind the given model LOD to show. Value -1 disables this feature.
|
||||
/// </summary>
|
||||
API_PROPERTY(Attributes="EditorOrder(50), DefaultValue(-1), Limit(-1, 100, 0.1f), EditorDisplay(\"Model\", \"Forced LOD\")")
|
||||
FORCE_INLINE int32 GetForcedLOD() const
|
||||
{
|
||||
return static_cast<int32>(_forcedLod);
|
||||
}
|
||||
int32 GetForcedLOD() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the model forced Level Of Detail index. Allows to bind the given model LOD to show. Value -1 disables this feature.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetForcedLOD(int32 value)
|
||||
{
|
||||
_forcedLod = static_cast<char>(Math::Clamp(value, -1, 100));
|
||||
}
|
||||
API_PROPERTY() void SetForcedLOD(int32 value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model sort order key used when sorting drawable objects during rendering. Use lower values to draw object before others, higher values are rendered later (on top). Can be use to control transparency drawing.
|
||||
/// </summary>
|
||||
API_PROPERTY(Attributes="EditorOrder(60), DefaultValue(0), EditorDisplay(\"Model\")")
|
||||
int32 GetSortOrder() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the model sort order key used when sorting drawable objects during rendering. Use lower values to draw object before others, higher values are rendered later (on top). Can be use to control transparency drawing.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetSortOrder(int32 value);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this model has valid lightmap data.
|
||||
/// </summary>
|
||||
API_PROPERTY() FORCE_INLINE bool HasLightmap() const
|
||||
{
|
||||
return Lightmap.TextureIndex != INVALID_INDEX;
|
||||
}
|
||||
API_PROPERTY() bool HasLightmap() const;
|
||||
|
||||
/// <summary>
|
||||
/// Removes the lightmap data from the model.
|
||||
/// </summary>
|
||||
API_FUNCTION() FORCE_INLINE void RemoveLightmap()
|
||||
{
|
||||
Lightmap.TextureIndex = INVALID_INDEX;
|
||||
}
|
||||
API_FUNCTION() void RemoveLightmap();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the material used to render mesh at given index (overriden by model instance buffer or model default).
|
||||
@@ -156,10 +144,7 @@ public:
|
||||
/// <summary>
|
||||
/// Returns true if model instance is using custom painted vertex colors buffer, otherwise it will use vertex colors from the original asset.
|
||||
/// </summary>
|
||||
API_PROPERTY() bool HasVertexColors() const
|
||||
{
|
||||
return _vertexColorsCount != 0;
|
||||
}
|
||||
API_PROPERTY() bool HasVertexColors() const;
|
||||
|
||||
/// <summary>
|
||||
/// Removes the vertex colors buffer from this instance.
|
||||
|
||||
@@ -576,6 +576,7 @@ void ParticleEffect::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
SERIALIZE(IsLooping);
|
||||
SERIALIZE(UpdateWhenOffscreen);
|
||||
SERIALIZE(DrawModes);
|
||||
SERIALIZE(SortOrder);
|
||||
}
|
||||
|
||||
void ParticleEffect::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
|
||||
@@ -674,6 +675,7 @@ void ParticleEffect::Deserialize(DeserializeStream& stream, ISerializeModifier*
|
||||
DESERIALIZE(IsLooping);
|
||||
DESERIALIZE(UpdateWhenOffscreen);
|
||||
DESERIALIZE(DrawModes);
|
||||
DESERIALIZE(SortOrder);
|
||||
|
||||
if (_parameters.HasItems())
|
||||
{
|
||||
|
||||
@@ -246,6 +246,12 @@ public:
|
||||
API_FIELD(Attributes="EditorDisplay(\"Particle Effect\"), EditorOrder(75), DefaultValue(DrawPass.Default)")
|
||||
DrawPass DrawModes = DrawPass::Default;
|
||||
|
||||
/// <summary>
|
||||
/// The object sort order key used when sorting drawable objects during rendering. Use lower values to draw object before others, higher values are rendered later (on top). Can be use to control transparency drawing.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorDisplay(\"Particle Effect\"), EditorOrder(80), DefaultValue(0)")
|
||||
int16 SortOrder = 0;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the effect parameters collection. Those parameters are instanced from the <see cref="ParticleSystem"/> that contains a linear list of emitters and every emitter has a list of own parameters.
|
||||
|
||||
@@ -154,7 +154,7 @@ void Particles::OnEffectDestroy(ParticleEffect* effect)
|
||||
|
||||
typedef Array<int32, FixedAllocation<PARTICLE_EMITTER_MAX_MODULES>> RenderModulesIndices;
|
||||
|
||||
void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCall& drawCall, DrawPass drawModes, StaticFlags staticFlags, ParticleEmitterInstance& emitterData, const RenderModulesIndices& renderModulesIndices)
|
||||
void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCall& drawCall, DrawPass drawModes, StaticFlags staticFlags, ParticleEmitterInstance& emitterData, const RenderModulesIndices& renderModulesIndices, int16 sortOrder)
|
||||
{
|
||||
// Skip if CPU buffer is empty
|
||||
if (buffer->CPU.Count == 0)
|
||||
@@ -417,7 +417,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
// Submit draw call
|
||||
SpriteRenderer.SetupDrawCall(drawCall);
|
||||
drawCall.InstanceCount = buffer->CPU.Count;
|
||||
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false);
|
||||
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false, sortOrder);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -445,7 +445,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
// Submit draw call
|
||||
mesh.GetDrawCallGeometry(drawCall);
|
||||
drawCall.InstanceCount = buffer->CPU.Count;
|
||||
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false);
|
||||
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false, sortOrder);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -505,7 +505,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
drawCall.Draw.StartIndex = ribbonModulesDrawIndicesStart[ribbonModuleIndex];
|
||||
drawCall.Draw.IndicesCount = ribbonModulesDrawIndicesCount[ribbonModuleIndex];
|
||||
drawCall.InstanceCount = 1;
|
||||
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false);
|
||||
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false, sortOrder);
|
||||
|
||||
ribbonModuleIndex++;
|
||||
|
||||
@@ -574,7 +574,7 @@ void CleanupGPUParticlesSorting()
|
||||
GPUParticlesSorting = nullptr;
|
||||
}
|
||||
|
||||
void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCall& drawCall, DrawPass drawModes, StaticFlags staticFlags, ParticleEmitterInstance& emitterData, const RenderModulesIndices& renderModulesIndices)
|
||||
void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCall& drawCall, DrawPass drawModes, StaticFlags staticFlags, ParticleEmitterInstance& emitterData, const RenderModulesIndices& renderModulesIndices, int16 sortOrder)
|
||||
{
|
||||
const auto context = GPUDevice::Instance->GetMainContext();
|
||||
auto emitter = buffer->Emitter;
|
||||
@@ -829,7 +829,7 @@ void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
drawCall.Draw.IndirectArgsBuffer = buffer->GPU.IndirectDrawArgsBuffer;
|
||||
drawCall.Draw.IndirectArgsOffset = indirectDrawCallIndex * sizeof(GPUDrawIndexedIndirectArgs);
|
||||
if (dp != DrawPass::None)
|
||||
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false);
|
||||
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false, sortOrder);
|
||||
indirectDrawCallIndex++;
|
||||
|
||||
break;
|
||||
@@ -859,7 +859,7 @@ void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
drawCall.Draw.IndirectArgsBuffer = buffer->GPU.IndirectDrawArgsBuffer;
|
||||
drawCall.Draw.IndirectArgsOffset = indirectDrawCallIndex * sizeof(GPUDrawIndexedIndirectArgs);
|
||||
if (dp != DrawPass::None)
|
||||
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false);
|
||||
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false, sortOrder);
|
||||
indirectDrawCallIndex++;
|
||||
}
|
||||
|
||||
@@ -887,13 +887,17 @@ void Particles::DrawParticles(RenderContext& renderContext, ParticleEffect* effe
|
||||
{
|
||||
// Setup
|
||||
auto& view = renderContext.View;
|
||||
const auto drawModes = view.Pass & effect->DrawModes;
|
||||
const DrawPass drawModes = view.Pass & effect->DrawModes;
|
||||
if (drawModes == DrawPass::None || SpriteRenderer.Init())
|
||||
return;
|
||||
Matrix worlds[2];
|
||||
Matrix::Translation(-renderContext.View.Origin, worlds[0]); // World
|
||||
renderContext.View.GetWorldMatrix(effect->GetTransform(), worlds[1]); // Local
|
||||
const auto staticFlags = effect->GetStaticFlags();
|
||||
float worldDeterminantSigns[2];
|
||||
worldDeterminantSigns[0] = Math::FloatSelect(worlds[0].RotDeterminant(), 1, -1);
|
||||
worldDeterminantSigns[1] = Math::FloatSelect(worlds[1].RotDeterminant(), 1, -1);
|
||||
const StaticFlags staticFlags = effect->GetStaticFlags();
|
||||
const int16 sortOrder = effect->SortOrder;
|
||||
|
||||
// Draw lights
|
||||
for (int32 emitterIndex = 0; emitterIndex < effect->Instance.Emitters.Count(); emitterIndex++)
|
||||
@@ -922,7 +926,7 @@ void Particles::DrawParticles(RenderContext& renderContext, ParticleEffect* effe
|
||||
auto emitter = buffer->Emitter;
|
||||
|
||||
drawCall.World = worlds[(int32)emitter->SimulationSpace];
|
||||
drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1);
|
||||
drawCall.WorldDeterminantSign = worldDeterminantSigns[(int32)emitter->SimulationSpace];
|
||||
drawCall.Particle.Particles = buffer;
|
||||
|
||||
// Check if need to render any module
|
||||
@@ -1002,11 +1006,11 @@ void Particles::DrawParticles(RenderContext& renderContext, ParticleEffect* effe
|
||||
switch (buffer->Mode)
|
||||
{
|
||||
case ParticlesSimulationMode::CPU:
|
||||
DrawEmitterCPU(renderContext, buffer, drawCall, drawModes, staticFlags, emitterData, renderModulesIndices);
|
||||
DrawEmitterCPU(renderContext, buffer, drawCall, drawModes, staticFlags, emitterData, renderModulesIndices, sortOrder);
|
||||
break;
|
||||
#if COMPILE_WITH_GPU_PARTICLES
|
||||
case ParticlesSimulationMode::GPU:
|
||||
DrawEmitterGPU(renderContext, buffer, drawCall, drawModes, staticFlags, emitterData, renderModulesIndices);
|
||||
DrawEmitterGPU(renderContext, buffer, drawCall, drawModes, staticFlags, emitterData, renderModulesIndices, sortOrder);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -412,12 +412,28 @@ void RenderList::Clear()
|
||||
_instanceBuffer.Clear();
|
||||
}
|
||||
|
||||
FORCE_INLINE void CalculateSortKey(const RenderContext& renderContext, DrawCall& drawCall)
|
||||
struct PackedSortKey
|
||||
{
|
||||
union
|
||||
{
|
||||
uint64 Data;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 DistanceKey;
|
||||
uint16 BatchKey;
|
||||
uint16 SortKey;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
FORCE_INLINE void CalculateSortKey(const RenderContext& renderContext, DrawCall& drawCall, int16 sortOrder)
|
||||
{
|
||||
const Float3 planeNormal = renderContext.View.Direction;
|
||||
const float planePoint = -Float3::Dot(planeNormal, renderContext.View.Position);
|
||||
const float distance = Float3::Dot(planeNormal, drawCall.ObjectPosition) - planePoint;
|
||||
const uint32 sortKey = RenderTools::ComputeDistanceSortKey(distance);
|
||||
PackedSortKey key;
|
||||
key.DistanceKey = RenderTools::ComputeDistanceSortKey(distance);
|
||||
uint32 batchKey = GetHash(drawCall.Geometry.IndexBuffer);
|
||||
batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[0]);
|
||||
batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[1]);
|
||||
@@ -427,10 +443,12 @@ FORCE_INLINE void CalculateSortKey(const RenderContext& renderContext, DrawCall&
|
||||
if (drawCall.Material->CanUseInstancing(handler))
|
||||
handler.GetHash(drawCall, batchKey);
|
||||
batchKey += (int32)(471 * drawCall.WorldDeterminantSign);
|
||||
drawCall.SortKey = (uint64)batchKey << 32 | (uint64)sortKey;
|
||||
key.SortKey = (uint16)(sortOrder - MIN_int16);
|
||||
key.BatchKey = (uint16)batchKey;
|
||||
drawCall.SortKey = key.Data;
|
||||
}
|
||||
|
||||
void RenderList::AddDrawCall(const RenderContext& renderContext, DrawPass drawModes, StaticFlags staticFlags, DrawCall& drawCall, bool receivesDecals)
|
||||
void RenderList::AddDrawCall(const RenderContext& renderContext, DrawPass drawModes, StaticFlags staticFlags, DrawCall& drawCall, bool receivesDecals, int16 sortOrder)
|
||||
{
|
||||
#if ENABLE_ASSERTION_LOW_LAYERS
|
||||
// Ensure that draw modes are non-empty and in conjunction with material draw modes
|
||||
@@ -439,7 +457,7 @@ void RenderList::AddDrawCall(const RenderContext& renderContext, DrawPass drawMo
|
||||
#endif
|
||||
|
||||
// Append draw call data
|
||||
CalculateSortKey(renderContext, drawCall);
|
||||
CalculateSortKey(renderContext, drawCall, sortOrder);
|
||||
const int32 index = DrawCalls.Add(drawCall);
|
||||
|
||||
// Add draw call to proper draw lists
|
||||
@@ -468,7 +486,7 @@ void RenderList::AddDrawCall(const RenderContext& renderContext, DrawPass drawMo
|
||||
}
|
||||
}
|
||||
|
||||
void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawPass drawModes, StaticFlags staticFlags, ShadowsCastingMode shadowsMode, const BoundingSphere& bounds, DrawCall& drawCall, bool receivesDecals)
|
||||
void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawPass drawModes, StaticFlags staticFlags, ShadowsCastingMode shadowsMode, const BoundingSphere& bounds, DrawCall& drawCall, bool receivesDecals, int16 sortOrder)
|
||||
{
|
||||
#if ENABLE_ASSERTION_LOW_LAYERS
|
||||
// Ensure that draw modes are non-empty and in conjunction with material draw modes
|
||||
@@ -478,7 +496,7 @@ void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawP
|
||||
const RenderContext& mainRenderContext = renderContextBatch.Contexts.Get()[0];
|
||||
|
||||
// Append draw call data
|
||||
CalculateSortKey(mainRenderContext, drawCall);
|
||||
CalculateSortKey(mainRenderContext, drawCall, sortOrder);
|
||||
const int32 index = DrawCalls.Add(drawCall);
|
||||
|
||||
// Add draw call to proper draw lists
|
||||
@@ -514,7 +532,7 @@ void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawP
|
||||
{
|
||||
const RenderContext& renderContext = renderContextBatch.Contexts.Get()[i];
|
||||
ASSERT_LOW_LAYER(renderContext.View.Pass == DrawPass::Depth);
|
||||
drawModes = (DrawPass)(modes & renderContext.View.Pass);
|
||||
drawModes = modes & renderContext.View.Pass;
|
||||
if (drawModes != DrawPass::None && renderContext.View.CullingFrustum.Intersects(bounds))
|
||||
{
|
||||
renderContext.List->ShadowDepthDrawCallsList.Indices.Add(index);
|
||||
@@ -558,16 +576,17 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD
|
||||
#undef PREPARE_CACHE
|
||||
uint64* sortedKeys = SortingKeys[0].Get();
|
||||
|
||||
// Generate sort keys (by depth) and batch keys (higher bits)
|
||||
// Setup sort keys
|
||||
if (reverseDistance)
|
||||
{
|
||||
const uint32 sortKeyXor = reverseDistance ? MAX_uint32 : 0;
|
||||
for (int32 i = 0; i < listSize; i++)
|
||||
{
|
||||
const DrawCall& drawCall = drawCallsData[listData[i]];
|
||||
const uint32 sortKey = (uint32)drawCall.SortKey ^ sortKeyXor;
|
||||
const uint32 batchKey = (uint32)(drawCall.SortKey >> 32);
|
||||
sortedKeys[i] = (uint64)batchKey << 32 | (uint64)sortKey;
|
||||
PackedSortKey key;
|
||||
key.Data = drawCall.SortKey;
|
||||
key.DistanceKey ^= MAX_uint32; // Reverse depth
|
||||
key.SortKey ^= MAX_uint16; // Reverse sort order
|
||||
sortedKeys[i] = key.Data;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -605,7 +624,7 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD
|
||||
}
|
||||
|
||||
DrawBatch batch;
|
||||
batch.SortKey = sortedKeys[i] & MAX_uint32;
|
||||
batch.SortKey = sortedKeys[i];
|
||||
batch.StartIndex = i;
|
||||
batch.BatchSize = batchSize;
|
||||
batch.InstanceCount = instanceCount;
|
||||
|
||||
@@ -201,7 +201,7 @@ struct DrawBatch
|
||||
/// <summary>
|
||||
/// Draw calls sorting key (shared by the all draw calls withing a patch).
|
||||
/// </summary>
|
||||
uint32 SortKey;
|
||||
uint64 SortKey;
|
||||
|
||||
/// <summary>
|
||||
/// The first draw call index.
|
||||
@@ -489,7 +489,8 @@ public:
|
||||
/// <param name="staticFlags">The object static flags.</param>
|
||||
/// <param name="drawCall">The draw call data.</param>
|
||||
/// <param name="receivesDecals">True if the rendered mesh can receive decals.</param>
|
||||
void AddDrawCall(const RenderContext& renderContext, DrawPass drawModes, StaticFlags staticFlags, DrawCall& drawCall, bool receivesDecals);
|
||||
/// <param name="sortOrder">Object sorting key.</param>
|
||||
void AddDrawCall(const RenderContext& renderContext, DrawPass drawModes, StaticFlags staticFlags, DrawCall& drawCall, bool receivesDecals = true, int16 sortOrder = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the draw call to the draw lists and references it in other render contexts. Performs additional per-context frustum culling.
|
||||
@@ -501,7 +502,8 @@ public:
|
||||
/// <param name="bounds">The object bounds.</param>
|
||||
/// <param name="drawCall">The draw call data.</param>
|
||||
/// <param name="receivesDecals">True if the rendered mesh can receive decals.</param>
|
||||
void AddDrawCall(const RenderContextBatch& renderContextBatch, DrawPass drawModes, StaticFlags staticFlags, ShadowsCastingMode shadowsMode, const BoundingSphere& bounds, DrawCall& drawCall, bool receivesDecals);
|
||||
/// <param name="sortOrder">Object sorting key.</param>
|
||||
void AddDrawCall(const RenderContextBatch& renderContextBatch, DrawPass drawModes, StaticFlags staticFlags, ShadowsCastingMode shadowsMode, const BoundingSphere& bounds, DrawCall& drawCall, bool receivesDecals = true, int16 sortOrder = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the collected draw calls list.
|
||||
|
||||
@@ -130,7 +130,7 @@ void SpriteRender::Draw(RenderContext& renderContext)
|
||||
view.GetWorldMatrix(_transform, m2);
|
||||
Matrix::Multiply(m1, m2, world);
|
||||
}
|
||||
model->LODs[0].Draw(renderContext, _materialInstance, world, GetStaticFlags(), false, DrawModes, GetPerInstanceRandom());
|
||||
model->LODs[0].Draw(renderContext, _materialInstance, world, GetStaticFlags(), false, DrawModes, GetPerInstanceRandom(), SortOrder);
|
||||
}
|
||||
|
||||
void SpriteRender::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
@@ -147,6 +147,7 @@ void SpriteRender::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
SERIALIZE(Material);
|
||||
SERIALIZE(FaceCamera);
|
||||
SERIALIZE(DrawModes);
|
||||
SERIALIZE(SortOrder);
|
||||
}
|
||||
|
||||
void SpriteRender::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
|
||||
@@ -161,6 +162,7 @@ void SpriteRender::Deserialize(DeserializeStream& stream, ISerializeModifier* mo
|
||||
DESERIALIZE(Material);
|
||||
DESERIALIZE(FaceCamera);
|
||||
DESERIALIZE(DrawModes);
|
||||
DESERIALIZE(SortOrder);
|
||||
|
||||
SetImage();
|
||||
if (_paramColor)
|
||||
|
||||
@@ -84,6 +84,12 @@ public:
|
||||
API_FIELD(Attributes="EditorOrder(50), DefaultValue(DrawPass.Default), EditorDisplay(\"Sprite\")")
|
||||
DrawPass DrawModes = DrawPass::Default;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the object sort order key used when sorting drawable objects during rendering. Use lower values to draw object before others, higher values are rendered later (on top). Can be use to control transparency drawing.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(60), DefaultValue(0), EditorDisplay(\"Sprite\")")
|
||||
int16 SortOrder = 0;
|
||||
|
||||
private:
|
||||
void OnMaterialLoaded();
|
||||
void SetImage();
|
||||
|
||||
@@ -392,7 +392,7 @@ void TextRender::Draw(RenderContext& renderContext)
|
||||
drawCall.Draw.IndicesCount = e.IndicesCount;
|
||||
drawCall.Draw.StartIndex = e.StartIndex;
|
||||
drawCall.Material = e.Material;
|
||||
renderContext.List->AddDrawCall(renderContext, chunkDrawModes, GetStaticFlags(), drawCall, true);
|
||||
renderContext.List->AddDrawCall(renderContext, chunkDrawModes, GetStaticFlags(), drawCall, true, SortOrder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,6 +450,7 @@ void TextRender::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
SERIALIZE(Font);
|
||||
SERIALIZE(ShadowsMode);
|
||||
SERIALIZE(DrawModes);
|
||||
SERIALIZE(SortOrder);
|
||||
SERIALIZE_MEMBER(Bounds, _layoutOptions.Bounds);
|
||||
SERIALIZE_MEMBER(HAlignment, _layoutOptions.HorizontalAlignment);
|
||||
SERIALIZE_MEMBER(VAlignment, _layoutOptions.VerticalAlignment);
|
||||
@@ -470,6 +471,7 @@ void TextRender::Deserialize(DeserializeStream& stream, ISerializeModifier* modi
|
||||
DESERIALIZE(Font);
|
||||
DESERIALIZE(ShadowsMode);
|
||||
DESERIALIZE(DrawModes);
|
||||
DESERIALIZE(SortOrder);
|
||||
DESERIALIZE_MEMBER(Bounds, _layoutOptions.Bounds);
|
||||
DESERIALIZE_MEMBER(HAlignment, _layoutOptions.HorizontalAlignment);
|
||||
DESERIALIZE_MEMBER(VAlignment, _layoutOptions.VerticalAlignment);
|
||||
|
||||
@@ -110,6 +110,12 @@ public:
|
||||
API_FIELD(Attributes="EditorOrder(80), DefaultValue(ShadowsCastingMode.All), EditorDisplay(\"Text\")")
|
||||
ShadowsCastingMode ShadowsMode = ShadowsCastingMode::All;
|
||||
|
||||
/// <summary>
|
||||
/// The object sort order key used when sorting drawable objects during rendering. Use lower values to draw object before others, higher values are rendered later (on top). Can be use to control transparency drawing.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(85), DefaultValue(0), EditorDisplay(\"Text\")")
|
||||
int16 SortOrder = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layout options. Layout is defined in local space of the object (on XY plane).
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user