package mesh import "math" // Vec3 is a point or direction in 3D space. type Vec3 struct{ X, Y, Z float64 } func (a Vec3) Add(b Vec3) Vec3 { return Vec3{a.X + b.X, a.Y + b.Y, a.Z + b.Z} } func (a Vec3) Sub(b Vec3) Vec3 { return Vec3{a.X - b.X, a.Y - b.Y, a.Z - b.Z} } func (a Vec3) Mul(s float64) Vec3 { return Vec3{a.X * s, a.Y * s, a.Z * s} } func (a Vec3) Dot(b Vec3) float64 { return a.X*b.X + a.Y*b.Y + a.Z*b.Z } func (a Vec3) Len() float64 { return math.Sqrt(a.Dot(a)) } func (a Vec3) Cross(b Vec3) Vec3 { return Vec3{ a.Y*b.Z - a.Z*b.Y, a.Z*b.X - a.X*b.Z, a.X*b.Y - a.Y*b.X, } } // Norm returns the unit vector, or the zero vector for zero-length input. func (a Vec3) Norm() Vec3 { l := a.Len() if l == 0 { return Vec3{} } return a.Mul(1 / l) } // Min/Max return the component-wise minimum/maximum. func (a Vec3) Min(b Vec3) Vec3 { return Vec3{math.Min(a.X, b.X), math.Min(a.Y, b.Y), math.Min(a.Z, b.Z)} } func (a Vec3) Max(b Vec3) Vec3 { return Vec3{math.Max(a.X, b.X), math.Max(a.Y, b.Y), math.Max(a.Z, b.Z)} } // Mat4 is a row-major 4x4 transform matrix. type Mat4 [16]float64 func Identity() Mat4 { return Mat4{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, } } // Mul returns m * n (n is applied first when transforming points). func (m Mat4) Mul(n Mat4) Mat4 { var r Mat4 for row := 0; row < 4; row++ { for col := 0; col < 4; col++ { sum := 0.0 for k := 0; k < 4; k++ { sum += m[row*4+k] * n[k*4+col] } r[row*4+col] = sum } } return r } // Apply transforms a point (w = 1). func (m Mat4) Apply(v Vec3) Vec3 { return Vec3{ m[0]*v.X + m[1]*v.Y + m[2]*v.Z + m[3], m[4]*v.X + m[5]*v.Y + m[6]*v.Z + m[7], m[8]*v.X + m[9]*v.Y + m[10]*v.Z + m[11], } } // Det3 is the determinant of the upper-left 3x3. Negative means the // transform mirrors space, which flips triangle winding. func (m Mat4) Det3() float64 { return m[0]*(m[5]*m[10]-m[6]*m[9]) - m[1]*(m[4]*m[10]-m[6]*m[8]) + m[2]*(m[4]*m[9]-m[5]*m[8]) } func Translate(t Vec3) Mat4 { m := Identity() m[3], m[7], m[11] = t.X, t.Y, t.Z return m } func ScaleXYZ(s Vec3) Mat4 { m := Identity() m[0], m[5], m[10] = s.X, s.Y, s.Z return m } func RotateX(deg float64) Mat4 { s, c := math.Sincos(deg * math.Pi / 180) return Mat4{ 1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, } } func RotateY(deg float64) Mat4 { s, c := math.Sincos(deg * math.Pi / 180) return Mat4{ c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1, } } func RotateZ(deg float64) Mat4 { s, c := math.Sincos(deg * math.Pi / 180) return Mat4{ c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, } }