Class: Bestguigui::Render3D::Camera

Inherits:
Object
  • Object
show all
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

Instance Method Summary collapse

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

#angleObject (readonly)

Returns the value of attribute angle.



27
28
29
# File 'lib/bestguigui/render_3d/camera.rb', line 27

def angle
  @angle
end

#angle_vObject (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_matrixObject (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_matrixObject (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_frameObject

À 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. Inutile si tu utilises #frame, qui l'appelle pour toi.



104
105
106
107
108
# File 'lib/bestguigui/render_3d/camera.rb', line 104

def finish_frame
  glDisable(GL_DEPTH_TEST)
  glUseProgram(0)
  glBindVertexArray(0)
end

#frame(app) ⇒ Object

Encadre le rendu 3D d'une frame : ouvre le contexte GL de Gosu, prépare l'état GL (depth test), exécute le bloc, puis nettoie l'état avant de rendre la main à Gosu. Remplace le couple manuel prepare_frame/finish_frame — plus rien à oublier ni à déséquilibrer :

def draw
@camera.frame(app) do
  @map.draw(@camera)
  @hero.draw(@camera)
end
draw_hud # 2D, hors du bloc
end


78
79
80
81
82
83
84
# File 'lib/bestguigui/render_3d/camera.rb', line 78

def frame(app)
  app.gl do
    prepare_frame
    yield
    finish_frame
  end
end

#prepare_frameObject

À 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). Inutile si tu utilises #frame, qui l'appelle pour toi.



92
93
94
95
# File 'lib/bestguigui/render_3d/camera.rb', line 92

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