Slide 1

Slide 1 text

࡞ͬͯΘ͔Δ ϨϯμϦϯά ύΠϓϥΠϯ d$16Ͱ%ඳըd iOSDC Japan 2018

Slide 2

Slide 2 text

!UB@LB@UTV ذෞݝࡏॅ ࣗݾ঺հ

Slide 3

Slide 3 text

!UB@LB@UTV ذෞݝࡏॅ ࣗݾ঺հ %$"%ܥϓϩάϥϚʔ

Slide 4

Slide 4 text

!UB@LB@UTV ذෞݝࡏॅ ࣗݾ঺հ %$"%ܥϓϩάϥϚʔ %$".ܥϓϩάϥϚʔ

Slide 5

Slide 5 text

!UB@LB@UTV ذෞݝࡏॅ ࣗݾ঺հ %$"%ܥϓϩάϥϚʔ %$".ܥϓϩάϥϚʔ ձࣾઃཱ

Slide 6

Slide 6 text

!UB@LB@UTV ذෞݝࡏॅ ࣗݾ঺հ %$"%ܥϓϩάϥϚʔ %$".ܥϓϩάϥϚʔ ϑϦʔϥϯεˡ/PX ձࣾઃཱ

Slide 7

Slide 7 text

!UB@LB@UTV ذෞݝࡏॅ ࣗݾ঺հ %$"%ܥϓϩάϥϚʔ %$".ܥϓϩάϥϚʔ ϑϦʔϥϯεˡ/PX ձࣾઃཱ

Slide 8

Slide 8 text

֓ཁ ཧղ ෼ղ ࠶ߏங ϨϯμϦϯά ύΠϓϥΠϯͷ

Slide 9

Slide 9 text

ཧղ ϨϯμϦϯά ύΠϓϥΠϯͷ 6OEFSTUBOEJOH

Slide 10

Slide 10 text

σʔλ͔Βը૾ͳͲΛಘΔ͜ͱ ϨϯμϦϯά ύΠϓϥΠϯͱ͸ ϨϯμϦϯάɿ ෳ਺ͷॲཧΛ௚ྻʹܨ͍ͩҰ࿈ͷॲཧ ύΠϓϥΠϯɿ %άϥϑΟοΫεΛܭࢉ͢Δ ॲཧํࣜͷͭ

Slide 11

Slide 11 text

ϨϯμϦϯά ύΠϓϥΠϯͰඳ͚Δ΋ͷ ɾ఺

Slide 12

Slide 12 text

ɾ఺ ɾઢ ϨϯμϦϯά ύΠϓϥΠϯͰඳ͚Δ΋ͷ

Slide 13

Slide 13 text

ɾ఺ ɾઢ ɾࡾ֯ܗ ϨϯμϦϯά ύΠϓϥΠϯͰඳ͚Δ΋ͷ

Slide 14

Slide 14 text

ɾ఺ ɾઢ ɾࡾ֯ܗ ϙϦΰϯ ϓϦϛςΟϒ ϓϦϛςΟϒ

Slide 15

Slide 15 text

ɾ఺ʜ௖఺ͭ ɾઢʜ௖఺ͭ ɾࡾ֯ܗʜ௖఺ͭ ϓϦϛςΟϒ

Slide 16

Slide 16 text

௖఺ଐੑ ௖఺ଐੑ ɾҐஔ

Slide 17

Slide 17 text

௖఺ଐੑ ɾ৭ ௖఺ଐੑ ɾҐஔ

Slide 18

Slide 18 text

௖఺ଐੑ ɾ৭ ௖఺ଐੑ ɾҐஔ ɾ๏ઢϕΫτϧ ɾʜ ɾςΫενϟ࠲ඪ

Slide 19

Slide 19 text

%σʔλ ύΠϓϥΠϯ ϨϯμϦϯά ϑϨʔϜόοϑΝ ϨϯμϦϯάύΠϓϥΠϯͷೖग़ྗ

Slide 20

Slide 20 text

ϨϯμϦϯάύΠϓϥΠϯͷೖग़ྗ ௖఺ྻ ύΠϓϥΠϯ ϨϯμϦϯά ϑϨʔϜόοϑΝ

Slide 21

Slide 21 text

ϨϯμϦϯάύΠϓϥΠϯͷೖग़ྗ ௖఺ྻ ύΠϓϥΠϯ ϨϯμϦϯά ϑϨʔϜόοϑΝ

Slide 22

Slide 22 text

ϨϯμϦϯάύΠϓϥΠϯͷೖग़ྗ ௖఺ྻ 6OJGPSN ڞ௨σʔλ ύΠϓϥΠϯ ϨϯμϦϯά ϑϨʔϜόοϑΝ

Slide 23

Slide 23 text

ϨϯμϦϯάύΠϓϥΠϯͷೖग़ྗ ௖఺ྻ ύΠϓϥΠϯ ϨϯμϦϯά ϑϨʔϜόοϑΝ ඳը໋ྩ %SBX$BMM 6OJGPSN ڞ௨σʔλ

Slide 24

Slide 24 text

%FDPNQPTJUJPO ෼ղ ϨϯμϦϯά ύΠϓϥΠϯͷ

Slide 25

Slide 25 text

ϨϯμϦϯάύΠϓϥΠϯͷೖग़ྗ ௖఺ྻ ϑϨʔϜόοϑΝ 6OJGPSN ڞ௨σʔλ ύΠϓϥΠϯ ϨϯμϦϯά

Slide 26

Slide 26 text

ϨϯμϦϯάύΠϓϥΠϯͷೖग़ྗ ௖఺ྻ ϓϦϛςΟϒΞηϯϒϦ ௖఺ॲཧ ϥελϥΠζ ϑϥάϝϯτॲཧ ϐΫηϧૢ࡞ 6OJGPSN ڞ௨σʔλ ϑϨʔϜόοϑΝ

Slide 27

Slide 27 text

௖఺ॲཧ ϓϦϛςΟϒΞηϯϒϦ ϥελϥΠζ ϑϥάϝϯτॲཧ ϐΫηϧૢ࡞ ϑϨʔϜόοϑΝ ௖఺ྻ ௖఺ॲཧ

Slide 28

Slide 28 text

௖఺ॲཧ ௖఺ྻ ೖྗɿ ௖఺ྻ ग़ྗɿ ௖఺ॲཧ

Slide 29

Slide 29 text

௖఺ॲཧɿ௖఺γΣʔμʔ ௖఺ ௖఺ ௖఺γΣʔμʔ ڞ௨σʔλ ɾଐੑ" ɾҐஔ ɾଐੑ# ɾଐੑ$ ɾଐੑ% ɾҐஔ ɾଐੑ&

Slide 30

Slide 30 text

௖఺ॲཧɿ௖఺γΣʔμʔ ɾ৭ ɾҐஔ ɾ๏ઢϕΫτϧ ɾ৭ ɾҐஔ ௖఺ଐੑ ௖఺ଐੑ ௖఺γΣʔμʔ

Slide 31

Slide 31 text

௖఺ॲཧɿΫϦοϐϯά ΫϦοϐϯάۭؒ .FUBMͰ͸ −1 ≦ x ≦ 1 −1 ≦ y ≦ 1 0 ≦ z ≦ 1

Slide 32

Slide 32 text

௖఺ॲཧɿΫϦοϐϯά

Slide 33

Slide 33 text

௖఺ॲཧɿΫϦοϐϯά

Slide 34

Slide 34 text

௖఺ॲཧɿΫϦοϐϯά

Slide 35

Slide 35 text

௖఺ॲཧɿΫϦοϐϯά

Slide 36

Slide 36 text

௖఺ॲཧɿΫϦοϐϯά

Slide 37

Slide 37 text

௖఺ॲཧɿΫϦοϐϯά

Slide 38

Slide 38 text

௖఺ॲཧɿΫϦοϐϯά

Slide 39

Slide 39 text

௖఺ॲཧɿϏϡʔϙʔτม׵ ΫϦοϐϯάۭؒ Ϗϡʔ Ϗϡʔϙʔτ Y Z

Slide 40

Slide 40 text

௖఺ॲཧɿϏϡʔϙʔτม׵ ΫϦοϐϯάۭؒ Ϗϡʔ Ϗϡʔϙʔτ Y Z

Slide 41

Slide 41 text

ϓϦ ϛ ςΟϒ ΞηϯϒϦ ϥελϥΠζ ϑϥάϝϯτॲཧ ϐΫηϧૢ࡞ ϑϨʔϜόοϑΝ ௖఺ྻ ௖఺ॲཧ ϓϦϛςΟϒΞηϯϒϦ

Slide 42

Slide 42 text

ϓϦϛςΟϒΞηϯϒϦ ௖఺ྻ ೖྗɿ ϓϦϛςΟϒྻ ग़ྗɿ ϓϦϛςΟϒ ΞηϯϒϦ

Slide 43

Slide 43 text

ϓϦϛςΟϒΞηϯϒϦ V[0] V[1] V[2] V[3] V[4]

Slide 44

Slide 44 text

1PJOUT ϓϦϛςΟϒΞηϯϒϦ V[1] V[2] V[3] V[4] Point[0] Point[1] Point[2] Point[3] Point[4] V[0]

Slide 45

Slide 45 text

-JOFT ϓϦϛςΟϒΞηϯϒϦ V[0] V[1] V[2] V[3] V[4] Line[0] Line[1]

Slide 46

Slide 46 text

-JOF4USJQ ϓϦϛςΟϒΞηϯϒϦ V[0] V[1] V[2] V[3] V[4] Line[0] Line[1] Line[2] Line[3]

Slide 47

Slide 47 text

5SJBOHMFT ϓϦϛςΟϒΞηϯϒϦ V[0] V[1] V[2] V[3] V[4] Triangle[0]

Slide 48

Slide 48 text

5SJBOHMF4USJQ ϓϦϛςΟϒΞηϯϒϦ V[0] V[1] V[2] V[3] V[4] Triangle[0] Triangle[1] Triangle[2]

Slide 49

Slide 49 text

5SJBOHMF'BO ϓϦϛςΟϒΞηϯϒϦ -JOF-PPQ Triangle[0] Triangle[1] Triangle[2] Line[0] Line[1] Line[2] Line[3] Line[4] V[0] V[1] V[2] V[3] V[4] V[4] V[0] V[1] V[2] V[3]

Slide 50

Slide 50 text

ϓϦϛςΟϒΞηϯϒϦɿΧϦϯά Φϓγϣϯ

Slide 51

Slide 51 text

ϓϦϛςΟϒΞηϯϒϦɿΧϦϯά Φϓγϣϯ

Slide 52

Slide 52 text

ϓϦϛςΟϒΞηϯϒϦɿΧϦϯά Φϓγϣϯ

Slide 53

Slide 53 text

ϓϦϛςΟϒΞηϯϒϦɿΧϦϯά Φϓγϣϯ ໘ͷ޲͖ʁ

Slide 54

Slide 54 text

0 2 1 ࣌ܭճΓ $8 ϓϦϛςΟϒΞηϯϒϦɿΧϦϯά Φϓγϣϯ 0 1 2 ൓࣌ܭճΓ $$8 PS

Slide 55

Slide 55 text

ϥελϥΠζ ϓϦϛςΟϒΞηϯϒϦ ϑϥάϝϯτॲཧ ϐΫηϧૢ࡞ ϑϨʔϜόοϑΝ ௖఺ྻ ௖఺ॲཧ ϥελϥΠζ

Slide 56

Slide 56 text

ϥελϥΠζ ϓϦϛςΟϒྻ ೖྗɿ ϑϥάϝϯτྻ ग़ྗɿ ϥελϥΠζ

Slide 57

Slide 57 text

ϥελϥΠζ

Slide 58

Slide 58 text

ϥελϥΠζ

Slide 59

Slide 59 text

ϥελϥΠζ ϑϥάϝϯτ ɾ;஋ ɾϐΫηϧ࠲ඪ ɾଐੑ" ɾଐੑ# ɾ

Slide 60

Slide 60 text

ϥελϥΠζ

Slide 61

Slide 61 text

ϥελϥΠζ

Slide 62

Slide 62 text

ϥελϥΠζɿϑϥάϝϯτͷ஋ P0 P1 P s t P = t s + t P0 + s s + t P1 = w0 P0 + w1 P1 (w0 + w1 = 1) AP = w0 AP0 + w1 AP1 AX ɿ఺ X ͷଐੑ஋

Slide 63

Slide 63 text

ϥελϥΠζ

Slide 64

Slide 64 text

ϥελϥΠζ

Slide 65

Slide 65 text

ϥελϥΠζɿϑϥάϝϯτͷ஋ P0 P1 Q s1 t1 Q = t1 s1 + t1 P0 + s1 s1 + t1 P1 = w0 P0 + w1 P1 + w2 P2 (w0 + w1 + w2 = 1) P P2 s2 t2 P = t2 s2 + t2 Q + s2 s2 + t2 P2 AP = w0 AP0 + w1 AP1 + w2 AP2

Slide 66

Slide 66 text

ϑϥά ϝϯτ ॲཧ ϓϦϛςΟϒΞηϯϒϦ ϐΫηϧૢ࡞ ϑϨʔϜόοϑΝ ௖఺ྻ ௖఺ॲཧ ϥελϥΠζ ϑϥάϝϯτॲཧ

Slide 67

Slide 67 text

ϑϥάϝϯτॲཧ ৭ ϑϥάϝϯτྻ ग़ྗɿ ϑϥάϝϯτྻ ೖྗɿ ϑϥάϝϯτ ॲཧ

Slide 68

Slide 68 text

ϑϥάϝϯτॲཧ ϑϥά ϝϯτ ɾϐΫηϧ࠲ඪ ɾଐੑ" ɾଐੑ# ɾ;஋ ɾ৭ ɾ ڞ௨σʔλ ϑϥάϝϯτ γΣʔμʔ

Slide 69

Slide 69 text

ϑϥάϝϯτॲཧ ϑϥά ϝϯτ ɾϐΫηϧ࠲ඪ ɾଐੑ" ɾଐੑ# ɾ;஋ ɾϐΫηϧ࠲ඪ ɾ৭ ɾ;஋ ɾ ڞ௨σʔλ ৭ ϑϥά ϝϯτ ϑϥάϝϯτ γΣʔμʔ

Slide 70

Slide 70 text

ϑϥάϝϯτॲཧɿϑϥάϝϯτγΣʔμʔ ϑϥάϝϯτγΣʔμʔ ɾϐΫηϧ࠲ඪ ɾςΫενϟ࠲ඪ ɾ৭ ςΫενϟ ڞ௨σʔλ ɾ;஋

Slide 71

Slide 71 text

ϐΫηϧ ૢ࡞ ϓϦϛςΟϒΞηϯϒϦ ϑϨʔϜόοϑΝ ௖఺ྻ ௖఺ॲཧ ϥελϥΠζ ϑϥάϝϯτॲཧ ϐΫηϧૢ࡞

Slide 72

Slide 72 text

ϐΫηϧૢ࡞ ϑϨʔϜόοϑΝ ग़ྗɿ ৭ ϑϥάϝϯτྻ ೖྗɿ ϐΫηϧૢ࡞ ΧϥʔόοϑΝ σϓεόοϑΝ εςϯγϧόοϑΝ

Slide 73

Slide 73 text

ϐΫηϧૢ࡞ɿσϓεςετ Φϓγϣϯ ྘Λઌʹॻ͍ͨ৔߹ ਫ৭Λઌʹॻ͍ͨ৔߹

Slide 74

Slide 74 text

ϐΫηϧૢ࡞ɿσϓεςετ Φϓγϣϯ ௨աͨ͠;஋Λ ্ॻ͖ 0.6 0.4 0.2 σϓεόοϑΝ 0.6 0.4 0.2 0.6 0.4 0.2 0.6 0.4 0.2 0.5 0.5 0.5 0.5 0.5 0.5 0.6 0.5 0.5 0.6 0.5 0.5 0.6 0.4 0.5 0.6 0.4 0.2 0.5 0.5 0.5 0.5 0.5 σϓεόοϑΝ ϑϥά ϝϯτ ϑϥά ϝϯτ

Slide 75

Slide 75 text

ϐΫηϧૢ࡞ɿϒϨϯσΟϯά Φϓγϣϯ α × +(1 − α) × =

Slide 76

Slide 76 text

3FDPOTUSVDUJPO ࠶ߏங ϨϯμϦϯά ύΠϓϥΠϯͷ

Slide 77

Slide 77 text

Լ४උ

Slide 78

Slide 78 text

ࠞͥ߹ΘͤՄೳͳܕ protocol Addable { static func +(lhs:Self, rhs:Self) -> Self } protocol Scalable { static func *(scale:Float, value:Self) -> Self } protocol Blendable : Addable, Scalable { }

Slide 79

Slide 79 text

৭ͷ४උ struct Color4f : Blendable { let r: Float let g: Float let b: Float let a: Float }

Slide 80

Slide 80 text

৭ͷ४උ struct Color4ui { let r: UInt8 let g: UInt8 let b: UInt8 let a: UInt8 }

Slide 81

Slide 81 text

௖఺ͷ४උ class Vertex3 { var position : float3 var attribute : T . . . } class Vertex4 { var position : float4 var attribute : T . . . }

Slide 82

Slide 82 text

ϑϥάϝϯτͷ४උ class Fragment { let x: Int let y: Int let z: Float let attribute: T . . . }

Slide 83

Slide 83 text

ϑϨʔϜόοϑΝͷ४උ protocol BufferPlane { associatedtype CellType var width: Int { get } var height: Int { get } subscript(x: Int, y: Int) -> CellType { get set } }

Slide 84

Slide 84 text

class ColorBuffer : BufferPlane { let width: Int let height: Int subscript (x: Int, y: Int) -> Color4ui { . . . } } ϑϨʔϜόοϑΝͷ४උ

Slide 85

Slide 85 text

class DepthBuffer : BufferPlane { let width: Int let height: Int subscript (x: Int, y: Int) -> Float { . . . } } ϑϨʔϜόοϑΝͷ४උ

Slide 86

Slide 86 text

Ϗϡʔͷ४උ CALayer

Slide 87

Slide 87 text

Ϗϡʔϙʔτͷ४උ class Viewport { let x: Int let y: Int let width: Int let height: Int . . . }

Slide 88

Slide 88 text

ύΠϓϥΠϯͷ४උ class RenderPipeline { var vertexBuffer : [Vertex4]! var viewport: Viewport? var vertexShader : ((Vertex4) -> Vertex4)! var fragmentShader : ((Fragment) -> Color4f?)! var colorBuffer : ColorBuffer! var depthBuffer : DepthBuffer? . . . }

Slide 89

Slide 89 text

௖఺ॲཧ ϓϦϛςΟϒΞηϯϒϦ ϥελϥΠζ ϑϥάϝϯτॲཧ ϐΫηϧૢ࡞ ϑϨʔϜόοϑΝ ௖఺ྻ ௖఺ॲཧ ͷ ࠶ߏங

Slide 90

Slide 90 text

௖఺ॲཧ let convertedVertices = vertexBuffer.map { (vertex:Vertex4) -> Vertex3 in let v = vertexShader(vertex) // divide by w let pos = v.position.project() // Viewport Transformation let screenPosition = transform(position: pos, toViewport: vp) return Vertex3(position: screenPosition, attribute: v.attribute) }

Slide 91

Slide 91 text

ϓϦ ϛ ςΟϒ ΞηϯϒϦ ϥελϥΠζ ϑϥάϝϯτॲཧ ϐΫηϧૢ࡞ ϑϨʔϜόοϑΝ ௖఺ྻ ௖఺ॲཧ ϓϦϛςΟϒΞηϯϒϦ ͷ ࠶ߏங

Slide 92

Slide 92 text

ϓϦϛςΟϒΞηϯϒϦ enum Primitive { case point(Vertex3) case line(Vertex3, Vertex3) case triangle(Vertex3, Vertex3, Vertex3) }

Slide 93

Slide 93 text

ϓϦϛςΟϒΞηϯϒϦ var primitives: [Primitive] . . . let numOfTriangles = convertedVertices.count / 3 primitives = (0...triangle(convertedVertices[$0*3], convertedVertices[$0*3 + 1], convertedVertices[$0*3 + 2]) }.filter{ (primitive) -> Bool in if cullFace { return primitive.isCCW() } else { return true } }

Slide 94

Slide 94 text

ϥελϥΠζ ϓϦϛςΟϒΞηϯϒϦ ϑϥάϝϯτॲཧ ϐΫηϧૢ࡞ ϑϨʔϜόοϑΝ ௖఺ྻ ௖఺ॲཧ ϥελϥΠζ ͷ ࠶ߏங

Slide 95

Slide 95 text

ϥελϥΠζ var result = [Fragment]() . . .// minX, maxX, minY, maxYΛٻΊ͓ͯ͘ for py in minY..

Slide 96

Slide 96 text

ͷ ࠶ߏங ϑϥά ϝϯτ ॲཧ ϓϦϛςΟϒΞηϯϒϦ ϐΫηϧૢ࡞ ϑϨʔϜόοϑΝ ௖఺ྻ ௖఺ॲཧ ϥελϥΠζ ϑϥάϝϯτॲཧ

Slide 97

Slide 97 text

ϑϥά ϝϯτॲཧ // Fragment Processing let fragmentResults = fragments.map{ (fragment) -> Fragment? in if let color = fragmentShader(fragment) { return Fragment( x: fragment.x, y: fragment.y, z: fragment.z, attribute: color) } else { return nil } }.compactMap { $0 }

Slide 98

Slide 98 text

ͷ ࠶ߏங ϐΫηϧ ૢ࡞ ϓϦϛςΟϒΞηϯϒϦ ϑϨʔϜόοϑΝ ௖఺ྻ ௖఺ॲཧ ϥελϥΠζ ϑϥάϝϯτॲཧ ϐΫηϧૢ࡞

Slide 99

Slide 99 text

ϐΫηϧૢ࡞ // Per Sampling Operation fragmentResults.forEach { (fragment) in if let depthBuffer = depthBuffer { if depthBuffer[fragment.x, fragment.y] > fragment.z { return } depthBuffer[fragment.x, fragment.y] = fragment.z } colorBuffer[fragment.x, fragment.y] = fragment.attribute.toColor4ui() }

Slide 100

Slide 100 text

׬੒

Slide 101

Slide 101 text

%&.0

Slide 102

Slide 102 text

ղઆɿ.BU$BQ .BUFSJBM$BQUVSFT

Slide 103

Slide 103 text

ղઆɿ.BU$BQ .BUFSJBM$BQUVSFT ςΫενϟ 1.0 1.0

Slide 104

Slide 104 text

ղઆɿ.BU$BQ .BUFSJBM$BQUVSFT ςΫενϟ 1.0 1.0 ୯Ґ๏ઢϕΫτϧ

Slide 105

Slide 105 text

ղઆɿ.BU$BQ .BUFSJBM$BQUVSFT ςΫενϟ 1.0 1.0 ୯Ґ๏ઢϕΫτϧ ൒෼ʹͯ͠ Φϑηοτ

Slide 106

Slide 106 text

ղઆɿ.BU$BQ .BUFSJBM$BQUVSFT ςΫενϟ 1.0 1.0 ୯Ґ๏ઢϕΫτϧ

Slide 107

Slide 107 text

·ͱΊ

Slide 108

Slide 108 text

·ͱΊ ɾϨϯμϦϯάύΠϓϥΠϯ͸࡞ΕΔ

Slide 109

Slide 109 text

·ͱΊ ɾϨϯμϦϯάύΠϓϥΠϯ͸࡞ΕΔ ɾࣗ෼Ͱ࡞ͬͯΈΔͱཧղ͕ਂ·Δ

Slide 110

Slide 110 text

·ͱΊ ɾϨϯμϦϯάύΠϓϥΠϯ͸࡞ΕΔ ɾࣗ෼Ͱ࡞ͬͯΈΔͱཧղ͕ਂ·Δ ɾ(16͍͢͝

Slide 111

Slide 111 text

·ͱΊ ɾϨϯμϦϯάύΠϓϥΠϯ͸࡞ΕΔ ɾࣗ෼Ͱ࡞ͬͯΈΔͱཧղ͕ਂ·Δ ɾ(16͍͢͝ ɾࠓͲ͖ͷεϚʔτϑΥϯͷ$16΋͍͢͝

Slide 112

Slide 112 text

·ͱΊ ɾϨϯμϦϯάύΠϓϥΠϯ͸࡞ΕΔ ɾࣗ෼Ͱ࡞ͬͯΈΔͱཧղ͕ਂ·Δ ɾ(16͍͢͝ ɾϓϩάϥϛϯάָ͍͠ ɾࠓͲ͖ͷεϚʔτϑΥϯͷ$16΋͍͢͝

Slide 113

Slide 113 text

&OKPZ 1SPHSBNNJOH

Slide 114

Slide 114 text

ςΫενϟϚοϐϯάૉࡐɿ https://www.3dxo.com/textures إૉࡐɿ Θͨ͠ MatCapૉࡐɿ https://www.pixelfondue.com/blog/30matcaps