You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

264 lines
11 KiB

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.VFX;
namespace UnityEditor.VFX.Block
{
class PositionBox : PositionShapeBase
{
public sealed override bool supportCustomSpawn => false;
public class InputProperties
{
[Tooltip("Sets the box used for positioning the particles.")]
public OrientedBox Box = OrientedBox.defaultValue;
}
protected static IEnumerable<VFXNamedExpression> GetVolumeExpressions(PositionShape.PositionMode positionMode, VFXExpression boxSize, VFXExpression thickness)
{
if (positionMode == PositionShape.PositionMode.ThicknessAbsolute ||
positionMode == PositionShape.PositionMode.ThicknessRelative)
{
VFXExpression factor = VFXValue.Constant(Vector3.zero);
switch (positionMode)
{
case PositionShape.PositionMode.ThicknessAbsolute:
factor = VFXOperatorUtility.Clamp(
VFXOperatorUtility.CastFloat(thickness * VFXValue.Constant(2.0f), VFXValueType.Float3),
VFXValue.Constant(0.0f), boxSize);
break;
case PositionShape.PositionMode.ThicknessRelative:
factor = VFXOperatorUtility.CastFloat(VFXOperatorUtility.Saturate(thickness),
VFXValueType.Float3) * boxSize;
break;
default:
throw new NotImplementedException();
}
factor = new VFXExpressionMax(factor, VFXValue.Constant(new Vector3(0.0001f, 0.0001f, 0.0001f)));
var volumeXY = new VFXExpressionCombine(boxSize.x, boxSize.y, factor.z);
var volumeXZ = new VFXExpressionCombine(boxSize.x, boxSize.z - factor.z, factor.y);
var volumeYZ = new VFXExpressionCombine(boxSize.y - factor.y, boxSize.z - factor.z, factor.x);
var volumes = new VFXExpressionCombine(
volumeXY.x * volumeXY.y * volumeXY.z,
volumeXZ.x * volumeXZ.y * volumeXZ.z,
volumeYZ.x * volumeYZ.y * volumeYZ.z
);
var cumulativeVolumes = new VFXExpressionCombine(
volumes.x,
volumes.x + volumes.y,
volumes.x + volumes.y + volumes.z
);
yield return new VFXNamedExpression(volumeXY, "volumeXY");
yield return new VFXNamedExpression(volumeXZ, "volumeXZ");
yield return new VFXNamedExpression(volumeYZ, "volumeYZ");
yield return new VFXNamedExpression(cumulativeVolumes, "cumulativeVolumes");
}
}
public override IEnumerable<VFXNamedExpression> GetParameters(PositionShape positionBase, List<VFXNamedExpression> allSlots)
{
VFXExpression transform = null;
VFXExpression thickness = null;
foreach (var slot in allSlots)
{
if (slot.name == "Box")
transform = slot.exp;
else if (slot.name == nameof(PositionShape.ThicknessProperties.Thickness))
thickness = slot.exp;
}
VFXExpression boxSize;
if (positionBase.positionMode == PositionBase.PositionMode.ThicknessAbsolute)
{
boxSize = new VFXExpressionExtractScaleFromMatrix(transform);
var invBoxSize = VFXOperatorUtility.OneExpression[VFXValueType.Float3] / boxSize;
var zero = VFXOperatorUtility.ZeroExpression[VFXValueType.Float3];
var invScaleMatrix = new VFXExpressionTRSToMatrix(zero, zero, invBoxSize);
transform = new VFXExpressionTransformMatrix(transform, invScaleMatrix);
}
else
{
boxSize = VFXOperatorUtility.OneExpression[VFXValueType.Float3];
}
//If possible, remove scale to allow zero scale matrices (see UUM-62355)
var transformForInversion = transform;
var isInverseTransposeBoxOrthonormal = VFXOperatorUtility.FalseExpression;
if (positionBase.inputSlots[0].space == VFXSpace.None || positionBase.inputSlots[0].space == positionBase.GetParent().space)
{
if (transform is VFXExpressionTRSToMatrix)
{
transformForInversion = new VFXExpressionTRSToMatrix(VFXOperatorUtility.ZeroExpression[VFXValueType.Float3], transform.parents[1], VFXOperatorUtility.OneExpression[VFXValueType.Float3]);
isInverseTransposeBoxOrthonormal = VFXOperatorUtility.TrueExpression;
}
}
else
{
if (transform is not VFXExpressionTransformMatrix)
throw new InvalidOperationException("Unexpected missing space conversion");
var left = transform.parents[0];
var right = transform.parents[1];
if (right is VFXExpressionTRSToMatrix)
{
right = new VFXExpressionTRSToMatrix(VFXOperatorUtility.ZeroExpression[VFXValueType.Float3], right.parents[1], VFXOperatorUtility.OneExpression[VFXValueType.Float3]);
transformForInversion = new VFXExpressionTransformMatrix(left, right);
//inverseTransposeBoxOrthonormal still false, LocalToWorld can contains scale
}
}
yield return new VFXNamedExpression(transform, "Box");
yield return new VFXNamedExpression(VFXOperatorUtility.InverseTransposeTRS(transformForInversion), "InverseTransposeBox");
yield return new VFXNamedExpression(isInverseTransposeBoxOrthonormal, "IsInverseTransposeBoxOrthonormal");
yield return new VFXNamedExpression(boxSize, "Box_size");
foreach (var p in GetVolumeExpressions(positionBase.positionMode, boxSize, thickness))
yield return p;
}
public override string GetSource(PositionShape positionBase)
{
string outSource;
if (positionBase.positionMode == PositionShape.PositionMode.Volume)
{
outSource = @"
float3 localRand3 = RAND3 - (float3)0.5f;
float3 outPos = Box_size * localRand3;
";
outSource += @"
float3 outPosSizeGreaterThanZero = max(Box_size, VFX_EPSILON) * localRand3;
float3 planeBound = 0.5f * Box_size;
float top = planeBound.z - outPosSizeGreaterThanZero.z;
float bottom = planeBound.z + outPosSizeGreaterThanZero.z;
float front = planeBound.y - outPosSizeGreaterThanZero.y;
float back = planeBound.y + outPosSizeGreaterThanZero.y;
float right = planeBound.x - outPosSizeGreaterThanZero.x;
float left = planeBound.x + outPosSizeGreaterThanZero.x;
float3 outDir = float3( 0, 0, 1);
float3 outUp = float3(-1, 0, 0);
float3 outTan = float3( 0, -1, 0);
float min = top;
if (bottom < min) { outDir = float3( 0, 0, -1); outUp = float3( -1, 0, 0); outTan = float3( 0, 1, 0); min = bottom; }
if (front < min) { outDir = float3( 0, 1, 0); outUp = float3( -1, 0, 0); outTan = float3( 0, 0, 1); min = front; }
if (back < min) { outDir = float3( 0, -1, 0); outUp = float3( -1, 0, 0); outTan = float3( 0, 0, -1); min = back; }
if (right < min) { outDir = float3( 1, 0, 0); outUp = float3( 0, 0, 1); outTan = float3( 0, -1, 0); min = right; }
if (left < min) { outDir = float3(-1, 0, 0); outUp = float3( 0, 0, -1); outTan = float3( 0, -1, 0); min = left; }
";
}
else if (positionBase.positionMode == PositionShape.PositionMode.Surface)
{
outSource = @"
float areaXY = max(Box_size.x * Box_size.y, VFX_EPSILON);
float areaXZ = max(Box_size.x * Box_size.z, VFX_EPSILON);
float areaYZ = max(Box_size.y * Box_size.z, VFX_EPSILON);
float face = RAND * (areaXY + areaXZ + areaYZ);
float flip = (RAND >= 0.5f) ? 1.0f : -1.0f;
float3 cube = float3(RAND2 - 0.5f, flip * 0.5f);
float3 outDir;
float3 outUp;
float3 outTan;
if (face < areaXY)
{
cube = cube.xyz;
outDir = float3(0, 0, flip);
outUp = float3(-1, 0, 0);
outTan = float3(0, -flip, 0);
}
else if(face < areaXY + areaXZ)
{
cube = cube.xzy;
outDir = float3(0, flip, 0);
outUp = float3(-1, 0, 0);
outTan = float3(0, 0, flip);
}
else
{
cube = cube.zxy;
outDir = float3(flip, 0, 0);
outUp = float3(0, 0, flip);
outTan = float3(0, -1, 0);
}
float3 outPos = cube * Box_size;
";
}
else if (positionBase.positionMode == PositionShape.PositionMode.ThicknessAbsolute || positionBase.positionMode == PositionShape.PositionMode.ThicknessRelative)
{
outSource = @"
float face = RAND * cumulativeVolumes.z;
float flip = (RAND >= 0.5f) ? 1.0f : -1.0f;
float3 cube = float3(RAND2 * 2.0f - 1.0f, -RAND);
float3 outDir;
float3 outUp;
float3 outTan;
if (face < cumulativeVolumes.x)
{
cube = (cube * volumeXY).xyz + float3(0.0f, 0.0f, Box_size.z);
cube.z *= flip;
outDir = float3(0, 0, flip);
outUp = float3(-1, 0, 0);
outTan = float3(0, -flip, 0);
}
else if(face < cumulativeVolumes.y)
{
cube = (cube * volumeXZ).xzy + float3(0.0f, Box_size.y, 0.0f);
cube.y *= flip;
outDir = float3(0, flip, 0);
outUp = float3(-1, 0, 0);
outTan = float3(0, 0, flip);
}
else
{
cube = (cube * volumeYZ).zxy + float3(Box_size.x, 0.0f, 0.0f);
cube.x *= flip;
outDir = float3(flip, 0, 0);
outUp = float3(0, 0, flip);
outTan = float3(0, -1, 0);
}
float3 outPos = cube * 0.5f;
";
}
else
{
throw new NotImplementedException();
}
outSource += @"
outPos = mul(Box, float4(outPos, 1.0f)).xyz;
outUp = mul(InverseTransposeBox, float4(outUp, 0.0f)).xyz;
outDir = mul(InverseTransposeBox, float4(outDir, 0.0f)).xyz;
if (!IsInverseTransposeBoxOrthonormal)
{
outDir = normalize(outDir);
outUp = normalize(outUp);
}
outTan = cross(outDir, outUp);
";
if (positionBase.applyOrientation.HasFlag(PositionBase.Orientation.Direction))
{
outSource += string.Format(positionBase.composeDirectionFormatString, "outDir");
}
if (positionBase.applyOrientation.HasFlag(PositionBase.Orientation.Axes))
{
outSource += VFXBlockUtility.GetComposeString(positionBase.compositionAxes, "axisX", "outTan", "blendAxes") + "\n";
outSource += VFXBlockUtility.GetComposeString(positionBase.compositionAxes, "axisY", "outDir", "blendAxes") + "\n";
outSource += VFXBlockUtility.GetComposeString(positionBase.compositionAxes, "axisZ", "outUp", "blendAxes") + "\n";
}
outSource += string.Format(positionBase.composePositionFormatString, "outPos");
return outSource;
}
}
}