diff options
| -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.pngBinary files differ index 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  } | 
