Repository navigation
Expand file tree
/
Copy pathshader.go
More file actions
97 lines (87 loc) · 2.95 KB
/
Copy pathshader.go
File metadata and controls
97 lines (87 loc) · 2.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package aeno
import (
"math"
)
// Shader shader interface
type Shader interface {
Vertex(Vertex) Vertex
Fragment(Vertex, *Object) Color
}
// PhongShader implements Phong shading with an optional texture.
type PhongShader struct {
Matrix Matrix
LightDirection Vector
CameraPosition Vector
AmbientColor Color
DiffuseColor Color
SpecularColor Color
SpecularPower float64
EnableOutline bool // A switch to turn the effect on/off
OutlineColor Color // The color of the outline
OutlineFactor float64 // Controls line thickness (lower is thicker)
}
// NewPhongShader f
func NewPhongShader(matrix Matrix, lightDirection, cameraPosition Vector, ambient Color, diffuse Color) *PhongShader {
specular := Color{1, 1, 1, 1}
return &PhongShader{
Matrix: matrix,
LightDirection: lightDirection,
CameraPosition: cameraPosition,
AmbientColor: ambient,
DiffuseColor: diffuse,
SpecularColor: specular,
SpecularPower: 0,
EnableOutline: false,
OutlineColor: HexColor("000000"),
OutlineFactor: 0.05,
}
}
// Vertex f
func (shader *PhongShader) Vertex(v Vertex) Vertex {
v.Output = shader.Matrix.MulPositionW(v.Position)
return v
}
// Fragment f
func (shader *PhongShader) Fragment(v Vertex, fromObject *Object) Color {
if shader.EnableOutline {
viewDirection := shader.CameraPosition.Sub(v.Position).Normalize()
dot := viewDirection.Dot(v.Normal)
// If the surface normal is nearly perpendicular to the view direction, it's an edge.
if math.Abs(dot) < shader.OutlineFactor {
return shader.OutlineColor
}
}
// If the object is flagged to use vertex colors, we return the
// interpolated vertex color and skip all lighting and texturing.
color := fromObject.Color
if fromObject.UseVertexColor {
color = color.Mul(v.Color)
}
light := shader.AmbientColor
if fromObject.Texture != nil {
sample := fromObject.Texture.BilinearSample(v.Texture.X, v.Texture.Y)
if fromObject.UseVertexColor {
color = color.Mul(sample)
} else if sample.A > 0 {
color = color.Lerp(sample.DivScalar(sample.A), sample.A)
}
}
diffuse := math.Max(v.Normal.Dot(shader.LightDirection), 0)
light = light.Add(shader.DiffuseColor.MulScalar(diffuse))
if diffuse > 0 && shader.SpecularPower > 0 {
camera := shader.CameraPosition.Sub(v.Position).Normalize()
reflected := shader.LightDirection.Negate().Reflect(v.Normal)
specular := math.Max(camera.Dot(reflected), 0)
if specular > 0 {
specular = math.Pow(specular, shader.SpecularPower)
light = light.Add(shader.SpecularColor.MulScalar(specular))
}
}
final := color.Mul(light).Min(White)
if color.A > 0.0001 && color.A < 1.0 {
return final.DivScalar(color.A).Alpha(color.A)
} else if color.A <= 0.0001 {
return color.Alpha(0)
}
return final.Alpha(color.A)
}