diff options
author | xengineering <mail2xengineering@protonmail.com> | 2021-05-31 10:41:31 +0200 |
---|---|---|
committer | xengineering <mail2xengineering@protonmail.com> | 2021-05-31 13:27:05 +0200 |
commit | c53d6d94e4ee8ca01d857ed5f86899be048ef7f4 (patch) | |
tree | 0861e150a931ae3dc6bc02a94faa4f9ed0c890d9 | |
parent | 47ef2d48af8d9efc23b65f13546528e061bad13d (diff) | |
download | stlscope-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-- | Makefile | 2 | ||||
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | app.go | 2 | ||||
-rw-r--r-- | data/example.png | bin | 10424 -> 3180 bytes | |||
-rw-r--r-- | graphics.go | 55 | ||||
-rw-r--r-- | main.go | 2 | ||||
-rw-r--r-- | stl.go | 53 |
7 files changed, 98 insertions, 22 deletions
@@ -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 @@ -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 @@ -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 Binary files differindex 2d8a256..26935de 100644 --- a/data/example.png +++ b/data/example.png 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 } @@ -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") @@ -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 } |