summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xScripts/Fold/Editor/FoldEditorWindow.cs87
-rwxr-xr-xScripts/Fold/Editor/FoldPipelineBuilder.cs42
-rwxr-xr-xScripts/Fold/Editor/README.md41
-rwxr-xr-xbrdf.cginc4
-rwxr-xr-xvertex.cginc70
-rwxr-xr-xvertex_deformation.slang98
6 files changed, 288 insertions, 54 deletions
diff --git a/Scripts/Fold/Editor/FoldEditorWindow.cs b/Scripts/Fold/Editor/FoldEditorWindow.cs
index e2a94e1..e8faf1f 100755
--- a/Scripts/Fold/Editor/FoldEditorWindow.cs
+++ b/Scripts/Fold/Editor/FoldEditorWindow.cs
@@ -205,12 +205,15 @@ public class FoldEditorWindow : EditorWindow
menu.AddItem(new GUIContent("Plane to Tube"), false, () => AddOperation(new PlaneToTubeOp()));
menu.AddItem(new GUIContent("Plane to Hemi-Octahedron"), false, () => AddOperation(new PlaneToHemiOctahedronOp()));
menu.AddItem(new GUIContent("Hemi-Octahedron to Plane"), false, () => AddOperation(new HemiOctahedronToPlaneOp()));
+ menu.AddItem(new GUIContent("Plane to Octahedron"), false, () => AddOperation(new PlaneToOctahedronOp()));
+ menu.AddItem(new GUIContent("Octahedron to Plane"), false, () => AddOperation(new OctahedronToPlaneOp()));
menu.AddSeparator("");
menu.AddItem(new GUIContent("Point Align"), false, () => AddOperation(new PointAlignOp()));
menu.AddItem(new GUIContent("Axis Align"), false, () => AddOperation(new AxisAlignOp()));
menu.AddSeparator("");
menu.AddItem(new GUIContent("Scale"), false, () => AddOperation(new ScaleOp()));
menu.AddItem(new GUIContent("Translate"), false, () => AddOperation(new TranslateOp()));
+ menu.AddItem(new GUIContent("Rotate"), false, () => AddOperation(new RotateOp()));
menu.AddItem(new GUIContent("Norm Conversion"), false, () => AddOperation(new NormConversionOp()));
menu.AddItem(new GUIContent("Seal"), false, () => AddOperation(new SealOp()));
menu.AddSeparator("");
@@ -274,6 +277,9 @@ public class FoldEditorWindow : EditorWindow
FoldPipelineBuilder.Opcodes.HemiOctahedronToPlane => new HemiOctahedronToPlaneOp(slot),
FoldPipelineBuilder.Opcodes.Scale => new ScaleOp(slot),
FoldPipelineBuilder.Opcodes.Translate => new TranslateOp(slot),
+ FoldPipelineBuilder.Opcodes.PlaneToOctahedron => new PlaneToOctahedronOp(slot),
+ FoldPipelineBuilder.Opcodes.OctahedronToPlane => new OctahedronToPlaneOp(slot),
+ FoldPipelineBuilder.Opcodes.Rotate => new RotateOp(slot),
FoldPipelineBuilder.Opcodes.PointAlign => new PointAlignOp(slot),
FoldPipelineBuilder.Opcodes.AxisAlign => new AxisAlignOp(slot),
FoldPipelineBuilder.Opcodes.NormConversion => new NormConversionOp(slot),
@@ -418,6 +424,37 @@ public class TranslateOp : DeformOperation
}
[System.Serializable]
+public class RotateOp : DeformOperation
+{
+ public Vector3 center = Vector3.zero;
+ public Vector3 axis = Vector3.up;
+ public float angleDeg = 90f;
+ public float t = 1f;
+
+ public RotateOp() { }
+ public RotateOp(FoldSlot slot)
+ {
+ center = slot.vec0;
+ axis = slot.vec1;
+ angleDeg = slot.float0 * Mathf.Rad2Deg;
+ t = slot.float1;
+ }
+
+ public override string GetDisplayName() => "Rotate";
+
+ public override void DrawParameters()
+ {
+ center = EditorGUILayout.Vector3Field("Center", center);
+ axis = EditorGUILayout.Vector3Field("Axis", axis);
+ angleDeg = EditorGUILayout.Slider("Angle", angleDeg, 0f, 360f);
+ t = EditorGUILayout.Slider("Interpolation (t)", t, 0f, 1f);
+ }
+
+ public override void ApplyTo(FoldPipelineBuilder builder) =>
+ builder.Rotate(center, axis, angleDeg * Mathf.Deg2Rad, t);
+}
+
+[System.Serializable]
public class HemiOctahedronToPlaneOp : DeformOperation
{
public Vector3 p = Vector3.zero;
@@ -443,6 +480,56 @@ public class HemiOctahedronToPlaneOp : DeformOperation
}
[System.Serializable]
+public class PlaneToOctahedronOp : DeformOperation
+{
+ public Vector3 p = Vector3.zero;
+ public Vector3 r = Vector3.right;
+ public Vector3 s = Vector3.forward;
+ public float t = 1f;
+
+ public PlaneToOctahedronOp() { }
+ public PlaneToOctahedronOp(FoldSlot slot) { p = slot.vec0; r = slot.vec1; s = slot.vec2; t = slot.float0; }
+
+ public override string GetDisplayName() => "Plane to Octahedron";
+
+ public override void DrawParameters()
+ {
+ p = EditorGUILayout.Vector3Field("Origin (p)", p);
+ r = EditorGUILayout.Vector3Field("R Axis", r);
+ s = EditorGUILayout.Vector3Field("S Axis", s);
+ t = EditorGUILayout.Slider("Interpolation (t)", t, 0f, 1f);
+ }
+
+ public override void ApplyTo(FoldPipelineBuilder builder) =>
+ builder.PlaneToOctahedron(p, r, s, t);
+}
+
+[System.Serializable]
+public class OctahedronToPlaneOp : DeformOperation
+{
+ public Vector3 p = Vector3.zero;
+ public Vector3 r = Vector3.right;
+ public Vector3 s = Vector3.forward;
+ public float t = 1f;
+
+ public OctahedronToPlaneOp() { }
+ public OctahedronToPlaneOp(FoldSlot slot) { p = slot.vec0; r = slot.vec1; s = slot.vec2; t = slot.float0; }
+
+ public override string GetDisplayName() => "Octahedron to Plane";
+
+ public override void DrawParameters()
+ {
+ p = EditorGUILayout.Vector3Field("Origin (p)", p);
+ r = EditorGUILayout.Vector3Field("R Axis", r);
+ s = EditorGUILayout.Vector3Field("S Axis", s);
+ t = EditorGUILayout.Slider("Interpolation (t)", t, 0f, 1f);
+ }
+
+ public override void ApplyTo(FoldPipelineBuilder builder) =>
+ builder.OctahedronToPlane(p, r, s, t);
+}
+
+[System.Serializable]
public class PointAlignOp : DeformOperation
{
public Vector3 po = Vector3.zero;
diff --git a/Scripts/Fold/Editor/FoldPipelineBuilder.cs b/Scripts/Fold/Editor/FoldPipelineBuilder.cs
index 2dc2291..731ceeb 100755
--- a/Scripts/Fold/Editor/FoldPipelineBuilder.cs
+++ b/Scripts/Fold/Editor/FoldPipelineBuilder.cs
@@ -60,6 +60,9 @@ public class FoldPipelineBuilder
public const int HemiOctahedronToPlane = 10;
public const int Scale = 11;
public const int Translate = 12;
+ public const int PlaneToOctahedron = 13;
+ public const int OctahedronToPlane = 14;
+ public const int Rotate = 15;
}
FoldPipelineBuilder() { }
@@ -133,6 +136,45 @@ public class FoldPipelineBuilder
return this;
}
+ public FoldPipelineBuilder PlaneToOctahedron(Vector3 p, Vector3 r, Vector3 s, float t)
+ {
+ slots.Add(new FoldSlot
+ {
+ opcode = Opcodes.PlaneToOctahedron,
+ vec0 = p,
+ vec1 = r,
+ vec2 = s,
+ float0 = t
+ });
+ return this;
+ }
+
+ public FoldPipelineBuilder OctahedronToPlane(Vector3 p, Vector3 r, Vector3 s, float t)
+ {
+ slots.Add(new FoldSlot
+ {
+ opcode = Opcodes.OctahedronToPlane,
+ vec0 = p,
+ vec1 = r,
+ vec2 = s,
+ float0 = t
+ });
+ return this;
+ }
+
+ public FoldPipelineBuilder Rotate(Vector3 center, Vector3 axis, float angle, float t)
+ {
+ slots.Add(new FoldSlot
+ {
+ opcode = Opcodes.Rotate,
+ vec0 = center,
+ vec1 = axis,
+ float0 = angle,
+ float1 = t
+ });
+ return this;
+ }
+
public FoldPipelineBuilder HemiOctahedronToPlane(Vector3 p, Vector3 r, Vector3 s, float t)
{
slots.Add(new FoldSlot
diff --git a/Scripts/Fold/Editor/README.md b/Scripts/Fold/Editor/README.md
index d2b7494..7e6224a 100755
--- a/Scripts/Fold/Editor/README.md
+++ b/Scripts/Fold/Editor/README.md
@@ -89,47 +89,6 @@ Applies fractal Brownian motion deformation.
### Custom(opcode, f0-f3, v0-v3)
For advanced use cases or custom opcodes.
-## Presets (Code)
-
-Use built-in presets from code:
-
-```csharp
-FoldPresets.TubeToPlaneFull(material);
-FoldPresets.NormConvL2ToL1(material);
-FoldPresets.NormConvL2ToLinf(material);
-```
-
-## Adding Custom Presets
-
-Edit `FoldEditorWindow.cs` to add presets to the "Load Presets" menu:
-
-```csharp
-// In ShowPresetsMenu():
-menu.AddItem(new GUIContent("My Custom Effect"), false, () => LoadPreset_MyEffect());
-
-// Add the preset loader method:
-void LoadPreset_MyEffect()
-{
- operations.Clear();
- AddOperation(new TubeToPlaneOp());
- var norm = new NormConversionOp();
- norm.inputK = 2f;
- norm.outputK = 1f;
- AddOperation(norm);
-}
-```
-
-Or use the fluent API in code:
-
-```csharp
-public static void MyCustomEffect(Material mat) =>
- FoldPipelineBuilder.Create()
- .For(mat)
- .TubeToPlane(Vector3.zero, Vector3.right, Vector3.forward, 1f)
- .NormConversion(2f, 1f, 0.5f)
- .Apply();
-```
-
## Pipeline Chaining
Operations are applied in the order they're chained:
diff --git a/brdf.cginc b/brdf.cginc
index d44ce14..d064823 100755
--- a/brdf.cginc
+++ b/brdf.cginc
@@ -250,12 +250,8 @@ float4 brdf(Pbr pbr, LightData data) {
// Standard split-sum IBL
float3 f0_spec = lerp(f0, pbr.albedo.xyz, pbr.metallic);
- //float3 ibl_specular_reflectance = f0_spec * dfg.x + dfg.y;
float3 ibl_specular_reflectance = lerp(dfg.xxx, dfg.yyy, f0_spec);
- //float3 ibl_specular_reflectance = f0_spec * dfg.x;
float3 indirect_specular = data.indirect.specular * ibl_specular_reflectance;
-
- //return float4(data.indirect.specular, 1);
specular += indirect_specular;
remainder = saturate(remainder - indirect_specular);
diff --git a/vertex.cginc b/vertex.cginc
index 7c448ab..c4da8ca 100755
--- a/vertex.cginc
+++ b/vertex.cginc
@@ -17,6 +17,9 @@
#define OPCODE_HEMI_OCTAHEDRON_TO_PLANE 10
#define OPCODE_SCALE 11
#define OPCODE_TRANSLATE 12
+#define OPCODE_PLANE_TO_OCTAHEDRON 13
+#define OPCODE_OCTAHEDRON_TO_PLANE 14
+#define OPCODE_ROTATE 15
#if defined(_VERTEX_DEFORMATION)
@@ -210,6 +213,55 @@ void apply_translate_normal(inout float3 objPos, inout float3 objNorm,
translate_normal(objPos, objNorm, objTan, offset, t);
}
+void apply_plane_to_octahedron(inout float3 objPos, float4 v0, float4 v1, float4 v2, float f0) {
+ float3 p = v0.xyz;
+ float3 r = v1.xyz;
+ float3 s = v2.xyz;
+ float t = f0;
+ objPos = plane_to_octahedron(objPos, p, r, s, t);
+}
+
+void apply_plane_to_octahedron_normal(inout float3 objPos, inout float3 objNorm, inout float3 objTan, float4 v0, float4 v1, float4 v2, float f0) {
+ float3 p = v0.xyz;
+ float3 r = v1.xyz;
+ float3 s = v2.xyz;
+ float t = f0;
+ plane_to_octahedron_normal(objPos, objNorm, objTan, p, r, s, t);
+}
+
+void apply_octahedron_to_plane(inout float3 objPos, float4 v0, float4 v1, float4 v2, float f0) {
+ float3 p = v0.xyz;
+ float3 r = v1.xyz;
+ float3 s = v2.xyz;
+ float t = f0;
+ objPos = octahedron_to_plane(objPos, p, r, s, t);
+}
+
+void apply_octahedron_to_plane_normal(inout float3 objPos, inout float3 objNorm, inout float3 objTan, float4 v0, float4 v1, float4 v2, float f0) {
+ float3 p = v0.xyz;
+ float3 r = v1.xyz;
+ float3 s = v2.xyz;
+ float t = f0;
+ octahedron_to_plane_normal(objPos, objNorm, objTan, p, r, s, t);
+}
+
+void apply_rotate(inout float3 objPos, float4 v0, float4 v1, float f0, float f1) {
+ float3 p = v0.xyz;
+ float3 axis = v1.xyz;
+ float angle = f0;
+ float t = f1;
+ objPos = rotate(objPos, p, axis, angle, t);
+}
+
+void apply_rotate_normal(inout float3 objPos, inout float3 objNorm,
+ inout float3 objTan, float4 v0, float4 v1, float f0, float f1) {
+ float3 p = v0.xyz;
+ float3 axis = v1.xyz;
+ float angle = f0;
+ float t = f1;
+ rotate_normal(objPos, objNorm, objTan, p, axis, angle, t);
+}
+
void deform(inout float3 objPos) {
const float t = getTime();
@@ -454,6 +506,15 @@ void deform(inout float3 objPos) {
case OPCODE_TRANSLATE:
apply_translate(objPos, v0, f0);
break;
+ case OPCODE_PLANE_TO_OCTAHEDRON:
+ apply_plane_to_octahedron(objPos, v0, v1, v2, f0);
+ break;
+ case OPCODE_OCTAHEDRON_TO_PLANE:
+ apply_octahedron_to_plane(objPos, v0, v1, v2, f0);
+ break;
+ case OPCODE_ROTATE:
+ apply_rotate(objPos, v0, v1, f0, f1);
+ break;
}
}
}
@@ -705,6 +766,15 @@ void deform_normal(inout float3 objPos, inout float3 objNorm, inout float3 objTa
case OPCODE_TRANSLATE:
apply_translate_normal(objPos, objNorm, objTan, v0, f0);
break;
+ case OPCODE_PLANE_TO_OCTAHEDRON:
+ apply_plane_to_octahedron_normal(objPos, objNorm, objTan, v0, v1, v2, f0);
+ break;
+ case OPCODE_OCTAHEDRON_TO_PLANE:
+ apply_octahedron_to_plane_normal(objPos, objNorm, objTan, v0, v1, v2, f0);
+ break;
+ case OPCODE_ROTATE:
+ apply_rotate_normal(objPos, objNorm, objTan, v0, v1, f0, f1);
+ break;
}
}
}
diff --git a/vertex_deformation.slang b/vertex_deformation.slang
index 0883c84..de53394 100755
--- a/vertex_deformation.slang
+++ b/vertex_deformation.slang
@@ -483,10 +483,7 @@ public void fbm_normal(inout float3 xyz, inout float3 normal, inout float3 tange
tangent = mul(jac, tangent);
}
-// Maps a plane to a hemi-octahedron (half octahedron).
-// Uses octahedral parameterization consistent with pbrt's OctahedralVector.
-// Input: plane on [-1,1]² in the (r, rxs) plane
-// Output: unit hemisphere with pole at +s direction
+// Maps a plane on [-1, 1] on xz plane to a hemi-octahedron with radius 1.
[Differentiable]
public float3 plane_to_hemi_octahedron(float3 xyz,
no_diff float3 p, no_diff float3 r_cart, no_diff float3 s_cart,
@@ -526,7 +523,7 @@ public float3 plane_to_hemi_octahedron(float3 xyz,
oct_pos = float3(x_unrot, oct_pos.y, z_unrot);
// Interpolate between original position and sphere position
- float3 result = dlerp(xyz0, oct_pos, dmin(t, 1.0f));
+ float3 result = dlerp(xyz0, oct_pos, t);
// Map back to cartesian basis
xyz = mul(to_cart, result) + p;
@@ -539,9 +536,7 @@ public void plane_to_hemi_octahedron_normal(inout float3 xyz, inout float3 norma
R3R3_NORMALS(xyz, normal, tangent, plane_to_hemi_octahedron, p, r, s, t);
}
-// Maps a hemi-octahedron to a plane (inverse of plane_to_hemi_octahedron).
-// Input: unit hemisphere with pole at +s direction
-// Output: plane on [-1,1]² in the (r, rxs) plane
+// Maps a hemi-octahedron with raidus 1 to a quad on [-1, 1] on the (r, rxs) plane.
[Differentiable]
public float3 hemi_octahedron_to_plane(float3 xyz,
no_diff float3 p, no_diff float3 r_cart, no_diff float3 s_cart,
@@ -577,7 +572,7 @@ public float3 hemi_octahedron_to_plane(float3 xyz,
float3 plane_pos = float3(x_plane, 0.0f, z_plane);
// Interpolate between original position and plane position
- float3 result = dlerp(xyz0, plane_pos, dmin(t, 1.0f));
+ float3 result = dlerp(xyz0, plane_pos, t);
// Map back to cartesian basis
xyz = mul(to_cart, result) + p;
@@ -590,6 +585,73 @@ public void hemi_octahedron_to_plane_normal(inout float3 xyz, inout float3 norma
R3R3_NORMALS(xyz, normal, tangent, hemi_octahedron_to_plane, p, r, s, t);
}
+// Maps [-1, 1] on (r, rxs) plane to a unit sphere using octahedral mapping.
+[Differentiable]
+public float3 plane_to_octahedron(float3 xyz,
+ no_diff float3 p, no_diff float3 r_cart, no_diff float3 s_cart,
+ no_diff float t) {
+ r_cart = normalize(r_cart);
+ s_cart = normalize(s_cart);
+ float3 rxs_cart = cross(s_cart, r_cart);
+ float3x3 to_rsrxs = float3x3(r_cart, s_cart, rxs_cart);
+ float3x3 to_cart = transpose(to_rsrxs);
+
+ xyz = mul(to_rsrxs, xyz - p);
+ float3 xyz0 = xyz;
+
+ float l1_norm = dabs(xyz.x) + dabs(xyz.z);
+ if (l1_norm > 1) {
+ xyz.x = sign(xyz0.x) * (1 - dabs(xyz0.z));
+ xyz.z = sign(xyz0.z) * (1 - dabs(xyz0.x));
+ }
+ xyz.y = 1 - l1_norm;
+
+ xyz *= (1 + xyz0.y);
+
+ float3 result = dlerp(xyz0, xyz, t);
+
+ xyz = mul(to_cart, result) + p;
+ return xyz;
+}
+
+public void plane_to_octahedron_normal(inout float3 xyz, inout float3 normal,
+ inout float3 tangent, float3 p, float3 r, float3 s, float t) {
+ R3R3_NORMALS(xyz, normal, tangent, plane_to_octahedron, p, r, s, t);
+}
+
+// Maps a unit sphere to a plane using octahedral mapping.
+[Differentiable]
+public float3 octahedron_to_plane(float3 xyz,
+ no_diff float3 p, no_diff float3 r_cart, no_diff float3 s_cart,
+ no_diff float t) {
+ r_cart = normalize(r_cart);
+ s_cart = normalize(s_cart);
+ float3 rxs_cart = cross(s_cart, r_cart);
+ float3x3 to_rsrxs = float3x3(r_cart, s_cart, rxs_cart);
+ float3x3 to_cart = transpose(to_rsrxs);
+
+ xyz = mul(to_rsrxs, xyz - p);
+ float3 xyz0 = xyz;
+
+ float l1_norm = dabs(xyz.x) + dabs(xyz.y) + dabs(xyz.z);
+ xyz /= l1_norm;
+ float2 xz_tmp = xyz.xz;
+ if (xyz.y < 0) {
+ xyz.x = sign(xz_tmp[0]) * (1 - dabs(xz_tmp[1]));
+ xyz.z = sign(xz_tmp[1]) * (1 - dabs(xz_tmp[0]));
+ }
+ xyz.y = 0;
+
+ float3 result = dlerp(xyz0, xyz, t);
+ xyz = mul(to_cart, result) + p;
+ return xyz;
+}
+
+public void octahedron_to_plane_normal(inout float3 xyz, inout float3 normal,
+ inout float3 tangent, float3 p, float3 r, float3 s, float t) {
+ R3R3_NORMALS(xyz, normal, tangent, octahedron_to_plane, p, r, s, t);
+}
+
[Differentiable]
public float3 scale(float3 xyz,
no_diff float3 k, no_diff float t) {
@@ -612,5 +674,23 @@ public void translate_normal(inout float3 xyz, inout float3 normal,
R3R3_NORMALS(xyz, normal, tangent, translate, offset, t);
}
+[Differentiable]
+public float3 rotate(float3 xyz,
+ no_diff float3 p, no_diff float3 axis, no_diff float angle, no_diff float t) {
+ float theta = angle * t;
+ float3 a = normalize(axis);
+ float c = cos(theta);
+ float s = sin(theta);
+ float3 v = xyz - p;
+ // Rodrigues' rotation formula
+ float3 rotated = v * c + cross(a, v) * s + a * dot(a, v) * (1.0f - c);
+ return rotated + p;
+}
+
+public void rotate_normal(inout float3 xyz, inout float3 normal,
+ inout float3 tangent, float3 p, float3 axis, float angle, float t) {
+ R3R3_NORMALS(xyz, normal, tangent, rotate, p, axis, angle, t);
+}
+
#endif // __CUSTOM31_INC