obj_parser 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +3 -2
- data/lib/obj_parser/face.rb +1 -1
- data/lib/obj_parser/math_utils.rb +1 -1
- data/lib/obj_parser/obj.rb +11 -11
- data/lib/obj_parser/obj_parser.rb +1 -1
- data/lib/obj_parser/point.rb +1 -1
- data/lib/obj_parser/single_indexed_obj.rb +1 -1
- data/lib/obj_parser/version.rb +2 -2
- data/lib/obj_parser.rb +1 -1
- data/obj_parser.gemspec +1 -1
- data/test/math_utils_test.rb +14 -14
- data/test/obj_parser_spec.rb +3 -2
- data/test/obj_spec.rb +3 -3
- data/test/single_indexed_obj_spec.rb +3 -3
- data/test/test_helper.rb +1 -2
- metadata +1 -1
data/README.md
CHANGED
@@ -6,6 +6,7 @@ Can merge vertice, normals, and textures indexes into a single index for OpenGL
|
|
6
6
|
|
7
7
|
- Support triangle primitives
|
8
8
|
- Support only one model per obj file
|
9
|
+
- Did not support materials
|
9
10
|
|
10
11
|
## Installation
|
11
12
|
|
@@ -25,10 +26,10 @@ Or install it yourself as:
|
|
25
26
|
|
26
27
|
Sample to parse an obj file, generate tangents and transform to a single indexed 3D model.
|
27
28
|
|
28
|
-
@parser =
|
29
|
+
@parser = ObjParser::ObjParser.new
|
29
30
|
obj = @parser.load(File.open("/Users/lcobos/development/ios/OpenGL-4/models/cube.obj"))
|
30
31
|
obj.compute_tangents
|
31
|
-
obj =
|
32
|
+
obj = ObjParser::SingleIndexedObj.build_with_obj(obj)
|
32
33
|
|
33
34
|
puts obj.vertice.map(&:data).join(",")
|
34
35
|
puts obj.normals.map(&:data).join(",")
|
data/lib/obj_parser/face.rb
CHANGED
data/lib/obj_parser/obj.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require_relative 'face'
|
2
2
|
require_relative 'math_utils'
|
3
3
|
|
4
|
-
module
|
4
|
+
module ObjParser
|
5
5
|
class Obj
|
6
6
|
VERTEX_BY_FACE = 3
|
7
7
|
attr_accessor :normals, :normals_indexes
|
@@ -41,35 +41,35 @@ module ObjLoader
|
|
41
41
|
pindex = 0
|
42
42
|
self.faces.each do |face|
|
43
43
|
pindex += 1
|
44
|
-
tangent_for_face =
|
45
|
-
tangent_for_face =
|
44
|
+
tangent_for_face = ObjParser::MathUtils::tangent_for_vertices_and_texures(face.vertice.map(&:data), face.textures.map(&:data))
|
45
|
+
tangent_for_face = ObjParser::MathUtils::normalized_vector(tangent_for_face)
|
46
46
|
#set the same tangent for the 3 vertex of current face
|
47
47
|
#re-compute tangents for duplicates vertices to get tangent per face
|
48
48
|
face.vertice.each_with_index do |vertex, index|
|
49
|
-
vertex.tangent.data =
|
49
|
+
vertex.tangent.data = ObjParser::MathUtils::sum_vectors(vertex.tangent.data, tangent_for_face)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
53
|
#orthonormalize
|
54
54
|
self.faces.each_with_index do |face,pindex|
|
55
55
|
face.vertice.each_with_index do |vertex, index|
|
56
|
-
vertex.tangent.data =
|
57
|
-
vertex.tangent.data =
|
56
|
+
vertex.tangent.data = ObjParser::MathUtils::orthogonalized_vector_with_vector(vertex.tangent.data, self.normals[self.normals_indexes[pindex * 3 + index]].data)
|
57
|
+
vertex.tangent.data = ObjParser::MathUtils::normalized_vector(vertex.tangent.data)
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
61
|
#binormal should be computed with per vertex tangent and summed for each vertex
|
62
62
|
self.faces.each_with_index do |face,pindex|
|
63
63
|
face.vertice.each_with_index do |vertex, index|
|
64
|
-
binormal =
|
65
|
-
vertex.binormal.data =
|
64
|
+
binormal = ObjParser::MathUtils::cross_product(self.normals[self.normals_indexes[pindex * 3 + index]].data, vertex.tangent.data)
|
65
|
+
vertex.binormal.data = ObjParser::MathUtils::sum_vectors(vertex.binormal.data, binormal)
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
69
|
self.faces.each_with_index do |face,pindex|
|
70
70
|
face.vertice.each_with_index do |vertex, index|
|
71
|
-
vertex.binormal.data =
|
72
|
-
if(
|
71
|
+
vertex.binormal.data = ObjParser::MathUtils::normalized_vector(vertex.binormal.data)
|
72
|
+
if(ObjParser::MathUtils::dot(ObjParser::MathUtils::cross_product(self.normals[self.normals_indexes[pindex * 3 + index]].data, vertex.tangent.data), vertex.binormal.data) < 0.0)
|
73
73
|
vertex.tangent.data[3] = -1.0
|
74
74
|
else
|
75
75
|
vertex.tangent.data[3] = 1.0
|
@@ -88,7 +88,7 @@ module ObjLoader
|
|
88
88
|
self.resolve_faces
|
89
89
|
result = self.faces.each_with_index.map do |face, index|
|
90
90
|
face.vertice.map do |vertex|
|
91
|
-
("%.2f" %
|
91
|
+
("%.2f" % ObjParser::MathUtils::dot(vertex.tangent.data[0..2], vertex.normal.data)).to_f
|
92
92
|
end.reduce(&:+)
|
93
93
|
end.reduce(&:+)
|
94
94
|
puts "RESULT: tangents and normals are orthogonal -> [#{result == 0 ? "VALID" : "NOT VALID"}]"
|
data/lib/obj_parser/point.rb
CHANGED
data/lib/obj_parser/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module
|
2
|
-
VERSION = "0.0.
|
1
|
+
module ObjParser
|
2
|
+
VERSION = "0.0.2"
|
3
3
|
end
|
data/lib/obj_parser.rb
CHANGED
data/obj_parser.gemspec
CHANGED
@@ -5,7 +5,7 @@ require 'obj_parser/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "obj_parser"
|
8
|
-
spec.version =
|
8
|
+
spec.version = ObjParser::VERSION
|
9
9
|
spec.authors = ["Laurent Cobos"]
|
10
10
|
spec.email = ["laurent@11factory.fr"]
|
11
11
|
spec.summary = %q{3D obj file parser.}
|
data/test/math_utils_test.rb
CHANGED
@@ -1,52 +1,52 @@
|
|
1
1
|
require 'test/unit'
|
2
2
|
require 'obj_parser'
|
3
3
|
|
4
|
-
class
|
4
|
+
class ObjParser::MathUtilsTest < Test::Unit::TestCase
|
5
5
|
|
6
6
|
def test_tangent_computing_given_vertices_and_normal
|
7
7
|
vertices = [[0,0,0], [1,0,0], [1,1,0]]
|
8
8
|
textures = [[0,1], [1,1], [1,0]]
|
9
|
-
assert_equal [1,0,0],
|
9
|
+
assert_equal [1,0,0], ObjParser::MathUtils.tangent_for_vertices_and_texures(vertices, textures)
|
10
10
|
end
|
11
11
|
|
12
12
|
def test_tangent2_and_binormal_computing_given_vertices_and_normal
|
13
13
|
vertices = [[0,0,0], [1,0,0], [1,1,0]]
|
14
14
|
textures = [[0,1], [1,1], [1,0]]
|
15
15
|
normal = [0,0,-1]
|
16
|
-
assert_array_in_delta [1.29289321881345, -0.707106781186547, 0.0],
|
16
|
+
assert_array_in_delta [1.29289321881345, -0.707106781186547, 0.0], ObjParser::MathUtils.tangent2_for_vertices_and_texures(vertices, textures), 0.00001
|
17
17
|
end
|
18
18
|
|
19
19
|
def test_vector_length
|
20
|
-
assert_equal 0,
|
21
|
-
assert_equal 1,
|
22
|
-
assert_equal Math.sqrt(29),
|
20
|
+
assert_equal 0, ObjParser::MathUtils::vector_length([0,0,0])
|
21
|
+
assert_equal 1, ObjParser::MathUtils::vector_length([1,0,0])
|
22
|
+
assert_equal Math.sqrt(29), ObjParser::MathUtils.vector_length([2,3,4])
|
23
23
|
end
|
24
24
|
|
25
25
|
def test_vector_normalization
|
26
|
-
assert_equal [0,0,0],
|
27
|
-
assert_equal [1,0,0],
|
28
|
-
assert_array_in_delta [0.371390676354104, 0.557086014531156, 0.742781352708207],
|
26
|
+
assert_equal [0,0,0], ObjParser::MathUtils.normalized_vector([0,0,0])
|
27
|
+
assert_equal [1,0,0], ObjParser::MathUtils.normalized_vector([1,0,0])
|
28
|
+
assert_array_in_delta [0.371390676354104, 0.557086014531156, 0.742781352708207], ObjParser::MathUtils.normalized_vector([2,3,4]), 0.00001
|
29
29
|
end
|
30
30
|
|
31
31
|
def test_dot_product
|
32
32
|
v1 = [1,0,0]
|
33
33
|
v2 = [0,1,0]
|
34
|
-
assert_equal 0,
|
34
|
+
assert_equal 0, ObjParser::MathUtils.dot(v1, v2)
|
35
35
|
v2 = [1,1,0]
|
36
|
-
assert_equal 1,
|
36
|
+
assert_equal 1, ObjParser::MathUtils.dot(v1, v2)
|
37
37
|
end
|
38
38
|
|
39
39
|
def test_orthogonalize
|
40
40
|
v1 = [0.2,1,0]
|
41
41
|
v2 = [1,0,0]
|
42
|
-
assert_equal [0,1,0],
|
42
|
+
assert_equal [0,1,0], ObjParser::MathUtils.orthogonalized_vector_with_vector(v1, v2)
|
43
43
|
end
|
44
44
|
|
45
45
|
def test_normal_computing_given_face_vertices
|
46
46
|
vertices = [[0,0,0], [1,0,0], [1,1,0]]
|
47
|
-
assert_equal [0,0,1].map(&:to_s),
|
47
|
+
assert_equal [0,0,1].map(&:to_s), ObjParser::MathUtils.normal_for_face_with_vertices(vertices).map(&:to_s)
|
48
48
|
vertices = [[0,0,0], [0,0,1], [0,1,0]]
|
49
|
-
assert_equal [-1,0,0].map(&:to_s),
|
49
|
+
assert_equal [-1,0,0].map(&:to_s), ObjParser::MathUtils.normal_for_face_with_vertices(vertices).map(&:to_s)
|
50
50
|
end
|
51
51
|
|
52
52
|
private
|
data/test/obj_parser_spec.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'test_helper'
|
2
|
+
require 'stringio'
|
2
3
|
|
3
|
-
describe
|
4
|
+
describe ObjParser::ObjParser do
|
4
5
|
|
5
6
|
it "should get obj vertice, normals, textures and indexes" do
|
6
|
-
@parser =
|
7
|
+
@parser = ObjParser::ObjParser.new
|
7
8
|
obj = @parser.load(StringIO.new(sample_cube_obj))
|
8
9
|
obj.vertice.take(3).map(&:data).must_equal([p([0.0,0.0,0.0]), p([0.0,0.0,1.0]), p([0.0,1.0,0.0])].map(&:data))
|
9
10
|
obj.normals.count.must_equal(6)
|
data/test/obj_spec.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe ObjParser::Obj do
|
4
4
|
|
5
5
|
before do
|
6
|
-
@obj =
|
6
|
+
@obj = ObjParser::Obj.new
|
7
7
|
@obj.vertice = [p([0.0,0.0,0.0]), p([0.0,0.0,1.0]), p([0.0,1.0,0.0]), p([0.0,1.0,1.0])]
|
8
8
|
@obj.vertice_indexes = [0, 1, 2, 1, 2, 3]
|
9
9
|
@obj.normals = [p([1.0,0.0,0.0]), p([0.0,1.0,0.0])]
|
@@ -24,7 +24,7 @@ describe ObjLoader::Obj do
|
|
24
24
|
@obj.compute_tangents
|
25
25
|
result = @obj.faces.each_with_index.map do |face, index|
|
26
26
|
face.vertice.map do |vertex|
|
27
|
-
("%.2f" %
|
27
|
+
("%.2f" % ObjParser::MathUtils::dot(vertex.tangent.data[0..2], vertex.normal.data)).to_f
|
28
28
|
end.reduce(&:+)
|
29
29
|
end.reduce(&:+)
|
30
30
|
result.must_equal(0)
|
@@ -1,14 +1,14 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe ObjParser::SingleIndexedObj do
|
4
4
|
|
5
5
|
before do
|
6
|
-
@obj =
|
6
|
+
@obj = ObjParser::Obj.new
|
7
7
|
@obj.vertice = [p([0.0,0.0,0.0]), p([0.0,0.0,1.0]), p([0.0,1.0,0.0]), p([0.0,1.0,1.0])]
|
8
8
|
@obj.vertice_indexes = [0, 1, 2, 0, 2, 3]
|
9
9
|
@obj.normals = [p([1.0,0.0,0.0]), p([0.0,1.0,0.0])]
|
10
10
|
@obj.normals_indexes = [1, 0, 1, 1, 0, 0]
|
11
|
-
@single_indexed_obj =
|
11
|
+
@single_indexed_obj = ObjParser::SingleIndexedObj.build_with_obj(@obj)
|
12
12
|
end
|
13
13
|
|
14
14
|
describe 'compute detailed vertice' do
|
data/test/test_helper.rb
CHANGED