// Spin rotates the current direction by the given number degrees around each // axis. Generally this is called with one direction change at a time. func (p *pov) Spin(x, y, z float64) { if x != 0 { rotation := lin.NewQ().SetAa(1, 0, 0, lin.Rad(x)) p.dir.Mult(rotation, p.dir) } if y != 0 { rotation := lin.NewQ().SetAa(0, 1, 0, lin.Rad(y)) p.dir.Mult(p.dir, rotation) } if z != 0 { rotation := lin.NewQ().SetAa(0, 0, 1, lin.Rad(z)) p.dir.Mult(rotation, p.dir) } }
// drawScene renders the 3D models consisting of one VAO func (tag *trtag) drawScene() { gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) tag.checkError("gl.Clear") gl.UseProgram(tag.shaders) tag.checkError("gl.UseProgram") gl.BindVertexArray(tag.vao) tag.checkError("gl.BindVertexArray") // Use a modelview matrix and quaternion to rotate the 3D object. tag.mvp64.SetQ(lin.NewQ().SetAa(0, 1, 0, lin.Rad(-tag.rotateAngle))) tag.mvp64.TranslateMT(0, 0, -4) tag.mvp64.Mult(tag.mvp64, tag.persp) tag.mvp32 = renderMatrix(tag.mvp64, tag.mvp32) gl.UniformMatrix4fv(tag.mvpRef, 1, false, tag.mvp32.Pointer()) if err := gl.GetError(); err != 0 { fmt.Printf("gl.UniformMatrix error %d\n", err) } gl.DrawElements(gl.TRIANGLES, int32(len(tag.faces)), gl.UNSIGNED_BYTE, gl.Pointer(nil)) if err := gl.GetError(); err != 0 { fmt.Printf("gl.DrawElements error %d\n", err) } // cleanup gl.UseProgram(0) tag.checkError("gl.UseProgram-0") gl.BindVertexArray(0) tag.checkError("gl.BindVertexArray-0") // rotate based on time... not on how fast the computer runs. if time.Now().Sub(tag.lastTime).Seconds() > 0.01 { tag.rotateAngle += 1 tag.lastTime = time.Now() } }
// Update is the regular engine callback. func (cm *cmtag) Update(input *vu.Input) { if input.Resized { cm.resize() } // own the rotation. dir := lin.NewQ().SetAa(0, 1, 0, lin.Rad(cm.turn)) cm.bod.SetRotation(dir.GetS()) if cm.switchCam { // apply physics location to the camera. x, y, z := cm.bod.Location() cm.scene.SetViewLocation(x, y, z) cm.scene.SetViewRotation(dir.GetS()) cm.scene.SetViewTilt(-cm.look) } else { // keep camera at a fixed location. cm.scene.SetViewLocation(0, 10, 25) cm.scene.SetViewRotation(0, 0, 0, 1) cm.scene.SetViewTilt(0) } // handle user requests. for press, rel := range input.Down { switch press { case "W": cm.move(zaxis, -1, rel < 0) // back and forth. case "S": cm.move(zaxis, 1, rel < 0) case "A": cm.move(xaxis, -1, rel < 0) // left and right case "D": cm.move(xaxis, 1, rel < 0) // switch camera between first and fixed third person. case "C": if time.Now().After(cm.last.Add(cm.holdoff)) { cm.switchCam = !cm.switchCam cm.last = time.Now() } } } // apply rotation based on mouse changes. xdiff := cm.pmx - input.Mx ydiff := cm.pmy - input.My cm.spin(yaxis, xdiff) // rotate left/right (around y-axis) cm.spin(xaxis, ydiff) // rotate up/down (around x-axis) cm.pmx, cm.pmy = input.Mx, input.My }
// model transform must be done in rotation, scale, translate order. func (p *part) mt() *lin.M4 { mt := p.model.SetQ(lin.NewQ().Inv(p.dir)) // rotation. mt.ScaleSM(p.Scale()) // scale is applied first (on left of rotation) return mt.TranslateMT(p.Location()) // translate is applied last (on right of rotation). }