-
Notifications
You must be signed in to change notification settings - Fork 1
/
material.go
118 lines (105 loc) · 3.06 KB
/
material.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package raytracer
import (
"image"
"log"
"os"
"path/filepath"
"strings"
)
// Images map to hold image data in memory for repeating images.
var Images map[string][][]Vector
// BumpMapNormals cache to hold bump map information in memory.
var BumpMapNormals map[string][][]Vector
type indice [4]int64
// Material definition.
type Material struct {
Color Vector `json:"color"`
Texture string `json:"texture"`
Transmission float64 `json:"transmission"`
IndexOfRefraction float64 `json:"index_of_refraction"`
Indices []indice `json:"indices"`
Glossiness float64 `json:"glossiness"`
Roughness float64 `json:"roughness"`
Light bool `json:"light"`
LightStrength float64 `json:"light_strength"`
}
func loadImage(scenePath, texture string) (imageHasAlpha bool) {
textureName := texture
_, err := os.Stat(texture)
if os.IsNotExist(err) {
texture = filepath.Join(scenePath, texture)
}
imageFile, err := os.Open(texture)
if err != nil {
log.Printf("Material texture [%s] can't be opened\n", texture)
imageFile.Close() // defer has over-head
return
}
src, _, err := image.Decode(imageFile)
if err != nil {
log.Printf("Error reading image file [%s]: [%s]\n", texture, err.Error())
imageFile.Close()
return
}
imgBounds := src.Bounds().Max
Images[textureName] = make([][]Vector, imgBounds.X)
for i := 0; i < imgBounds.X; i++ {
Images[textureName][i] = make([]Vector, imgBounds.Y)
for j := 0; j < imgBounds.Y; j++ {
r, g, b, a := src.At(i, j).RGBA()
r, g, b, a = r>>8, g>>8, b>>8, a>>8
result := Vector{
float64(r) / 255,
float64(g) / 255,
float64(b) / 255,
float64(a) / 255,
}
if result[3] < 1 {
imageHasAlpha = true
}
Images[textureName][i][j] = result
}
}
imageFile.Close()
log.Printf("Image %s loaded: Alpha %t", texture, imageHasAlpha)
return imageHasAlpha
}
func loadBumpMap(scenePath, texture string) {
ext := filepath.Ext(texture)
base := strings.TrimSuffix(texture, ext)
texturePath := filepath.Dir(texture)
bumpTexture := filepath.Join(texturePath, base+"_bump"+ext)
_, err := os.Stat(bumpTexture)
if os.IsNotExist(err) {
bumpTexture = filepath.Join(scenePath, bumpTexture)
}
imageFile, err := os.Open(bumpTexture)
if err != nil {
imageFile.Close() // defer has over-head
return
}
src, _, err := image.Decode(imageFile)
if err != nil {
log.Printf("Error reading image file [%s]: [%s]\n", texture, err.Error())
imageFile.Close()
return
}
log.Printf("Image Bump Map %s loaded", bumpTexture)
imgBounds := src.Bounds().Max
BumpMapNormals[texture] = make([][]Vector, imgBounds.X)
for i := 0; i < imgBounds.X; i++ {
BumpMapNormals[texture][i] = make([]Vector, imgBounds.Y)
for j := 0; j < imgBounds.Y; j++ {
r, g, b, _ := src.At(i, j).RGBA()
r, g, b = r>>8, g>>8, b>>8
bump := normalizeVector(Vector{
(float64(r) / 255),
(float64(g) / 255),
(float64(b) / 255),
1,
})
BumpMapNormals[texture][i][j] = normalizeVector(subVector(scaleVector(bump, 2), Vector{1, 1, 1, 0}))
}
}
imageFile.Close()
}