mittsu-gltf 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.
- checksums.yaml +7 -0
- data/README.md +25 -0
- data/Rakefile +11 -0
- data/lib/mittsu/gltf/exporter.rb +168 -0
- data/lib/mittsu/gltf/version.rb +5 -0
- data/lib/mittsu/gltf.rb +3 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7357b9b37036619cd1dcac6a0272db90d88f6e0caf567805c4df6f15ada7c272
|
4
|
+
data.tar.gz: e9ee54d8195e9b1635163fccc9855dc9bd3a3b61333f2c8b61ac620e65899f84
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9c66bb2249b83c4b1b7f8291ab8e619851c08dc462eb0310f08ca0198f9c20bd8cd5f9199f82d438d0dc9cc6dedadd7013129a19eec387942318efa8ef55f41b
|
7
|
+
data.tar.gz: 4dc4dd25b9001add1c635608dcd3d769a5c4c3828f7a915f33e0694b3c91c697af9120b46b293b56cad9a5338096f1dea88031ee38827048077a2d7ccff370fc
|
data/README.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Mittsu: GLTF
|
2
|
+
GLTF support for [Mittsu](https://github.com/danini-the-panini/mittsu).
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
|
6
|
+
Just install:
|
7
|
+
|
8
|
+
`bundle add mittsu-gltf`
|
9
|
+
|
10
|
+
Then require in your code:
|
11
|
+
|
12
|
+
`require 'mittsu/gltf'`
|
13
|
+
|
14
|
+
## Usage
|
15
|
+
|
16
|
+
Currently this gem just includes an exporter. Loading GLTF files might happen at some point.
|
17
|
+
|
18
|
+
```
|
19
|
+
exporter = Mittsu::GLTFExporter.new
|
20
|
+
exporter.export(object, "output.gltf")
|
21
|
+
```
|
22
|
+
|
23
|
+
## About
|
24
|
+
|
25
|
+
This code was originally written for [Manyfold](https://manyfold.app), supported by funding from [NLNet](https://nlnet.nl) and [NGI Zero](https://ngi.eu/ngi-projects/ngi-zero/).
|
data/Rakefile
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
require "jbuilder"
|
2
|
+
require "base64"
|
3
|
+
|
4
|
+
module Mittsu
|
5
|
+
class GLTFExporter
|
6
|
+
COMPONENT_TYPES = {
|
7
|
+
# 8 bit
|
8
|
+
byte: 5120,
|
9
|
+
unsigned_byte: 5121,
|
10
|
+
# 16 bit
|
11
|
+
short: 5122,
|
12
|
+
unsigned_short: 5123,
|
13
|
+
# 32 bit
|
14
|
+
unsigned_int: 5125,
|
15
|
+
float: 5126
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
GPU_BUFFER_TYPES = {
|
19
|
+
array_buffer: 34962,
|
20
|
+
element_array_buffer: 34963
|
21
|
+
}
|
22
|
+
|
23
|
+
ELEMENT_TYPES = [
|
24
|
+
"SCALAR",
|
25
|
+
"VEC2",
|
26
|
+
"VEC3",
|
27
|
+
"VEC4",
|
28
|
+
"MAT2",
|
29
|
+
"MAT3",
|
30
|
+
"MAT4"
|
31
|
+
].freeze
|
32
|
+
|
33
|
+
def initialize(options = {})
|
34
|
+
@node_indexes = []
|
35
|
+
@nodes = []
|
36
|
+
@buffers = []
|
37
|
+
@meshes = []
|
38
|
+
@buffer_views = []
|
39
|
+
@accessors = []
|
40
|
+
end
|
41
|
+
|
42
|
+
def export(object, filename)
|
43
|
+
object.traverse do |obj|
|
44
|
+
@node_indexes << add_mesh(obj) if obj.is_a? Mittsu::Mesh
|
45
|
+
end
|
46
|
+
File.write(
|
47
|
+
filename,
|
48
|
+
Jbuilder.new do |json|
|
49
|
+
json.asset do
|
50
|
+
json.generator "Mittsu-GLTF"
|
51
|
+
json.version "2.0"
|
52
|
+
end
|
53
|
+
json.scene 0
|
54
|
+
json.scenes [{
|
55
|
+
nodes: @node_indexes
|
56
|
+
}]
|
57
|
+
json.nodes { json.array! @nodes }
|
58
|
+
json.meshes { json.array! @meshes }
|
59
|
+
json.buffers { json.array! @buffers }
|
60
|
+
json.bufferViews { json.array! @buffer_views }
|
61
|
+
json.accessors { json.array! @accessors }
|
62
|
+
end.target!
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Parse is here for consistency with THREE.js's weird naming of exporter methods
|
67
|
+
alias_method :parse, :export
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def add_mesh(mesh)
|
72
|
+
# Pack faces into an array
|
73
|
+
pack_string = (mesh.geometry.faces.count > (2**16)) ? "L<*" : "S<*"
|
74
|
+
faces = mesh.geometry.faces.map { |x| [x.a, x.b, x.c] }
|
75
|
+
data = faces.flatten.pack(pack_string)
|
76
|
+
# Add bufferView and accessor for faces
|
77
|
+
face_accessor_index = add_accessor(
|
78
|
+
buffer_view: add_buffer_view(
|
79
|
+
buffer: @buffers.count,
|
80
|
+
offset: 0,
|
81
|
+
length: data.length,
|
82
|
+
target: :element_array_buffer
|
83
|
+
),
|
84
|
+
component_type: (mesh.geometry.faces.count > (2**16)) ? :unsigned_int : :unsigned_short,
|
85
|
+
count: mesh.geometry.faces.count * 3,
|
86
|
+
type: "SCALAR",
|
87
|
+
min: 0,
|
88
|
+
max: mesh.geometry.vertices.count - 1
|
89
|
+
)
|
90
|
+
# Add padding to get to integer multiple of float size
|
91
|
+
padding = 4 - (data.length % 4)
|
92
|
+
data += Array.new(padding, 0).pack("C*")
|
93
|
+
# Pack vertices in as floats
|
94
|
+
offset = data.length
|
95
|
+
vertices = mesh.geometry.vertices.map(&:elements)
|
96
|
+
data += vertices.flatten.pack("f*")
|
97
|
+
# Add bufferView and accessor for vertices
|
98
|
+
mesh.geometry.compute_bounding_box
|
99
|
+
vertex_accessor_index = add_accessor(
|
100
|
+
buffer_view: add_buffer_view(
|
101
|
+
buffer: @buffers.count,
|
102
|
+
offset: offset,
|
103
|
+
length: data.length - offset,
|
104
|
+
target: :array_buffer
|
105
|
+
),
|
106
|
+
component_type: :float,
|
107
|
+
count: mesh.geometry.vertices.count,
|
108
|
+
type: "VEC3",
|
109
|
+
min: mesh.geometry.bounding_box.min.elements,
|
110
|
+
max: mesh.geometry.bounding_box.max.elements
|
111
|
+
)
|
112
|
+
# Encode and store in buffers
|
113
|
+
@buffers << {
|
114
|
+
uri: "data:application/octet-stream;base64," + Base64.strict_encode64(data),
|
115
|
+
byteLength: data.length
|
116
|
+
}
|
117
|
+
# Add mesh
|
118
|
+
mesh_index = @meshes.count
|
119
|
+
@meshes << {
|
120
|
+
"primitives" => [
|
121
|
+
{
|
122
|
+
"attributes" => {
|
123
|
+
"POSITION" => vertex_accessor_index
|
124
|
+
},
|
125
|
+
"indices" => face_accessor_index
|
126
|
+
}
|
127
|
+
]
|
128
|
+
}
|
129
|
+
# Add node
|
130
|
+
index = @nodes.count
|
131
|
+
@nodes << {
|
132
|
+
mesh: mesh_index
|
133
|
+
}
|
134
|
+
index
|
135
|
+
end
|
136
|
+
|
137
|
+
def add_buffer_view(buffer:, offset:, length:, target: nil)
|
138
|
+
# Check args
|
139
|
+
raise ArgumentError.new("invalid GPU buffer target: #{target}") unless target.nil? || GPU_BUFFER_TYPES.keys.include?(target)
|
140
|
+
index = @buffer_views.count
|
141
|
+
@buffer_views << {
|
142
|
+
buffer: buffer,
|
143
|
+
byteOffset: offset,
|
144
|
+
byteLength: length,
|
145
|
+
target: GPU_BUFFER_TYPES[target]
|
146
|
+
}
|
147
|
+
index
|
148
|
+
end
|
149
|
+
|
150
|
+
def add_accessor(buffer_view:, component_type:, count:, type:, min:, max:, offset: 0)
|
151
|
+
# Check args
|
152
|
+
raise ArgumentError.new("invalid component type: #{component_type}") unless COMPONENT_TYPES.key?(component_type)
|
153
|
+
raise ArgumentError.new("invalid element type: #{type}") unless ELEMENT_TYPES.include?(type)
|
154
|
+
# Add data
|
155
|
+
index = @accessors.count
|
156
|
+
@accessors << {
|
157
|
+
bufferView: buffer_view,
|
158
|
+
byteOffset: offset,
|
159
|
+
componentType: COMPONENT_TYPES[component_type],
|
160
|
+
count: count,
|
161
|
+
type: type,
|
162
|
+
min: Array(min),
|
163
|
+
max: Array(max)
|
164
|
+
}
|
165
|
+
index
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
data/lib/mittsu/gltf.rb
ADDED
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mittsu-gltf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- James Smith
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-12-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mittsu
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jbuilder
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.13'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.13'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '13.2'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '13.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.13'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.13'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: standard
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.41'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.41'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop-rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.2'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.2'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop-rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.6'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.6'
|
111
|
+
description: GLTF file support for Mittsu
|
112
|
+
email:
|
113
|
+
- james@floppy.org.uk
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- README.md
|
119
|
+
- Rakefile
|
120
|
+
- lib/mittsu/gltf.rb
|
121
|
+
- lib/mittsu/gltf/exporter.rb
|
122
|
+
- lib/mittsu/gltf/version.rb
|
123
|
+
homepage: https://github.com/manyfold3d/mittsu-gltf
|
124
|
+
licenses:
|
125
|
+
- MIT
|
126
|
+
metadata:
|
127
|
+
homepage_uri: https://github.com/manyfold3d/mittsu-gltf
|
128
|
+
source_code_uri: https://github.com/manyfold3d/mittsu-gltf
|
129
|
+
changelog_uri: https://github.com/manyfold3d/mittsu-gltf/releases
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options: []
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '3.1'
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
requirements: []
|
145
|
+
rubygems_version: 3.5.11
|
146
|
+
signing_key:
|
147
|
+
specification_version: 4
|
148
|
+
summary: GLTF file support for Mittsu
|
149
|
+
test_files: []
|