Unity Graphics Programming Guide
Unity Graphics Programming Guide
IndieVisualLab
2017-10-22 IndieVisualLab
1
Unity
Shader
[Link]
Processing openFrameworks
3DCG Unity
3DCG
IndieVisualLab (& )
Unity
Unity
Unity
2
2
1 Unity 7
1.1 . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . 7
1.2 Unity . . . .. . . . . . . . . . . . . . . . . . . . . 8
1.3 . . . . .. . . . . . . . . . . . . . . . . . . . . 11
1.4 . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . 27
1.5 . . . . . . . . . . . . . . . . . . 34
1.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
1.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2 ComputeShader 37
2.1 . . . . . . . . . . . . . . . . . 38
2.2 (1) : GPU . . . . . . . . . . . 39
2.3 (2) : GPU . . . . . . . . . 46
2.4 . . . . . . . . . . . . . . . . . . . . 51
2.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3 GPU 56
3.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.2 Boids . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.3 . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
3.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
4 81
4.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
4.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
3
4.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
4.4 . . . . . . . . . . . . . . . . . . 83
4.5 . . . . . . . . . . . . . . . . . . . . . . . . 83
4.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
4.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
4.8 . . . . . . . . . . . . . . . . . . . 92
4.9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
4.10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
4.11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
5 SPH 94
5.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
5.2 . . . . . . . . . . . . . . . . . . . . . . . . 96
5.3 SPH . . . . . . . . . . . . . . . . . 100
5.4 SPH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
5.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
5.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
6 114
6.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
6.2 Geometry Shader . . . . . . . . . . . . . . . . . . . . . . . 114
6.3 Geometry Shader . . . . . . . . . . . . . . . . . . . . . . . 115
6.4 Geometry Shader . . . . . . . . . . . . . . . . . . . . . . . 117
6.5 Grass Shader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
6.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
6.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
7 130
7.1 . . . . . . . . . . . . . . . . . . . . 130
7.2 . . . . . . . . . . . . . . . . . . . . . . . . . . 132
7.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
7.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
7.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
7.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
7.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
8 MCMC 149
8.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
4
8.2 . . . . . . . . . . . . . . . . . . . . . . . . . . 150
8.3 . . . . . . . . . . . . . . . . . . . . . . . . . 150
8.4 MCMC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
8.5 . . . . . . . . . . . . . . . . . . . . . . . . . . 155
8.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
8.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
10 ProjectionSpray 168
10.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
10.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
172
5
6
1
Unity
1.1
Procedural Modeling 3D
Rhinoceros*1 CAD
Grasshopper *2
•
•
*1 [Link]
*2 [Link]
7
1 Unity
1.1.1
Sphere radius
segments
1.1.2
1.2 Unity
Unity Mesh
3D 1 3
Mesh
Unity
Mesh
3
1 3
0 1 2 2 3 4 5
8
1.2 Unity
a [Link]
uv
normal
[Link]
Assets/ProceduralModeling
C# Assets/Procedu-
ralModeling/Scripts C#
Unity5.0
1.2.1 Quad
Quad
Quad 4 2
Unity Primitive Mesh
1.1 Quad 0 3
index index
0,1,2 2,3,0
9
1 Unity
[Link]
Mesh
// Mesh
var mesh = new Mesh();
Quad 4 Vector3
uv 4
// Quad size
var hsize = size * 0.5f;
// Quad
var vertices = new Vector3[] {
new Vector3(-hsize, hsize, 0f), // 1 Quad
new Vector3( hsize, hsize, 0f), // 2 Quad
new Vector3( hsize, -hsize, 0f), // 3 Quad
new Vector3(-hsize, -hsize, 0f) // 4 Quad
};
// Quad uv
var uv = new Vector2[] {
new Vector2(0f, 0f), // 1 uv
new Vector2(1f, 0f), // 2 uv
new Vector2(1f, 1f), // 3 uv
new Vector2(0f, 1f) // 4 uv
};
// Quad
var normals = new Vector3[] {
new Vector3(0f, 0f, -1f), // 1
new Vector3(0f, 0f, -1f), // 2
new Vector3(0f, 0f, -1f), // 3
new Vector3(0f, 0f, -1f) // 4
};
index
// Quad index 3 1 ( )
var triangles = new int[] {
0, 1, 2, // 1
2, 3, 0 // 2
};
10
1.3
Mesh
[Link] = vertices;
[Link] = uv;
[Link] = normals;
[Link] = triangles;
// Mesh culling
[Link]();
return mesh;
1.2.2 ProceduralModelingBase
ProceduralModelingBase
Quad
size Mesh
MeshFilter Editor
[Link]
ProceduralModelingMaterial enum
UV
1.3
11
1 Unity
1.3.1 Plane
Plane Quad
1.3 Plane
Quad 1 Plane
12
1.3
1.4 Plane
[Link]
// (0.0 ~ 1.0)
var winv = 1f / (widthSegments - 1);
var hinv = 1f / (heightSegments - 1);
[Link](new Vector3(
(rx - 0.5f) * width,
0f,
(0.5f - ry) * height
));
[Link](new Vector2(rx, ry));
[Link](new Vector3(0f, 1f, 0f));
}
13
1 Unity
index
[Link](a);
[Link](b);
[Link](c);
[Link](c);
[Link](d);
[Link](a);
}
}
ParametricPlaneBase
Plane y 0
ParametricPlaneBase
Plane
[Link]
// Plane
14
1.3
// (0.0 ~ 1.0)
var winv = 1f / (widthSegments - 1);
var hinv = 1f / (heightSegments - 1);
//
[Link] = vertices;
[Link]();
//
[Link]();
return mesh;
}
[Link] ParametricPlaneBase
MountainPlane TerrainPlane GameObject
15
1 Unity
1.3.2 Cylinder
Cylinder
1.6 Cylinder
Cylinder
[Link], [Link]
16
1.3
1.7
( ) radius (x, y) =
([Link]( ) * radius, [Link]( ) * radius)
radius segments
//
float cos = [Link](rad), sin = [Link](rad);
float x = cos * radius, y = sin * radius;
}
Cylinder
1 1 Quad
2
1 Cylinder
Quad
17
1 Unity
1.8 Cylinder
a d [Link]
index
[Link]
Cylinder
GenerateCap
//
float top = height * 0.5f, bottom = -height * 0.5f;
//
GenerateCap(segments + 1, top, bottom, radius, vertices, uvs, normals, true);
//
// index
var len = (segments + 1) * 2;
//
for (int i = 0; i < segments + 1; i++) {
int idx = i * 2;
int a = idx, b = idx + 1, c = (idx + 2) % len, d = (idx + 3) % len;
18
1.3
[Link](a);
[Link](c);
[Link](b);
[Link](d);
[Link](b);
[Link](c);
}
GenerateCap List
void GenerateCap(
int segments,
float top,
float bottom,
float radius,
List<Vector3> vertices,
List<Vector2> uvs,
List<Vector3> normals,
bool side
) {
for (int i = 0; i < segments; i++) {
// 0.0 ~ 1.0
float ratio = (float)i / (segments - 1);
// 0.0 ~ 2
float rad = ratio * PI2;
//
float cos = [Link](rad), sin = [Link](rad);
float x = cos * radius, z = sin * radius;
Vector3 tp = new Vector3(x, top, z), bp = new Vector3(x, bottom, z);
//
[Link](tp);
[Link](new Vector2(ratio, 1f));
//
[Link](bp);
[Link](new Vector2(ratio, 0f));
if(side) {
//
var normal = new Vector3(cos, 0f, sin);
[Link](normal);
[Link](normal);
} else {
[Link](new Vector3(0f, 1f, 0f)); //
[Link](new Vector3(0f, -1f, 0f)); //
}
}
}
Cylinder openEnded
19
1 Unity
GenerateCap
side true false
GenerateCap
20
1.3
//
if(openEnded) {
//
GenerateCap(
segments + 1,
top,
bottom,
radius,
vertices,
uvs,
normals,
false
);
//
[Link](new Vector3(0f, top, 0f));
[Link](new Vector2(0.5f, 1f));
[Link](new Vector3(0f, 1f, 0f));
//
[Link](new Vector3(0f, bottom, 0f)); // bottom
[Link](new Vector2(0.5f, 0f));
[Link](new Vector3(0f, -1f, 0f));
var it = [Link] - 2;
var ib = [Link] - 1;
21
1 Unity
// index offset
var offset = len;
//
for (int i = 0; i < len; i += 2) {
[Link](it);
[Link]((i + 2) % len + offset);
[Link](i + offset);
}
//
for (int i = 1; i < len; i += 2) {
[Link](ib);
[Link](i + offset);
[Link]((i + 2) % len + offset);
}
}
1.3.3 Tubular
Tubular
1.11 Tubular
Cylinder Tubular
Tubular
Tubular
22
1.3
1.12 Tubular
1 Tubular
1 1 Cylinder
Cylinder
Tubular
CurveBase 3
CurveBase CatmullRomCurve
CatmullRomCurve
CurveBase tangent
23
1 Unity
GetPointAt(float) GetTangentAt(float)
[0.0 ~ 1.0] 0.0 1.0
Frenet frame
3
tangent normal
binormal
3 Frenet frame
24
1.3
[Link]
Tubular CatmullRomCurve Catmull-
RomCurve
CatmullRomCurve 4
Tubular
// Frenet frame
var frames = [Link](tubularSegments, closed);
25
1 Unity
// Tubular
for(int i = 0; i < tubularSegments; i++) {
GenerateSegment(curve, frames, vertices, normals, tangents, i);
}
//
GenerateSegment(
curve,
frames,
vertices,
normals,
tangents,
(!closed) ? tubularSegments : 0
);
// uv
for (int i = 0; i <= tubularSegments; i++) {
for (int j = 0; j <= radialSegments; j++) {
float u = 1f * j / radialSegments;
float v = 1f * i / tubularSegments;
[Link](new Vector2(u, v));
}
}
//
for (int j = 1; j <= tubularSegments; j++) {
for (int i = 1; i <= radialSegments; i++) {
int a = (radialSegments + 1) * (j - 1) + (i - 1);
int b = (radialSegments + 1) * j + (i - 1);
int c = (radialSegments + 1) * j + i;
int d = (radialSegments + 1) * (j - 1) + i;
void GenerateSegment(
CurveBase curve,
List<FrenetFrame> frames,
List<Vector3> vertices,
List<Vector3> normals,
List<Vector4> tangents,
int index
26
1.4
) {
// 0.0 ~ 1.0
var u = 1f * index / tubularSegments;
var p = [Link](u);
var fr = frames[index];
var N = [Link];
var B = [Link];
//
float cos = [Link](rad), sin = [Link](rad);
var v = (cos * N + sin * B).normalized;
[Link](p + radius * v);
[Link](v);
1.4
ProceduralModeling
1.4.1
ProceduralModeling
Unity Editor Tree
API*3 Speed Tree* 4
1.4.2 L-System
L-System L-
System Aristid Lindenmayer 1968
*3 [Link]
*4 [Link]
27
1 Unity
L-System L
L-System
1.15 30
[Link]
L-System
• :a
• 1: a -> ab
• 2: b -> a
L-System LSystem
28
1.4
LSystem
• Draw:
• Turn Left:
• Turn Right:
• : Draw
[Link]
L-System
Fractal 1
1.4.3 [Link]
L-System
ProceduralTree
ProceduralTree LSystem
LSystem
ProceduralTree
29
1 Unity
1.16 [Link]
TreeData
TreeData
TreeData
tangent
normal binormal
growthAngleMin growAngleMax
tangent normal binormal
tangent
30
1.4
1.17 T
tangent N normal B
binormal
growthAngleScale growthAngleScale
generation 0
//
var scale = [Link](
1f,
[Link],
1f - 1f * generation / generations
);
// normal
var qn = [Link](scale * [Link](), normal);
// binormal
var qb = [Link](scale * [Link](), binormal);
// tangent qn * qb
[Link] = from + (qn * qb) * tangent * length;
31
1 Unity
TreeBranch
TreeBranch
generations length radius
TreeData
TreeBranch
1 TreeBranch TreeBranch TreeBranch
List<TreeBranch> children TreeBranch
TreeSegment
Tubular 1
Cylinder
TreeSegment Segment
// TreeSegment tangent
// normal binormal FrenetFrame
FrenetFrame frame;
// TreeSegment
Vector3 position;
// TreeSegment ( )
float radius;
1 TreeSegment
FrenetFrame Cylinder
ProceduralTree
ProceduralTree Tubular
TreeBranch TreeSegment Tubular 1
32
1.4
//
// uv (uv.y)
// [0.0 ~ 1.0]
float maxLength = TraverseMaxLength(root);
// 1 1 Mesh
Traverse(root, (branch) => {
var offset = [Link];
//
for(int i = 0, n = [Link]; i < n; i++) {
var t = 1f * i / (n - 1);
var v = vOffset + vLength * t;
//
for (int j = 1; j <= [Link]; j++) {
for (int i = 1; i <= [Link]; i++) {
33
1 Unity
a += offset;
b += offset;
c += offset;
d += offset;
1.5
Teddy
*5 [Link]
34
1.5
2002 2
*6
3D
• 2
• Delaunay Triangula-
tion *7
• 2
3
SIGGRAPH
*8
*6 [Link]
*7 [Link]
*8 [Link]
*9 [Link]
35
1 Unity
1.6
•
•
Unity
3D
1.7
• CEDEC2008 --
- [Link]
• The Algorithmic Beauty of Plants - [Link]
• nervous system - [Link]
36
2
ComputeShader
CG
[Link]
UnityGraphicsProgramming SimpleComputeShader
37
2 ComputeShader
2.1
2.1
GPU 1 1
( )
1 1
(x, y, z) 3
(4, 1, 1) 4*1*1=4 (2, 2,
1) 2*2*1=4 4
2
(4, 1, 1) 2
38
2.2 (1) : GPU
(4, 1, 1)
3 (2, 1, 1)
(4, 4, 1) 2*1*
1=2 2 4 * 4 * 1 = 16
2 * 16 = 32
•
•
• (GPU) (CPU)
(1)
2.2 (1)
39
2 ComputeShader
2.2.1
SimpleComputeShader_Array.compute
RWStructuredBuffer<int> intBuffer;
float floatValue;
[numthreads(4, 1, 1)]
void KernelFunction_A(uint3 groupID : SV_GroupID,
uint3 groupThreadID : SV_GroupThreadID)
{
intBuffer[groupThreadID.x] = groupThreadID.x * floatValue;
}
[numthreads(4, 1, 1)]
void KernelFunction_B(uint3 groupID : SV_GroupID,
uint3 groupThreadID : SV_GroupThreadID)
{
intBuffer[groupThreadID.x] += 1;
}
numthreads SV_GroupID
2.2.2
GPU 1
1 1
KernelFunction_A KernelFunction_B
#pragma kernel
1
#pragma kernel
0, 1
40
2.2 (1) : GPU
2.2.3
RWStructuredBuffer<int> intBuffer}
(CPU) CPU
intValue
2.2.4 numthreads
numthreads (Attribute) ( )
(x, y, z) (4, 1, 1) 4*1*
1=4 (2, 2, 1) 2*2*1=4
4
2.2.5 ( )
CPU
groupID : SV_GroupID g
roupThreadID : SV_GroupThreadID
( )
SV_GroupID
(x, y, z) SV_GroupThreadID
(x, y, z)
(4, 4, 1) (2, 2, 1) SV_GroupID
(0 ~ 3, 0 ~ 3, 0) SV_GroupThreadID (0 ~ 1, 0 ~ 1, 0)
SV_~
41
2 ComputeShader
2.2.6 ( )
groupThreadID
(4, 1, 1) groupThreadID
(0 ~ 3, 0, 0)
SimpleComputeShader_Array.compute
[numthreads(4, 1, 1)]
void KernelFunction_A(uint3 groupID : SV_GroupID,
uint3 groupThreadID : SV_GroupThreadID)
{
intBuffer[groupThreadID.x] = groupThreadID.x * intValue;
}
(1, 1, 1) (
) 1 4*1*1
groupThreadID.x 0~3
groupID 3
2.2.7
• | comuteShader
• | kernelIndex_KernelFunction_A, B
• | intComputeBuffer
SimpleComputeShader_Array.cs
42
2.2 (1) : GPU
void Start()
{
this.kernelIndex_KernelFunction_A
= [Link]("KernelFunction_A");
this.kernelIndex_KernelFunction_B
= [Link]("KernelFunction_B");
[Link]("intValue", 1);
2.2.8
#pragma kernel 0, 1
FindKernel
SimpleComputeShader_Array.cs
this.kernelIndex_KernelFunction_A
= [Link]("KernelFunction_A");
this.kernelIndex_KernelFunction_B
= [Link]("KernelFunction_B");
2.2.9
(GPU) CPU
Unity ComputeBuffer
SimpleComputeShader_Array.cs
43
2 ComputeShader
int[4]
(1)
(2) GPU (3) CPU
2.2.10
SimpleComputeShader_Array.cs
[Link]("intValue", 1);
(CPU) (GPU)
ComputeSh
[Link]~
intValue 1
2.2.11
( ) [Link]
ch
X*Y*Z 1*1*
1=1
SimpleComputeShader_Array.cs
[Link]
(this.kernelIndex_KernelFunction_A, 1, 1, 1);
[Link](result);
( ) [Link]
44
2.2 (1) : GPU
2.2.12 (A)
1*1*1=1 4*1*1=4
intValue 1
SimpleComputeShader_Array.compute
[numthreads(4, 1, 1)]
void KernelFunction_A(uint3 groupID : SV_GroupID,
uint3 groupThreadID : SV_GroupThreadID)
{
intBuffer[groupThreadID.x] = groupThreadID.x * intValue;
}
groupThreadID(SV_GroupThreadID)
(0 ~ 3, 0, 0)
groupThreadID.x 0~3 intBuffer[0] =
0 intBuffer[3] = 3
2.2.13 (B)
1
KernelFunction_A
KernelFunction_B KernelFunction_A
KernelFunction_B
SimpleComputeShader_Array.cs
[Link]
(this.kernelIndex_KernelFunction_B, "intBuffer", [Link]);
[Link](this.kernelIndex_KernelFunction_B, 1, 1, 1);
[Link](result);
2.2.14 (B)
KernelFunction_B intBuffer K
ernelFunction_A
45
2 ComputeShader
SimpleComputeShader_Array.compute
RWStructuredBuffer<int> intBuffer;
[numthreads(4, 1, 1)]
void KernelFunction_B
(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID)
{
intBuffer[groupThreadID.x] += 1;
}
2.2.15
ComputeBuffer
SimpleComputeShader_Array.cs
[Link]();
2.2.16 (1)
(4, 1, 1) (2, 2, 1) 4
2
(2)
•
• (2 )
(2)
46
2.3 (2) : GPU
2.3 (2)
2.3.1
(8, 8, 1) 1 8 * 8 * 1 = 64
RWTexture2D<float4>
SimpleComputeShader_Texture.compute
RWTexture2D<float4> textureBuffer;
[numthreads(8, 8, 1)]
void KernelFunction_A(uint3 dispatchThreadID : SV_DispatchThreadID)
{
float width, height;
[Link](width, height);
textureBuffer[[Link]]
= float4(dispatchThreadID.x / width,
dispatchThreadID.x / width,
dispatchThreadID.x / width,
1);
}
47
2 ComputeShader
2.3.2 SV_DispatchThreadID
(1) SV_DispatchThradID
(x,y,z)
SV_DispathThreadID SV_Group_ID * numthreads + SV_GroupThreadID
SV_Group_ID (x, y, z) SV_GroupT
hreadID (x, y, z)
(1)
(2, 2, 1) (4, 1, 1)
1 (0, 1, 0) (2,
0, 0) SV_DispatchThreadID (0, 1,
0) * (4, 1, 1) + (2, 0, 0) = (0, 1, 0) + (2, 0, 0) = (2, 1, 0)
(2)
(2, 2, 1) (4, 1, 1)
(1, 1, 0) (3, 0, 0)
SV_DispatchThreadID (1, 1, 0) * (4, 1, 1) +
(3, 0, 0) = (4, 1, 0) + (3, 0, 0) = (7, 1, 0)
2.3.3 ( )
(2) [Link]
SimpleComputeShader_Texture.compute
textureBuffer[[Link]]
= float4(dispatchThreadID.x / width,
dispatchThreadID.x / width,
dispatchThreadID.x / width,
1);
512x512 dispatchThr
eadID.x 0 ~ 511 dispatchThreadID / width 0 ~ 0.998
48
2.3 (2) : GPU
[Link] (= )
✓ ✏
RGBA 0~1
0 1
✒ ✑
2.3.4
(1)
(2)
SimpleComputeShader_Texture.cs
RenderTexture renderTexture_A;
void Start()
{
this.renderTexture_A = new RenderTexture
(512, 512, 0, RenderTextureFormat.ARGB32);
this.renderTexture_A.enableRandomWrite = true;
this.renderTexture_A.Create();
RenderTexture Ren
[Link]
• [Link] - Unity
– [Link]
[Link]
2.3.5
( )
SimpleComputeShader_Texture.cs
49
2 ComputeShader
void Start()
{
[Link]
(this.kernelIndex_KernelFunction_A,
out threadSizeX, out threadSizeY, out threadSizeZ);
2.3.6
Dispath
( ) /
( )
512 8
512 / 8 = 64 64
64 * 64 = 4096
SimpleComputeShader_Texture.cs
void Update()
{
[Link]
(this.kernelIndex_KernelFunction_A,
this.renderTexture_A.width / this.kernelThreadSize_KernelFunction_A.x,
this.renderTexture_A.height / this.kernelThreadSize_KernelFunction_A.y,
this.kernelThreadSize_KernelFunction_A.z);
plane_A.GetComponent<Renderer>()
.[Link] = this.renderTexture_A;
8 * 8 * 1 = 64 (= )
4096 4096 * 64 = 262,144
512 * 512 = 262,144
x y
0
50
2.4
2.3.7
(2)
(2) 1
✓ ✏
✒ ✑
2.4
51
2 ComputeShader
2.4.1 GPU
2.4 GPU
GPU
52
2.4
SM Streaming Processor(SP) SM
SP
SM
(DRAM )
SM
SP
SP 4 byte
( )
SM L1
SM SP(= )
53
2 ComputeShader
GPU DRAM
GPU
( )
2.4.2
( )
2.4.3
( )
• ShaderModel cs_4_x
– Z 1
– X*Y*Z 768
• ShaderModel cs_5_0
54
2.5
– Z 64
– X*Y*Z 1024
(x, y, z) 65535
16 KB,
256 byte
2.5
• GPU - GPU -
[Link]
• Windows CUDA - - http://
[Link]/gtc/2013/jp/sessions/[Link]
55
3
GPU
3.1
ComputeShader Boids
Boids
2
CPU
GPU
Unity GPU GPGPU
ComputeShader GPU
ComputeShader
Unity GPU
3.2 Boids
Boids Craig Reynolds
1986 1987 ACM SIGGRAPH Flocks, Herds, and
56
3.3
Reynolds
1. Separation
2. Alignment
3. Cohesion
3.1 Boids
3.3
3.3.1
[Link]
Unity Assets/BoidsSimulationOnGPU
[Link]
57
3 GPU
3.3.2
ComputeShader GPU
ComputeShader API
GPU API
[Link]
Unity 5.6
3.4
58
3.4
3.2 UnityEditor
3.4.1 [Link]
Boids GPU
ComputeShader
[Link]
using UnityEngine;
using [Link];
using [Link];
using [Link];
59
3 GPU
//
const int SIMULATION_BLOCK_SIZE = 256;
//
public float CohesionNeighborhoodRadius = 2.0f;
//
public float AlignmentNeighborhoodRadius = 2.0f;
//
public float SeparateNeighborhoodRadius = 1.0f;
//
public float MaxSpeed = 5.0f;
//
public float MaxSteerForce = 0.5f;
//
public float CohesionWeight = 1.0f;
//
public float AlignmentWeight = 1.0f;
//
public float SeparateWeight = 3.0f;
//
public float AvoidWallWeight = 10.0f;
//
public Vector3 WallCenter = [Link];
//
public Vector3 WallSize = new Vector3(32.0f, 32.0f, 32.0f);
#endregion
#region Accessors
// Boid
public ComputeBuffer GetBoidDataBuffer()
{
return this._boidDataBuffer != null ? this._boidDataBuffer : null;
}
//
public int GetMaxObjectNum()
{
60
3.4
return [Link];
}
//
public Vector3 GetSimulationAreaCenter()
{
return [Link];
}
//
public Vector3 GetSimulationAreaSize()
{
return [Link];
}
#endregion
void Update()
{
//
Simulation();
}
void OnDestroy()
{
//
ReleaseBuffer();
}
void OnDrawGizmos()
{
//
[Link] = [Link];
[Link](WallCenter, WallSize);
}
#endregion
// Boid , Force
var forceArr = new Vector3[MaxObjectNum];
var boidDataArr = new BoidData[MaxObjectNum];
for (var i = 0; i < MaxObjectNum; i++)
{
61
3 GPU
forceArr[i] = [Link];
boidDataArr[i].Position = [Link] * 1.0f;
boidDataArr[i].Velocity = [Link] * 0.1f;
}
_boidForceBuffer.SetData(forceArr);
_boidDataBuffer.SetData(boidDataArr);
forceArr = null;
boidDataArr = null;
}
//
void Simulation()
{
ComputeShader cs = BoidsCS;
int id = -1;
//
int threadGroupSize = [Link](MaxObjectNum
/ SIMULATION_BLOCK_SIZE);
//
id = [Link]("ForceCS"); // ID
[Link]("_MaxBoidObjectNum", MaxObjectNum);
[Link]("_CohesionNeighborhoodRadius",
CohesionNeighborhoodRadius);
[Link]("_AlignmentNeighborhoodRadius",
AlignmentNeighborhoodRadius);
[Link]("_SeparateNeighborhoodRadius",
SeparateNeighborhoodRadius);
[Link]("_MaxSpeed", MaxSpeed);
[Link]("_MaxSteerForce", MaxSteerForce);
[Link]("_SeparateWeight", SeparateWeight);
[Link]("_CohesionWeight", CohesionWeight);
[Link]("_AlignmentWeight", AlignmentWeight);
[Link]("_WallCenter", WallCenter);
[Link]("_WallSize", WallSize);
[Link]("_AvoidWallWeight", AvoidWallWeight);
[Link](id, "_BoidDataBufferRead", _boidDataBuffer);
[Link](id, "_BoidForceBufferWrite", _boidForceBuffer);
[Link](id, threadGroupSize, 1, 1); // ComputeShader
//
id = [Link]("IntegrateCS"); // ID
[Link]("_DeltaTime", [Link]);
[Link](id, "_BoidForceBufferRead", _boidForceBuffer);
[Link](id, "_BoidDataBufferWrite", _boidDataBuffer);
[Link](id, threadGroupSize, 1, 1); // ComputeShader
}
//
void ReleaseBuffer()
{
if (_boidDataBuffer != null)
{
_boidDataBuffer.Release();
_boidDataBuffer = null;
}
62
3.4
if (_boidForceBuffer != null)
{
_boidForceBuffer.Release();
_boidForceBuffer = null;
}
}
#endregion
}
ComputeShader GPU
GPU
Boid
63
3 GPU
3.4.2 [Link]
GPU 2 1
1
[Link]
//
#pragma kernel ForceCS //
#pragma kernel IntegrateCS // ,
// Boid
struct BoidData
{
float3 velocity; //
float3 position; //
};
//
#define SIMULATION_BLOCK_SIZE 256
// Boid
StructuredBuffer<BoidData> _BoidDataBufferRead;
// Boid ,
RWStructuredBuffer<BoidData> _BoidDataBufferWrite;
// Boid
StructuredBuffer<float3> _BoidForceBufferRead;
// Boid ,
RWStructuredBuffer<float3> _BoidForceBufferWrite;
float _DeltaTime; //
float _SeparateNeighborhoodRadius; //
float _AlignmentNeighborhoodRadius; //
float _CohesionNeighborhoodRadius; //
float _MaxSpeed; //
float _MaxSteerForce; //
float _SeparateWeight; //
float _AlignmentWeight; //
float _CohesionWeight; //
float4 _WallCenter; //
float4 _WallSize; //
float _AvoidWallWeight; //
//
float3 limit(float3 vec, float max)
{
float length = sqrt(dot(vec, vec)); //
return (length > max && length > 0) ? [Link] * (max / length) : [Link];
64
3.4
//
float3 avoidWall(float3 position)
{
float3 wc = _WallCenter.xyz;
float3 ws = _WallSize.xyz;
float3 acc = float3(0, 0, 0);
// x
acc.x = (position.x < wc.x - ws.x * 0.5) ? acc.x + 1.0 : acc.x;
acc.x = (position.x > wc.x + ws.x * 0.5) ? acc.x - 1.0 : acc.x;
// y
acc.y = (position.y < wc.y - ws.y * 0.5) ? acc.y + 1.0 : acc.y;
acc.y = (position.y > wc.y + ws.y * 0.5) ? acc.y - 1.0 : acc.y;
// z
acc.z = (position.z < wc.z - ws.z * 0.5) ? acc.z + 1.0 : acc.z;
acc.z = (position.z > wc.z + ws.z * 0.5) ? acc.z - 1.0 : acc.z;
return acc;
}
// Boid
groupshared BoidData boid_data[SIMULATION_BLOCK_SIZE];
//
[numthreads(SIMULATION_BLOCK_SIZE, 1, 1)]
void ForceCS
(
uint3 DTid : SV_DispatchThreadID, // ID
uint3 Gid : SV_GroupID, // ID
uint3 GTid : SV_GroupThreadID, // ID
uint GI : SV_GroupIndex // SV_GroupThreadID 0-255
)
{
const unsigned int P_ID = DTid.x; // ID
float3 P_position = _BoidDataBufferRead[P_ID].position; //
float3 P_velocity = _BoidDataBufferRead[P_ID].velocity; //
// SIMULATION_BLOCK_SIZE ( )
[loop]
for (uint N_block_ID = 0; N_block_ID < (uint)_MaxBoidObjectNum;
N_block_ID += SIMULATION_BLOCK_SIZE)
{
// SIMULATION_BLOCK_SIZE Boid
boid_data[GI] = _BoidDataBufferRead[N_block_ID + GI];
65
3 GPU
//
//
//
GroupMemoryBarrierWithGroupSync();
//
for (int N_tile_ID = 0; N_tile_ID < SIMULATION_BLOCK_SIZE;
N_tile_ID++)
{
//
float3 N_position = boid_data[N_tile_ID].position;
//
float3 N_velocity = boid_data[N_tile_ID].velocity;
//
float3 diff = P_position - N_position;
//
float dist = sqrt(dot(diff, diff));
//
float3 sepSteer = (float3)0.0;
if (sepCount > 0)
{
sepSteer = sepPosSum / (float)sepCount; //
sepSteer = normalize(sepSteer) * _MaxSpeed; //
sepSteer = sepSteer - P_velocity; //
sepSteer = limit(sepSteer, _MaxSteerForce); //
}
66
3.4
//
float3 aliSteer = (float3)0.0;
if (aliCount > 0)
{
aliSteer = aliVelSum / (float)aliCount; //
aliSteer = normalize(aliSteer) * _MaxSpeed; //
aliSteer = aliSteer - P_velocity; //
aliSteer = limit(aliSteer, _MaxSteerForce); //
}
//
float3 cohSteer = (float3)0.0;
if (cohCount > 0)
{
// /
cohPosSum = cohPosSum / (float)cohCount;
cohSteer = cohPosSum - P_position; //
cohSteer = normalize(cohSteer) * _MaxSpeed; //
cohSteer = cohSteer - P_velocity; //
cohSteer = limit(cohSteer, _MaxSteerForce); //
}
force += aliSteer * _AlignmentWeight; //
force += cohSteer * _CohesionWeight; //
force += sepSteer * _SeparateWeight; //
_BoidForceBufferWrite[P_ID] = force; //
}
// ,
[numthreads(SIMULATION_BLOCK_SIZE, 1, 1)]
void IntegrateCS
(
uint3 DTid : SV_DispatchThreadID // ID
)
{
const unsigned int P_ID = DTid.x; //
//
force += avoidWall([Link]) * _AvoidWallWeight;
_BoidDataBufferWrite[P_ID] = b; //
}
ForceCS
groupshared
shared memory
67
3 GPU
SIMULATION_BLOCK_SIZE
3.3 GPU
GroupMemoryBarrierWithGroupSync()
GroupMemoryBarrierWithGroupSync()
GroupMemoryBarrierWithGroupSync()
boid_data
Separation
68
3.4
Alignment
Velocity
Cohesion
3.4.3 [Link]
Boids
[Link]
using [Link];
using [Link];
using UnityEngine;
// GameObject GPUBoids
[RequireComponent(typeof(GPUBoids))]
public class BoidsRender : MonoBehaviour
{
#region Paremeters
// Boids
public Vector3 ObjectScale = new Vector3(0.1f, 0.2f, 0.5f);
#endregion
69
3 GPU
void Update ()
{
//
RenderInstancedMesh();
}
void OnDisable()
{
//
if (argsBuffer != null)
[Link]();
argsBuffer = null;
}
#endregion
//
uint numIndices = (InstanceMesh != null) ?
(uint)[Link](0) : 0;
//
args[0] = numIndices;
//
args[1] = (uint)[Link]();
[Link](args); //
// Boid
[Link]("_BoidDataBuffer",
[Link]());
// Boid
[Link]("_ObjectScale", ObjectScale);
//
var bounds = new Bounds
(
[Link](), //
[Link]() //
);
// GPU
70
3.4
[Link]
(
InstanceMesh, //
0, // submesh
InstanceRenderMaterial, //
bounds, //
argsBuffer // GPU
);
}
#endregion
}
GPU
Mesh GameObject
ComputeShader
CPU GPU
Unity
GPU GameObject
Mesh
[Link]() Graph-
[Link] GPU
ComputeBuffer GPU
Start() GPU
3 ComputeBuffer-
[Link] .
RenderInstancedMesh() GPU
InstanceRenderMaterial SetBuffer
Boids Boid
[Link]
submesh
Update()
3.4.4 [Link]
[Link]
71
3 GPU
[Link]
Shader "Hidden/GPUBoids/BoidsRender"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Standard vertex:vert addshadow
#pragma instancing_options procedural:setup
struct Input
{
float2 uv_MainTex;
};
// Boid
struct BoidData
{
float3 velocity; //
float3 position; //
};
#ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
// Boid
StructuredBuffer<BoidData> _BoidDataBuffer;
#endif
sampler2D _MainTex; //
half _Glossiness; //
half _Metallic; //
fixed4 _Color; //
//
float4x4 eulerAnglesToRotationMatrix(float3 angles)
{
float ch = cos(angles.y); float sh = sin(angles.y); // heading
float ca = cos(angles.z); float sa = sin(angles.z); // attitude
float cb = cos(angles.x); float sb = sin(angles.x); // bank
72
3.4
//
void vert(inout appdata_full v)
{
#ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
// ID Boid
BoidData boidData = _BoidDataBuffer[unity_InstanceID];
//
float4x4 object2world = (float4x4)0;
//
object2world._11_22_33_44 = float4([Link], 1.0);
// Y
float rotY =
atan2([Link].x, [Link].z);
// X
float rotX =
-asin([Link].y / (length([Link])
+ 1e-8)); // 0
//
float4x4 rotMatrix =
eulerAnglesToRotationMatrix(float3(rotX, rotY, 0));
//
object2world = mul(rotMatrix, object2world);
//
object2world._14_24_34 += [Link];
//
[Link] = mul(object2world, [Link]);
//
[Link] = normalize(mul(object2world, [Link]));
#endif
}
void setup()
{
}
//
void surf (Input IN, inout SurfaceOutputStandard o)
{
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
[Link] = [Link];
[Link] = _Metallic;
[Link] = _Glossiness;
}
ENDCG
}
FallBack "Diffuse"
}
73
3 GPU
surf() Standard
vert()
#pragma instancing_options procedural:FunctionName
[Link]
Unity
FunctionName
[Link]
[Link]
unity_ObjectToWorld ,
unity_WorldToObject
Boids
setup
Boid
Vertex Shader
unity_InstanceID ID
ID Boid StructuredBuffer
Boid
Boid
Boid
3
74
3.4
3.4
Z X
atan2
75
3 GPU
3.5
Y
asin
Y
76
3.4
3.6
Boid
4x4 object2world
XYZ Sx Sy Sz
S
⎛ ⎞
Sx 0 0 0
⎜ 0 Sy 0 0 ⎟
S=⎝
0 0 Sz 0 ⎠
0 0 0 1
11 12 13 14
21 22 23 24
31 32 33 34
41 42 43 44
11 22 33 XYZ 44 1
77
3 GPU
XYZ Rx Ry Rz
⎛ ⎞
1 0 0 0
⎜ 0 cos(φ) −sin(φ) 0 ⎟
Rx (φ) = ⎝
0 sin(φ) cos(φ) 0 ⎠
0 0 0 1
⎛ ⎞
cos(θ) 0 sin(θ) 0
⎜ 0 1 0 0 ⎟
Ry (θ) = ⎝
−sin(θ) 0 cos(θ) 0 ⎠
0 0 0 1
⎛ ⎞
cos(ψ) −sin(ψ) 0 0
⎜ sin(ψ) cos(ψ) 0 0 ⎟
Rz (ψ) = ⎝
0 0 1 0 ⎠
0 0 0 1
Unity
3.7
Tx Ty Tz
78
3.4
⎛ ⎞
1 0 0 Tx
⎜ 0 1 0 Ty ⎟
T=⎝
0 0 1 Tz ⎠
0 0 0 1
Boid
3.4.5
3.8
79
3 GPU
3.5
Boids
GPU CPU
3.6
• Boids Background and Update - [Link]
• THE NATURE OF CODE - [Link]
• Real-Time Particle Systems on the GPU in Dy-
namic Environments - [Link]
[Link]/wordpress/media/2013/02/Chapter7-Drone-Real-
TimeParticleSystemsOnThe_GPU.pdf
• Practical Rendering and Computation with Direct3D 11 -
[Link]
• GPU - [Link]
80
4
4.1
ComputeShader
4.2
4.2.1
[Link]
Assets/StabeFluids
4.2.2
• ComputeShader 5.0
• Unity5.6.2, Unity2017.1.1
4.3
81
4
4.3.1
4.3.2
FLIP
82
4.4
4.4
∂−
→u −
→
= − (−
→
u · ∇) −
→
u + ν∇2 −
→
u + f
∂t
∂ρ
= − (−
→
u · ∇) ρ + κ∇2 ρ + S
∂t
∇·−
→
u =0
3
3
4.5
0 0
∇·−
→
u =0
83
4
4.5.1 Divergence
∂u ∂v
∇·−
→
u = ∇ · (u, v) = +
∂x ∂y
∇ ' ( 2
∂ ∂
∂x , ∂y
∇
∇f
4.1 x, y
x
x ∆x y
y ∆y
84
4.6
4.6
4.6.1 Gradient
' (
∂f ∂f
∇f (x, y) =
∂x , ∂y
∇f (grad f )
f
4.6.2 Laplacian
∂2f ∂2f
∆f = ∇2 f = ∇ · ∇f = 2
+ 2
∂x ∂y
(
)
∇2 f ∇ · ∇f
85
4
∇2 −
→
u = ∇∇ · −
→
u −∇×∇×−
→
u
' (
2−
→ ∂ 2 ux ∂ 2 ux ∂ 2 ux ∂ 2 uy ∂ 2 uy ∂ 2 uy ∂ 2 uz ∂ 2 uz ∂ 2 uz
∇ u = + + + + + +
∂x2 ∂y 2 ∂z 2 , ∂x2 ∂y 2 ∂z 2 , ∂x2 ∂y 2 ∂z 2
4.6.3
∂−
→u −
→
= − (−
→
u · ∇) −
→
u + ν∇2 −
→
u + f
∂t
−
→ −
→
u ν kinematic viscosity f force
4.6.4
0 UI
RWTexture2D ID
float visc; //
float dt; //
float velocityCoef; //
float densityCoef; //
86
4.6
4.6.5
ν∇2 −
→
u
∇ ∆
−
→
u
Stable SOR
87
4
#define GS_ITERATE 4
[unroll]
for (int k = 0; k < GS_ITERATE; k++) {
velocity[id] = (prev[id].xy + a * (
velocity[int2(id.x - 1, id.y)] +
velocity[int2(id.x + 1, id.y)] +
velocity[int2(id.x, id.y - 1)] +
velocity[int2(id.x, id.y + 1)]
)) / (1 + 4 * a);
SetBoundaryVelocity(id, w, h);
}
}
}
SetBoundaryVelocity
4.6.6
∇·−
→
u =0
ComputeShader
88
4.6
3
> Poisson >
3
SetBound~
// Step1.
//step1
[numthreads(THREAD_X, THREAD_Y, THREAD_Z)]
void ProjectStep1(uint2 id : SV_DispatchThreadID)
{
uint w, h;
[Link](w, h);
prev[id] = float3(0.0,
-0.5 *
(uvd.x * (velocity[int2(id.x + 1, id.y)].x -
velocity[int2(id.x - 1, id.y)].x)) +
(uvd.y * (velocity[int2(id.x, id.y + 1)].y -
velocity[int2(id.x, id.y - 1)].y)),
prev[id].z);
SetBoundaryDivergence(id, w, h);
SetBoundaryDivPositive(id, w, h);
}
}
// Step2.
//step2 step1 Poisson
[numthreads(THREAD_X, THREAD_Y, THREAD_Z)]
void ProjectStep2(uint2 id : SV_DispatchThreadID)
{
uint w, h;
[Link](w, h);
89
4
// Step3.
//step3 u = 0 .
[numthreads(THREAD_X, THREAD_Y, THREAD_Z)]
void ProjectStep3(uint2 id : SV_DispatchThreadID)
{
uint w, h;
[Link](w, h);
velX = velocity[id].x;
velY = velocity[id].y;
4.6.7
− (−
→
u · ∇) −
→
u
90
4.7
dfdt = dt * (w + h) * 0.5;
// .
x = (float)id.x - dfdt * prev[id].x;
y = (float)id.y - dfdt * prev[id].y;
// .
clamp(x, 0.5, w + 0.5);
clamp(y, 0.5, h + 0.5);
// .
ddx0 = floor(x);
ddx1 = ddx0 + 1;
ddy0 = floor(y);
ddy1 = ddy0 + 1;
// .
s1 = x - ddx0;
s0 = 1.0 - s1;
t1 = y - ddy0;
t0 = 1.0 - t1;
// 1step
4.7
∂ρ
= − (−
→
u · ∇) ρ + κ∇2 ρ + S
∂t
−
→
u κ S
91
4
ν
κ 3
4.8
•
•
–
–
–
–
•
–
–
StableFluid
4.9
92
4.10
4.2
4.10
Unity
GPU
2 FPS
GPU
4.11
• Jos Stam. SIGGRAPH 1999. Stable Fluids
93
5
SPH
SPH
5.1
5.1.1
(
5.1 )
5.1 : :
94
5.1
5.1.2 ( )
*1
φ = φ(−
→
x , t)
t −
→
x φ
∂φ
∂t
−
→
x
*2
−
→
x0
t
−
→
x (−
→
x 0 , t)
φ = φ(−
→
x (−
→
x 0 , t), t)
∆t
φ(−
→
x (−
→
x 0 , t + ∆t), t + ∆t) − φ(−
→
x (−
→
x 0 , t), t)
lim
∆t→0 ∆t
) ∂φ ∂xi ∂φ
= +
i
∂x i ∂t ∂t
⎛⎛ ⎞ ⎛ ∂ ⎞ ⎞
u1 ∂x1 ∂
= ⎝⎝u2 ⎠ · ⎝ ∂x2 ⎠ + ⎠ φ
∂
u3 ∂ ∂t
∂x3
*1
*2
95
5 SPH
∂
=( +−
→
u · grad)φ
∂t
D ∂
:= +−
→
u · grad
Dt ∂t
5.1.3
∇·−
→
u =0
*3
5.2
96
5.2
5.2.1
( NS )
D−
→
u 1
= − ∇p + ν∇ · ∇−
→
u +−
→
g
Dt ρ
NS
NS
NS
5.2
(*4 )
m −
→
x −
→
u V
5.2
−
→ −
→
f m−
→
a = f
m−
→
g
*4 ’Blob’
97
5 SPH
−∇p
−∇p
*5 −V ∇p
( )
µ µ∇ · ∇−
→
u
−
→
m−
→
a = f
D−
→
u
m = −V ∇p + V µ∇ · ∇−
→
u + m−
→
g
Dt
m ρV (V )
D−
→
u
ρ = −∇p + µ∇ · ∇−
→
u + ρ−
→
g
Dt
ρ
D−→
u 1 µ
= − ∇p + ∇ · ∇−
→
u +−
→
g
Dt ρ ρ
µ
ν
ρ
*5
98
5.2
D−
→
u 1
= − ∇p + ν∇ · ∇−
→
u +−
→
g
Dt ρ
NS
5.2.2
∆t ∆t
−
→ D−
→
u ∆−
→
u
a = ≡
Dt ∆t
∆−
→
u
∆−
→
u = ∆t−
→
a
−
→ ∂−
→x ∆−
→
x
u = ≡
∂t ∆t
∆−
→
x = ∆t−
→
u
−
→
un
−
→
u n+1
−
→
u n+1 = −
→
u n + ∆−
→
u =−
→
u n + ∆t−
→
a
−
→
xn
−
→
x n+1
−
→
x n+1 = −
→
x n + ∆−
→
x =−
→
x n + ∆t−
→
u
99
5 SPH
5.3 SPH
NS
CG
SPH
SPH
1996 Desbrun *6 CG
GPU
SPH
5.3.1
SPH
5.3
5.3 2
*6 Desbrun and Cani, Smoothed Particles: A new paradigm for animating highly deformable
bodies, Eurographics Workshop on Computer Animation and Simulation (EGCAS), 1996.
100
5.3 SPH
*7
SPH φ
) φj
φ(−
→
x)= mj W (−
→
xj − −
→
x , h)
ρj
j∈N
N, m, ρ, h
W
) φj
∇φ(−
→
x)= mj ∇W (−
→
xj − −
→
x , h)
ρj
j∈N
) φj 2
∇2 φ(−
→
x)= mj ∇ W (−
→
xj − −
→
x , h)
ρj
j∈N
W
*8
5.3.2
)
ρ(−
→
x)= mj Wpoly6 (−
→
xj − −
→
x , h)
j∈N
5.4 Poly6
*7 ComputeShader
*8 "CG - "
101
5 SPH
5.3.3
) −
→
uj −− →
ui 2
fivisc = µ∇2 −
→
ui =µ mj ∇ Wvisc (−
→
xj − −
→
x , h)
ρj
j∈N
∇2 Wvisc
5.5 Viscosity
5.3.4
1 1 ) pj − pi
fipress = − ∇pi = − mj ∇Wspiky (−
→
xj − −
→
x , h)
ρi ρi 2ρj
j∈N
Wspiky
5.6 Spiky
Tait
*' (γ +
ρ
p=B −1
ρ0
B
102
5.4 SPH
SPH *9
5.4 SPH
([Link]
UnityGraphicsProgramming) Assets/SPHFluid
SPH
5.4.1
5.1 ([Link])
5.4.2 SPH
CPU
(
103
5 SPH
Update )
m
) φj
φ(−
→
x)= m W (−
→
xj − −
→
x , h)
ρj
j∈N
5.2 ([Link])
CPU ( ) GPU
1: [Link]("_NumParticles", numParticles);
2: [Link]("_TimeStep", timeStep);
3: [Link]("_Smoothlen", smoothlen);
4: [Link]("_PressureStiffness", pressureStiffness);
5: [Link]("_RestDensity", restDensity);
6: [Link]("_Viscosity", viscosity);
7: [Link]("_DensityCoef", densityCoef);
8: [Link]("_GradPressureCoef", gradPressureCoef);
9: [Link]("_LapViscosityCoef", lapViscosityCoef);
10: [Link]("_WallStiffness", wallStiffness);
11: [Link]("_Range", range);
12: [Link]("_Gravity", gravity);
1: int _NumParticles; //
2: float _TimeStep; // (dt)
3: float _Smoothlen; //
4: float _PressureStiffness; // Becker
5: float _RestDensity; //
6: float _DensityCoef; //
7: float _GradPressureCoef; //
8: float _LapViscosityCoef; //
9: float _WallStiffness; //
10: float _Viscosity; //
104
5.4 SPH
5.4.3
5.5 ([Link])
1: [numthreads(THREAD_SIZE_X, 1, 1)]
2: void DensityCS(uint3 DTid : SV_DispatchThreadID) {
3: uint P_ID = DTid.x; // ID
4:
5: float h_sq = _Smoothlen * _Smoothlen;
6: float2 P_position = _ParticlesBufferRead[P_ID].position;
7:
8: // (O(n^2))
9: float density = 0;
10: for (uint N_ID = 0; N_ID < _NumParticles; N_ID++) {
11: if (N_ID == P_ID) continue; //
12:
13: float2 N_position = _ParticlesBufferRead[N_ID].position;
14:
15: float2 diff = N_position - P_position; //
16: float r_sq = dot(diff, diff); // 2
17:
18: //
19: if (r_sq < h_sq) {
20: // 2
21: density += CalculateDensity(r_sq);
22: }
23: }
24:
25: //
26: _ParticlesDensityBufferWrite[P_ID].density = density;
27: }
(10
for ) 11
h 19 if
( ) 9 0
105
5 SPH
)
ρ(−
→
x)= mj Wpoly6 (−
→
xj − −
→
x , h)
j∈N
Poly6 Poly6
5.6
5.6 ([Link])
5.5 25
5.4.4
5.7 ([Link])
1: [numthreads(THREAD_SIZE_X, 1, 1)]
2: void PressureCS(uint3 DTid : SV_DispatchThreadID) {
3: uint P_ID = DTid.x; // ID
4:
5: float P_density = _ParticlesDensityBufferRead[P_ID].density;
6: float P_pressure = CalculatePressure(P_density);
7:
8: //
9: _ParticlesPressureBufferWrite[P_ID].pressure = P_pressure;
10: }
∇−
→
u
∇2 p = ρ
∆t
Tait
*' (γ +
ρ
p=B −1
ρ0
106
5.4 SPH
5.4.5
5.9 ([Link])
1: [numthreads(THREAD_SIZE_X, 1, 1)]
2: void ForceCS(uint3 DTid : SV_DispatchThreadID) {
3: uint P_ID = DTid.x; // ID
4:
5: float2 P_position = _ParticlesBufferRead[P_ID].position;
6: float2 P_velocity = _ParticlesBufferRead[P_ID].velocity;
7: float P_density = _ParticlesDensityBufferRead[P_ID].density;
8: float P_pressure = _ParticlesPressureBufferRead[P_ID].pressure;
9:
10: const float h_sq = _Smoothlen * _Smoothlen;
11:
12: // (O(n^2))
13: float2 press = float2(0, 0);
14: float2 visco = float2(0, 0);
15: for (uint N_ID = 0; N_ID < _NumParticles; N_ID++) {
16: if (N_ID == P_ID) continue; //
17:
18: float2 N_position = _ParticlesBufferRead[N_ID].position;
19:
20: float2 diff = N_position - P_position;
21: float r_sq = dot(diff, diff);
22:
23: //
24: if (r_sq < h_sq) {
25: float N_density
26: = _ParticlesDensityBufferRead[N_ID].density;
27: float N_pressure
28: = _ParticlesPressureBufferRead[N_ID].pressure;
29: float2 N_velocity
30: = _ParticlesBufferRead[N_ID].velocity;
31: float r = sqrt(r_sq);
32:
33: //
34: press += CalculateGradPressure(...);
35:
36: //
37: visco += CalculateLapVelocity(...);
38: }
39: }
40:
41: //
42: float2 force = press + _Viscosity * visco;
43:
44: //
45: _ParticlesForceBufferWrite[P_ID].acceleration = force / P_density;
107
5 SPH
46: }
31
1 1 ) pj − pi
fipress = − ∇pi = − mj ∇Wpress (−
→
xj − −
→
x , h)
ρi ρi 2ρj
j∈N
5.10 ([Link])
34
) −
→
uj −− →
ui 2
fivisc = µ∇2 −
→
ui =µ mj ∇ Wvisc (−
→
xj − −
→
x , h)
ρj
j∈N
5.11 ([Link])
5.9 39
5.4.6
5.12 ([Link])
1: [numthreads(THREAD_SIZE_X, 1, 1)]
2: void IntegrateCS(uint3 DTid : SV_DispatchThreadID) {
3: const unsigned int P_ID = DTid.x; // ID
108
5.4 SPH
4:
5: //
6: float2 position = _ParticlesBufferRead[P_ID].position;
7: float2 velocity = _ParticlesBufferRead[P_ID].velocity;
8: float2 acceleration = _ParticlesForceBufferRead[P_ID].acceleration;
9:
10: //
11: if (distance(position, _MousePos.xy) < _MouseRadius && _MouseDown) {
12: float2 dir = position - _MousePos.xy;
13: float pushBack = _MouseRadius-length(dir);
14: acceleration += 100 * pushBack * normalize(dir);
15: }
16:
17: // -----
18:
19: // ( )
20: float dist = dot(float3(position, 1), float3(1, 0, 0));
21: acceleration += min(dist, 0) * -_WallStiffness * float2(1, 0);
22:
23: dist = dot(float3(position, 1), float3(0, 1, 0));
24: acceleration += min(dist, 0) * -_WallStiffness * float2(0, 1);
25:
26: dist = dot(float3(position, 1), float3(-1, 0, _Range.x));
27: acceleration += min(dist, 0) * -_WallStiffness * float2(-1, 0);
28:
29: dist = dot(float3(position, 1), float3(0, -1, _Range.y));
30: acceleration += min(dist, 0) * -_WallStiffness * float2(0, -1);
31:
32: //
33: acceleration += _Gravity;
34:
35: //
36: velocity += _TimeStep * acceleration;
37: position += _TimeStep * velocity;
38:
39: //
40: _ParticlesBufferWrite[P_ID].position = position;
41: _ParticlesBufferWrite[P_ID].velocity = velocity;
42: }
(19-30 )
(213-218 )
33
(36-37 )
109
5 SPH
5.4.7
5.13 ([Link])
ComputeShader
ComputeBuffer
∆t
60FPS ∆t = 1/60
∆t = 1/60 1
∆t = 1/(60 × iterarion) 1
iterarion
110
5.4 SPH
5.14 ([Link])
1: //
2: for (int i = 0; i<iterations; i++) {
3: RunFluidSolver();
4: }
5.4.8
GPU
2
5.15 ([Link])
5.4.9
5.16 ([Link])
1: void DrawParticle() {
2:
3: Material m = RenderParticleMat;
4:
5: var inverseViewMatrix = [Link];
6:
7: [Link](0);
8: [Link]("_InverseMatrix", inverseViewMatrix);
9: [Link]("_WaterColor", WaterColor);
10: [Link]("_ParticlesBuffer", [Link]);
11: [Link]([Link], [Link]);
12: }
10
111
5 SPH
11
5.17 ([Link])
1: struct FluidParticle {
2: float2 position;
3: float2 velocity;
4: };
5:
6: StructuredBuffer<FluidParticle> _ParticlesBuffer;
7:
8: // --------------------------------------------------------------------
9: // Vertex Shader
10: // --------------------------------------------------------------------
11: v2g vert(uint id : SV_VertexID) {
12:
13: v2g o = (v2g)0;
14: [Link] = float3(_ParticlesBuffer[id].[Link], 0);
15: [Link] = float4(0, 0.1, 0.1, 1);
16: return o;
17: }
1-6
14 id : SV_VertexID
5.7
*10
5.7
*10 Plane
112
5.5
5.5
5.8
([Link]
5.6
SPH SPH
SPH
113
6
6.1
Geometry Shader(
) Geometry Shader
( Grass Shader)
Geometry Shader
Geometry Shader
Unity Github
[Link]
CPU
114
6.3 Geometry Shader
Vertex Shader
triangle 3 line 2
point 1 vertex shader
Vertex Shader
Geometry Shader
6.1 Triangles
Quad Geometry Shader Geometry Shader
2 Line
0,1,2
0,2,3
115
6
6.1 Quad
triangle
9 3 Geometry Shader
1
3
Geometry Shader MaxVertexCount
MaxVertexCount
9 Geometry Shader 0 ~9
Geometry Shader
1024
Vertex Shader
Geometry Shader
Geometry Shader Vertex Shader
Geometry Shader Fragment Shader
116
6.4 Geometry Shader
Geometry Shader 0
(x, y, z, w) (r, g,
b, a) 8 GPU
1024 128(1024/8)
1024
Geometry Shader 128
2 (Quad
) Geometry Shader 256 (128 *2
)
128 MaxVertexCount
[Link]
Shader "Custom/SimpleGeometryShader"
{
Properties
{
_Height("Height", float) = 5.0
_TopColor("Top Color", Color) = (0.0, 0.0, 1.0, 1.0)
_BottomColor("Bottom Color", Color) = (1.0, 0.0, 0.0, 1.0)
}
117
6
SubShader
{
Tags { "RenderType" = "Opaque"}
LOD 100
Cull Off
Lighting Off
Pass
{
CGPROGRAM
#pragma target 5.0
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
#include "[Link]"
struct v2g
{
float4 pos : SV_POSITION;
};
struct g2f
{
float4 pos : SV_POSITION;
float4 col : COLOR;
};
v2g vert(appdata_full v)
{
v2g o;
[Link] = [Link];
return o;
}
[maxvertexcount(12)]
void geom(triangle v2g input[3],
inout TriangleStream<g2f> outStream)
{
float4 p0 = input[0].pos;
float4 p1 = input[1].pos;
float4 p2 = input[2].pos;
g2f out0;
[Link] = UnityObjectToClipPos(p0);
[Link] = _BottomColor;
g2f out1;
[Link] = UnityObjectToClipPos(p1);
[Link] = _BottomColor;
118
6.4 Geometry Shader
g2f out2;
[Link] = UnityObjectToClipPos(p2);
[Link] = _BottomColor;
g2f o;
[Link] = UnityObjectToClipPos(c);
[Link] = _TopColor;
// bottom
[Link](out0);
[Link](out1);
[Link](out2);
[Link]();
// sides
[Link](out0);
[Link](out1);
[Link](o);
[Link]();
[Link](out1);
[Link](out2);
[Link](o);
[Link]();
[Link](out2);
[Link](out0);
[Link](o);
[Link]();
}
Quad (2 )
6.2 6.3
119
6
6.2
6.3
Geometry Shader
// Geometry Shader
#pragma geometry geom
[maxvertexcount(12)]
void geom(triangle v2g input[3], inout TriangleStream<g2f> outStream)
Geometry Shader
120
6.4 Geometry Shader
6.4.1
triangle
3 3
triangle point 1
geom(point v2f input[1]) 1
6.4.2
TriangleStream
TriangleStrema
PointStream LineStream
[maxvertexcount(12)] 12
1 3 4
3 3*4 12
12
6.4.3
g2f out0;
[Link] = UnityObjectToClipPos(p0);
[Link] = _BottomColor;
121
6
g2f out1;
[Link] = UnityObjectToClipPos(p1);
[Link] = _BottomColor;
g2f out2;
[Link] = UnityObjectToClipPos(p2);
[Link] = _BottomColor;
g2f o;
[Link] = UnityObjectToClipPos(c);
[Link] = _TopColor;
// bottom
[Link](out0);
[Link](out1);
[Link](out2);
[Link]();
// sides
[Link](out0);
[Link](out1);
[Link](o);
[Link]();
[Link](out1);
[Link](out2);
[Link](o);
[Link]();
[Link](out2);
[Link](out0);
[Link](o);
[Link]();
g2f
Vertex Shader
outStream Append
RestartStrip
TriangleStream Append
Append
RestartStrip
Append RestartSt
rip
122
6.5 Grass Shader
Shader "Custom/Grass" {
Properties
{
//
_Height("Height", float) = 80
//
_Width("Width", float) = 2.5
//
_BottomHeight("Bottom Height", float) = 0.3
//
_MiddleHeight("Middle Height", float) = 0.4
//
_TopHeight("Top Height", float) = 0.5
//
_BottomWidth("Bottom Width", float) = 0.5
//
_MiddleWidth("Middle Width", float) = 0.4
//
_TopWidth("Top Width", float) = 0.2
//
_BottomBend("Bottom Bend", float) = 1.0
//
_MiddleBend("Middle Bend", float) = 1.0
//
_TopBend("Top Bend", float) = 2.0
//
_WindPower("Wind Power", float) = 1.0
//
_TopColor("Top Color", Color) = (1.0, 1.0, 1.0, 1.0)
//
_BottomColor("Bottom Color", Color) = (0.0, 0.0, 0.0, 1.0)
//
_HeightMap("Height Map", 2D) = "white"
//
_RotationMap("Rotation Map", 2D) = "black"
//
_WindMap("Wind Map", 2D) = "black"
}
SubShader
{
123
6
LOD 100
Cull Off
Pass
{
CGPROGRAM
#pragma target 5.0
#include "[Link]"
float _WindPower;
float4 _TopColor, _BottomColor;
sampler2D _HeightMap, _RotationMap, _WindMap;
struct v2g
{
float4 pos : SV_POSITION;
float3 nor : NORMAL;
float4 hei : TEXCOORD0;
float4 rot : TEXCOORD1;
float4 wind : TEXCOORD2;
};
struct g2f
{
float4 pos : SV_POSITION;
float4 color : COLOR;
};
v2g vert(appdata_full v)
{
v2g o;
float4 uv = float4([Link], 0.0f, 0.0f);
[Link] = [Link];
[Link] = [Link];
[Link] = tex2Dlod(_HeightMap, uv);
[Link] = tex2Dlod(_RotationMap, uv);
[Link] = tex2Dlod(_WindMap, uv);
return o;
}
[maxvertexcount(7)]
void geom(triangle v2g i[3], inout TriangleStream<g2f> stream)
{
float4 p0 = i[0].pos;
float4 p1 = i[1].pos;
124
6.5 Grass Shader
float4 p2 = i[2].pos;
float3 n0 = i[0].nor;
float3 n1 = i[1].nor;
float3 n2 = i[2].nor;
g2f o[7];
// Bottom.
o[0].pos = center - dir * bottomWidth;
o[0].color = _BottomColor;
// Bottom to Middle.
o[2].pos = center - dir * middleWidth + normal * bottomHeight;
o[2].color = lerp(_BottomColor, _TopColor, 0.33333f);
// Middle to Top.
o[4].pos = o[3].pos - dir * topWidth + normal * middleHeight;
o[4].color = lerp(_BottomColor, _TopColor, 0.66666f);
// Top.
o[6].pos = o[5].pos + dir * topWidth + normal * topHeight;
o[6].color = _TopColor;
// Bend.
dir = float4(1.0f, 0.0f, 0.0f, 1.0f);
o[2].pos += dir
* (_WindPower * wind * _BottomBend)
* sin(_Time);
o[3].pos += dir
125
6
[unroll]
for (int i = 0; i < 7; i++) {
o[i].pos = UnityObjectToClipPos(o[i].pos);
[Link](o[i]);
}
}
Plane 6.4
126
6.5 Grass Shader
6.5.1
1
6.5 7
6.5
6.5.2
(
)
6.5.3
127
6
Geometry Shader
Geometry Shader
Vertex Shader
...
[unroll]
for (int i = 0; i < 7; i++) {
o[i].pos = UnityObjectToClipPos(o[i].pos);
[Link](o[i]);
}
7 Append
RestartStrip
for [unroll]
6.6
Geometry Shader
CPU
128
6.7
Geometry Shader
Geometry Shader
GPU
Geometry Shader
6.7
• 13 : - [Link]
jp/library/bb172497
• in MSDN -
[Link]
•
- [Link]
129
7
7.1
7.1.1
3
William E. Lorensen Harvey E. Cline 1987
2005
7.1.2
3
7.1 3
130
7.1
1
1 0
0.5
7.2
8 256 15
15
7.3
131
7
7.2
UnityGraphicsProgramming Unity
[Link]
Assets/GPUMarchingCubes
Paul Bourke Polygonising a scalar field *1
Unity
• C#
• ComputeBuffer
•
GPUMarchingCubesDrawMesh
7.2.1 GeometryShader
8
CPU (C# )
GeometryShader GeometryShader
VertexShader FragmentShader Shader VertexShader
1 6
Shader (GPU )
GeometryShader MarchingCubes
GPUMarchingCubesDrawMesh
7.1
132
7.2
using UnityEngine;
#region public
public int segmentNum = 32; //
[Range(0,1)]
public float threashold = 0.5f; //
[Range(0,1)]
public float metallic = 0; //
[Range(0, 1)]
public float glossiness = 0.5f; //
#endregion
#region private
int vertexMax = 0; //
Mesh[] meshs = null; // Mesh
Material[] materials = null; // Mesh
float renderScale = 1f / 32f; //
MarchingCubesDefines mcDefines = null; // MarchingCubes
#endregion
GeometryShader
3 1
64 64*64*64=262,144
Unity2017.1.1f1 65,535
65,535
7.2
void Initialize()
{
vertexMax = segmentNum * segmentNum * segmentNum;
// 1Cube segmentNum
renderScale = 1f / segmentNum;
CreateMesh();
// MarchingCubes
133
7
void CreateMesh()
{
// Mesh 65535 Mesh
int vertNum = 65535;
int meshNum = [Link]((float)vertexMax / vertNum); //
Mesh
[Link]("meshNum " + meshNum );
// Mesh
Bounds bounds = new Bounds(
[Link],
new Vector3(segmentNum, segmentNum, segmentNum) * renderScale
);
int id = 0;
for (int i = 0; i < meshNum; i++)
{
//
Vector3[] vertices = new Vector3[vertNum];
int[] indices = new int[vertNum];
for(int j = 0; j < vertNum; j++)
{
vertices[j].x = id % segmentNum;
vertices[j].y = (id / segmentNum) % segmentNum;
vertices[j].z = (id / (segmentNum * segmentNum)) % segmentNum;
indices[j] = j;
id++;
}
// Mesh
meshs[i] = new Mesh();
meshs[i].vertices = vertices;
// GeometryShader MeshTopology Points
meshs[i].SetIndices(indices, [Link], 0);
meshs[i].bounds = bounds;
7.2.2 ComputeBuffer
[Link]
ComputeBuffer
ComputeBuffer
GPU
134
7.2
C#
( ) 4096
ComputeShader
C#
ComputeBuffer
7.3 ComputeBuffer
void Initialize()
{
vertexMax = segmentNum * segmentNum * segmentNum;
// 1Cube segmentNum
renderScale = 1f / segmentNum;
CreateMesh();
// MarchingCubes
mcDefines = new MarchingCubesDefines();
}
Initialize() MarchingCubesDefines
7.2.3
Unity
[Link]() public
DiffuseColor
MarchingCubesDefines ComputeBuffer [Link]ffer
7.4
void RenderMesh()
{
Vector3 halfSize = new Vector3(segmentNum, segmentNum, segmentNum)
* renderScale * 0.5f;
Matrix4x4 trs = [Link](
[Link],
135
7
[Link],
[Link]
);
materials[i].SetVector("_HalfSize", halfSize);
materials[i].SetColor("_DiffuseColor", DiffuseColor);
materials[i].SetColor("_EmissionColor", EmissionColor);
materials[i].SetMatrix("_Matrix", trs);
7.3
7.5
void Update()
{
RenderMesh();
}
Unity
[Link]() Unity
Update() OnRenderObject()
OnPostRender()
136
7.4
7.4
[Link]
7.4.1
7.6
//
struct appdata
{
float4 vertex : POSITION; //
};
//
struct v2g
{
float4 pos : SV_POSITION; //
};
//
struct g2f_light
{
float4 pos : SV_POSITION; //
float3 normal : NORMAL; //
float4 worldPos : TEXCOORD0; //
half3 sh : TEXCOORD3; // SH
};
//
struct g2f_shadow
{
float4 pos : SV_POSITION; //
float4 hpos : TEXCOORD1;
};
7.7
137
7
int _SegmentNum;
float _Scale;
float _Threashold;
float4 _DiffuseColor;
float3 _HalfSize;
float4x4 _Matrix;
float _EmissionIntensity;
half3 _EmissionColor;
half _Glossiness;
half _Metallic;
StructuredBuffer<float3> vertexOffset;
StructuredBuffer<int> cubeEdgeFlags;
StructuredBuffer<int2> edgeConnection;
StructuredBuffer<float3> edgeDirection;
StructuredBuffer<int> triangleConnectionTable;
C# RenderMesh() mate-
[Link] MarchingCubesDefines Compute-
Buffer StructuredBuffer< >
7.4.2
7.8
//
struct appdata
{
float4 vertex : POSITION; //
};
//
struct v2g
{
float4 pos : SV_POSITION; //
};
//
v2g vert(appdata v)
{
v2g o = (v2g)0;
[Link] = [Link];
return o;
}
138
7.4
7.4.3
7.9
//
[maxvertexcount(15)] //
void geom_light(point v2g input[1],
inout TriangleStream<g2f_light> outStream)
[maxvertexcount(15)]
1
5 3*5 15
maxvertexcount () 15
7.10 8
float cubeValue[8]; // 8
// 8
for (i = 0; i < 8; i++) {
cubeValue[i] = Sample(
pos.x + vertexOffset[i].x,
pos.y + vertexOffset[i].y,
pos.z + vertexOffset[i].z
);
}
pos
vertexOffset pos
1 8
vertexOffset
139
7
7.4
7.11
//
float Sample(float x, float y, float z) {
//
if ((x <= 1) ||
(y <= 1) ||
(z <= 1) ||
(x >= (_SegmentNum - 1)) ||
(y >= (_SegmentNum - 1)) ||
(z >= (_SegmentNum - 1))
)
return 0;
float3 spPos;
float result = 0;
//
for (int i = 0; i < 3; i++) {
float sp = -sphere(
pos - float3(0.5, 0.25 + 0.25 * i, 0.5),
0.1 + (sin(_Time.y * 8.0 + i * 23.365) * 0.5 + 0.5) * 0.025) + 0.5;
result = smoothMax(result, sp, 14);
}
return result;
}
3D
140
7.4
7.12
pos (0,0,0)
radius
length(pos) pos
radius
pos
Inigo Quilez
[Link]
7.13 3
// 3
for (int i = 0; i < 3; i++) {
float sp = -sphere(
pos - float3(0.5, 0.25 + 0.25 * i, 0.5),
0.1 + (sin(_Time.y * 8.0 + i * 23.365) * 0.5 + 0.5) * 0.025) + 0.5;
result = smoothMax(result, sp, 14);
}
1 8 pos
141
7
0.5
3
7.14 smoothMax
smoothMax
3
7.15
//
for (i = 0; i < 8; i++) {
if (cubeValue[i] <= _Threashold) {
flagIndex |= (1 << i);
}
}
//
if ((edgeFlags == 0) || (edgeFlags == 255)) {
return;
}
flagIndex
flagIndex cubeEdgeFlags
edgeFlags
7.16
//
142
7.4
vertex = vertexOffset[edgeConnection[i].x]
+ offset * edgeDirection[i];
// Sample
edgeNormals[i] = getNormal(
defpos.x + vertex.x,
defpos.y + vertex.y,
defpos.z + vertex.z
);
}
}
edgeFlags
getOffset 2
(offset) offset
getNormal
7.17
//
int vindex = 0;
int findex = 0;
// 5
for (i = 0; i < 5; i++) {
findex = flagIndex * 16 + 3 * i;
if (triangleConnectionTable[findex] < 0)
break;
//
for (j = 0; j < 3; j++) {
vindex = triangleConnectionTable[findex + j];
// Transform
float4 ppos = mul(_Matrix, float4(edgeVertices[vindex], 1));
[Link] = UnityObjectToClipPos(ppos);
[Link](o); //
}
[Link](); //
}
triangleConnec-
143
7
tionTable Trans-
form UnityObjectToClipPos()
UnityObjectToWorldNormal()
[Link]() RestartStrip()
Append() RestartStrip()
TriangleStream 1
3 Append
7.4.4
Unity GI( )
Generate code SurfaceShader
7.18
//
void frag_light(g2f_light IN,
out half4 outDiffuse : SV_Target0,
out half4 outSpecSmoothness : SV_Target1,
out half4 outNormal : SV_Target2,
out half4 outEmission : SV_Target3)
G-Buffer (SV_Target) 4
7.19 SurfaceOutputStandard
#ifdef UNITY_COMPILER_HLSL
SurfaceOutputStandard o = (SurfaceOutputStandard)0;
#else
SurfaceOutputStandard o;
#endif
[Link] = _DiffuseColor.rgb;
[Link] = _EmissionColor * _EmissionIntensity;
[Link] = _Metallic;
[Link] = _Glossiness;
[Link] = 1.0;
[Link] = 1.0;
[Link] = normal;
SurfaceOutputStandard
7.20 GI
144
7.4
[Link] = [Link];
[Link][0] = unity_SpecCube0_HDR;
[Link][1] = unity_SpecCube1_HDR;
#if UNITY_SPECCUBE_BOX_PROJECTION
[Link][0] = unity_SpecCube0_BoxMax;
[Link][0] = unity_SpecCube0_ProbePosition;
[Link][1] = unity_SpecCube1_BoxMax;
[Link][1] = unity_SpecCube1_BoxMin;
[Link][1] = unity_SpecCube1_ProbePosition;
#endif
GI UnityGIInput LightnintStandard_GI()
GI UnityGI
7.21
#ifndef UNITY_HDR_ON
[Link] = exp2(-[Link]);
#endif
LightingStandard_Deferred()
Emission HDR exp
145
7
7.4.5
7.22
int vindex = 0;
int findex = 0;
for (i = 0; i < 5; i++) {
findex = flagIndex * 16 + 3 * i;
if (triangleConnectionTable[findex] < 0)
break;
float3 norm;
norm = UnityObjectToWorldNormal(normalize(edgeNormals[vindex]));
[Link](o);
}
[Link]();
}
UnityClipSpaceShadowCasterPos() UnityApplyLinearShadowBias()
7.4.6
7.23
//
fixed4 frag_shadow(g2f_shadow i) : SV_Target
{
return [Link].z / [Link].w;
}
146
7.5
return 0;
Unity
7.5
7.5
7.6
7.6
3D
ASTORONEER*2
*2 ASTRONEER [Link]
147
7
7.7
• Polygonising a scalar field - [Link]
• modeling with distance functions -
[Link]
148
8
MCMC
8.1
MCMC
MCMC
MCMC
MCMC
149
8 MCMC
8.2
UnityGraphicsProgramming Unity
[Link]
Assets/ProceduralModeling
8.3
MCMC
MCMC
•
•
•
•
8.3.1
P(X) X
1/6
1/6
X P(X)
X
X X = X( )
8.3.2
X X
= X( )
X X = X( , t)
150
8.4 MCMC
8.3.3
X P(X)
P(X) X
8.3.4
P
P=P P
8.1 stationaryDistribution
8.4 MCMC
MCMC
MCMC
151
8 MCMC
8.4.1
float pi;
float trial = 10000;
float count = 0;
pi = 4 * count / trial;
1x1
8.4.2
152
8.4 MCMC
8.2 MarkovChain
8.4.3
MCMC
153
8 MCMC
8.3 Irreducibility
8.4 Aperiodicity
154
8.5
8.4.4
1. x x Q(x|x’) = Q(x’|x)
Q Q
2. 1
0 <= r < 1
P(x) P(x’) P(x’)/P(x) P(x’)/P(x)
>r
MH
MH
8.5
MCMC
void Prepare()
{
var sn = new SimplexNoiseGenerator();
for (int x = 0; x < lEdge; x++)
for (int y = 0; y < lEdge; y++)
for (int z = 0; z < lEdge; z++)
{
var i = x + lEdge * y + lEdge * lEdge * z;
var val = [Link](x, y, z);
data[i] = new Vector4(x, y, z, val);
155
8 MCMC
}
}
MCMC
MCMC
Reset
burn-in
156
8.5
next _curr
(O(n^3)
)
157
8 MCMC
8.6
MCMC
MCMC
8.7
• 2012
MCMC ( )
• Olle Haggstrom, (2017) MCMC :
158
9
MultiPlane
PerspectiveProjection
CG
CG
UnityGraphicsProgramming Unity
*1 Assets/RoomProjection
2016 12 *2
9.1 CG
CG
D
CG
*1 [Link]
*2 [Link]
159
9 MultiPlane PerspectiveProjection
9.1
9.2
CG
D
9.2
160
9.2
9.3
9.4
161
9 MultiPlane PerspectiveProjection
9.3
P roj
• C :
• V :
C = P roj ∗ V
C Cw NDC
Cx Cy Cz
N DC = ( , , )
Cw Cw Cw
Cw = −Vz P roj
Z NDC
−1 ≤ x, y, z ≤ 1 Vz Vx,y
P roj
nearClipPlane N farClipPlane F
9.5 N,F
• −1 ≤ x ≤ 1
162
9.3
• Cw (= −Vz )
Nz
P roj[0, 0] =
Nx
x,z P roj[0][0] = Fz
Fx
x,z
Nz
P roj[1, 1] =
Ny
z P roj ∗ V
Cz = P roj[2, 2] ∗ Vz + P roj[2, 3] ∗ Vw ( Vw = 1)
Cz
N DCz = Cw = −Vz
Cw
Nz − 1, Fz 1 a = P roj[2, 2], b = P roj[2, 3]
1 1
−1 = (aNz + b), 1= (aFz + b)
Nz Fz
Fz + N z −2Fz Nz
P roj[2, 2] = a = , P roj[2, 3] = b =
Fz − N z Fz − N z
Cw = −Vw
P roj[3, 2] = −1
P roj
⎛ ⎞
Nz
Nx 0 0 0
⎜ 0 Nz
0 0 ⎟
P roj = ⎜
⎝ 0
Ny
Fz +Nz
⎟
⎠
0 Fz −Nz
−2Fz Nz
Fz −Nz
0 0 −1 0
163
9 MultiPlane PerspectiveProjection
9.3.1 [Link]
Unity Cam-
[Link]
OpenGL *3 −1 ≤ N DCz ≤ 1 Cw = −Vw
Unity
[Link]
N DCz Z
*4
9.4
9.4.1
fov fieldOfView, aspect
Unity Inspector
faceSize distance
9.1
9.4.2
*3 [Link]
*4 [Link]
164
9.4
9.6
NDC
x,y Projection
⎛ ⎞
Nz
Nx 0 0 0
⎜ 0 Nz
0 0 ⎟
P roj = ⎜
⎝ 0
Ny
Fz +Nz
⎟
⎠
0 Fz −Nz
−2Fz Nz
Fz −Nz
0 0 −1 0
LensShift NDC -1 1
9.2
165
9 MultiPlane PerspectiveProjection
9.5
CG
9.7
*5 [Link]
166
9.6
9.8
9.6
HMD
VR
•
–
–
CAVE *6
*6 [Link]
167
10
ProjectionSpray
10.1
10.1.1 ProjectionSpray
Github
[Link]
3D
168
10.1
10.1 1
10.2 2
169
10 ProjectionSpray
10.3 3
10.4 4
Unity
10.2
170
10.2
Unity
[Link]
( _ )
171
1 Unity - / @mattatz
Web
• [Link]
• [Link]
• [Link]
2 ComputeShader - @XJINE
• [Link]
• [Link]
• [Link]
3 GPU - / @irishoak
MV
VJ
sugi-cho mattatz Aqueduct
• [Link]
• [Link]
• [Link]
• [Link]
172
4 - / @sakope
• [Link]
• [Link]
5 SPH - / @kodai100
TouchDesigner
twitter
• [Link]
• [Link]
• [Link]
6 - @a3geek
• [Link]
• [Link]
7 - @kaiware007
Twitter VJ
• [Link]
• [Link]
• [Link]
8 MCMC 3 - @ komietty
Web
twitter
173
• [Link]
• [Link]
9 MultiPlanePerspectiveProjection - / @fuqunaga
• [Link]
• [Link]
• [Link]
10 ProjectionSpray - / @sugi_cho
Unity hi@[Link]
• [Link]
• [Link]
• [Link]
LAN
174
Unity Graphics Programming
2017 10 22 3 v1.0.0
IndieVisualLab
IndieVisualLab
IndieVisualLab
175
Geometry Shaders allow dynamic modification of geometric primitives, enabling complex transformations such as adding vertices, changing the topology of 3D models, and creating or displacing geometry in single shader stages. They provide significant advantages over traditional shaders by allowing real-time topology changes without the need to transfer data back to the CPU or re-upload vertex buffers, which can be resource-intensive. This makes them ideal for procedural content generation, such as dynamic effects or terrain tessellation in 3D environments .
The ParametricPlaneBase class calculates the positions of mesh vertices by iterating through segments on the plane using width and height segments. It computes relative positions using normalized coordinates, multiples them by the width and height inverse of the segments to scale correctly, and assigns these values to mesh vertices. A Depth function is used to determine the vertices' y-coordinate, allowing modification of the plane's surface. The calculated vertices are assigned back to the mesh object, and functions like RecalculateBounds and RecalculateNormals are called to update the mesh's data for rendering .
The Boids model leverages separation, alignment, and cohesion rules to mimic natural flocking behavior. Separation ensures that boids maintain a comfortable distance from each other, preventing crowding. Alignment causes each boid to steer towards the average heading of its neighbors, promoting uniform movement. Cohesion encourages each boid to move towards the average position of its group, maintaining unity within the flock. Together, these rules form a decentralized system that simulates complex group dynamics using simple local interactions without external control .
The Frenet Frame helps define the orientation of a tubular structure around a central curve by computing tangent, normal, and binormal vectors at each point along the curve. These frames ensure correct rotation and scaling of the tube cross-sections, enabling the tube to bend and twist naturally with the path. In procedural modeling, the ComputeFrenetFrames method generates these frames, allowing for smooth extrusions around the path, and ensuring vertices and normals align correctly for the tubular geometry .
L-Systems offer computational efficiency in generating fractal patterns due to their recursive rewriting rules which allow complex shapes to be described succinctly and expanded iteratively, minimizing memory footprint compared with storing and manipulating large datasets. This symbolic representation supports rapid prototyping and visualization of fractal geometry, providing an elegant method for generating intricate patterns dynamically. Additionally, they adapt well to parallel processing, enabling large-scale computations suitable for graphical applications and simulations .
L-System modeling contributes significantly to procedural generation by using iterative string rewriting to simulate growth patterns found in nature, especially suited for tree-like structures. Each iteration refines the complexity of the model by applying rules to replace parts of the string, which are interpreted into geometric shapes. This powerful abstraction enables the creation of realistic plant growth patterns in 3D modeling, allowing for variance and scalability in complex scenes, thereby enhancing the richness of virtual environments dynamically .
Using parameterized curves like Catmull-Rom splines in procedural generation allows for smooth, natural shaping of tubular structures, as these splines provide precise control over curve tangents without requiring explicit handle points. This results in smoother trajectories that can be effortlessly integrated into tubular geometries, ensuring that the generated structure follows an intuitive path that mimics organic forms or fulfills specific design requirements. Such an approach facilitates complex modeling tasks by offering continuous control over the curve's shape and continuity .
Radial segmentation in a pipeline architecture determines the circular resolution of cylindrical objects, defining the number of sides or 'slices' that comprise the round face of the cylinder. A higher radial segment count results in a smoother and more circular appearance, while fewer segments create a more polygonal shape. These segments are crucial for balancing performance and visual quality, as increasing segments requires more computations but provides a finer surface representation, enhancing the realism of cylindrical models .
The GenerateCap method is crucial for creating end caps for 3D shapes like cylinders to define boundaries and ensure surface completion. This method involves calculating the edge vertices along a defined radius by iterating through segments, computing cosine and sine based on segment angle, and multiplying these by the radius to define vertex positions at the top and bottom. It adds these vertices to lists for positioning and UV texture coordinates, adjusts normals depending on whether it is a side face or an end cap, and calculates triangles for mesh connectivity, ensuring a closed shape .
Compute Shaders are leveraged in GPU programming to parallelize computations and offload intensive tasks from the CPU, significantly improving performance for simulations like Boids flocking. By executing parallel operations for each boid's movement simultaneously, these shaders handle large numbers of boids efficiently, managing position updates and behavioral calculations in real-time. This approach accelerates flocking simulations by harnessing the massive parallel processing power of GPUs, reducing computation time and enhancing simulation responsiveness and scale .