package camera import ( "zworld/engine/object" "zworld/engine/renderapi" "zworld/engine/renderapi/color" "zworld/plugins/math/mat4" "zworld/plugins/math/vec3" ) // Camera Group type Object struct { object.Object *Camera } // Camera Component type Camera struct { object.Component Args Viewport renderapi.Screen Aspect float32 Proj mat4.T View mat4.T ViewInv mat4.T ViewProj mat4.T ViewProjInv mat4.T Eye vec3.T Forward vec3.T } type Args struct { Fov float32 Near float32 Far float32 Clear color.T } // New creates a new camera component. func New(args Args) *Camera { return object.NewComponent(&Camera{ Args: args, Aspect: 1, }) } func NewObject(args Args) *Object { return object.New("Camera", &Object{ Camera: New(args), }) } func (cam *Object) Name() string { return "Camera" } // Unproject screen space coordinates into world space func (cam *Camera) Unproject(pos vec3.T) vec3.T { // screen space -> clip space pos.Y = 1 - pos.Y pos = pos.Scaled(2).Sub(vec3.One) // unproject to world space by multiplying inverse view-projection return cam.ViewProjInv.TransformPoint(pos) } func (cam *Camera) RenderArgs(screen renderapi.Screen) renderapi.Args { // todo: passing the global viewport allows the camera to modify the actual render viewport // update view & view-projection matrices cam.Viewport = screen cam.Aspect = float32(cam.Viewport.Width) / float32(cam.Viewport.Height) cam.Proj = mat4.Perspective(cam.Fov, cam.Aspect, cam.Near, cam.Far) // calculate the view matrix. // should be the inverse of the cameras transform matrix tf := cam.Transform() cam.Eye = tf.WorldPosition() cam.Forward = tf.Forward() cam.ViewInv = tf.Matrix() cam.View = cam.ViewInv.Invert() cam.ViewProj = cam.Proj.Mul(&cam.View) cam.ViewProjInv = cam.ViewProj.Invert() return renderapi.Args{ Viewport: cam.Viewport, Near: cam.Near, Far: cam.Far, Fov: cam.Fov, Projection: cam.Proj, View: cam.View, ViewInv: cam.ViewInv, VP: cam.ViewProj, VPInv: cam.ViewProjInv, MVP: cam.ViewProj, Clear: cam.Clear, Position: cam.Transform().WorldPosition(), Forward: cam.Transform().Forward(), } }