Class: Bestguigui::Render3D::Camera
- Inherits:
-
Object
- Object
- Bestguigui::Render3D::Camera
- Includes:
- OpenGL
- Defined in:
- lib/bestguigui/render_3d/camera.rb
Overview
Caméra perspective en orbite autour d'une cible (angle horizontal + vertical + distance) — le classique d'une vue 3ème personne. Calcule ses matrices vue/projection à la main plutôt que de piloter la pile figée (gluPerspective/gluLookAt) : le pipeline moderne (shaders) n'a pas de pile de matrices globale, chaque objet reçoit les siennes en uniform.
@camera = Bestguigui::Render3D::Camera.new(app)
def update(dt)
@camera.update(@hero.x, @hero.y, @hero.z)
end
def draw
app.gl do
@camera.prepare_frame
@map.draw(@camera)
@hero.draw(@camera)
@camera.finish_frame
end
end
Instance Attribute Summary collapse
-
#angle ⇒ Object
readonly
Returns the value of attribute angle.
-
#angle_v ⇒ Object
readonly
Returns the value of attribute angle_v.
-
#projection_matrix ⇒ Object
readonly
Returns the value of attribute projection_matrix.
-
#view_matrix ⇒ Object
readonly
Returns the value of attribute view_matrix.
Instance Method Summary collapse
-
#finish_frame ⇒ Object
À appeler juste après avoir fini de dessiner en 3D, avant de rendre la main à Gosu (HUD, minimap, ou un tout autre state 2D à la frame suivante).
-
#initialize(app, distance: 128, fovy: 45, near: 1, far: 1000, angle: 90, angle_v: 14, height: 32) ⇒ Camera
constructor
A new instance of Camera.
-
#prepare_frame ⇒ Object
À appeler une fois par frame, en tout début de ton bloc `app.gl do ...
- #rotate(delta_angle: 0, delta_angle_v: 0) ⇒ Object
-
#update(target_x, target_y, target_z) ⇒ Object
Repositionne la caméra en orbite autour de (target_x, target_y, target_z) et recalcule vue/projection.
Constructor Details
#initialize(app, distance: 128, fovy: 45, near: 1, far: 1000, angle: 90, angle_v: 14, height: 32) ⇒ Camera
Returns a new instance of Camera.
29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/bestguigui/render_3d/camera.rb', line 29 def initialize(app, distance: 128, fovy: 45, near: 1, far: 1000, angle: 90, angle_v: 14, height: 32) @app = app @distance = distance @fovy = fovy @near = near @far = far @angle = angle @angle_v = angle_v @height = height @view_matrix = Mat4.identity @projection_matrix = Mat4.identity end |
Instance Attribute Details
#angle ⇒ Object (readonly)
Returns the value of attribute angle.
27 28 29 |
# File 'lib/bestguigui/render_3d/camera.rb', line 27 def angle @angle end |
#angle_v ⇒ Object (readonly)
Returns the value of attribute angle_v.
27 28 29 |
# File 'lib/bestguigui/render_3d/camera.rb', line 27 def angle_v @angle_v end |
#projection_matrix ⇒ Object (readonly)
Returns the value of attribute projection_matrix.
27 28 29 |
# File 'lib/bestguigui/render_3d/camera.rb', line 27 def projection_matrix @projection_matrix end |
#view_matrix ⇒ Object (readonly)
Returns the value of attribute view_matrix.
27 28 29 |
# File 'lib/bestguigui/render_3d/camera.rb', line 27 def view_matrix @view_matrix end |
Instance Method Details
#finish_frame ⇒ Object
À appeler juste après avoir fini de dessiner en 3D, avant de rendre la main à Gosu (HUD, minimap, ou un tout autre state 2D à la frame suivante). Sans ça, GL_DEPTH_TEST reste actif et surtout NOTRE shader/VAO restent liés (glUseProgram/glBindVertexArray) — Gosu dessinerait alors son propre 2D à travers notre shader (qui attend des uniforms de caméra 3D), donnant un écran noir.
83 84 85 86 87 |
# File 'lib/bestguigui/render_3d/camera.rb', line 83 def finish_frame glDisable(GL_DEPTH_TEST) glUseProgram(0) glBindVertexArray(0) end |
#prepare_frame ⇒ Object
À appeler une fois par frame, en tout début de ton bloc app.gl do ... end, avant de dessiner quoi que ce soit en 3D. Active le test
de profondeur et vide le depth buffer — sans ça, l'ordre d'affichage
dépend juste de l'ordre des appels draw, pas de la vraie distance à
la caméra (objets qui s'affichent par-dessus d'autres censés être
devant).
72 73 74 75 |
# File 'lib/bestguigui/render_3d/camera.rb', line 72 def prepare_frame glEnable(GL_DEPTH_TEST) glClear(GL_DEPTH_BUFFER_BIT) end |
#rotate(delta_angle: 0, delta_angle_v: 0) ⇒ Object
61 62 63 64 |
# File 'lib/bestguigui/render_3d/camera.rb', line 61 def rotate(delta_angle: 0, delta_angle_v: 0) @angle += delta_angle @angle_v += delta_angle_v end |
#update(target_x, target_y, target_z) ⇒ Object
Repositionne la caméra en orbite autour de (target_x, target_y, target_z) et recalcule vue/projection.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/bestguigui/render_3d/camera.rb', line 45 def update(target_x, target_y, target_z) t_x = target_x t_y = target_y + @height t_z = target_z v = Math.cos(@angle_v * Math::PI / 180.0) x = t_x + (@distance * v * Math.cos(@angle * Math::PI / 180.0)) z = t_z + (@distance * v * Math.sin(@angle * Math::PI / 180.0)) y = t_y + (@distance * Math.sin(@angle_v * Math::PI / 180.0)) ratio = @app.fullscreen? ? Gosu.screen_width.to_f / Gosu.screen_height : @app.width.to_f / @app.height @view_matrix = Mat4.look_at([x, y, z], [t_x, t_y, t_z], [0, 1, 0]) @projection_matrix = Mat4.perspective(@fovy, ratio, @near, @far) end |