3rb 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +2 -0
  3. data/3rb.gemspec +29 -0
  4. data/CHANGELOG.md +12 -0
  5. data/LICENSE +21 -0
  6. data/README.md +321 -0
  7. data/Rakefile +13 -0
  8. data/examples/01_hello_cube.rb +29 -0
  9. data/examples/02_basic_geometries.rb +56 -0
  10. data/examples/03_materials.rb +61 -0
  11. data/examples/04_lighting.rb +63 -0
  12. data/examples/05_animation.rb +79 -0
  13. data/examples/06_custom_shader.rb +92 -0
  14. data/examples/07_scene_graph.rb +74 -0
  15. data/examples/08_orbit_controls.rb +50 -0
  16. data/examples/09_3d_chart.rb +71 -0
  17. data/examples/10_procedural_terrain.rb +140 -0
  18. data/examples/11_particle_system.rb +68 -0
  19. data/examples/12_model_loader.rb +73 -0
  20. data/examples/13_game_prototype.rb +145 -0
  21. data/examples/14_utah_teapot.rb +291 -0
  22. data/examples/15_stanford_bunny.rb +200 -0
  23. data/examples/16_cornell_box.rb +373 -0
  24. data/examples/17_weird_fractal4.rb +130 -0
  25. data/examples/18_platonic_solids.rb +268 -0
  26. data/lib/3rb/animation/animation_clip.rb +287 -0
  27. data/lib/3rb/animation/animation_mixer.rb +366 -0
  28. data/lib/3rb/cameras/camera.rb +50 -0
  29. data/lib/3rb/cameras/orthographic_camera.rb +92 -0
  30. data/lib/3rb/cameras/perspective_camera.rb +103 -0
  31. data/lib/3rb/controls/orbit_controls.rb +341 -0
  32. data/lib/3rb/core/buffer_attribute.rb +172 -0
  33. data/lib/3rb/core/group.rb +9 -0
  34. data/lib/3rb/core/object3d.rb +298 -0
  35. data/lib/3rb/core/scene.rb +78 -0
  36. data/lib/3rb/dsl/helpers.rb +57 -0
  37. data/lib/3rb/dsl/scene_builder.rb +288 -0
  38. data/lib/3rb/ffi/glfw.rb +61 -0
  39. data/lib/3rb/ffi/opengl.rb +137 -0
  40. data/lib/3rb/ffi/platform.rb +65 -0
  41. data/lib/3rb/geometries/box_geometry.rb +101 -0
  42. data/lib/3rb/geometries/buffer_geometry.rb +345 -0
  43. data/lib/3rb/geometries/cone_geometry.rb +29 -0
  44. data/lib/3rb/geometries/cylinder_geometry.rb +149 -0
  45. data/lib/3rb/geometries/plane_geometry.rb +75 -0
  46. data/lib/3rb/geometries/sphere_geometry.rb +93 -0
  47. data/lib/3rb/geometries/torus_geometry.rb +77 -0
  48. data/lib/3rb/lights/ambient_light.rb +9 -0
  49. data/lib/3rb/lights/directional_light.rb +57 -0
  50. data/lib/3rb/lights/hemisphere_light.rb +26 -0
  51. data/lib/3rb/lights/light.rb +27 -0
  52. data/lib/3rb/lights/point_light.rb +68 -0
  53. data/lib/3rb/lights/rect_area_light.rb +35 -0
  54. data/lib/3rb/lights/spot_light.rb +88 -0
  55. data/lib/3rb/loaders/gltf_loader.rb +304 -0
  56. data/lib/3rb/loaders/loader.rb +94 -0
  57. data/lib/3rb/loaders/obj_loader.rb +186 -0
  58. data/lib/3rb/loaders/texture_loader.rb +55 -0
  59. data/lib/3rb/materials/basic_material.rb +70 -0
  60. data/lib/3rb/materials/lambert_material.rb +102 -0
  61. data/lib/3rb/materials/material.rb +114 -0
  62. data/lib/3rb/materials/phong_material.rb +106 -0
  63. data/lib/3rb/materials/shader_material.rb +104 -0
  64. data/lib/3rb/materials/standard_material.rb +106 -0
  65. data/lib/3rb/math/color.rb +246 -0
  66. data/lib/3rb/math/euler.rb +156 -0
  67. data/lib/3rb/math/math_utils.rb +132 -0
  68. data/lib/3rb/math/matrix3.rb +269 -0
  69. data/lib/3rb/math/matrix4.rb +501 -0
  70. data/lib/3rb/math/quaternion.rb +337 -0
  71. data/lib/3rb/math/vector2.rb +216 -0
  72. data/lib/3rb/math/vector3.rb +366 -0
  73. data/lib/3rb/math/vector4.rb +233 -0
  74. data/lib/3rb/native/gl.rb +382 -0
  75. data/lib/3rb/native/native.rb +55 -0
  76. data/lib/3rb/native/window.rb +111 -0
  77. data/lib/3rb/native.rb +9 -0
  78. data/lib/3rb/objects/line.rb +116 -0
  79. data/lib/3rb/objects/mesh.rb +40 -0
  80. data/lib/3rb/objects/points.rb +71 -0
  81. data/lib/3rb/renderers/opengl_renderer.rb +567 -0
  82. data/lib/3rb/renderers/renderer.rb +60 -0
  83. data/lib/3rb/renderers/shader_lib.rb +100 -0
  84. data/lib/3rb/textures/cube_texture.rb +26 -0
  85. data/lib/3rb/textures/data_texture.rb +35 -0
  86. data/lib/3rb/textures/render_target.rb +125 -0
  87. data/lib/3rb/textures/texture.rb +190 -0
  88. data/lib/3rb/version.rb +5 -0
  89. data/lib/3rb.rb +86 -0
  90. data/shaders/basic.frag +19 -0
  91. data/shaders/basic.vert +15 -0
  92. data/shaders/common/lights.glsl +53 -0
  93. data/shaders/common/uniforms.glsl +9 -0
  94. data/shaders/lambert.frag +37 -0
  95. data/shaders/lambert.vert +22 -0
  96. data/shaders/phong.frag +51 -0
  97. data/shaders/phong.vert +28 -0
  98. data/shaders/standard.frag +92 -0
  99. data/shaders/standard.vert +28 -0
  100. metadata +155 -0
@@ -0,0 +1,291 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Utah Teapot
5
+ # Created by Martin Newell at the University of Utah in 1975.
6
+ # Public domain icon in computer graphics.
7
+
8
+ require_relative "../lib/3rb"
9
+
10
+ class UtahTeapot
11
+ PATCHES = [
12
+ # Rim (top of body)
13
+ [[1.4, 2.25, 0.0], [1.3375, 2.38125, 0.0], [1.4375, 2.38125, 0.0], [1.5, 2.25, 0.0],
14
+ [1.4, 2.25, 0.784], [1.3375, 2.38125, 0.749], [1.4375, 2.38125, 0.805], [1.5, 2.25, 0.84],
15
+ [0.784, 2.25, 1.4], [0.749, 2.38125, 1.3375], [0.805, 2.38125, 1.4375], [0.84, 2.25, 1.5],
16
+ [0.0, 2.25, 1.4], [0.0, 2.38125, 1.3375], [0.0, 2.38125, 1.4375], [0.0, 2.25, 1.5]],
17
+ [[0.0, 2.25, 1.4], [0.0, 2.38125, 1.3375], [0.0, 2.38125, 1.4375], [0.0, 2.25, 1.5],
18
+ [-0.784, 2.25, 1.4], [-0.749, 2.38125, 1.3375], [-0.805, 2.38125, 1.4375], [-0.84, 2.25, 1.5],
19
+ [-1.4, 2.25, 0.784], [-1.3375, 2.38125, 0.749], [-1.4375, 2.38125, 0.805], [-1.5, 2.25, 0.84],
20
+ [-1.4, 2.25, 0.0], [-1.3375, 2.38125, 0.0], [-1.4375, 2.38125, 0.0], [-1.5, 2.25, 0.0]],
21
+ [[-1.4, 2.25, 0.0], [-1.3375, 2.38125, 0.0], [-1.4375, 2.38125, 0.0], [-1.5, 2.25, 0.0],
22
+ [-1.4, 2.25, -0.784], [-1.3375, 2.38125, -0.749], [-1.4375, 2.38125, -0.805], [-1.5, 2.25, -0.84],
23
+ [-0.784, 2.25, -1.4], [-0.749, 2.38125, -1.3375], [-0.805, 2.38125, -1.4375], [-0.84, 2.25, -1.5],
24
+ [0.0, 2.25, -1.4], [0.0, 2.38125, -1.3375], [0.0, 2.38125, -1.4375], [0.0, 2.25, -1.5]],
25
+ [[0.0, 2.25, -1.4], [0.0, 2.38125, -1.3375], [0.0, 2.38125, -1.4375], [0.0, 2.25, -1.5],
26
+ [0.784, 2.25, -1.4], [0.749, 2.38125, -1.3375], [0.805, 2.38125, -1.4375], [0.84, 2.25, -1.5],
27
+ [1.4, 2.25, -0.784], [1.3375, 2.38125, -0.749], [1.4375, 2.38125, -0.805], [1.5, 2.25, -0.84],
28
+ [1.4, 2.25, 0.0], [1.3375, 2.38125, 0.0], [1.4375, 2.38125, 0.0], [1.5, 2.25, 0.0]],
29
+ # Body upper
30
+ [[1.5, 2.25, 0.0], [1.75, 1.725, 0.0], [2.0, 1.2, 0.0], [2.0, 0.75, 0.0],
31
+ [1.5, 2.25, 0.84], [1.75, 1.725, 0.98], [2.0, 1.2, 1.12], [2.0, 0.75, 1.12],
32
+ [0.84, 2.25, 1.5], [0.98, 1.725, 1.75], [1.12, 1.2, 2.0], [1.12, 0.75, 2.0],
33
+ [0.0, 2.25, 1.5], [0.0, 1.725, 1.75], [0.0, 1.2, 2.0], [0.0, 0.75, 2.0]],
34
+ [[0.0, 2.25, 1.5], [0.0, 1.725, 1.75], [0.0, 1.2, 2.0], [0.0, 0.75, 2.0],
35
+ [-0.84, 2.25, 1.5], [-0.98, 1.725, 1.75], [-1.12, 1.2, 2.0], [-1.12, 0.75, 2.0],
36
+ [-1.5, 2.25, 0.84], [-1.75, 1.725, 0.98], [-2.0, 1.2, 1.12], [-2.0, 0.75, 1.12],
37
+ [-1.5, 2.25, 0.0], [-1.75, 1.725, 0.0], [-2.0, 1.2, 0.0], [-2.0, 0.75, 0.0]],
38
+ [[-1.5, 2.25, 0.0], [-1.75, 1.725, 0.0], [-2.0, 1.2, 0.0], [-2.0, 0.75, 0.0],
39
+ [-1.5, 2.25, -0.84], [-1.75, 1.725, -0.98], [-2.0, 1.2, -1.12], [-2.0, 0.75, -1.12],
40
+ [-0.84, 2.25, -1.5], [-0.98, 1.725, -1.75], [-1.12, 1.2, -2.0], [-1.12, 0.75, -2.0],
41
+ [0.0, 2.25, -1.5], [0.0, 1.725, -1.75], [0.0, 1.2, -2.0], [0.0, 0.75, -2.0]],
42
+ [[0.0, 2.25, -1.5], [0.0, 1.725, -1.75], [0.0, 1.2, -2.0], [0.0, 0.75, -2.0],
43
+ [0.84, 2.25, -1.5], [0.98, 1.725, -1.75], [1.12, 1.2, -2.0], [1.12, 0.75, -2.0],
44
+ [1.5, 2.25, -0.84], [1.75, 1.725, -0.98], [2.0, 1.2, -1.12], [2.0, 0.75, -1.12],
45
+ [1.5, 2.25, 0.0], [1.75, 1.725, 0.0], [2.0, 1.2, 0.0], [2.0, 0.75, 0.0]],
46
+ # Body lower
47
+ [[2.0, 0.75, 0.0], [2.0, 0.3, 0.0], [1.5, 0.075, 0.0], [1.5, 0.0, 0.0],
48
+ [2.0, 0.75, 1.12], [2.0, 0.3, 1.12], [1.5, 0.075, 0.84], [1.5, 0.0, 0.84],
49
+ [1.12, 0.75, 2.0], [1.12, 0.3, 2.0], [0.84, 0.075, 1.5], [0.84, 0.0, 1.5],
50
+ [0.0, 0.75, 2.0], [0.0, 0.3, 2.0], [0.0, 0.075, 1.5], [0.0, 0.0, 1.5]],
51
+ [[0.0, 0.75, 2.0], [0.0, 0.3, 2.0], [0.0, 0.075, 1.5], [0.0, 0.0, 1.5],
52
+ [-1.12, 0.75, 2.0], [-1.12, 0.3, 2.0], [-0.84, 0.075, 1.5], [-0.84, 0.0, 1.5],
53
+ [-2.0, 0.75, 1.12], [-2.0, 0.3, 1.12], [-1.5, 0.075, 0.84], [-1.5, 0.0, 0.84],
54
+ [-2.0, 0.75, 0.0], [-2.0, 0.3, 0.0], [-1.5, 0.075, 0.0], [-1.5, 0.0, 0.0]],
55
+ [[-2.0, 0.75, 0.0], [-2.0, 0.3, 0.0], [-1.5, 0.075, 0.0], [-1.5, 0.0, 0.0],
56
+ [-2.0, 0.75, -1.12], [-2.0, 0.3, -1.12], [-1.5, 0.075, -0.84], [-1.5, 0.0, -0.84],
57
+ [-1.12, 0.75, -2.0], [-1.12, 0.3, -2.0], [-0.84, 0.075, -1.5], [-0.84, 0.0, -1.5],
58
+ [0.0, 0.75, -2.0], [0.0, 0.3, -2.0], [0.0, 0.075, -1.5], [0.0, 0.0, -1.5]],
59
+ [[0.0, 0.75, -2.0], [0.0, 0.3, -2.0], [0.0, 0.075, -1.5], [0.0, 0.0, -1.5],
60
+ [1.12, 0.75, -2.0], [1.12, 0.3, -2.0], [0.84, 0.075, -1.5], [0.84, 0.0, -1.5],
61
+ [2.0, 0.75, -1.12], [2.0, 0.3, -1.12], [1.5, 0.075, -0.84], [1.5, 0.0, -0.84],
62
+ [2.0, 0.75, 0.0], [2.0, 0.3, 0.0], [1.5, 0.075, 0.0], [1.5, 0.0, 0.0]],
63
+ # Handle
64
+ [[-1.6, 1.875, 0.0], [-2.3, 1.875, 0.0], [-2.7, 1.875, 0.0], [-2.7, 1.65, 0.0],
65
+ [-1.6, 1.875, 0.3], [-2.3, 1.875, 0.3], [-2.7, 1.875, 0.3], [-2.7, 1.65, 0.3],
66
+ [-1.5, 2.1, 0.3], [-2.5, 2.1, 0.3], [-3.0, 2.1, 0.3], [-3.0, 1.65, 0.3],
67
+ [-1.5, 2.1, 0.0], [-2.5, 2.1, 0.0], [-3.0, 2.1, 0.0], [-3.0, 1.65, 0.0]],
68
+ [[-1.5, 2.1, 0.0], [-2.5, 2.1, 0.0], [-3.0, 2.1, 0.0], [-3.0, 1.65, 0.0],
69
+ [-1.5, 2.1, -0.3], [-2.5, 2.1, -0.3], [-3.0, 2.1, -0.3], [-3.0, 1.65, -0.3],
70
+ [-1.6, 1.875, -0.3], [-2.3, 1.875, -0.3], [-2.7, 1.875, -0.3], [-2.7, 1.65, -0.3],
71
+ [-1.6, 1.875, 0.0], [-2.3, 1.875, 0.0], [-2.7, 1.875, 0.0], [-2.7, 1.65, 0.0]],
72
+ [[-2.7, 1.65, 0.0], [-2.7, 1.425, 0.0], [-2.5, 0.975, 0.0], [-2.0, 0.75, 0.0],
73
+ [-2.7, 1.65, 0.3], [-2.7, 1.425, 0.3], [-2.5, 0.975, 0.3], [-2.0, 0.75, 0.3],
74
+ [-3.0, 1.65, 0.3], [-3.0, 1.2, 0.3], [-2.65, 0.7875, 0.3], [-1.9, 0.45, 0.3],
75
+ [-3.0, 1.65, 0.0], [-3.0, 1.2, 0.0], [-2.65, 0.7875, 0.0], [-1.9, 0.45, 0.0]],
76
+ [[-3.0, 1.65, 0.0], [-3.0, 1.2, 0.0], [-2.65, 0.7875, 0.0], [-1.9, 0.45, 0.0],
77
+ [-3.0, 1.65, -0.3], [-3.0, 1.2, -0.3], [-2.65, 0.7875, -0.3], [-1.9, 0.45, -0.3],
78
+ [-2.7, 1.65, -0.3], [-2.7, 1.425, -0.3], [-2.5, 0.975, -0.3], [-2.0, 0.75, -0.3],
79
+ [-2.7, 1.65, 0.0], [-2.7, 1.425, 0.0], [-2.5, 0.975, 0.0], [-2.0, 0.75, 0.0]],
80
+ # Spout
81
+ [[1.7, 1.275, 0.0], [2.6, 1.275, 0.0], [2.3, 1.95, 0.0], [2.7, 2.25, 0.0],
82
+ [1.7, 1.275, 0.66], [2.6, 1.275, 0.66], [2.3, 1.95, 0.25], [2.7, 2.25, 0.25],
83
+ [1.7, 0.45, 0.66], [3.1, 0.675, 0.66], [2.4, 1.875, 0.25], [3.3, 2.25, 0.25],
84
+ [1.7, 0.45, 0.0], [3.1, 0.675, 0.0], [2.4, 1.875, 0.0], [3.3, 2.25, 0.0]],
85
+ [[1.7, 0.45, 0.0], [3.1, 0.675, 0.0], [2.4, 1.875, 0.0], [3.3, 2.25, 0.0],
86
+ [1.7, 0.45, -0.66], [3.1, 0.675, -0.66], [2.4, 1.875, -0.25], [3.3, 2.25, -0.25],
87
+ [1.7, 1.275, -0.66], [2.6, 1.275, -0.66], [2.3, 1.95, -0.25], [2.7, 2.25, -0.25],
88
+ [1.7, 1.275, 0.0], [2.6, 1.275, 0.0], [2.3, 1.95, 0.0], [2.7, 2.25, 0.0]],
89
+ [[2.7, 2.25, 0.0], [2.8, 2.325, 0.0], [2.9, 2.325, 0.0], [2.8, 2.25, 0.0],
90
+ [2.7, 2.25, 0.25], [2.8, 2.325, 0.25], [2.9, 2.325, 0.15], [2.8, 2.25, 0.15],
91
+ [3.3, 2.25, 0.25], [3.525, 2.34375, 0.25], [3.45, 2.3625, 0.15], [3.2, 2.25, 0.15],
92
+ [3.3, 2.25, 0.0], [3.525, 2.34375, 0.0], [3.45, 2.3625, 0.0], [3.2, 2.25, 0.0]],
93
+ [[3.3, 2.25, 0.0], [3.525, 2.34375, 0.0], [3.45, 2.3625, 0.0], [3.2, 2.25, 0.0],
94
+ [3.3, 2.25, -0.25], [3.525, 2.34375, -0.25], [3.45, 2.3625, -0.15], [3.2, 2.25, -0.15],
95
+ [2.7, 2.25, -0.25], [2.8, 2.325, -0.25], [2.9, 2.325, -0.15], [2.8, 2.25, -0.15],
96
+ [2.7, 2.25, 0.0], [2.8, 2.325, 0.0], [2.9, 2.325, 0.0], [2.8, 2.25, 0.0]],
97
+ # Lid knob
98
+ [[0.0, 3.0, 0.0], [0.8, 3.0, 0.0], [0.0, 2.7, 0.0], [0.2, 2.55, 0.0],
99
+ [0.0, 3.0, 0.0], [0.8, 3.0, 0.45], [0.0, 2.7, 0.0], [0.2, 2.55, 0.112],
100
+ [0.0, 3.0, 0.0], [0.45, 3.0, 0.8], [0.0, 2.7, 0.0], [0.112, 2.55, 0.2],
101
+ [0.0, 3.0, 0.0], [0.0, 3.0, 0.8], [0.0, 2.7, 0.0], [0.0, 2.55, 0.2]],
102
+ [[0.0, 3.0, 0.0], [0.0, 3.0, 0.8], [0.0, 2.7, 0.0], [0.0, 2.55, 0.2],
103
+ [0.0, 3.0, 0.0], [-0.45, 3.0, 0.8], [0.0, 2.7, 0.0], [-0.112, 2.55, 0.2],
104
+ [0.0, 3.0, 0.0], [-0.8, 3.0, 0.45], [0.0, 2.7, 0.0], [-0.2, 2.55, 0.112],
105
+ [0.0, 3.0, 0.0], [-0.8, 3.0, 0.0], [0.0, 2.7, 0.0], [-0.2, 2.55, 0.0]],
106
+ [[0.0, 3.0, 0.0], [-0.8, 3.0, 0.0], [0.0, 2.7, 0.0], [-0.2, 2.55, 0.0],
107
+ [0.0, 3.0, 0.0], [-0.8, 3.0, -0.45], [0.0, 2.7, 0.0], [-0.2, 2.55, -0.112],
108
+ [0.0, 3.0, 0.0], [-0.45, 3.0, -0.8], [0.0, 2.7, 0.0], [-0.112, 2.55, -0.2],
109
+ [0.0, 3.0, 0.0], [0.0, 3.0, -0.8], [0.0, 2.7, 0.0], [0.0, 2.55, -0.2]],
110
+ [[0.0, 3.0, 0.0], [0.0, 3.0, -0.8], [0.0, 2.7, 0.0], [0.0, 2.55, -0.2],
111
+ [0.0, 3.0, 0.0], [0.45, 3.0, -0.8], [0.0, 2.7, 0.0], [0.112, 2.55, -0.2],
112
+ [0.0, 3.0, 0.0], [0.8, 3.0, -0.45], [0.0, 2.7, 0.0], [0.2, 2.55, -0.112],
113
+ [0.0, 3.0, 0.0], [0.8, 3.0, 0.0], [0.0, 2.7, 0.0], [0.2, 2.55, 0.0]],
114
+ # Lid
115
+ [[0.2, 2.55, 0.0], [0.4, 2.4, 0.0], [1.3, 2.4, 0.0], [1.3, 2.25, 0.0],
116
+ [0.2, 2.55, 0.112], [0.4, 2.4, 0.224], [1.3, 2.4, 0.728], [1.3, 2.25, 0.728],
117
+ [0.112, 2.55, 0.2], [0.224, 2.4, 0.4], [0.728, 2.4, 1.3], [0.728, 2.25, 1.3],
118
+ [0.0, 2.55, 0.2], [0.0, 2.4, 0.4], [0.0, 2.4, 1.3], [0.0, 2.25, 1.3]],
119
+ [[0.0, 2.55, 0.2], [0.0, 2.4, 0.4], [0.0, 2.4, 1.3], [0.0, 2.25, 1.3],
120
+ [-0.112, 2.55, 0.2], [-0.224, 2.4, 0.4], [-0.728, 2.4, 1.3], [-0.728, 2.25, 1.3],
121
+ [-0.2, 2.55, 0.112], [-0.4, 2.4, 0.224], [-1.3, 2.4, 0.728], [-1.3, 2.25, 0.728],
122
+ [-0.2, 2.55, 0.0], [-0.4, 2.4, 0.0], [-1.3, 2.4, 0.0], [-1.3, 2.25, 0.0]],
123
+ [[-0.2, 2.55, 0.0], [-0.4, 2.4, 0.0], [-1.3, 2.4, 0.0], [-1.3, 2.25, 0.0],
124
+ [-0.2, 2.55, -0.112], [-0.4, 2.4, -0.224], [-1.3, 2.4, -0.728], [-1.3, 2.25, -0.728],
125
+ [-0.112, 2.55, -0.2], [-0.224, 2.4, -0.4], [-0.728, 2.4, -1.3], [-0.728, 2.25, -1.3],
126
+ [0.0, 2.55, -0.2], [0.0, 2.4, -0.4], [0.0, 2.4, -1.3], [0.0, 2.25, -1.3]],
127
+ [[0.0, 2.55, -0.2], [0.0, 2.4, -0.4], [0.0, 2.4, -1.3], [0.0, 2.25, -1.3],
128
+ [0.112, 2.55, -0.2], [0.224, 2.4, -0.4], [0.728, 2.4, -1.3], [0.728, 2.25, -1.3],
129
+ [0.2, 2.55, -0.112], [0.4, 2.4, -0.224], [1.3, 2.4, -0.728], [1.3, 2.25, -0.728],
130
+ [0.2, 2.55, 0.0], [0.4, 2.4, 0.0], [1.3, 2.4, 0.0], [1.3, 2.25, 0.0]]
131
+ ].freeze
132
+
133
+ def self.create(tessellation: 8, wireframe: false)
134
+ positions = []
135
+ normals = []
136
+ indices = []
137
+ vertex_count = 0
138
+
139
+ PATCHES.each do |patch|
140
+ tessellate_patch(patch, tessellation, positions, normals, indices, vertex_count)
141
+ vertex_count = positions.length / 3
142
+ end
143
+
144
+ geometry = Sunrb::BufferGeometry.new
145
+ geometry.set_attribute(:position, Sunrb::Float32BufferAttribute.new(positions, 3))
146
+ geometry.set_attribute(:normal, Sunrb::Float32BufferAttribute.new(normals, 3))
147
+ geometry.set_index(indices)
148
+
149
+ material = Sunrb::MeshStandardMaterial.new(
150
+ color: 0xc0c0c0,
151
+ metalness: 0.3,
152
+ roughness: 0.4,
153
+ wireframe: wireframe
154
+ )
155
+
156
+ mesh = Sunrb::Mesh.new(geometry, material)
157
+ mesh.name = "utah_teapot"
158
+ mesh.scale.set(0.5, 0.5, 0.5)
159
+ mesh.position.y = -0.75
160
+ mesh
161
+ end
162
+
163
+ def self.tessellate_patch(patch, divisions, positions, normals, indices, base_vertex)
164
+ points = []
165
+ normal_vectors = []
166
+
167
+ (0..divisions).each do |i|
168
+ u = i.to_f / divisions
169
+ (0..divisions).each do |j|
170
+ v = j.to_f / divisions
171
+ point = evaluate_bezier(patch, u, v)
172
+ normal = calculate_normal(patch, u, v)
173
+ points << point
174
+ normal_vectors << normal
175
+ end
176
+ end
177
+
178
+ points.each { |p| positions.push(p[0], p[1], p[2]) }
179
+ normal_vectors.each { |n| normals.push(n[0], n[1], n[2]) }
180
+
181
+ (0...divisions).each do |i|
182
+ (0...divisions).each do |j|
183
+ a = base_vertex + i * (divisions + 1) + j
184
+ b = a + 1
185
+ c = a + (divisions + 1)
186
+ d = c + 1
187
+
188
+ indices.push(a, c, b)
189
+ indices.push(b, c, d)
190
+ end
191
+ end
192
+ end
193
+
194
+ def self.evaluate_bezier(patch, u, v)
195
+ bu = bezier_basis(u)
196
+ bv = bezier_basis(v)
197
+
198
+ x = y = z = 0.0
199
+ 4.times do |i|
200
+ 4.times do |j|
201
+ idx = i * 4 + j
202
+ weight = bu[i] * bv[j]
203
+ x += patch[idx][0] * weight
204
+ y += patch[idx][1] * weight
205
+ z += patch[idx][2] * weight
206
+ end
207
+ end
208
+
209
+ [x, y, z]
210
+ end
211
+
212
+ def self.bezier_basis(t)
213
+ t2 = t * t
214
+ t3 = t2 * t
215
+ mt = 1.0 - t
216
+ mt2 = mt * mt
217
+ mt3 = mt2 * mt
218
+
219
+ [mt3, 3.0 * mt2 * t, 3.0 * mt * t2, t3]
220
+ end
221
+
222
+ def self.calculate_normal(patch, u, v)
223
+ epsilon = 0.001
224
+ u0 = [u - epsilon, 0.0].max
225
+ u1 = [u + epsilon, 1.0].min
226
+ v0 = [v - epsilon, 0.0].max
227
+ v1 = [v + epsilon, 1.0].min
228
+
229
+ p0 = evaluate_bezier(patch, u0, v)
230
+ p1 = evaluate_bezier(patch, u1, v)
231
+ p2 = evaluate_bezier(patch, u, v0)
232
+ p3 = evaluate_bezier(patch, u, v1)
233
+
234
+ du = [p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]]
235
+ dv = [p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]]
236
+
237
+ nx = du[1] * dv[2] - du[2] * dv[1]
238
+ ny = du[2] * dv[0] - du[0] * dv[2]
239
+ nz = du[0] * dv[1] - du[1] * dv[0]
240
+
241
+ len = Math.sqrt(nx * nx + ny * ny + nz * nz)
242
+ return [0, 1, 0] if len < 0.0001
243
+
244
+ [nx / len, ny / len, nz / len]
245
+ end
246
+ end
247
+
248
+ scene = Sunrb::Scene.new
249
+ scene.background = Sunrb::Color.new(0x2c3e50)
250
+
251
+ camera = Sunrb::PerspectiveCamera.new(fov: 45, aspect: 800.0 / 600.0, near: 0.1, far: 1000)
252
+ camera.position.set(4, 3, 4)
253
+ camera.look_at(Sunrb::Vector3.new(0, 0, 0))
254
+
255
+ ambient = Sunrb::AmbientLight.new(color: 0x404040)
256
+ scene.add(ambient)
257
+
258
+ key_light = Sunrb::DirectionalLight.new(color: 0xffffff, intensity: 0.8)
259
+ key_light.position.set(5, 5, 5)
260
+ scene.add(key_light)
261
+
262
+ fill_light = Sunrb::DirectionalLight.new(color: 0x4488ff, intensity: 0.3)
263
+ fill_light.position.set(-5, 3, -5)
264
+ scene.add(fill_light)
265
+
266
+ teapot_solid = UtahTeapot.create(tessellation: 16, wireframe: false)
267
+ teapot_solid.position.set(-1.5, 0, 0)
268
+ scene.add(teapot_solid)
269
+
270
+ teapot_wire = UtahTeapot.create(tessellation: 8, wireframe: true)
271
+ teapot_wire.position.set(1.5, 0, 0)
272
+ scene.add(teapot_wire)
273
+
274
+ floor_geo = Sunrb::PlaneGeometry.new(width: 20, height: 20)
275
+ floor_mat = Sunrb::MeshStandardMaterial.new(color: 0x1a1a2e, roughness: 0.9)
276
+ floor = Sunrb::Mesh.new(floor_geo, floor_mat)
277
+ floor.rotation.x = -Math::PI / 2
278
+ floor.position.y = -1.5
279
+ scene.add(floor)
280
+
281
+ puts "=== Utah Teapot (Bezier Patches) ==="
282
+ puts "Left: Solid | Right: Wireframe"
283
+ puts "Press ESC to exit"
284
+
285
+ renderer = Sunrb::OpenGLRenderer.new(width: 800, height: 600, title: "Utah Teapot - Bezier Patches")
286
+
287
+ renderer.run do |delta|
288
+ teapot_solid.rotation.y += delta * 0.3
289
+ teapot_wire.rotation.y += delta * 0.3
290
+ renderer.render(scene, camera)
291
+ end
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Stanford Bunny - Neural Network SDF using SIREN
5
+ # Based on https://www.shadertoy.com/view/wtVyWK
6
+
7
+ require_relative "../lib/3rb"
8
+
9
+ VERTEX_SHADER = <<~GLSL
10
+ #version 330 core
11
+
12
+ layout(location = 0) in vec3 position;
13
+ layout(location = 2) in vec2 uv;
14
+
15
+ out vec2 vUv;
16
+
17
+ void main() {
18
+ vUv = uv;
19
+ gl_Position = vec4(position.xy * 2.0, 0.0, 1.0);
20
+ }
21
+ GLSL
22
+
23
+ FRAGMENT_SHADER = <<~GLSL
24
+ #version 330 core
25
+
26
+ in vec2 vUv;
27
+
28
+ uniform float iTime;
29
+ uniform vec2 iResolution;
30
+ uniform vec3 iMouse;
31
+
32
+ out vec4 fragColor;
33
+
34
+ vec3 erot(vec3 p, vec3 ax, float ro) {
35
+ return mix(dot(p, ax) * ax, p, cos(ro)) + sin(ro) * cross(ax, p);
36
+ }
37
+
38
+ float scene(vec3 p) {
39
+ if (length(p) > 1.0) {
40
+ return length(p) - 0.8;
41
+ }
42
+
43
+ vec4 f00 = sin(p.y * vec4(-3.02, 1.95, -3.42, -0.60) + p.z * vec4(3.08, 0.85, -2.25, -0.24) - p.x * vec4(-0.29, 1.16, -3.74, 2.89) + vec4(-0.71, 4.50, -3.24, -3.50));
44
+ vec4 f01 = sin(p.y * vec4(-0.40, -3.61, 3.23, -0.14) + p.z * vec4(-0.36, 3.64, -3.91, 2.66) - p.x * vec4(2.90, -0.54, -2.75, 2.71) + vec4(7.02, -5.41, -1.12, -7.41));
45
+ vec4 f02 = sin(p.y * vec4(-1.77, -1.28, -4.29, -3.20) + p.z * vec4(-3.49, -2.81, -0.64, 2.79) - p.x * vec4(3.15, 2.14, -3.85, 1.83) + vec4(-2.07, 4.49, 5.33, -2.17));
46
+ vec4 f03 = sin(p.y * vec4(-0.49, 0.68, 3.05, 0.42) + p.z * vec4(-2.87, 0.78, 3.78, -3.41) - p.x * vec4(-2.65, 0.33, 0.07, -0.64) + vec4(-3.24, -5.90, 1.14, -4.71));
47
+
48
+ vec4 f10 = sin(mat4(-0.34, 0.06, -0.59, -0.76, 0.10, -0.19, -0.12, 0.44, 0.64, -0.02, -0.26, 0.15, -0.16, 0.21, 0.91, 0.15) * f00 +
49
+ mat4(0.01, 0.54, -0.77, 0.11, 0.06, -0.14, 0.43, 0.51, -0.18, 0.08, 0.39, 0.20, 0.33, -0.49, -0.10, 0.19) * f01 +
50
+ mat4(0.27, 0.22, 0.43, 0.53, 0.18, -0.17, 0.23, -0.64, -0.14, 0.02, -0.10, 0.16, -0.13, -0.06, -0.04, -0.36) * f02 +
51
+ mat4(-0.13, 0.29, -0.29, 0.08, 1.13, 0.02, -0.83, 0.32, -0.32, 0.04, -0.31, -0.16, 0.14, -0.03, -0.20, 0.39) * f03 +
52
+ vec4(0.73, -4.28, -1.56, -1.80)) / 1.0 + f00;
53
+
54
+ vec4 f11 = sin(mat4(-1.11, 0.55, -0.12, -1.00, 0.16, 0.15, -0.30, 0.31, -0.01, 0.01, 0.31, -0.42, -0.29, 0.38, -0.04, 0.71) * f00 +
55
+ mat4(0.96, -0.02, 0.86, 0.52, -0.14, 0.60, 0.44, 0.43, 0.02, -0.15, -0.49, -0.05, -0.06, -0.25, -0.03, -0.22) * f01 +
56
+ mat4(0.52, 0.44, -0.05, -0.11, -0.56, -0.10, -0.61, -0.40, -0.04, 0.55, 0.32, -0.07, -0.02, 0.28, 0.26, -0.49) * f02 +
57
+ mat4(0.02, -0.32, 0.06, -0.17, -0.59, 0.00, -0.24, 0.60, -0.06, 0.13, -0.21, -0.27, -0.12, -0.14, 0.58, -0.55) * f03 +
58
+ vec4(-2.24, -3.48, -0.80, 1.41)) / 1.0 + f01;
59
+
60
+ vec4 f12 = sin(mat4(0.44, -0.06, -0.79, -0.46, 0.05, -0.60, 0.30, 0.36, 0.35, 0.12, 0.02, 0.12, 0.40, -0.26, 0.63, -0.21) * f00 +
61
+ mat4(-0.48, 0.43, -0.73, -0.40, 0.11, -0.01, 0.71, 0.05, -0.25, 0.25, -0.28, -0.20, 0.32, -0.02, -0.84, 0.16) * f01 +
62
+ mat4(0.39, -0.07, 0.90, 0.36, -0.38, -0.27, -1.86, -0.39, 0.48, -0.20, -0.05, 0.10, -0.00, -0.21, 0.29, 0.63) * f02 +
63
+ mat4(0.46, -0.32, 0.06, 0.09, 0.72, -0.47, 0.81, 0.78, 0.90, 0.02, -0.21, 0.08, -0.16, 0.22, 0.32, -0.13) * f03 +
64
+ vec4(3.38, 1.20, 0.84, 1.41)) / 1.0 + f02;
65
+
66
+ vec4 f13 = sin(mat4(-0.41, -0.24, -0.71, -0.25, -0.24, -0.75, -0.09, 0.02, -0.27, -0.42, 0.02, 0.03, -0.01, 0.51, -0.12, -1.24) * f00 +
67
+ mat4(0.64, 0.31, -1.36, 0.61, -0.34, 0.11, 0.14, 0.79, 0.22, -0.16, -0.29, -0.70, 0.02, -0.37, 0.49, 0.39) * f01 +
68
+ mat4(0.79, 0.47, 0.54, -0.47, -1.13, -0.35, -1.03, -0.22, -0.67, -0.26, 0.10, 0.21, -0.07, -0.73, -0.11, 0.72) * f02 +
69
+ mat4(0.43, -0.23, 0.13, 0.09, 1.38, -0.63, 1.57, -0.20, 0.39, -0.14, 0.42, 0.13, -0.57, -0.08, -0.21, 0.21) * f03 +
70
+ vec4(-0.34, -3.28, 0.43, -0.52)) / 1.0 + f03;
71
+
72
+ f00 = sin(mat4(-0.72, 0.23, -0.89, 0.52, 0.38, 0.19, -0.16, -0.88, 0.26, -0.37, 0.09, 0.63, 0.29, -0.72, 0.30, -0.95) * f10 +
73
+ mat4(-0.22, -0.51, -0.42, -0.73, -0.32, 0.00, -1.03, 1.17, -0.20, -0.03, -0.13, -0.16, -0.41, 0.09, 0.36, -0.84) * f11 +
74
+ mat4(-0.21, 0.01, 0.33, 0.47, 0.05, 0.20, -0.44, -1.04, 0.13, 0.12, -0.13, 0.31, 0.01, -0.34, 0.41, -0.34) * f12 +
75
+ mat4(-0.13, -0.06, -0.39, -0.22, 0.48, 0.25, 0.24, -0.97, -0.34, 0.14, 0.42, -0.00, -0.44, 0.05, 0.09, -0.95) * f13 +
76
+ vec4(0.48, 0.87, -0.87, -2.06)) / 1.4 + f10;
77
+
78
+ f01 = sin(mat4(-0.27, 0.29, -0.21, 0.15, 0.34, -0.23, 0.85, -0.09, -1.15, -0.24, -0.05, -0.25, -0.12, -0.73, -0.17, -0.37) * f10 +
79
+ mat4(-1.11, 0.35, -0.93, -0.06, -0.79, -0.03, -0.46, -0.37, 0.60, -0.37, -0.14, 0.45, -0.03, -0.21, 0.02, 0.59) * f11 +
80
+ mat4(-0.92, -0.17, -0.58, -0.18, 0.58, 0.60, 0.83, -1.04, -0.80, -0.16, 0.23, -0.11, 0.08, 0.16, 0.76, 0.61) * f12 +
81
+ mat4(0.29, 0.45, 0.30, 0.39, -0.91, 0.66, -0.35, -0.35, 0.21, 0.16, -0.54, -0.63, 1.10, -0.38, 0.20, 0.15) * f13 +
82
+ vec4(-1.72, -0.14, 1.92, 2.08)) / 1.4 + f11;
83
+
84
+ f02 = sin(mat4(1.00, 0.66, 1.30, -0.51, 0.88, 0.25, -0.67, 0.03, -0.68, -0.08, -0.12, -0.14, 0.46, 1.15, 0.38, -0.10) * f10 +
85
+ mat4(0.51, -0.57, 0.41, -0.09, 0.68, -0.50, -0.04, -1.01, 0.20, 0.44, -0.60, 0.46, -0.09, -0.37, -1.30, 0.04) * f11 +
86
+ mat4(0.14, 0.29, -0.45, -0.06, -0.65, 0.33, -0.37, -0.95, 0.71, -0.07, 1.00, -0.60, -1.68, -0.20, -0.00, -0.70) * f12 +
87
+ mat4(-0.31, 0.69, 0.56, 0.13, 0.95, 0.36, 0.56, 0.59, -0.63, 0.52, -0.30, 0.17, 1.23, 0.72, 0.95, 0.75) * f13 +
88
+ vec4(-0.90, -3.26, -0.44, -3.11)) / 1.4 + f12;
89
+
90
+ f03 = sin(mat4(0.51, -0.98, -0.28, 0.16, -0.22, -0.17, -1.03, 0.22, 0.70, -0.15, 0.12, 0.43, 0.78, 0.67, -0.85, -0.25) * f10 +
91
+ mat4(0.81, 0.60, -0.89, 0.61, -1.03, -0.33, 0.60, -0.11, -0.06, 0.01, -0.02, -0.44, 0.73, 0.69, 1.02, 0.62) * f11 +
92
+ mat4(-0.10, 0.52, 0.80, -0.65, 0.40, -0.75, 0.47, 1.56, 0.03, 0.05, 0.08, 0.31, -0.03, 0.22, -1.63, 0.07) * f12 +
93
+ mat4(-0.18, -0.07, -1.22, 0.48, -0.01, 0.56, 0.07, 0.15, 0.24, 0.25, -0.09, -0.54, 0.23, -0.08, 0.20, 0.36) * f13 +
94
+ vec4(-1.11, -4.28, 1.02, -0.23)) / 1.4 + f13;
95
+
96
+ return dot(f00, vec4(0.09, 0.12, -0.07, -0.03)) + dot(f01, vec4(-0.04, 0.07, -0.08, 0.05)) +
97
+ dot(f02, vec4(-0.01, 0.06, -0.02, 0.07)) + dot(f03, vec4(-0.05, 0.07, 0.03, 0.04)) - 0.16;
98
+ }
99
+
100
+ vec3 norm(vec3 p) {
101
+ mat3 k = mat3(p, p, p) - mat3(0.001);
102
+ return normalize(scene(p) - vec3(scene(k[0]), scene(k[1]), scene(k[2])));
103
+ }
104
+
105
+ void main() {
106
+ vec2 fragCoord = vUv * iResolution;
107
+ vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
108
+ vec2 mouse = (iMouse.xy - 0.5 * iResolution.xy) / iResolution.y;
109
+
110
+ vec3 cam = normalize(vec3(1.5, uv));
111
+ vec3 init = vec3(-5.0, 0.0, 0.0);
112
+
113
+ float yrot = 0.5;
114
+ float zrot = iTime * 0.2;
115
+ if (iMouse.z > 0.0) {
116
+ yrot += -4.0 * mouse.y;
117
+ zrot = 4.0 * mouse.x;
118
+ }
119
+ cam = erot(cam, vec3(0.0, 1.0, 0.0), yrot);
120
+ init = erot(init, vec3(0.0, 1.0, 0.0), yrot);
121
+ cam = erot(cam, vec3(0.0, 0.0, 1.0), zrot);
122
+ init = erot(init, vec3(0.0, 0.0, 1.0), zrot);
123
+
124
+ vec3 p = init;
125
+ bool hit = false;
126
+ for (int i = 0; i < 150 && !hit; i++) {
127
+ float dist = scene(p);
128
+ hit = dist * dist < 1e-6;
129
+ p += dist * cam;
130
+ if (distance(p, init) > 5.0) break;
131
+ }
132
+
133
+ vec3 n = norm(p);
134
+ vec3 r = reflect(cam, n);
135
+ vec3 nz = p - erot(p, vec3(1.0), 2.0) + erot(p, vec3(1.0), 4.0);
136
+ float spec = length(sin(r * 3.5 + sin(nz * 120.0) * 0.15) * 0.4 + 0.6) / sqrt(3.0);
137
+ spec *= smoothstep(-0.3, 0.2, scene(p + r * 0.2));
138
+ vec3 col = vec3(0.1, 0.1, 0.12) * spec + pow(spec, 8.0);
139
+ float bgdot = length(sin(cam * 8.0) * 0.4 + 0.6) / 2.0;
140
+ vec3 bg = vec3(0.1, 0.1, 0.11) * bgdot + pow(bgdot, 10.0);
141
+
142
+ vec4 result = hit ? vec4(col, 1.0) : vec4(bg, 1.0);
143
+ fragColor = smoothstep(-0.02, 1.05, sqrt(result)) * (1.0 - dot(uv, uv) * 0.5);
144
+ fragColor.a = 1.0;
145
+ }
146
+ GLSL
147
+
148
+ scene = Sunrb::Scene.new
149
+ scene.background = Sunrb::Color.new(0x000000)
150
+
151
+ camera = Sunrb::OrthographicCamera.new(
152
+ left: -5, right: 5, top: 5, bottom: -5, near: 0.1, far: 20
153
+ )
154
+ camera.position.z = 8
155
+
156
+ geometry = Sunrb::PlaneGeometry.new(width: 2, height: 2)
157
+
158
+ shader_material = Sunrb::ShaderMaterial.new(
159
+ vertex_shader: VERTEX_SHADER,
160
+ fragment_shader: FRAGMENT_SHADER,
161
+ uniforms: {
162
+ iTime: 0.0,
163
+ iResolution: Sunrb::Vector2.new(800, 600),
164
+ iMouse: Sunrb::Vector3.new(0, 0, 0)
165
+ }
166
+ )
167
+
168
+ quad = Sunrb::Mesh.new(geometry, shader_material)
169
+ scene.add(quad)
170
+
171
+ puts "=== Stanford Bunny - Neural Network SDF ==="
172
+ puts "Based on SIREN networks: https://vsitzmann.github.io/siren/"
173
+ puts "Drag mouse to rotate, press ESC to exit"
174
+
175
+ renderer = Sunrb::OpenGLRenderer.new(width: 800, height: 600, title: "Stanford Bunny - Neural Network SDF")
176
+
177
+ time = 0.0
178
+ mouse_x = 0.0
179
+ mouse_y = 0.0
180
+ mouse_pressed = false
181
+
182
+ renderer.on_mouse_move do |x, y|
183
+ mouse_x = x
184
+ mouse_y = 600 - y
185
+ end
186
+
187
+ renderer.on_mouse_button do |button, action, _mods|
188
+ mouse_pressed = (button == 0 && action == 1)
189
+ end
190
+
191
+ renderer.run do |delta|
192
+ time += delta
193
+ shader_material.uniforms[:iTime] = time
194
+ shader_material.uniforms[:iMouse] = Sunrb::Vector3.new(
195
+ mouse_x,
196
+ mouse_y,
197
+ mouse_pressed ? 1.0 : 0.0
198
+ )
199
+ renderer.render(scene, camera)
200
+ end