-
Notifications
You must be signed in to change notification settings - Fork 0
/
materials.go
103 lines (88 loc) · 2.92 KB
/
materials.go
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
98
99
100
101
102
103
package jbtracer
import "math"
type Material struct {
Color *Color
Ambient float64
Diffuse float64
Specular float64
Shininess float64
Pattern Pattern
Reflective float64
Transparency float64
RefractiveIndex float64
}
func NewMaterial() *Material {
return &Material{
Color: White,
Ambient: 0.1,
Diffuse: 0.9,
Specular: 0.9,
Shininess: 200,
Pattern: nil,
Reflective: 0.0,
Transparency: 0.0,
RefractiveIndex: 1.0,
}
}
func (a *Material) Equal(b *Material) bool {
if a == nil || b == nil {
return false
} else if !a.Color.Equal(b.Color) {
return false
} else if !EqualFloat64(a.Ambient, b.Ambient) {
return false
} else if !EqualFloat64(a.Diffuse, b.Diffuse) {
return false
} else if !EqualFloat64(a.Specular, b.Specular) {
return false
} else if !EqualFloat64(a.Shininess, b.Shininess) {
return false
} else if a.Pattern != nil && b.Pattern != nil && !a.Pattern.Equal(b.Pattern) {
return false
}
return true
}
// Lighting uses the Phong Reflection Model to simulate the lighting on a single
// point on the Material
func (material *Material) Lighting(light *PointLight, object Shape, point, eyev, normalv *Tuple, inShadow bool) *Color {
// Get the color, from a Pattern if there is one
var color *Color
if material.Pattern != nil {
color = PatternAt(material.Pattern, object, point)
} else {
color = material.Color
}
// combine the surface color with the light's color/intensity
effectiveColor := color.Multiply(light.Intensity)
// find the direction to the light source
lightv := light.Position.Subtract(point).Normalize()
// compute the ambient contribution
ambient := effectiveColor.MultiplyScalar(material.Ambient)
// if we are in shadow diffuse and specular do not contribute
if inShadow {
return ambient
}
// light_dot_normal represents the cosine of the angle between the
// light vector and the normal vector. A negative number means the
// light is on the other side of the surface; again diffuse and Specular
// do not contribute
lightDotNormal := lightv.Dot(normalv)
if lightDotNormal < 0 {
return ambient
}
// compute the diffuse contribution
diffuse := effectiveColor.MultiplyScalar(material.Diffuse).MultiplyScalar(lightDotNormal)
// reflect_dot_eye represents the cosine of the angle between the
// reflection vector and the eye vector. A negative number means the
// light reflects away from the eye; specular does not contribute.
reflectv := lightv.Multiply(-1).Reflect(normalv)
reflectDotEye := reflectv.Dot(eyev)
if reflectDotEye <= 0 {
return ambient.Add(diffuse)
}
// compute the specular contribution
factor := math.Pow(reflectDotEye, material.Shininess)
specular := light.Intensity.MultiplyScalar(material.Specular).MultiplyScalar(factor)
// Add the three contributions together to get the final shading
return ambient.Add(diffuse).Add(specular)
}