Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Joy with 3D Graphics Using Ruby

Avatar for ydah ydah
August 10, 2025

Joy with 3D Graphics Using Ruby

RubyConf Taiwan x COSCUP 2025 「Joy with 3D Graphics Using Ruby」の発表スライド #rubyconftw

Avatar for ydah

ydah

August 10, 2025
Tweet

More Decks by ydah

Other Decks in Programming

Transcript

  1. Sunday, August 10, 2025 COSCUP x RubyConf TW 2025 @ydah

    ルビーコンフタイワン ルビーコンフタイワン ルビーコンフタイワン Joy with 3D Graphics Using Ruby Now Loading...
  2. Joy with 3D Graphics Using Ruby ✦ߴా ༤େ / Yudai

    Takada ✦GitHub: ydah, Twitter: ydah_ ✦Open Source Software Programmar ✦CRuby committer, mainly develop parser related features ✦A committer of ruby/lrama LALR parser generator $whoiam 4
  3. Joy with 3D Graphics Using Ruby 3D drawing APIs ✦How

    to Draw 3D Graphics on a Computer ✦OpenGL: It Works Anywhere, It's Traditional, It's Generic ✦DirectX: Microsoft Platform Specialization ✦Vulkan: A spiritual successor to OpenGL, a low-level API for fi ne control of the GPU ✦Metal: A low-level, low-overhead hardware-accelerated 3D graphic and compute shader API created by Apple 11
  4. Joy with 3D Graphics Using Ruby What is OpenGL? ✦OpenGL

    (Open Graphics Library) is an industry standard API for hardware-independent 2D and 3D graphics rendering ✦It's cross-platform, and is used in a wide range of fi elds, from visualization of scienti fi c and technological calculations to game development 13
  5. Joy with 3D Graphics Using Ruby ✦opengl-bindings2 ✦https://github.com/vaiorabbit/ruby-opengl ✦There is

    an o ff i cial wrapper, but recent Ruby fails to install the gem ✦https://github.com/larskanis/opengl ✦Looking at the commit log, the last commit was 7 years ago 14 Library for working with OpenGL in Ruby
  6. Joy with 3D Graphics Using Ruby ✦The writing style is

    completely different before and after OpenGL 3.0, so be careful ✦It is better to understand which style is written before reading ✦In the old style, vertex data is sent one by one from the CPU to the GPU and drawn between the instruction blocks glBegin() and glEnd() ✦In the modern standard method, the vertex data is transferred to a memory area on the GPU called Vertex Buffer Object, and the shader is executed on the GPU, which allows fi ne control of the drawing process 15 Reading the sample code Tips
  7. Joy with 3D Graphics Using Ruby What does OpenGL not

    do? ✦Create a window ✦Handle keyboard and mouse input ✦Create an OpenGL context (drawing environment) 16
  8. Joy with 3D Graphics Using Ruby ✦Libraries that provide the

    peripheral functions needed to use OpenGL ✦It also abstracts OS-speci fi c processing ✦OpenGL is a drawing engine ✦GLFW/GLUT is a toolkit to interface with the platform 17 GLFW / GLUT Application GLFW or GLUT Graphics Driver OpenGL
  9. Joy with 3D Graphics Using Ruby ✦The OpenGL Utility Toolkit

    ✦A library developed in the 90s that features a simple API ✦Provides windowing, event handling, and basic drawing functions ✦Good for learning, but no longer in development ✦The original hasn't been maintained for over 20 years 18 GLUT
  10. Joy with 3D Graphics Using Ruby ✦Graphics Library Framework ✦More

    modern libraries introduced in 2002 ✦Support for multiple windows and monitors ✦Finer event control ✦Support for OpenGL 3.x/4.x, Vulkan, Metal, and other modern APIs 20 GLFW
  11. Joy with 3D Graphics Using Ruby ✦Windows ✦Get the binaries

    from https://www.glfw.org/download.html ✦Mac OS X/Linux ✦$ brew install glfw ✦ $ apt -y install libglfw3-dev 21 Getting Started with GLFW
  12. Joy with 3D Graphics Using Ruby 22 Create a window

    require 'opengl' require 'glfw' GLFW.load_lib('/opt/homebrew/lib/libglfw.dylib') GLFW.Init() window = GLFW.CreateWindow(300, 300, 'Example', nil, nil) until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GLFW.SwapBuffers(window) GLFW.PollEvents() end
  13. Joy with 3D Graphics Using Ruby 23 Create a window

    require 'opengl' require 'glfw' GLFW.load_lib('/opt/homebrew/lib/libglfw.dylib') GLFW.Init() window = GLFW.CreateWindow(300, 300, 'Example', nil, nil) until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GLFW.SwapBuffers(window) GLFW.PollEvents() end Load GLFW Library
  14. Joy with 3D Graphics Using Ruby 24 Create a window

    require 'opengl' require 'glfw' GLFW.load_lib('/opt/homebrew/lib/libglfw.dylib') GLFW.Init() window = GLFW.CreateWindow(300, 300, 'Example', nil, nil) until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GLFW.SwapBuffers(window) GLFW.PollEvents() end Initialize GLFW library
  15. Joy with 3D Graphics Using Ruby 25 Create a window

    require 'opengl' require 'glfw' GLFW.load_lib('/opt/homebrew/lib/libglfw.dylib') GLFW.Init() window = GLFW.CreateWindow(300, 300, 'Example', nil, nil) until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GLFW.SwapBuffers(window) GLFW.PollEvents() end Create a Window
  16. Joy with 3D Graphics Using Ruby 26 Create a window

    require 'opengl' require 'glfw' GLFW.load_lib('/opt/homebrew/lib/libglfw.dylib') GLFW.Init() window = GLFW.CreateWindow(300, 300, 'Example', nil, nil) until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GLFW.SwapBuffers(window) GLFW.PollEvents() end Main Loop
  17. Joy with 3D Graphics Using Ruby 28 Configuring Callbacks cb

    = GLFW.create_callback( : GLFWkeyfun) do |w,key,_,act,_| if key = = GLFW : : KEY_ESCAPE & & act = = GLFW : : PRESS GLFW.SetWindowShouldClose(w, 1) end end window = GLFW.CreateWindow(300, 300, 'Example', nil, nil) GLFW.SetKeyCallback(window, cb) until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GLFW.SwapBuffers(window) GLFW.PollEvents() end
  18. Joy with 3D Graphics Using Ruby 29 Configuring Callbacks cb

    = GLFW.create_callback( : GLFWkeyfun) do |w,key,_,act,_| if key = = GLFW : : KEY_ESCAPE & & act = = GLFW : : PRESS GLFW.SetWindowShouldClose(w, 1) end end window = GLFW.CreateWindow(300, 300, 'Example', nil, nil) GLFW.SetKeyCallback(window, cb) until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GLFW.SwapBuffers(window) GLFW.PollEvents() end Close window when Escape button is pressed
  19. Joy with 3D Graphics Using Ruby 30 Configuring Callbacks cb

    = GLFW.create_callback( : GLFWkeyfun) do |w,key,_,act,_| if key = = GLFW : : KEY_ESCAPE & & act = = GLFW : : PRESS GLFW.SetWindowShouldClose(w, 1) end end window = GLFW.CreateWindow(300, 300, 'Example', nil, nil) GLFW.SetKeyCallback(window, cb) until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GLFW.SwapBuffers(window) GLFW.PollEvents() end Set callback to window
  20. Joy with 3D Graphics Using Ruby 31 Configuring Callbacks cb

    = GLFW.create_callback( : GLFWkeyfun) do |w,key,_,act,_| if key = = GLFW : : KEY_ESCAPE & & act = = GLFW : : PRESS GLFW.SetWindowShouldClose(w, 1) end end window = GLFW.CreateWindow(300, 300, 'Example', nil, nil) GLFW.SetKeyCallback(window, cb) until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GLFW.SwapBuffers(window) GLFW.PollEvents() end Poll for events
  21. Joy with 3D Graphics Using Ruby Point Location ✦Internally, OpenGL

    uses four pieces of information to manage the position of a single point: ✦Homogeneous coordinates (x, y, z, w) ✦"Why do you need four pieces of information in three dimensions?" ✦For smooth computation of "projections" 32
  22. Joy with 3D Graphics Using Ruby ✦There are generally two

    types of coordinate systems ✦A right-handed coordinate system is positive in front of the z-axis and negative in the back of the z-axis ✦A left-handed coordinate system is negative in front of the z-axis and positive in the back of the z-axis 33 Point Location y +z x -z y -z x +z
  23. Joy with 3D Graphics Using Ruby ✦There are generally two

    types of coordinate systems ✦A right-handed coordinate system is positive in front of the z-axis and negative in the back of the z-axis ✦A left-handed coordinate system is negative in front of the z-axis and positive in the back of the z-axis 34 Point Location y +z x -z y -z x +z
  24. Joy with 3D Graphics Using Ruby Primitives 35 ✦Need to

    de fi ne basic units of what to draw ✦Types of primitives ✦Points ✦Lines ✦Polygons ✦De fi ned as a collection of vertices with positional information
  25. Joy with 3D Graphics Using Ruby What is required for

    drawing? 36 ✦De fi ne vertices ✦"This geometry consists of the coordinates (x1, y1, z1), (x2, y2, z2) and ..." and teach vertex position information ✦De fi ne primitives ✦"Draw a triangle using the previous vertex." and specify the type of primitive ✦Rendering ✦Convert de fi ned primitives into a form that can be displayed on the computer screen
  26. Joy with 3D Graphics Using Ruby 37 Draw triangles until

    GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.Begin(GL : : TRIANGLES) GL.Vertex2f(-0.8, -0.8) GL.Vertex2f(0.8, -0.8) GL.Vertex2f(0.0, 0.9) GL.End GLFW.SwapBuffers(window) GLFW.PollEvents() end
  27. Joy with 3D Graphics Using Ruby 38 Draw triangles until

    GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.Begin(GL : : TRIANGLES) GL.Vertex2f(-0.8, -0.8) GL.Vertex2f(0.8, -0.8) GL.Vertex2f(0.0, 0.9) GL.End GLFW.SwapBuffers(window) GLFW.PollEvents() end Declare to draw a triangle
  28. Joy with 3D Graphics Using Ruby 39 Draw triangles until

    GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.Begin(GL : : TRIANGLES) GL.Vertex2f(-0.8, -0.8) GL.Vertex2f(0.8, -0.8) GL.Vertex2f(0.0, 0.9) GL.End GLFW.SwapBuffers(window) GLFW.PollEvents() end De fi ning Coordinates for 3 Vertices
  29. Joy with 3D Graphics Using Ruby 40 Draw triangles until

    GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.Begin(GL : : TRIANGLES) GL.Vertex2f(-0.8, -0.8) GL.Vertex2f(0.8, -0.8) GL.Vertex2f(0.0, 0.9) GL.End GLFW.SwapBuffers(window) GLFW.PollEvents() end Signal that you have fi nished drawing the triangle
  30. Joy with 3D Graphics Using Ruby 42 Add color information

    until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.Begin(GL : : TRIANGLES) GL.Color3f(1.0, 0.0, 0.0) GL.Vertex2f(-0.8, -0.8) GL.Color3f(0.0, 1.0, 0.0) GL.Vertex2f(0.8, -0.8) GL.Color3f(0.0, 0.0, 1.0) GL.Vertex2f(0.0, 0.9) GL.End GLFW.SwapBuffers(window) GLFW.PollEvents() end
  31. Joy with 3D Graphics Using Ruby 43 Add color information

    until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.Begin(GL : : TRIANGLES) GL.Color3f(1.0, 0.0, 0.0) GL.Vertex2f(-0.8, -0.8) GL.Color3f(0.0, 1.0, 0.0) GL.Vertex2f(0.8, -0.8) GL.Color3f(0.0, 0.0, 1.0) GL.Vertex2f(0.0, 0.9) GL.End GLFW.SwapBuffers(window) GLFW.PollEvents() end Specifying Red, Blue, and Green Colors
  32. Joy with 3D Graphics Using Ruby 45 Add color information

    until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.Begin(GL : : TRIANGLES) GL.Color3f(1.0, 0.0, 0.0) GL.Vertex2f(-0.8, -0.8) GL.Color3f(0.0, 1.0, 0.0) GL.Vertex2f(0.8, -0.8) GL.Color3f(0.0, 0.0, 1.0) GL.Vertex2f(0.0, 0.9) GL.End GLFW.SwapBuffers(window) GLFW.PollEvents() end Automatically interpolate the color of each vertex
  33. Joy with 3D Graphics Using Ruby 46 Add Animation until

    GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.Begin(GL : : TRIANGLES) GL.Color3f(1.0, 0.0, 0.0) GL.Vertex2f(-0.8, -0.8) GL.Color3f(0.0, 1.0, 0.0) GL.Vertex2f(0.8, -0.8) GL.Color3f(0.0, 0.0, 1.0) GL.Vertex2f(0.0, 0.9) GL.End GL.Rotatef(1.0, 0.0, 0.0, 1.0) GLFW.SwapBuffers(window) GLFW.PollEvents() end
  34. Joy with 3D Graphics Using Ruby 47 Add Animation until

    GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.Begin(GL : : TRIANGLES) GL.Color3f(1.0, 0.0, 0.0) GL.Vertex2f(-0.8, -0.8) GL.Color3f(0.0, 1.0, 0.0) GL.Vertex2f(0.8, -0.8) GL.Color3f(0.0, 0.0, 1.0) GL.Vertex2f(0.0, 0.9) GL.End GL.Rotatef(1.0, 0.0, 0.0, 1.0) GLFW.SwapBuffers(window) GLFW.PollEvents() end Rotate 1.0 degrees around Z axis
  35. Joy with 3D Graphics Using Ruby 49 Clear Screen until

    GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.ClearColor(0.0, 0.0, 0.0, 0.0) GL.Clear(GL : : COLOR_BUFFER_BIT) GL.Begin(GL : : TRIANGLES) GL.Color3f(1.0, 0.0, 0.0) GL.Vertex2f(-0.8, -0.8) GL.Color3f(0.0, 1.0, 0.0) GL.Vertex2f(0.8, -0.8) GL.Color3f(0.0, 0.0, 1.0) GL.Vertex2f(0.0, 0.9) GL.End GL.Rotatef(1.0, 0.0, 0.0, 1.0) GLFW.SwapBuffers(window) GLFW.PollEvents() end
  36. Joy with 3D Graphics Using Ruby 50 Clear Screen until

    GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.ClearColor(0.0, 0.0, 0.0, 0.0) GL.Clear(GL : : COLOR_BUFFER_BIT) GL.Begin(GL : : TRIANGLES) GL.Color3f(1.0, 0.0, 0.0) GL.Vertex2f(-0.8, -0.8) GL.Color3f(0.0, 1.0, 0.0) GL.Vertex2f(0.8, -0.8) GL.Color3f(0.0, 0.0, 1.0) GL.Vertex2f(0.0, 0.9) GL.End GL.Rotatef(1.0, 0.0, 0.0, 1.0) GLFW.SwapBuffers(window) GLFW.PollEvents() end Set the screen clear color to black
  37. Joy with 3D Graphics Using Ruby 51 Clear Screen until

    GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.ClearColor(0.0, 0.0, 0.0, 0.0) GL.Clear(GL : : COLOR_BUFFER_BIT) GL.Begin(GL : : TRIANGLES) GL.Color3f(1.0, 0.0, 0.0) GL.Vertex2f(-0.8, -0.8) GL.Color3f(0.0, 1.0, 0.0) GL.Vertex2f(0.8, -0.8) GL.Color3f(0.0, 0.0, 1.0) GL.Vertex2f(0.0, 0.9) GL.End GL.Rotatef(1.0, 0.0, 0.0, 1.0) GLFW.SwapBuffers(window) GLFW.PollEvents() end Clear previous frame drawing
  38. Joy with 3D Graphics Using Ruby 54 Draw Six Faces

    GL.Begin(GL : : QUADS) GL.Color3f(1,0,0) # 1 GL.Vertex3f(-1,-1,1);GL.Vertex3f(1,-1,1);GL.Vertex3f(1,1,1);GL.Vertex3f(-1,1,1) GL.Color3f(0,1,0) # 2 GL.Vertex3f(-1,-1,-1);GL.Vertex3f(-1,1,-1);GL.Vertex3f(1,1,-1);GL.Vertex3f(1,-1,-1) GL.Color3f(0,0,1) # 3 GL.Vertex3f(-1,1,-1);GL.Vertex3f(-1,1,1);GL.Vertex3f(1,1,1);GL.Vertex3f(1,1,-1) GL.Color3f(1,1,0) # 4 GL.Vertex3f(-1,-1,-1);GL.Vertex3f(1,-1,-1);GL.Vertex3f(1,-1,1);GL.Vertex3f(-1,-1,1) GL.Color3f(0,1,1) # 5 GL.Vertex3f(1,-1,-1);GL.Vertex3f(1,1,-1);GL.Vertex3f(1,1,1);GL.Vertex3f(1,-1,1) GL.Color3f(1,0,1) # 6 GL.Vertex3f(-1,-1,-1);GL.Vertex3f(-1,-1,1);GL.Vertex3f(-1,1,1);GL.Vertex3f(-1,1,-1) GL.End()
  39. Joy with 3D Graphics Using Ruby Perspective Projections ✦This is

    the equivalent of a camera lens ✦Determines how 3D space is projected onto a 2D screen 56 Field of View -Z axis Near Clipping Plane Far Clipping Plane
  40. Joy with 3D Graphics Using Ruby 57 Setting the Projection

    Matrix GLFW.GetFramebufferSize(window, width_buf, height_buf) width = width_buf.unpack('I').f i rst height = height_buf.unpack('I').f i rst height = 1 if height = = 0 aspect = width.to_f / height.to_f GL.MatrixMode(GL : : PROJECTION) GL.LoadIdentity() fovy_degrees = 45.0 near_clip = 0.1 far_clip = 100.0 fovy_radians = fovy_degrees * Math : : PI / 180.0 top = Math.tan(fovy_radians / 2.0) * near_clip bottom = - top right = top * aspect left = - right GL.Frustum(left, right, bottom, top, near_clip, far_clip)
  41. Joy with 3D Graphics Using Ruby 58 Setting the Projection

    Matrix GLFW.GetFramebufferSize(window, width_buf, height_buf) width = width_buf.unpack('I').f i rst height = height_buf.unpack('I').f i rst height = 1 if height = = 0 aspect = width.to_f / height.to_f GL.MatrixMode(GL : : PROJECTION) GL.LoadIdentity() fovy_degrees = 45.0 near_clip = 0.1 far_clip = 100.0 fovy_radians = fovy_degrees * Math : : PI / 180.0 top = Math.tan(fovy_radians / 2.0) * near_clip bottom = - top right = top * aspect left = - right GL.Frustum(left, right, bottom, top, near_clip, far_clip) Computing window aspect ratio
  42. Joy with 3D Graphics Using Ruby 59 Setting the Projection

    Matrix GLFW.GetFramebufferSize(window, width_buf, height_buf) width = width_buf.unpack('I').f i rst height = height_buf.unpack('I').f i rst height = 1 if height = = 0 aspect = width.to_f / height.to_f GL.MatrixMode(GL : : PROJECTION) GL.LoadIdentity() fovy_degrees = 45.0 near_clip = 0.1 far_clip = 100.0 fovy_radians = fovy_degrees * Math : : PI / 180.0 top = Math.tan(fovy_radians / 2.0) * near_clip bottom = - top right = top * aspect left = - right GL.Frustum(left, right, bottom, top, near_clip, far_clip) Tells OpenGL that the matrix operation is on a Projection Matrix
  43. Joy with 3D Graphics Using Ruby 60 Setting the Projection

    Matrix GLFW.GetFramebufferSize(window, width_buf, height_buf) width = width_buf.unpack('I').f i rst height = height_buf.unpack('I').f i rst height = 1 if height = = 0 aspect = width.to_f / height.to_f GL.MatrixMode(GL : : PROJECTION) GL.LoadIdentity() fovy_degrees = 45.0 near_clip = 0.1 far_clip = 100.0 fovy_radians = fovy_degrees * Math : : PI / 180.0 top = Math.tan(fovy_radians / 2.0) * near_clip bottom = - top right = top * aspect left = - right GL.Frustum(left, right, bottom, top, near_clip, far_clip) Reset the currently selected matrix to the identity matrix
  44. Joy with 3D Graphics Using Ruby 61 Setting the Projection

    Matrix GLFW.GetFramebufferSize(window, width_buf, height_buf) width = width_buf.unpack('I').f i rst height = height_buf.unpack('I').f i rst height = 1 if height = = 0 aspect = width.to_f / height.to_f GL.MatrixMode(GL : : PROJECTION) GL.LoadIdentity() fovy_degrees = 45.0 near_clip = 0.1 far_clip = 100.0 fovy_radians = fovy_degrees * Math : : PI / 180.0 top = Math.tan(fovy_radians / 2.0) * near_clip bottom = - top right = top * aspect left = - right GL.Frustum(left, right, bottom, top, near_clip, far_clip) Set the vertical fi eld of view to determine how wide the camera can see
  45. Joy with 3D Graphics Using Ruby 62 Setting the Projection

    Matrix GLFW.GetFramebufferSize(window, width_buf, height_buf) width = width_buf.unpack('I').f i rst height = height_buf.unpack('I').f i rst height = 1 if height = = 0 aspect = width.to_f / height.to_f GL.MatrixMode(GL : : PROJECTION) GL.LoadIdentity() fovy_degrees = 45.0 near_clip = 0.1 far_clip = 100.0 fovy_radians = fovy_degrees * Math : : PI / 180.0 top = Math.tan(fovy_radians / 2.0) * near_clip bottom = - top right = top * aspect left = - right GL.Frustum(left, right, bottom, top, near_clip, far_clip) Determines the boundary beyond which objects are not drawn
  46. Joy with 3D Graphics Using Ruby 63 Setting the Projection

    Matrix GLFW.GetFramebufferSize(window, width_buf, height_buf) width = width_buf.unpack('I').f i rst height = height_buf.unpack('I').f i rst height = 1 if height = = 0 aspect = width.to_f / height.to_f GL.MatrixMode(GL : : PROJECTION) GL.LoadIdentity() fovy_degrees = 45.0 near_clip = 0.1 far_clip = 100.0 fovy_radians = fovy_degrees * Math : : PI / 180.0 top = Math.tan(fovy_radians / 2.0) * near_clip bottom = - top right = top * aspect left = - right GL.Frustum(left, right, bottom, top, near_clip, far_clip) Calculate near clip plane position information
  47. Joy with 3D Graphics Using Ruby 64 Setting the Projection

    Matrix GLFW.GetFramebufferSize(window, width_buf, height_buf) width = width_buf.unpack('I').f i rst height = height_buf.unpack('I').f i rst height = 1 if height = = 0 aspect = width.to_f / height.to_f GL.MatrixMode(GL : : PROJECTION) GL.LoadIdentity() fovy_degrees = 45.0 near_clip = 0.1 far_clip = 100.0 fovy_radians = fovy_degrees * Math : : PI / 180.0 top = Math.tan(fovy_radians / 2.0) * near_clip bottom = - top right = top * aspect left = - right GL.Frustum(left, right, bottom, top, near_clip, far_clip) Projection matrix for perspective projection is generated and set
  48. Joy with 3D Graphics Using Ruby ✦In 3D graphics, a

    matrix used to transform an object's coordinates in world space into camera space ✦Model Matrix ✦Matrix for transforming vertex data based on position, rotation, and scale in the world coordinate system ✦View Matrix ✦Matrix for de fi ne the position and orientation of the camera and transform world space coordinates into camera space Model-View Matrix 65
  49. Joy with 3D Graphics Using Ruby 66 Setting the Model-View

    Matrix GL.MatrixMode(GL : : MODELVIEW) GL.LoadIdentity() GL.Translatef(0.0, 0.0, -9.0) GL.Rotatef(rotation_angle, 1.0, 1.0, 0.0) rotation_angle += 0.5
  50. Joy with 3D Graphics Using Ruby 67 Setting the Model-View

    Matrix GL.MatrixMode(GL : : MODELVIEW) GL.LoadIdentity() GL.Translatef(0.0, 0.0, -9.0) GL.Rotatef(rotation_angle, 1.0, 1.0, 0.0) rotation_angle += 0.5 Declare that we are about to operate on a model view matrix and initialize the matrix
  51. Joy with 3D Graphics Using Ruby 68 Setting the Model-View

    Matrix GL.MatrixMode(GL : : MODELVIEW) GL.LoadIdentity() GL.Translatef(0.0, 0.0, -9.0) GL.Rotatef(rotation_angle, 1.0, 1.0, 0.0) rotation_angle += 0.5 Move the camera back 9.0 in the positive z-axis
  52. Joy with 3D Graphics Using Ruby 69 Setting the Model-View

    Matrix GL.MatrixMode(GL : : MODELVIEW) GL.LoadIdentity() GL.Translatef(0.0, 0.0, -9.0) GL.Rotatef(rotation_angle, 1.0, 1.0, 0.0) rotation_angle += 0.5 Animate by increasing the rotation angle by 0.5 degrees each frame
  53. Joy with 3D Graphics Using Ruby 71 Setting and Clearing

    Frames for Depth GL.Enable(GL : : DEPTH_TEST) until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.Clear(GL : : COLOR_BUFFER_BIT | GL : : DEPTH_BUFFER_BIT) # . . . end
  54. Joy with 3D Graphics Using Ruby 72 Setting and Clearing

    Frames for Depth GL.Enable(GL : : DEPTH_TEST) until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.Clear(GL : : COLOR_BUFFER_BIT | GL : : DEPTH_BUFFER_BIT) # . . . end Draw objects in the foreground to properly hide objects in the background
  55. Joy with 3D Graphics Using Ruby 73 Setting and Clearing

    Frames for Depth GL.Enable(GL : : DEPTH_TEST) until GLFW.WindowShouldClose(window) = = GLFW : : TRUE GL.Clear(GL : : COLOR_BUFFER_BIT | GL : : DEPTH_BUFFER_BIT) # . . . end Clear color and depth information
  56. Joy with 3D Graphics Using Ruby ✦We can now display

    3D objects on the screen in the correct position and shape ✦But it still looks like a fl at, shadowless picture ✦The last important element that adds reality is lighting and materials ✦They simulate how light bounces off the surface of an object and reaches our eyes Lighting and Materials 75
  57. Joy with 3D Graphics Using Ruby 77 Three types of

    light sources Specular Re fl ection Diffuse Re fl ection Ambient light
  58. Joy with 3D Graphics Using Ruby Three types of light

    sources ✦Ambient light ✦Indirect light that illuminates the entire surface evenly ✦Helps prevent shadows that do not shine directly into the light source from going black ✦Diffuse re fl ection ✦Re fl ection where light from a source scatters evenly across the surface of an object ✦Determines the brightness of illuminated surfaces ✦Specular re fl ection ✦A light source that re fl ects strongly in a particular direction ✦Produces a gloss 78
  59. Joy with 3D Graphics Using Ruby GL.Enable(GL : : LIGHTING)

    GL.Enable(GL : : LIGHT0) GL.Enable(GL : : NORMALIZE) ambient_light = [0.2, 0.2, 0.2, 1.0].pack('F*') diffuse_light = [1.0, 1.0, 1.0, 1.0].pack('F*') specular_light = [1.0, 1.0, 1.0, 1.0].pack('F*') GL.Lightfv(GL : : LIGHT0, GL : : AMBIENT, ambient_light) GL.Lightfv(GL : : LIGHT0, GL : : DIFFUSE, diffuse_light) GL.Lightfv(GL : : LIGHT0, GL : : SPECULAR, specular_light) GL.Enable(GL : : COLOR_MATERIAL) GL.ColorMaterial(GL : : FRONT, GL : : AMBIENT_AND_DIFFUSE) specular_material = [1.0, 1.0, 1.0, 1.0].pack('F*') shininess = 50.0 GL.Materialfv(GL : : FRONT, GL : : SPECULAR, specular_material) GL.Materialf(GL : : FRONT, GL : : SHININESS, shininess) 79 Lighting and Material Setup
  60. Joy with 3D Graphics Using Ruby GL.Enable(GL : : LIGHTING)

    GL.Enable(GL : : LIGHT0) GL.Enable(GL : : NORMALIZE) ambient_light = [0.2, 0.2, 0.2, 1.0].pack('F*') diffuse_light = [1.0, 1.0, 1.0, 1.0].pack('F*') specular_light = [1.0, 1.0, 1.0, 1.0].pack('F*') GL.Lightfv(GL : : LIGHT0, GL : : AMBIENT, ambient_light) GL.Lightfv(GL : : LIGHT0, GL : : DIFFUSE, diffuse_light) GL.Lightfv(GL : : LIGHT0, GL : : SPECULAR, specular_light) GL.Enable(GL : : COLOR_MATERIAL) GL.ColorMaterial(GL : : FRONT, GL : : AMBIENT_AND_DIFFUSE) specular_material = [1.0, 1.0, 1.0, 1.0].pack('F*') shininess = 50.0 GL.Materialfv(GL : : FRONT, GL : : SPECULAR, specular_material) GL.Materialf(GL : : FRONT, GL : : SHININESS, shininess) 80 Lighting and Material Setup Enable Lighting
  61. Joy with 3D Graphics Using Ruby GL.Enable(GL : : LIGHTING)

    GL.Enable(GL : : LIGHT0) GL.Enable(GL : : NORMALIZE) ambient_light = [0.2, 0.2, 0.2, 1.0].pack('F*') diffuse_light = [1.0, 1.0, 1.0, 1.0].pack('F*') specular_light = [1.0, 1.0, 1.0, 1.0].pack('F*') GL.Lightfv(GL : : LIGHT0, GL : : AMBIENT, ambient_light) GL.Lightfv(GL : : LIGHT0, GL : : DIFFUSE, diffuse_light) GL.Lightfv(GL : : LIGHT0, GL : : SPECULAR, specular_light) GL.Enable(GL : : COLOR_MATERIAL) GL.ColorMaterial(GL : : FRONT, GL : : AMBIENT_AND_DIFFUSE) specular_material = [1.0, 1.0, 1.0, 1.0].pack('F*') shininess = 50.0 GL.Materialfv(GL : : FRONT, GL : : SPECULAR, specular_material) GL.Materialf(GL : : FRONT, GL : : SHININESS, shininess) 81 Lighting and Material Setup Enables the 0th light among the available light sources
  62. Joy with 3D Graphics Using Ruby GL.Enable(GL : : LIGHTING)

    GL.Enable(GL : : LIGHT0) GL.Enable(GL : : NORMALIZE) ambient_light = [0.2, 0.2, 0.2, 1.0].pack('F*') diffuse_light = [1.0, 1.0, 1.0, 1.0].pack('F*') specular_light = [1.0, 1.0, 1.0, 1.0].pack('F*') GL.Lightfv(GL : : LIGHT0, GL : : AMBIENT, ambient_light) GL.Lightfv(GL : : LIGHT0, GL : : DIFFUSE, diffuse_light) GL.Lightfv(GL : : LIGHT0, GL : : SPECULAR, specular_light) GL.Enable(GL : : COLOR_MATERIAL) GL.ColorMaterial(GL : : FRONT, GL : : AMBIENT_AND_DIFFUSE) specular_material = [1.0, 1.0, 1.0, 1.0].pack('F*') shininess = 50.0 GL.Materialfv(GL : : FRONT, GL : : SPECULAR, specular_material) GL.Materialf(GL : : FRONT, GL : : SHININESS, shininess) 82 Lighting and Material Setup Automatically normalizes face orientation vectors so that lighting is computed correctly after scaling
  63. Joy with 3D Graphics Using Ruby GL.Enable(GL : : LIGHTING)

    GL.Enable(GL : : LIGHT0) GL.Enable(GL : : NORMALIZE) ambient_light = [0.2, 0.2, 0.2, 1.0].pack('F*') diffuse_light = [1.0, 1.0, 1.0, 1.0].pack('F*') specular_light = [1.0, 1.0, 1.0, 1.0].pack('F*') GL.Lightfv(GL : : LIGHT0, GL : : AMBIENT, ambient_light) GL.Lightfv(GL : : LIGHT0, GL : : DIFFUSE, diffuse_light) GL.Lightfv(GL : : LIGHT0, GL : : SPECULAR, specular_light) GL.Enable(GL : : COLOR_MATERIAL) GL.ColorMaterial(GL : : FRONT, GL : : AMBIENT_AND_DIFFUSE) specular_material = [1.0, 1.0, 1.0, 1.0].pack('F*') shininess = 50.0 GL.Materialfv(GL : : FRONT, GL : : SPECULAR, specular_material) GL.Materialf(GL : : FRONT, GL : : SHININESS, shininess) 83 Lighting and Material Setup Set to three light sources
  64. Joy with 3D Graphics Using Ruby GL.Enable(GL : : LIGHTING)

    GL.Enable(GL : : LIGHT0) GL.Enable(GL : : NORMALIZE) ambient_light = [0.2, 0.2, 0.2, 1.0].pack('F*') diffuse_light = [1.0, 1.0, 1.0, 1.0].pack('F*') specular_light = [1.0, 1.0, 1.0, 1.0].pack('F*') GL.Lightfv(GL : : LIGHT0, GL : : AMBIENT, ambient_light) GL.Lightfv(GL : : LIGHT0, GL : : DIFFUSE, diffuse_light) GL.Lightfv(GL : : LIGHT0, GL : : SPECULAR, specular_light) GL.Enable(GL : : COLOR_MATERIAL) GL.ColorMaterial(GL : : FRONT, GL : : AMBIENT_AND_DIFFUSE) specular_material = [1.0, 1.0, 1.0, 1.0].pack('F*') shininess = 50.0 GL.Materialfv(GL : : FRONT, GL : : SPECULAR, specular_material) GL.Materialf(GL : : FRONT, GL : : SHININESS, shininess) 84 Lighting and Material Setup Uses the color speci fi ed by GL.Color3f as the object's ambient and diffuse re fl ectance coe ffi cient
  65. Joy with 3D Graphics Using Ruby GL.Enable(GL : : LIGHTING)

    GL.Enable(GL : : LIGHT0) GL.Enable(GL : : NORMALIZE) ambient_light = [0.2, 0.2, 0.2, 1.0].pack('F*') diffuse_light = [1.0, 1.0, 1.0, 1.0].pack('F*') specular_light = [1.0, 1.0, 1.0, 1.0].pack('F*') GL.Lightfv(GL : : LIGHT0, GL : : AMBIENT, ambient_light) GL.Lightfv(GL : : LIGHT0, GL : : DIFFUSE, diffuse_light) GL.Lightfv(GL : : LIGHT0, GL : : SPECULAR, specular_light) GL.Enable(GL : : COLOR_MATERIAL) GL.ColorMaterial(GL : : FRONT, GL : : AMBIENT_AND_DIFFUSE) specular_material = [1.0, 1.0, 1.0, 1.0].pack('F*') shininess = 50.0 GL.Materialfv(GL : : FRONT, GL : : SPECULAR, specular_material) GL.Materialf(GL : : FRONT, GL : : SHININESS, shininess) 85 Lighting and Material Setup Sets the object's specularity and glossiness
  66. Joy with 3D Graphics Using Ruby 86 Setting the Model-View

    Matrix GL.MatrixMode(GL : : MODELVIEW) GL.LoadIdentity() GL.Translatef(0.0, 0.0, -9.0) light_pos = [2.0, 3.0, 4.0, 1.0].pack('F*') GL.Lightfv(GL : : LIGHT0, GL : : POSITION, light_pos) GL.Rotatef(rotation_angle, 1.0, 1.0, 0.0) rotation_angle += 0.5
  67. Joy with 3D Graphics Using Ruby 87 Setting the Model-View

    Matrix GL.MatrixMode(GL : : MODELVIEW) GL.LoadIdentity() GL.Translatef(0.0, 0.0, -9.0) light_pos = [2.0, 3.0, 4.0, 1.0].pack('F*') GL.Lightfv(GL : : LIGHT0, GL : : POSITION, light_pos) GL.Rotatef(rotation_angle, 1.0, 1.0, 0.0) rotation_angle += 0.5 Set light source position after camera movement but before object rotation
  68. Joy with 3D Graphics Using Ruby 88 Set of normal

    vectors GL.Begin(GL : : QUADS) GL.Normal3f(0.0, 0.0, 1.0) GL.Color3f(1, 0, 0) GL.Vertex3f(-1, -1, 1) GL.Vertex3f( 1, -1, 1) GL.Vertex3f( 1, 1, 1) GL.Vertex3f(-1, 1, 1) # . . . GL.End()
  69. Joy with 3D Graphics Using Ruby 89 Set of normal

    vectors GL.Begin(GL : : QUADS) GL.Normal3f(0.0, 0.0, 1.0) GL.Color3f(1, 0, 0) GL.Vertex3f(-1, -1, 1) GL.Vertex3f( 1, -1, 1) GL.Vertex3f( 1, 1, 1) GL.Vertex3f(-1, 1, 1) # . . . GL.End() Specify a normal vector for each face to correctly calculate lighting
  70. Joy with 3D Graphics Using Ruby Conclusion 92 ✦Ruby and

    OpenGL make it easy to draw 3D graphics ✦It's also a great way to learn the basics of 3D graphics ✦The world of 3D graphics is a deep and exciting fi eld to explore ✦I hope this talk will be your fi rst step into this exciting world!