summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxengineering <mail2xengineering@protonmail.com>2021-05-31 10:41:31 +0200
committerxengineering <mail2xengineering@protonmail.com>2021-05-31 13:27:05 +0200
commitc53d6d94e4ee8ca01d857ed5f86899be048ef7f4 (patch)
tree0861e150a931ae3dc6bc02a94faa4f9ed0c890d9
parent47ef2d48af8d9efc23b65f13546528e061bad13d (diff)
downloadstlscope-0.3.0.tar
stlscope-0.3.0.tar.zst
stlscope-0.3.0.zip
Implement ambient and diffuse Lighting0.3.0
-rw-r--r--Makefile2
-rw-r--r--README.md6
-rw-r--r--app.go2
-rw-r--r--data/example.pngbin10424 -> 3180 bytes
-rw-r--r--graphics.go55
-rw-r--r--main.go2
-rw-r--r--stl.go53
7 files changed, 98 insertions, 22 deletions
diff --git a/Makefile b/Makefile
index 447434f..75f31c8 100644
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@ clean:
rm -rf build
debug:
- go run ./... data/L.stl
+ go run ./... -debug data/L.stl
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
diff --git a/README.md b/README.md
index 503834f..d64b4c3 100644
--- a/README.md
+++ b/README.md
@@ -18,15 +18,19 @@ Have a look at `stlscope -h` to learn about further options.
## Development Milestones
Done (most recent first):
+- [x] improve graphics to better display the model (ambient and diffuse lighting)
- [x] package for Arch Linux (get a PKGBUILD file from [here](https://src.xengineering.eu/xengineering/pkgbuilds/src/branch/master/stlscope))
- [x] implement Makefile to support building
- [x] implement minimal viable product
To do (most important first):
+- [ ] allow window resizing
- [ ] implement controls to modify view
-- [ ] improve graphics to better display the model
- [ ] add support for ASCII STL format
- [ ] improve performance with GPU-based matrix-matrix-multiplication
+- [ ] create icon for stlscope
+- [ ] release version 1.0.0
+- [ ] add desktop support
## Further Ressources
diff --git a/app.go b/app.go
index 22548a3..30dfd44 100644
--- a/app.go
+++ b/app.go
@@ -58,7 +58,7 @@ func (application *App) handle() {
// generate and set transformation
trafo := application.homeTrafo
- trafo = mgl32.HomogRotate3D(float32(glfw.GetTime()) * 3, mgl32.Vec3{0, 1, 0}).Mul4(trafo) // apply time-based rotation
+ trafo = mgl32.HomogRotate3D(float32(glfw.GetTime()) * 0.4 * 6.282, mgl32.Vec3{0.1, 1, 0}).Mul4(trafo) // apply time-based rotation
application.graphics.setTrafo(trafo)
}
diff --git a/data/example.png b/data/example.png
index 2d8a256..26935de 100644
--- a/data/example.png
+++ b/data/example.png
Binary files differ
diff --git a/graphics.go b/graphics.go
index 7107926..fc195eb 100644
--- a/graphics.go
+++ b/graphics.go
@@ -13,6 +13,7 @@ import (
var (
vertices []float32
+ vertex_normals []float32
)
const (
@@ -21,21 +22,33 @@ const (
VERTEX_SHADER = `
#version 410
- uniform mat4 trafo;
+ in vec3 vp_model; // vertex position in model coordinate system
+ in vec3 vn_model; // vertex normal in model coordinate system
- in vec3 vp;
+ uniform mat4 trafo; // one single transformation matrix
+
+ out vec3 vn_eye; // vertex normal in eye coordinate system
void main() {
- gl_Position = trafo * vec4(vp, 1.0);
+ vn_eye = vec3(trafo * vec4(vn_model, 0.0)); // 0.0 because translation is ignored
+ gl_Position = trafo * vec4(vp_model, 1.0);
}
` + "\x00"
// fragment shader to draw surfaces
FRAGMENT_SHADER = `
#version 410
+
+ in vec3 vn_eye; // vertex normal in eye coordinate system
+
out vec4 frag_colour;
+
void main() {
- frag_colour = vec4(0, 0, 1, 1); // RGBA color format
+ vec3 ambient = vec3(0.3, 0.3, 0.3); // ambient colour is static
+ vec3 light_vector_eye = vec3(1.0, 0.1, -1.0);
+ vec3 diffuse = (vec3(1, 1, 1) - ambient) * max(dot(normalize(vn_eye), normalize(light_vector_eye)), 0.0);
+ vec3 color = (ambient + diffuse) * vec3(0, 0, 1); // hard-coded vector is color in RGB format
+ frag_colour = vec4(color, 1.0); // RGBA color format
}
` + "\x00"
)
@@ -79,10 +92,11 @@ func newGraphics() Graphics {
graphics.program = gl.CreateProgram()
gl.AttachShader(graphics.program, graphics.vertexShader)
gl.AttachShader(graphics.program, graphics.fragmentShader)
+ gl.Enable(gl.DEPTH_TEST)
gl.LinkProgram(graphics.program)
// create VAO
- graphics.vao = makeVao(vertices)
+ graphics.vao = makeVao(vertices, vertex_normals)
// create transformation matrix
//graphics.trafo = mgl32.HomogRotate3D(float32(glfw.GetTime()) * OMEGA, mgl32.Vec3{ROT_X, ROT_Y, ROT_Z})
@@ -100,26 +114,39 @@ func (graphics Graphics) draw() {
gl.UniformMatrix4fv(graphics.trafoUniform, 1, false, &graphics.trafo[0])
gl.BindVertexArray(graphics.vao)
- gl.DrawArrays(gl.LINE_STRIP, 0, int32(len(vertices)/3)) // POINTS, LINES, LINE_STRIP, LINE_LOOP, TRIANGLES, TRIANGLE_STRIP, TRIANGLE_FAN
+ gl.DrawArrays(gl.TRIANGLES, 0, int32(len(vertices)/3)) // POINTS, LINES, LINE_STRIP, LINE_LOOP, TRIANGLES, TRIANGLE_STRIP, TRIANGLE_FAN
}
// makeVao initializes and returns a vertex array from the points provided.
-func makeVao(points []float32) uint32 {
+func makeVao(points []float32, normals []float32) uint32 {
log.Println("Creating VAO")
- // start with vertex buffer object (VBO):
- var vbo uint32 // VBO ID
- gl.GenBuffers(1, &vbo)
- gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
+ // vertex buffer object (VBO) for positions:
+ var position_vbo uint32 // VBO ID
+ gl.GenBuffers(1, &position_vbo)
+ gl.BindBuffer(gl.ARRAY_BUFFER, position_vbo)
gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW)
- // vertex array objects (VAO) are a feature of newer GL implementations:
+ // vertex buffer object (VBO) for normals:
+ var normal_vbo uint32 // VBO ID
+ gl.GenBuffers(1, &normal_vbo)
+ gl.BindBuffer(gl.ARRAY_BUFFER, normal_vbo)
+ gl.BufferData(gl.ARRAY_BUFFER, 4*len(normals), gl.Ptr(normals), gl.STATIC_DRAW)
+
+ // vertex array objects (VAO) to combine VBOs:
var vao uint32 // VAO ID
gl.GenVertexArrays(1, &vao)
gl.BindVertexArray(vao)
- gl.EnableVertexAttribArray(0)
- gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
+
+ // connect position_vbo to vao
+ gl.BindBuffer(gl.ARRAY_BUFFER, position_vbo)
gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil) // tell GL to use 3D float vectors
+ gl.EnableVertexAttribArray(0)
+
+ // connect normal_vbo to vao
+ gl.BindBuffer(gl.ARRAY_BUFFER, normal_vbo)
+ gl.VertexAttribPointer(1, 3, gl.FLOAT, false, 0, nil) // tell GL to use 3D float vectors
+ gl.EnableVertexAttribArray(1)
return vao
}
diff --git a/main.go b/main.go
index 004fbf3..084b8ec 100644
--- a/main.go
+++ b/main.go
@@ -28,7 +28,7 @@ func main() {
if err != nil {
log.Fatal(err)
}
- vertices = stl.toVertices()
+ vertices,vertex_normals = stl.toVertices()
// lock this program to one OS thread (details: https://golang.org/pkg/runtime/#LockOSThread)
log.Println("Locking OS thread")
diff --git a/stl.go b/stl.go
index 35e69eb..60ada3e 100644
--- a/stl.go
+++ b/stl.go
@@ -20,6 +20,8 @@ type StlModel struct {
surface Surface
}
+type Vector3 [3]float32
+
// read and parse a given binary STL file
func ReadBinaryStlFile(filePath string) (StlModel, error) {
@@ -75,9 +77,12 @@ func ParseBinaryStlTriangle(data []byte) *Triangle { // FIXME: This function sh
return triangle
}
-func (stl StlModel) toVertices() []float32 {
+func (stl StlModel) toVertices() (vertex_position []float32, vertex_normal []float32) {
+
+ vertex_position = make([]float32, stl.numberOfTriangles * 9)
+ vertex_normal = make([]float32, stl.numberOfTriangles * 9)
- retval := make([]float32, stl.numberOfTriangles * 9)
+ var point0,point1,point2,edge0,edge1,normal Vector3;
for triangleIndex,triangle := range(stl.surface.triangles) {
@@ -85,13 +90,53 @@ func (stl StlModel) toVertices() []float32 {
for scalarIndex,scalar := range(point.scalars) {
- retval[triangleIndex*9+pointIndex*3+scalarIndex] = scalar
+ vertex_position[triangleIndex*9+pointIndex*3+scalarIndex] = scalar
}
}
+ // calculate normal
+ point0 = Vector3{triangle.points[0].scalars[0], triangle.points[0].scalars[1], triangle.points[0].scalars[2]}
+ point1 = Vector3{triangle.points[1].scalars[0], triangle.points[1].scalars[1], triangle.points[1].scalars[2]}
+ point2 = Vector3{triangle.points[2].scalars[0], triangle.points[2].scalars[1], triangle.points[2].scalars[2]}
+ edge0 = point1.subtract(point0)
+ edge1 = point2.subtract(point1)
+ normal = edge0.crossProduct(edge1)
+ normal.divideScalar(2.0) // length of normal vector corresponds to triangle area
+
+ // save normal to each vertex of the triangle
+ for i := 0; i<3; i++ {
+ vertex_normal[triangleIndex*9+i*3+0] = normal[0]
+ vertex_normal[triangleIndex*9+i*3+1] = normal[1]
+ vertex_normal[triangleIndex*9+i*3+2] = normal[2]
+ }
+
}
- return retval
+ return vertex_position, vertex_normal
+}
+
+func (vector *Vector3) divideScalar(scalar float32) {
+ vector[0] = vector[0] / scalar
+ vector[1] = vector[1] / scalar
+ vector[2] = vector[2] / scalar
+}
+
+func (vectorA Vector3) subtract(vectorB Vector3) (vectorC Vector3) {
+
+ vectorC[0] = vectorA[0] - vectorB[0]
+ vectorC[1] = vectorA[1] - vectorB[1]
+ vectorC[2] = vectorA[2] - vectorB[2]
+
+ return vectorC
+}
+
+func (vectorA Vector3) crossProduct(vectorB Vector3) (vectorC Vector3) {
+
+ vectorC[0] = vectorA[1] * vectorB[2] - vectorA[2] * vectorB[1]
+ vectorC[1] = vectorA[2] * vectorB[0] - vectorA[0] * vectorB[2]
+ vectorC[2] = vectorA[0] * vectorB[1] - vectorA[1] * vectorB[0]
+
+ return vectorC
}