using T3.Core.DataTypes.ShaderGraph; using T3.Core.Utils; namespace Lib.field.generate.sdf; [Guid("5b8604d0-65f4-45c9-9e85-4a044005a778")] internal sealed class PyramidSDF : Instance , ITransformable , IGraphNodeOp { [Output(Guid = "566667bd-e78b-4971-b567-3e1c3ea68701")] public readonly Slot Result = new(); IInputSlot ITransformable.TranslationInput => Center; IInputSlot ITransformable.RotationInput => null; IInputSlot ITransformable.ScaleInput => Scale; public Action TransformCallback { get; set; } public PyramidSDF() { ShaderNode = new ShaderGraphNode(this); Result.Value = ShaderNode; Result.UpdateAction += Update; } private void Update(EvaluationContext context) { TransformCallback?.Invoke(this, context); //needed for Gizmo ShaderNode.Update(context); var axis = Axis.GetEnumValue(context); var templateChanged = axis != _axis; if (!templateChanged) return; _axis = axis; ShaderNode.FlagCodeChanged(); } public ShaderGraphNode ShaderNode { get; } //Pyramid SDF by TheTurk: https://www.shadertoy.com/view/Ntd3DX public void GetPreShaderCode(CodeAssembleContext c, int inputIndex) { c.Globals["fPyramid"] = """ float fPyramid(float3 p, float3 center, float halfWidth, float halfDepth, float halfHeight, float ra) { p -= center; p.y += halfHeight; p.xz = abs(p.xz); float3 d1 = float3(max(p.x - halfWidth, 0.0), p.y, max(p.z - halfDepth, 0.0)); float3 n1 = float3(0.0, halfDepth, 2.0 * halfHeight); float k1 = dot(n1, n1); float h1 = dot(p - float3(halfWidth, 0.0, halfDepth), n1) / k1; float3 n2 = float3(k1, 2.0 * halfHeight * halfWidth, -halfDepth * halfWidth); float m1 = dot(p - float3(halfWidth, 0.0, halfDepth), n2) / dot(n2, n2); float3 d2 = p - clamp(p - n1 * h1 - n2 * max(m1, 0.0), float3(0., 0., 0.), float3(halfWidth, 2.0 * halfHeight, halfDepth)); float3 n3 = float3(2.0 * halfHeight, halfWidth, 0.0); float k2 = dot(n3, n3); float h2 = dot(p - float3(halfWidth, 0.0, halfDepth), n3) / k2; float3 n4 = float3(-halfWidth * halfDepth, 2.0 * halfHeight * halfDepth, k2); float m2 = dot(p - float3(halfWidth, 0.0, halfDepth), n4) / dot(n4, n4); float3 d3 = p - clamp(p - n3 * h2 - n4 * max(m2, 0.0), float3(0., 0., 0.), float3(halfWidth, 2.0 * halfHeight, halfDepth)); float d = sqrt(min(min(dot(d1, d1), dot(d2, d2)), dot(d3, d3))); return (max(max(h1, h2), -p.y) < 0.0 ? -d : d) - ra; } """; var a = _axisCodes0[(int)_axis]; c.AppendCall($"f{c}.w = fPyramid(p{c}.{a}, {ShaderNode}Center.{a}, {ShaderNode}Scale.x * {ShaderNode}UniformScale, {ShaderNode}Scale.z * {ShaderNode}UniformScale, {ShaderNode}Scale.y * {ShaderNode}UniformScale, {ShaderNode}Rounding);"); //c.AppendCall($"f{c}.xyz = p{c}.xyz;"); c.AppendCall($"f{c}.xyz = p.w < 0.5 ? p{c}.xyz : 1;"); // save local space } public void GetPostShaderCode(CodeAssembleContext cac, int inputIndex) { } private readonly string[] _axisCodes0 = [ "yxz", "xyz", "xzy", ]; private AxisTypes _axis; private enum AxisTypes { X, Y, Z, } [GraphParam] [Input(Guid = "92c03574-31e5-4ce2-9a76-ecab5f64d732")] public readonly InputSlot Center = new(); [GraphParam] [Input(Guid = "8d5c22bb-2910-4415-9bf8-ab304e35a5b2")] public readonly InputSlot Scale = new(); [GraphParam] [Input(Guid = "471d9c3b-ba5e-4b73-93cf-fb8ba76bf70e")] public readonly InputSlot UniformScale = new(); [GraphParam] [Input(Guid = "5b3e69cf-cb55-4428-b78c-76f4f22cf2ac")] public readonly InputSlot Rounding = new(); [Input(Guid = "09320506-1e5c-4da8-b522-9f89c143277f", MappedType = typeof(AxisTypes))] public readonly InputSlot Axis = new(); }