2.4K Views
March 21, 24
スライド概要
yakatabune.swift での発表資料です。
フリーランスiOSエンジニア 「エンジニアと人生」コミュニティ主宰
Animating Shapes with Simple Equations Shuichi Tsutsumi @shu223
Disclaimer • No Swift, only MSL (Metal Shader Language) • HOWEVER, the concept is universal — GLSL, HLSL, even Swift. • Hope you'll find the concept interesting!
参考書籍 リアルタイムグラフィックスの数学 ― GLSLではじめるシェーダプログラミング amazon 第II部「距離がつくりし世界」 のサンプルをMSLで写経し、 学びを整理したのが本発表
Examples of Animating Shapes
3D
2D
How to create animations like these?
Define the shape for each frame? and display the sequence of images? animatedImage(with: images, duration: 2.0)
! too hard...
Calculate the shape for each frame?
like vector images
<?xml version="1.0" standalone="no"?>
<svg width="200" height="250" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
<rect x="60" y="10" rx="10" ry="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
<circle cx="25" cy="75" r="20" stroke="red" fill="transparent" stroke-width="5"/>
<ellipse cx="75" cy="75" rx="20" ry="5" stroke="red" fill="transparent" stroke-width="5"/>
<line x1="10" x2="50" y1="110" y2="150" stroke="orange" stroke-width="5"/>
<polyline points="60 110 65 120 70 115 75 130 80 125 85 140 90 135 95 150 100 145"
stroke="orange" fill="transparent" stroke-width="5"/>
<polygon points="50 160 55 180 70 180 60 190 65 205 50 195 35 205 40 190 30 180 45 180"
stroke="green" fill="transparent" stroke-width="5"/>
<path d="M20,230 Q40,205 50,230 T90,230" fill="none" stroke="blue" stroke-width="5"/>
</svg>
! too difficult...
! You don't need to do that
Just use ONE function mix(x, y, a) • x: Shape 1 • y: Shape 2 • a: 0.0 - 1.0
!
How can we achieve the animation with just ONE function?
Explaining Step by Step
Sample code Available on GitHub: shu223/Metal-SDF-Examples
Representing Shapes with "Distance"
Signed Distance Function (SDF) Function Returning the Distance to a Shape • Returns 0 for points on the contour of the shape • Positive values for points outside the shape • Negative values for points inside the shape
SDF of a Circle for P(x, y)
Implementing SDF of a Circle ⬇ Metal Shader Language (MSL) float circleSDF(float2 p, float2 c, float r) { return length(p - c) - r; }
Rendering Circle SDF with MSL
float circleSDF(float2 p, float2 c, float r){
return length(p - c) - r;
}
float contour(float v) {
return step(abs(v), 0.008);
}
[[ stitchable ]] half4 circleShader(float2 position,
half4 color,
float4 boundingRect)
{
float2 p = (position.xy * 2.0 - boundingRect.zw) / min(boundingRect.z, boundingRect.w);
half3 rgb = contour(circleSDF(p, float2(0.0), 0.9));
return half4(rgb, 1);
}
Sample code: circleShader.metal
Implementing SDF of a Sphere float circleSDF(float2 p, float2 c, float r){ return length(p - c) - r; } ⬇ float sphereSDF(float3 p, float3 c, float r) { return length(p - c) - r; }
Rendering Sphere SDF
with MSL
float sphereSDF(float3 p, float3 c, float r) {
return length(p - c) - r;
}
!
Not explain today about 3D graphics...
(Camera, Lighting, Ray casting / Ray
marching)
Sample code: mathShader_8_6.metal
Recap on SDF • SDF is a function that returns the distance to a shape. • It enables the representing shapes using "distance". • Learned the SDF of a circle and sphere, and their implementations in MSL.
Controlling SDF Shapes
Combining Shapes The union of SDFs can be calculated with min(d1, d2) // Circle SDF 1 float d1 = circleSDF(p, float2(0, 0.5), 0.9); // Circle SDF 2 float d2 = circleSDF(p, float2(0, -0.5), 0.5); // The union of SDFs float u = min(d1, d2); → Enable SDF shapes to be combined. Sample code: minCircles.metal
Example of combining shapes using
min:
float d = 1.0;
for (float i = 0.0; i < 6.0; i++)
float3 cent = float3(cos(PI *
sin(PI *
0.0);
d = min(d, sphereSDF(p, cent,
}
{
i / 3.0),
i / 3.0),
0.2));
→ Represents six spheres with a single
SDF.
Morphing mix(d1, d2, a) enables Morphing between Shapes. • d1: SDF representing one sphere • d2: SDF representing six spheres • a: Cycles from 0.0 to 1.0 over time float a = abs(mod(time, 2.0) - 1.0); Sample code: mathShader_9_2.metal
Smooth Union
smin(d1, d2, k) enables a "smooth"
union between shapes.
// A min function that interpolates the junction for a smooth SDF union
float smin(float a, float b, float k) {
float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);
return mix(b, a, h) - k * h * (1.0 - h);
}
(The derivation process of this formula is on p129–130)
• d1: A smaller sphere
• d2: A larger sphere
• k: From left, 0.1, 0.3, 0.5
Sample code: mathShader_9_3.metal
Summary • Using SDF allows for representing shapes with "distance." • → Enable Shape Animations with Simple Equations and Functions. Sample code on GitHub: shu223/Metal-SDF-Examples