Class: Graphics
- Defined in:
- ext/ruby/qtruby/examples/ruboids/ruboids/Graphics.rb
Constant Summary collapse
- DEFAULT_SPHERE_ITERATIONS =
3
- XPLUS =
X
Point.new(1, 0, 0)
- XMINUS =
-X
Point.new(-1, 0, 0)
- YPLUS =
Y
Point.new(0, 1, 0)
- YMINUS =
-Y
Point.new(0, -1, 0)
- ZPLUS =
Z
Point.new(0, 0, 1)
- ZMINUS =
-Z
Point.new(0, 0, -1)
- OCTAHEDRON =
defined w/counter-clockwise triangles
[ Triangle.new(YPLUS, ZPLUS, XPLUS), Triangle.new(XMINUS, ZPLUS, YPLUS), Triangle.new(YMINUS, ZPLUS, XMINUS), Triangle.new(XPLUS, ZPLUS, YMINUS), Triangle.new(ZMINUS, YPLUS, XPLUS), Triangle.new(ZMINUS, XMINUS , YPLUS), Triangle.new(ZMINUS, YMINUS , XMINUS), Triangle.new(ZMINUS, XPLUS, YMINUS) ]
- SQUARE =
Defines counter-clockwise points used in OpenGL TRIANGLE_STRIP to create a circle on the X/Z plane. Don’t include center point here; It is added when outputting the circle.
[ XPLUS, ZMINUS, XMINUS, ZPLUS, XPLUS ]
- @@spheres =
Hash.new()
- @@circles =
Hash.new()
Class Method Summary collapse
-
.boxFromCorners(p0, p1) ⇒ Object
Build box from corners.
-
.buildCircle(iterations, circle) ⇒ Object
Different than buildSphere because we are creating triangles to be used in an OpenGL TRIANGLE_FAN operation.
-
.buildSphere(iterations, sphere) ⇒ Object
Subdivide each triangle in the oldObj approximation and normalize the new points thus generated to lie on the surface of the unit sphere.
-
.circle(iterations = DEFAULT_SPHERE_ITERATIONS, counterClockwise = true) ⇒ Object
Creates a circle in the X/Z plane.
- .degreesToRadians(deg) ⇒ Object
- .radiansToDegrees(rad) ⇒ Object
-
.rotations(v) ⇒ Object
Given a vector, return a point containing x, y, z rotation angles.
-
.sphere(iterations = DEFAULT_SPHERE_ITERATIONS, counterClockwise = true) ⇒ Object
sphere() (and buildSphere()) - generate a triangle mesh approximating a sphere by recursive subdivision.
Class Method Details
.boxFromCorners(p0, p1) ⇒ Object
Build box from corners. All faces are counter-clockwise.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'ext/ruby/qtruby/examples/ruboids/ruboids/Graphics.rb', line 73 def Graphics.boxFromCorners(p0, p1) pa = p0.dup() pb = p1.dup() # Make sure all coords of pa are < all coords of pb if pa.x > pb.x tmp = pa.x; pa.x = pb.x; pb.x = tmp end if pa.y > pb.y tmp = pa.y; pa.y = pb.y; pb.y = tmp end if pa.z > pb.z tmp = pa.z; pa.z = pb.z; pb.z = tmp end Begin(QUAD_STRIP) # top Vertex(pb.x, pb.y, pa.z) Vertex(pa.x, pb.y, pa.z) # top/front Vertex(pb.x, pb.y, pb.z) Vertex(pa.x, pb.y, pb.z) # front/bottom Vertex(pb.x, pa.y, pb.z) Vertex(pa.x, pa.y, pb.z) # bottom/back Vertex(pb.x, pa.y, pa.z) Vertex(pa.x, pa.y, pa.z) # back/top Vertex(pb.x, pb.y, pa.z) Vertex(pa.x, pb.y, pa.z) End() Begin(QUADS) # left Vertex(pa.x, pa.y, pb.z) Vertex(pa.x, pa.y, pa.z) Vertex(pa.x, pb.y, pa.z) Vertex(pa.x, pb.y, pb.z) # right Vertex(pb.x, pa.y, pb.z) Vertex(pb.x, pa.y, pa.z) Vertex(pb.x, pb.y, pa.z) Vertex(pb.x, pb.y, pb.z) End() end |
.buildCircle(iterations, circle) ⇒ Object
Different than buildSphere because we are creating triangles to be used in an OpenGL TRIANGLE_FAN operation. Thus the first point (the center) is always inviolate. We create new points between the remaining points.
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'ext/ruby/qtruby/examples/ruboids/ruboids/Graphics.rb', line 246 def Graphics.buildCircle(iterations, circle) oldObj = circle # Subdivide each starting line segment (maxlevel - 1) times iterations -= 1 iterations.times { # Create a new object. Allocate 2 * the number of points in the # the current approximation. Subtract one because the last point # (same as the first point) is simply copied. newObj = Array.new(oldObj.length * 2 - 1) prevP = nil j = 0 oldObj.each { | p | if !prevP.nil? newObj[j] = prevP j += 1 # New midpoint a = Point.midpoint(prevP, p) a.normalize!() newObj[j] = a j += 1 end prevP = p } newObj[j] = prevP # Copy last point # Continue subdividing new triangles oldObj = newObj } return oldObj end |
.buildSphere(iterations, sphere) ⇒ Object
Subdivide each triangle in the oldObj approximation and normalize
the new points thus generated to lie on the surface of the unit
sphere.
Each input triangle with vertices labelled [0,1,2] as shown
below will be turned into four new triangles:
Make new points
a = (0+2)/2
b = (0+1)/2
c = (1+2)/2
1
/\ Normalize a, b, c
/ \
b/____\ c Construct new counter-clockwise triangles
/\ /\ [a,b,0]
/ \ / \ [c,1,b]
/____\/____\ [c,b,a]
0 a 2 [2,c,a]
The normalize step (which makes each point a, b, c unit distance from the origin) is where we can modify the sphere’s shape.
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'ext/ruby/qtruby/examples/ruboids/ruboids/Graphics.rb', line 185 def Graphics.buildSphere(iterations, sphere) oldObj = sphere # Subdivide each starting triangle (maxlevel - 1) times iterations -= 1 iterations.times { # Create a new object. Allocate 4 * the number of points in the # the current approximation. newObj = Array.new(oldObj.length * 4) j = 0 oldObj.each { | oldt | # New midpoints a = Point.midpoint(oldt.points[0], oldt.points[2]) a.normalize!() b = Point.midpoint(oldt.points[0], oldt.points[1]) b.normalize!() c = Point.midpoint(oldt.points[1], oldt.points[2]) c.normalize!() # New triangeles. Their vertices are counter-clockwise. newObj[j] = Triangle.new(a, b, oldt.points[0]) j += 1 newObj[j] = Triangle.new(c, oldt.points[1], b) j += 1 newObj[j] = Triangle.new(c, b, a) j += 1 newObj[j] = Triangle.new(oldt.points[2], c, a) j += 1 } # Continue subdividing new triangles oldObj = newObj } return oldObj end |
.circle(iterations = DEFAULT_SPHERE_ITERATIONS, counterClockwise = true) ⇒ Object
Creates a circle in the X/Z plane. To have the circle’s normal point down (-Y), specify clockwise instead of counter-clockwise. To create the circle in another plane, call OpenGL’s Rotate() method before calling this.
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'ext/ruby/qtruby/examples/ruboids/ruboids/Graphics.rb', line 225 def Graphics.circle(iterations = DEFAULT_SPHERE_ITERATIONS, counterClockwise = true) if @@circles[iterations].nil? @@circles[iterations] = buildCircle(iterations, SQUARE) end circle = @@circles[iterations] Begin(TRIANGLE_FAN) Vertex(0, 0, 0) if counterClockwise circle.each { | p | Vertex(p.x, 0, p.z) } else circle.reverse.each { | p | Vertex(p.x, 0, p.z) } end End() end |
.degreesToRadians(deg) ⇒ Object
46 47 48 |
# File 'ext/ruby/qtruby/examples/ruboids/ruboids/Graphics.rb', line 46 def Graphics.degreesToRadians(deg) return deg * Math::PI / 180.0 end |
.radiansToDegrees(rad) ⇒ Object
42 43 44 |
# File 'ext/ruby/qtruby/examples/ruboids/ruboids/Graphics.rb', line 42 def Graphics.radiansToDegrees(rad) return rad * 180.0 / Math::PI end |
.rotations(v) ⇒ Object
Given a vector, return a point containing x, y, z rotation angles.
atan2(x, y) = the angle formed with the x axis by the ray from the origin to the point x,y
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'ext/ruby/qtruby/examples/ruboids/ruboids/Graphics.rb', line 54 def Graphics.rotations(v) return Point::ORIGIN.dup() if v.nil? return v if v == Point::ORIGIN x = Math.atan2(v.y, v.z) y = Math.atan2(v.z, v.x) z = Math.atan2(v.y, v.x) rot = Point.new(z, x, y) rot.add(Math::PI).multiplyBy(180.0).divideBy(Math::PI) rot.x = rot.x.to_i rot.y = rot.y.to_i rot.z = rot.z.to_i return rot end |
.sphere(iterations = DEFAULT_SPHERE_ITERATIONS, counterClockwise = true) ⇒ Object
sphere() (and buildSphere()) - generate a triangle mesh approximating a sphere by recursive subdivision. First approximation is an octahedron; each level of refinement increases the number of triangles by a factor of 4.
Level 3 (128 triangles) is a good tradeoff if gouraud shading is used to render the database.
Usage: sphere [level] [counterClockwise]
The value level is an integer >= 1 setting the recursion level (default = DEFAULT_SPHERE_ITERATIONS). The boolean counterClockwise causes triangles to be generated with vertices in counterclockwise order as viewed from the outside in a RHS coordinate system. The default is counter-clockwise.
Ruby version by Jim Menard ([email protected]), May 2001.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'ext/ruby/qtruby/examples/ruboids/ruboids/Graphics.rb', line 144 def Graphics.sphere(iterations = DEFAULT_SPHERE_ITERATIONS, counterClockwise = true) if @@spheres[iterations].nil? @@spheres[iterations] = buildSphere(iterations, OCTAHEDRON) end sphere = @@spheres[iterations] Begin(TRIANGLES) sphere.each { | triangle | triangle.points.each { | p | Vertex(p.x, p.y, p.z) if counterClockwise Vertex(p.z, p.y, p.x) if !counterClockwise } } End() end |