Files
tooll3--t3/Operators/Lib/field/space/_/ExecuteRepeatFieldAtPoints.cs
2026-07-13 13:13:17 +08:00

176 lines
6.0 KiB
C#

#nullable enable
using T3.Core.DataTypes.ShaderGraph;
using T3.Core.Utils;
namespace Lib.field.space._;
[Guid("296c774b-1cf0-4e37-9c22-7ac4fd5d78e5")]
internal sealed class ExecuteRepeatFieldAtPoints : Instance<ExecuteRepeatFieldAtPoints>
,IGraphNodeOp
{
[Output(Guid = "b246c7f7-04dd-4632-aff8-fa0a2c03af4f")]
public readonly Slot<ShaderGraphNode> Result = new();
public ExecuteRepeatFieldAtPoints()
{
ShaderNode = new ShaderGraphNode(this, null, InputField);
Result.Value = ShaderNode;
Result.UpdateAction += Update;
}
private void Update(EvaluationContext context)
{
var combineMethod = CombineMethod.GetEnumValue<CombineMethods>(context);
if (combineMethod != _combineMethod)
{
_combineMethod = combineMethod;
ShaderNode.FlagCodeChanged();
}
var buffer = Points.GetValue(context);
_count = buffer?.Srv?.Description != null ? buffer.Srv.Description.Buffer.ElementCount : 0;
if (buffer != null && buffer.Srv != null)
{
_srv = buffer.Srv.IsDisposed ? null : buffer.Srv;
}
else
{
_srv = null;
}
ShaderNode.Update(context);
// Get all parameters to clear operator dirty flag
InputField.DirtyFlag.Clear();
}
public ShaderGraphNode ShaderNode { get; }
void IGraphNodeOp.AddDefinitions(CodeAssembleContext c)
{
// This is initialized in ComputePointTransformMatrix.hlsl
c.ResourceTypes["PointMatrix"] = """
struct PointTransform
{
float4x4 WorldToPointObject;
float4 PointColor;
};
""";
c.Globals[nameof(ShaderGraphIncludes.GetColorBlendFactor)] = ShaderGraphIncludes.GetColorBlendFactor;
// Register global method
switch (_combineMethod)
{
case CombineMethods.UnionRound:
c.Globals["fOpUnionRound"]
= """
// The "Round" variant uses a quarter-circle to join the two objects smoothly:
float fOpUnionRound(float a, float b, float r) {
float2 u = max(float2(r - a,r - b), 0);
return max(r, min (a, b)) - length(u);
}
""";
break;
case CombineMethods.UnionSoft:
c.Globals["fOpUnionSoft"] = """
float fOpUnionSoft(float a, float b, float r) {
float e = max(r - abs(a - b), 0);
return min(a, b) - e*e*0.25/r;
}
""";
break;
}
}
bool IGraphNodeOp.TryBuildCustomCode(CodeAssembleContext c)
{
const int maxSteps = 100;
var fields = ShaderNode.InputNodes;
if (fields.Count == 0)
return true;
var inputField = fields[0];
c.AppendCall($"float4 pStart{c} = p{c};");
c.AppendCall($"float4 fLoop{c} = float4(1,1,1,99999);");
c.AppendCall($"for(int i{c} = 0; i{c} < {_count} && i{c} < {maxSteps}; i{c}++) {{");
c.Indent();
{
c.AppendCall($"f{c} = float4(1,1,1,9999);");
c.AppendCall($"p{c}.xyz = mul(float4(pStart{c}.xyz,1), {ShaderNode}PointTransforms[i{c}].WorldToPointObject).xyz;");
inputField?.CollectEmbeddedShaderCode(c);
// Multiply Point color
c.AppendCall($"f{c}.rgb *= {ShaderNode}PointTransforms[i{c}].PointColor.rgb;");
c.AppendCall($"fLoop{c}.rgb = lerp(fLoop{c}.rgb, f{c}.rgb, GetColorBlendFactor(fLoop{c}.w, f{c}.w, {ShaderNode}K ));");
// Combine initial value with new value...
switch (_combineMethod)
{
case CombineMethods.Union:
c.AppendCall($"fLoop{c}.w = min(f{c}.w, fLoop{c}.w);");
break;
case CombineMethods.UnionSoft:
c.AppendCall($"fLoop{c}.w = fOpUnionSoft(fLoop{c}.w, f{c}.w, {ShaderNode}K);");
break;
case CombineMethods.UnionRound:
c.AppendCall($"fLoop{c}.w = fOpUnionRound(fLoop{c}.w, f{c}.w, {ShaderNode}K);");
break;
}
}
c.Unindent();
c.AppendCall("}");
c.AppendCall($"f{c} = fLoop{c};");
return true;
}
void IGraphNodeOp.AppendShaderResources(ref List<ShaderGraphNode.SrvBufferReference> list)
{
if (_srv == null)
return;
// Skip if already added
foreach (var x in list)
{
if (x.Srv == _srv)
return;
}
list.Add(new ShaderGraphNode.SrvBufferReference($"StructuredBuffer<PointTransform> {ShaderNode}PointTransforms", _srv));
}
private int _count;
private ShaderResourceView? _srv; // This will later be passed on to the shader Stage by GenerateShaderCode
private CombineMethods _combineMethod;
private enum CombineMethods
{
Union,
UnionSoft,
UnionRound,
}
[Input(Guid = "bb4e6ad8-5941-4218-9e4b-4ba402be7ed4")]
public readonly InputSlot<T3.Core.DataTypes.ShaderGraphNode> InputField = new();
[Input(Guid = "1E5288D2-C2AE-4A1D-AD69-FE63D32A00C6")]
public readonly InputSlot<T3.Core.DataTypes.BufferWithViews> Points = new();
[GraphParam]
[Input(Guid = "9E4F5916-722D-4C4B-B1CA-814958A5B836")]
public readonly InputSlot<float> K = new();
[Input(Guid = "4648E514-B48C-4A98-A728-3EBF9BCFA0B7", MappedType = typeof(CombineMethods))]
public readonly InputSlot<int> CombineMethod = new();
}