tofu

Making something with OpenGL in Go
Log | Files | Refs

commit 1ec5b8b3dd5c6bd525846632517b91f1b97d2c84
parent 73e44436dd889b8a44ef3d90175e20983653b7c2
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Fri,  8 Nov 2024 11:55:46 +0900

move camera

Diffstat:
Mcmd/sample/main.go | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Mcmd/sample/vertex.glsl | 4++--
Mmath.go | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 166 insertions(+), 13 deletions(-)

diff --git a/cmd/sample/main.go b/cmd/sample/main.go @@ -17,6 +17,8 @@ const ( winW, winH = 800, 600 ) +var camera *tofu.Camera + func init() { runtime.LockOSThread() } @@ -28,7 +30,8 @@ func framebufferSizeCallback(w *glfw.Window, width int, height int) { gl.Viewport(0, 0, int32(width), int32(height)) } -func processInput(w *glfw.Window) { +func keyboardCallback(w *glfw.Window) { + const speed = 0.3 if w.GetKey(glfw.KeyQ) == glfw.Press { w.SetShouldClose(true) } @@ -44,33 +47,106 @@ func processInput(w *glfw.Window) { alpha = 0 } } + if w.GetKey(glfw.KeyW) == glfw.Press { + camera.Move(0, 0, -speed) + } + if w.GetKey(glfw.KeyS) == glfw.Press { + camera.Move(0, 0, speed) + } + if w.GetKey(glfw.KeyA) == glfw.Press { + camera.Move(-speed, 0, 0) + } + if w.GetKey(glfw.KeyD) == glfw.Press { + camera.Move(speed, 0, 0) + } + if w.GetKey(glfw.KeySpace) == glfw.Press { + camera.Move(0, speed, 0) + } + if w.GetKey(glfw.KeyLeftShift) == glfw.Press { + camera.Move(0, -speed, 0) + } +} + +var ( + cursorX, cursorY float32 + mouseCallbackFirstTime = true +) + +func mouseCallback(w *glfw.Window, x, y float64) { + const sensitivity = 0.01 + if mouseCallbackFirstTime { + cursorX, cursorY = float32(x), float32(y) + mouseCallbackFirstTime = false + return + } + dx, dy := cursorX - float32(x), float32(y) - cursorY + cursorX, cursorY = float32(x), float32(y) + dx *= sensitivity + dy *= sensitivity + camera.Yaw(dx) + camera.Pitch(dy) } var object = tofu.Object{ Vertices: []tofu.Point3D{ - tofu.Point3D{0.5, 0.5, 0.0}, - tofu.Point3D{0.5, -0.5, 0.0}, - tofu.Point3D{-0.5, -0.5, 0.0}, - tofu.Point3D{-0.5, 0.5, 0.0}, + tofu.Point3D{0.5, 0.5, -0.5}, + tofu.Point3D{0.5, -0.5, -0.5}, + tofu.Point3D{-0.5, -0.5, -0.5}, + tofu.Point3D{-0.5, 0.5, -0.5}, + tofu.Point3D{0.5, 0.5, 0.5}, + tofu.Point3D{0.5, -0.5, 0.5}, + tofu.Point3D{-0.5, -0.5, 0.5}, + tofu.Point3D{-0.5, 0.5, 0.5}, }, Colors: []color.Color{ color.RGBA{255, 0, 0, 255}, color.RGBA{0, 255, 0, 255}, color.RGBA{0, 0, 255, 255}, color.RGBA{255, 255, 0, 255}, + color.RGBA{255, 0, 0, 255}, + color.RGBA{0, 255, 0, 255}, + color.RGBA{0, 0, 255, 255}, + color.RGBA{255, 255, 0, 255}, }, TexCoords: []tofu.Point2D{ tofu.Point2D{1.0, 1.0}, tofu.Point2D{1.0, 0.0}, tofu.Point2D{0.0, 0.0}, tofu.Point2D{0.0, 1.0}, + tofu.Point2D{1.0, 1.0}, + tofu.Point2D{1.0, 0.0}, + tofu.Point2D{0.0, 0.0}, + tofu.Point2D{0.0, 1.0}, }, Faces: [][3]uint32{ {0, 1, 2}, {0, 2, 3}, + {0, 1, 5}, + {0, 5, 4}, + {1, 2, 6}, + {1, 6, 5}, + {2, 3, 7}, + {2, 7, 6}, + {3, 0, 4}, + {3, 4, 7}, + {4, 5, 6}, + {4, 6, 7}, }, } +var cubePositions = []tofu.Vec3{ + {0, 0, 0}, + {2, 5, -15}, + {-1.5, -2.2, -2.5}, + {-3.8, -2, -12.3}, + {2.4, -0.4, -3.5}, + {-1.7, 3.0, -7.5}, + {1.3, -2.0, -2.5}, + {1.5, 2.0, -2.5}, + {1.5, 0.2, -1.5}, + {-1.3, 1.0, -1.5}, +} + var alpha float32 = 0.2 func main() { @@ -122,18 +198,32 @@ func main() { if err := program.SetTexture(texture2, "texture2"); err != nil { log.Fatalf("set texture: %v", err) } + gl.Enable(gl.DEPTH_TEST) - window.SetFramebufferSizeCallback(framebufferSizeCallback) + camera = tofu.NewCamera() + camera.MoveTo(tofu.Vec3{0, 0, 3}) + camera.LookAt(tofu.Vec3{0, 0, 0}) - transform := tofu.Rotate(math.Pi/4, tofu.Vec3{0, 0, 1}) + window.SetFramebufferSizeCallback(framebufferSizeCallback) + window.SetCursorPosCallback(mouseCallback) + window.SetInputMode(glfw.CursorMode, glfw.CursorDisabled) for !window.ShouldClose() { - processInput(window) + keyboardCallback(window) gl.ClearColor(0.2, 0.3, 0.3, 1.0) - gl.Clear(gl.COLOR_BUFFER_BIT) + gl.Clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT) program.SetFloat32("alpha", alpha) - program.SetMat4("transform", transform) - gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, nil) + view := camera.View() + projection := tofu.Perspective(80*math.Pi/180, 800/600, 0.1, 100) + program.SetMat4("view", view) + program.SetMat4("projection", projection) + for _, p := range cubePositions { + model := tofu.Translate(p). + Mul(tofu.Rotate(float32(glfw.GetTime()), tofu.Vec3{0, 0, 1})). + Mul(tofu.Rotate(float32(glfw.GetTime()), tofu.Vec3{0, 1, 0})) + program.SetMat4("model", model) + gl.DrawElements(gl.TRIANGLES, 36, gl.UNSIGNED_INT, nil) + } window.SwapBuffers() glfw.PollEvents() } diff --git a/cmd/sample/vertex.glsl b/cmd/sample/vertex.glsl @@ -4,9 +4,9 @@ layout (location = 1) in vec3 col; layout (location = 2) in vec2 vtexCoord; out vec3 vcol; out vec2 texCoord; -uniform mat4 transform; +uniform mat4 projection, view, model; void main() { - gl_Position = transform * vec4(pos, 1.0); + gl_Position = projection * view * model * vec4(pos, 1.0); vcol = col; texCoord = vtexCoord; } diff --git a/math.go b/math.go @@ -4,6 +4,55 @@ import "math" type Vec3 [3]float32 + +func (v Vec3) Normalize() Vec3 { + r := float32(math.Sqrt(float64(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]))) + return Vec3{v[0] / r, v[1] / r, v[2] / r} +} + +func (v Vec3) Add(w Vec3) Vec3 { + return Vec3{v[0]+w[0], v[1]+w[1], v[2]+w[2]} +} + +func (v Vec3) Sub(w Vec3) Vec3 { + return Vec3{v[0]-w[0], v[1]-w[1], v[2]-w[2]} +} + +func (v Vec3) Inverse() Vec3 { + return Vec3{-v[0], -v[1], -v[2]} +} + +func (v Vec3) Cross(w Vec3) Vec3 { + return Vec3{ + v[1]*w[2] - v[2]*w[1], + v[2]*w[0] - v[0]*w[2], + v[0]*w[1] - v[1]*w[0], + } +} + +func (v Vec3) MulF(x float32) Vec3{ + return Vec3{v[0]*x, v[1]*x, v[2]*x} +} + +type Mat3 [9]float32 + +func Rotate3(rad float32, axis Vec3) Mat3 { + x, y, z := axis[0], axis[1], axis[2] + c := float32(math.Cos(float64(rad))) + d := 1 - c + s := float32(math.Sin(float64(rad))) + return Mat3{c + x*x*d, y*x*d + z*s, z*x*d - y*s, + x*y*d - z*s, c + y*y*d, z*y*d + x*s, + x*z*d + y*s, y*z*d - x*s, c + z*z*d} +} + +func (m Mat3) MulV(v Vec3) Vec3 { + return Vec3{ + m[0]*v[0]+m[3]*v[1]+m[6]*v[2], + m[1]*v[0]+m[4]*v[1]+m[7]*v[2], + m[2]*v[0]+m[5]*v[1]+m[8]*v[2]} +} + // column major type Mat4 [16]float32 @@ -42,3 +91,17 @@ func Rotate(rad float32, axis Vec3) Mat4 { x*z*d + y*s, y*z*d - x*s, c + z*z*d, 0, 0, 0, 0, 1} } + +func Perspective(fov, asp, min, max float32) Mat4 { + tan := float32(math.Tan(float64(fov/2))) + w := min * tan + h := w / asp + + var mat Mat4 + mat[0] = min / w + mat[5] = min / h + mat[10] = -(max + min) / (max - min) + mat[11] = -1 + mat[14] = -(2 * min * max) / (max - min) + return mat +}