// Calculate normals by using cross products along the triangle strips // and averaging the normals for each vertex func (terrain *Terrain) CalculateNormals() { var element_pos uint32 = 0 var AB, AC, cross_product mgl32.Vec3 // Loop through each triangle strip for x := uint32(0); x < terrain.XSize-1; x++ { // Loop along the strip for tri := uint32(0); tri < terrain.ZSize*2-2; tri++ { // Extract the vertex indices from the element array v1 := terrain.Indices[element_pos] v2 := terrain.Indices[element_pos+1] v3 := terrain.Indices[element_pos+2] // Define the two vectors for the triangle AB = terrain.Vertices[v2].Sub(terrain.Vertices[v1]) AC = terrain.Vertices[v3].Sub(terrain.Vertices[v1]) // Calculate the cross product cross_product = AB.Cross(AC) // Add this normal to the vertex normal for all three vertices in the triangle terrain.Normals[v1] = terrain.Normals[v1].Add(cross_product) terrain.Normals[v2] = terrain.Normals[v2].Add(cross_product) terrain.Normals[v3] = terrain.Normals[v3].Add(cross_product) // Move on to the next vertex along the strip element_pos++ } // Jump past the lat two element positions to reach the start of the strip element_pos += 2 } // Normalise the normals for v := uint32(0); v < terrain.XSize*terrain.ZSize; v++ { terrain.Normals[v] = terrain.Normals[v].Normalize() } }
func (f *Frustum) SetCamera(p, l, u mgl32.Vec3) { Z := p.Sub(l) Z = safeNormalize(Z) X := u.Cross(Z) X = safeNormalize(X) Y := Z.Cross(X) nc := p.Sub(Z.Mul(f.near)) fc := p.Sub(Z.Mul(f.far)) ntl := nc.Add(Y.Mul(f.nh)).Sub(X.Mul(f.nw)) ntr := nc.Add(Y.Mul(f.nh)).Add(X.Mul(f.nw)) nbl := nc.Sub(Y.Mul(f.nh)).Sub(X.Mul(f.nw)) nbr := nc.Sub(Y.Mul(f.nh)).Add(X.Mul(f.nw)) ftl := fc.Add(Y.Mul(f.fh)).Sub(X.Mul(f.fw)) ftr := fc.Add(Y.Mul(f.fh)).Add(X.Mul(f.fw)) fbl := fc.Sub(Y.Mul(f.fh)).Sub(X.Mul(f.fw)) fbr := fc.Sub(Y.Mul(f.fh)).Add(X.Mul(f.fw)) const ( top = iota bottom left right nearP farP ) f.planes[top].setPoints(ntr, ntl, ftl) f.planes[bottom].setPoints(nbl, nbr, fbr) f.planes[left].setPoints(ntl, nbl, fbl) f.planes[right].setPoints(nbr, ntr, fbr) f.planes[nearP].setPoints(ntl, ntr, nbr) f.planes[farP].setPoints(ftr, ftl, fbl) }
// Since go has multiple return values, I just went ahead and made it return the view and perspective matrices (in that order) rather than messing with getter methods func (c *Camera) ComputeViewPerspective() (mgl32.Mat4, mgl32.Mat4) { if mgl64.FloatEqual(-1.0, c.time) { c.time = glfw.GetTime() } currTime := glfw.GetTime() deltaT := currTime - c.time xPos, yPos := c.window.GetCursorPosition() c.window.SetCursorPosition(width/2.0, height/2.0) c.hAngle += mouseSpeed * ((width / 2.0) - float64(xPos)) c.vAngle += mouseSpeed * ((height / 2.0) - float64(yPos)) dir := mgl32.Vec3{ float32(math.Cos(c.vAngle) * math.Sin(c.hAngle)), float32(math.Sin(c.vAngle)), float32(math.Cos(c.vAngle) * math.Cos(c.hAngle))} right := mgl32.Vec3{ float32(math.Sin(c.hAngle - math.Pi/2.0)), 0.0, float32(math.Cos(c.hAngle - math.Pi/2.0))} up := right.Cross(dir) if c.window.GetKey(glfw.KeyUp) == glfw.Press || c.window.GetKey('W') == glfw.Press { c.pos = c.pos.Add(dir.Mul(float32(deltaT * speed))) } if c.window.GetKey(glfw.KeyDown) == glfw.Press || c.window.GetKey('S') == glfw.Press { c.pos = c.pos.Sub(dir.Mul(float32(deltaT * speed))) } if c.window.GetKey(glfw.KeyRight) == glfw.Press || c.window.GetKey('D') == glfw.Press { c.pos = c.pos.Add(right.Mul(float32(deltaT * speed))) } if c.window.GetKey(glfw.KeyLeft) == glfw.Press || c.window.GetKey('A') == glfw.Press { c.pos = c.pos.Sub(right.Mul(float32(deltaT * speed))) } // Adding to the original tutorial, Space goes up if c.window.GetKey(glfw.KeySpace) == glfw.Press { c.pos = c.pos.Add(up.Mul(float32(deltaT * speed))) } // Adding to the original tutorial, left control goes down if c.window.GetKey(glfw.KeyLeftControl) == glfw.Press { c.pos = c.pos.Sub(up.Mul(float32(deltaT * speed))) } fov := initialFOV //- 5.0*float64(glfw.MouseWheel()) proj := mgl32.Perspective(float32(fov), 4.0/3.0, 0.1, 100.0) view := mgl32.LookAtV(c.pos, c.pos.Add(dir), up) c.time = currTime return view, proj }