I
Ilmari Heikkinen
Here's something I've been hacking on for the past two months, an OpenGL
scenegraph engine written mostly in Ruby with some critical sections
inlined in C. It's been a educational experience
Librend is a simple scenegraph engine on top of OpenGL, SDL, Imlib2,
GLEW and Cairo that aims to make it quick and easy to write apps that
mix 2D, 3D and vector graphics.
I'm dubious about its suitability for public consumption at this stage
but I'll release it anyhow :I
Comments and questions welcome!
Homepage: http://librend.rubyforge.org/
Screenshots: http://librend.rubyforge.org/screenshots/
API docs: http://librend.rubyforge.org/rdoc/
Downloads: http://rubyforge.org/frs/?group_id=716
Librend implements a scenegraph 3D engine. The graph is a tree, and is
read from the root upwards.
You create Rend::Models and attach children to them. The models are then
drawn from root upwards, with the children using the properties of their
parents as the default.
Transforms cascade, so an object 4 levels down the tree has its base
position and rotation determined by applying all the positions and
rotations of its parents.
The scene root is given to the renderer, which draws the scenegraph to
the screen. There are no (well, shouldnÿt be) rendering API specific
parts in the scene graph, so itÿs quite API-independent. (Note: This is
not entirely true, there are some places which use API-specific
functions, e.g. the classes Sound and Shader and the current
unabstracted event model.)
Hereÿs an irb session showcasing setting up a scene and editing it on
the fly.
require 'rend'
# First, create the scene and some models.
scene = Rend::Model.new
ball = Rend::Sphere.new
cube = Rend::Cube.new
# Add the ball and the cube to the scene.
scene.attach ball, cube
# Set up the renderer and start running.
renderer = Rend::Renderer.new
renderer.scene = scene
# Let's move the ball up...
ball.position = [0, 2, 0]
# ...and tweak the camera a bit.
renderer.camera.fov = 60
renderer.camera.looking_at[1] = 1
renderer.camera.position[2] += 2
# Wouldn't it be nice if the cube rotated?
# Let's add a time handler to do just that.
cube.add_time_handler{|o,t| o.rotation = [(t*100)%360, 1, 0, 1]}
# Some light would be nice aswell.
scene.lights = [Rend::Light.newposition => [2, 5, 3])]
# The camera should orbit our scene, right?
renderer.camera.add_time_handler{|o,t|
o.position = [4.0*Math.sin(t/2), 2.0, 4.0*Math.cos(t/2)]
}
# The cube rotation makes the orbiting look all weird,
# let's take it out.
cube.time_handlers.clear
# The ball looks a bit crude, let's add some detail.
ball.geometry.radial_detail = 150
ball.geometry.axial_detail = 150
# And make it shiny red!
ball.material = Rend::Material.new
ball.material.diffuse = [1, 0, 0, 1] # red diffuse
ball.material.specular = [1, 1, 1, 1] # white specular
ball.material.shininess = 150
renderer.thread.kill # Oops, there goes our eventloop
renderer.run # but we can restart it
renderer.thread.join # and wait until someone exits the program
scenegraph engine written mostly in Ruby with some critical sections
inlined in C. It's been a educational experience
Librend is a simple scenegraph engine on top of OpenGL, SDL, Imlib2,
GLEW and Cairo that aims to make it quick and easy to write apps that
mix 2D, 3D and vector graphics.
I'm dubious about its suitability for public consumption at this stage
but I'll release it anyhow :I
Comments and questions welcome!
Homepage: http://librend.rubyforge.org/
Screenshots: http://librend.rubyforge.org/screenshots/
API docs: http://librend.rubyforge.org/rdoc/
Downloads: http://rubyforge.org/frs/?group_id=716
From the Rend module docs:
Librend implements a scenegraph 3D engine. The graph is a tree, and is
read from the root upwards.
You create Rend::Models and attach children to them. The models are then
drawn from root upwards, with the children using the properties of their
parents as the default.
Transforms cascade, so an object 4 levels down the tree has its base
position and rotation determined by applying all the positions and
rotations of its parents.
The scene root is given to the renderer, which draws the scenegraph to
the screen. There are no (well, shouldnÿt be) rendering API specific
parts in the scene graph, so itÿs quite API-independent. (Note: This is
not entirely true, there are some places which use API-specific
functions, e.g. the classes Sound and Shader and the current
unabstracted event model.)
Hereÿs an irb session showcasing setting up a scene and editing it on
the fly.
require 'rend'
# First, create the scene and some models.
scene = Rend::Model.new
ball = Rend::Sphere.new
cube = Rend::Cube.new
# Add the ball and the cube to the scene.
scene.attach ball, cube
# Set up the renderer and start running.
renderer = Rend::Renderer.new
renderer.scene = scene
# Let's move the ball up...
ball.position = [0, 2, 0]
# ...and tweak the camera a bit.
renderer.camera.fov = 60
renderer.camera.looking_at[1] = 1
renderer.camera.position[2] += 2
# Wouldn't it be nice if the cube rotated?
# Let's add a time handler to do just that.
cube.add_time_handler{|o,t| o.rotation = [(t*100)%360, 1, 0, 1]}
# Some light would be nice aswell.
scene.lights = [Rend::Light.newposition => [2, 5, 3])]
# The camera should orbit our scene, right?
renderer.camera.add_time_handler{|o,t|
o.position = [4.0*Math.sin(t/2), 2.0, 4.0*Math.cos(t/2)]
}
# The cube rotation makes the orbiting look all weird,
# let's take it out.
cube.time_handlers.clear
# The ball looks a bit crude, let's add some detail.
ball.geometry.radial_detail = 150
ball.geometry.axial_detail = 150
# And make it shiny red!
ball.material = Rend::Material.new
ball.material.diffuse = [1, 0, 0, 1] # red diffuse
ball.material.specular = [1, 1, 1, 1] # white specular
ball.material.shininess = 150
renderer.thread.kill # Oops, there goes our eventloop
renderer.run # but we can restart it
renderer.thread.join # and wait until someone exits the program