Skip to content

Commit 0e1d6a4

Browse files
VertexMesh
- Changed so that there is a separate set of indexes for vector normals OBJ Files - Work in progress for supporting textures
1 parent a2049f8 commit 0e1d6a4

File tree

19 files changed

+366
-149
lines changed

19 files changed

+366
-149
lines changed

integration/boofcv-swing/src/main/java/boofcv/gui/mesh/MeshColorizeOps.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Peter Abeles. All Rights Reserved.
2+
* Copyright (c) 2024, Peter Abeles. All Rights Reserved.
33
*
44
* This file is part of BoofCV (http://boofcv.org).
55
*
@@ -40,7 +40,7 @@ public class MeshColorizeOps {
4040
* @return SurfaceColor
4141
*/
4242
public static RenderMesh.SurfaceColor colorizeByVertex( VertexMesh mesh, int[] vertexColor ) {
43-
return ( shapeIdx ) -> vertexColor[mesh.indexes.get(mesh.offsets.get(shapeIdx))];
43+
return ( shapeIdx ) -> vertexColor[mesh.faceVertexes.get(mesh.faceOffsets.get(shapeIdx))];
4444
}
4545

4646
/**
@@ -57,7 +57,7 @@ public static RenderMesh.SurfaceColor colorizeByNormal( VertexMesh mesh ) {
5757
var axisZ = new Vector3D_F64(0, 0, 1);
5858

5959
for (int i = 0; i < mesh.size(); i++) {
60-
mesh.getShape(i, facet);
60+
mesh.getFaceVectors(i, facet);
6161

6262
// Handle case of invalid facet gracefully by assigning it to an arbitrary color
6363
if (facet.size < 3) {

main/boofcv-io/src/benchmark/java/boofcv/visualize/BenchmarkRenderMesh.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ private void createFlatSquareScene( CameraPinhole intrinsics, Random rand ) {
8787
shape.get(2).setTo(x1, y1, z);
8888
shape.get(3).setTo(x0, y1, z);
8989

90-
mesh.addShape(shape.toList());
90+
mesh.addFaceVectors(shape.toList());
9191
}
9292
}
9393

main/boofcv-io/src/main/java/boofcv/io/points/StlDataStructure.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,13 @@ public VertexMesh toMesh( @Nullable VertexMesh out ) {
186186
out = new VertexMesh();
187187

188188
out.vertexes.setTo(vertexes);
189-
out.indexes.setTo(facetVertsIdx);
189+
out.faceVertexes.setTo(facetVertsIdx);
190190

191191
// All facets are triangles
192-
out.offsets.resize(facetCount() + 1);
193-
out.offsets.set(0, 0);
194-
for (int i = 1; i < out.offsets.size; i++) {
195-
out.offsets.set(i, i*3);
192+
out.faceOffsets.resize(facetCount() + 1);
193+
out.faceOffsets.set(0, 0);
194+
for (int i = 1; i < out.faceOffsets.size; i++) {
195+
out.faceOffsets.set(i, i*3);
196196
}
197197

198198
return out;

main/boofcv-io/src/main/java/boofcv/io/points/impl/ObjFileCodec.java

+59-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Peter Abeles. All Rights Reserved.
2+
* Copyright (c) 2024, Peter Abeles. All Rights Reserved.
33
*
44
* This file is part of BoofCV (http://boofcv.org).
55
*
@@ -21,6 +21,8 @@
2121
import boofcv.alg.cloud.PointCloudReader;
2222
import boofcv.alg.cloud.PointCloudWriter;
2323
import boofcv.struct.mesh.VertexMesh;
24+
import georegression.struct.point.Point2D_F32;
25+
import georegression.struct.point.Point3D_F32;
2426
import georegression.struct.point.Point3D_F64;
2527
import org.ddogleg.struct.DogArray_I32;
2628

@@ -62,15 +64,36 @@ public static void save( VertexMesh mesh, Writer writer ) throws IOException {
6264
obj.addVertex(p.x, p.y, p.z);
6365
}
6466

67+
// Save vertex normals
68+
for (int i = 0; i < mesh.normals.size(); i++) {
69+
Point3D_F32 p = mesh.normals.getTemp(i);
70+
obj.addVertex(p.x, p.y, p.z);
71+
}
72+
73+
// Save vertex textures
74+
for (int i = 0; i < mesh.texture.size(); i++) {
75+
Point2D_F32 p = mesh.texture.getTemp(i);
76+
obj.addTextureVertex(p.x, p.y);
77+
}
78+
79+
// See how many different types of vertexes need to be saved
80+
int count = 0;
81+
if (mesh.vertexes.size() > 0)
82+
count++;
83+
if (mesh.normals.size() > 0)
84+
count++;
85+
if (mesh.texture.size() > 0)
86+
count++;
87+
6588
// Create the faces
6689
var indexes = new DogArray_I32();
67-
for (int i = 1; i < mesh.offsets.size; i++) {
68-
int idx0 = mesh.offsets.get(i - 1);
69-
int idx1 = mesh.offsets.get(i);
90+
for (int i = 1; i < mesh.faceOffsets.size; i++) {
91+
int idx0 = mesh.faceOffsets.get(i - 1);
92+
int idx1 = mesh.faceOffsets.get(i);
7093

7194
indexes.reset();
72-
indexes.addAll(mesh.indexes.data, idx0, idx1);
73-
obj.addFace(indexes);
95+
indexes.addAll(mesh.faceVertexes.data, idx0, idx1);
96+
obj.addFace(indexes, count);
7497
}
7598
}
7699

@@ -79,9 +102,16 @@ public static void load( InputStream input, PointCloudWriter output ) throws IOE
79102
@Override protected void addVertex( double x, double y, double z ) {
80103
output.add(x, y, z, 0);
81104
}
105+
106+
@Override protected void addVertexNormal( double x, double y, double z ) {}
107+
108+
@Override protected void addVertexTexture( double x, double y ) {}
109+
82110
@Override protected void addPoint( int vertex ) {}
111+
83112
@Override protected void addLine( DogArray_I32 vertexes ) {}
84-
@Override protected void addFace( DogArray_I32 vertexes ) {}
113+
114+
@Override protected void addFace( DogArray_I32 indexes, int vertexCount ) {}
85115
};
86116
obj.parse(new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)));
87117
}
@@ -92,11 +122,30 @@ public static void load( InputStream input, VertexMesh output ) throws IOExcepti
92122
@Override protected void addVertex( double x, double y, double z ) {
93123
output.vertexes.append(x, y, z);
94124
}
125+
126+
@Override protected void addVertexNormal( double x, double y, double z ) {
127+
output.normals.append((float)x, (float)y, (float)z);
128+
}
129+
130+
@Override protected void addVertexTexture( double x, double y ) {
131+
output.texture.append((float)x, (float)y);
132+
}
133+
95134
@Override protected void addPoint( int vertex ) {}
135+
96136
@Override protected void addLine( DogArray_I32 vertexes ) {}
97-
@Override protected void addFace( DogArray_I32 vertexes ) {
98-
output.indexes.addAll(vertexes);
99-
output.offsets.add(output.indexes.size);
137+
138+
@Override protected void addFace( DogArray_I32 indexes, int vertexCount ) {
139+
int types = indexes.size/vertexCount;
140+
for (int idxVert = 0; idxVert < vertexCount; idxVert++) {
141+
output.faceVertexes.add(indexes.get(idxVert)/types);
142+
for (int i = 1; i < types; i++) {
143+
if (indexes.get(i - 1) != indexes.get(i))
144+
throw new RuntimeException("Only vertexes types with the same index supported");
145+
}
146+
}
147+
148+
output.faceOffsets.add(output.faceVertexes.size);
100149
}
101150
};
102151
obj.parse(new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)));

main/boofcv-io/src/main/java/boofcv/io/points/impl/ObjFileReader.java

+50-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Peter Abeles. All Rights Reserved.
2+
* Copyright (c) 2024, Peter Abeles. All Rights Reserved.
33
*
44
* This file is part of BoofCV (http://boofcv.org).
55
*
@@ -29,12 +29,16 @@
2929
public abstract class ObjFileReader {
3030
DogArray_I32 vertexIndexes = new DogArray_I32();
3131
int vertexCount = 0;
32+
int vertexTextureCount = 0;
33+
int vertexNormalCount = 0;
3234

3335
/**
3436
* Decodes / reads the OBJ file encoded as text in the reader
3537
*/
3638
public void parse( BufferedReader reader ) throws IOException {
3739
vertexCount = 0;
40+
vertexTextureCount = 0;
41+
vertexNormalCount = 0;
3842

3943
var builder = new StringBuilder();
4044
int actualLineCount = 0;
@@ -77,14 +81,30 @@ public void parse( BufferedReader reader ) throws IOException {
7781
addVertex(x, y, z);
7882
vertexCount++;
7983
}
84+
85+
case "vn" -> {
86+
double x = Double.parseDouble(words[1]);
87+
double y = Double.parseDouble(words[2]);
88+
double z = Double.parseDouble(words[3]);
89+
addVertexNormal(x, y, z);
90+
vertexNormalCount++;
91+
}
92+
93+
case "vt" -> {
94+
double x = Double.parseDouble(words[1]);
95+
double y = Double.parseDouble(words[2]);
96+
addVertexTexture(x, y);
97+
vertexTextureCount++;
98+
}
99+
80100
case "p" -> addPoint(ensureIndex(Integer.parseInt(words[1])));
81101
case "l" -> {
82102
readPoints(words);
83103
addLine(vertexIndexes);
84104
}
85105
case "f" -> {
86-
readPoints(words);
87-
addFace(vertexIndexes);
106+
readFaceIndexes(words);
107+
addFace(vertexIndexes, words.length - 1);
88108
}
89109
default -> handleError(actualLineCount + " Unknown object type. '" + words[0] + "'");
90110
}
@@ -115,13 +135,39 @@ private void readPoints( String[] words ) {
115135
}
116136
}
117137

138+
private void readFaceIndexes( String[] words ) {
139+
vertexIndexes.reset();
140+
for (int i = 1; i < words.length; i++) {
141+
String word = words[i];
142+
143+
int idx0 = 0;
144+
int idx1 = word.indexOf('/');
145+
while (idx1 != -1) {
146+
vertexIndexes.add(ensureIndex(Integer.parseInt(word.substring(idx0, idx1))));
147+
idx0 = idx1 + 1;
148+
idx1 = word.indexOf('/', idx0);
149+
}
150+
vertexIndexes.add(ensureIndex(Integer.parseInt(word.substring(idx0))));
151+
}
152+
}
153+
118154
protected abstract void addVertex( double x, double y, double z );
119155

156+
protected abstract void addVertexNormal( double x, double y, double z );
157+
158+
protected abstract void addVertexTexture( double x, double y );
159+
120160
protected abstract void addPoint( int vertex );
121161

122162
protected abstract void addLine( DogArray_I32 vertexes );
123163

124-
protected abstract void addFace( DogArray_I32 vertexes );
164+
/**
165+
* Adds a face. Indexes are interleaved in vertex, normal, and texture order.
166+
*
167+
* @param indexes Indexes of vertex values
168+
* @param vertexCount Number of vertexes in the face
169+
*/
170+
protected abstract void addFace( DogArray_I32 indexes, int vertexCount );
125171

126172
/**
127173
* If something goes where it's passed here

main/boofcv-io/src/main/java/boofcv/io/points/impl/ObjFileWriter.java

+17-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Peter Abeles. All Rights Reserved.
2+
* Copyright (c) 2024, Peter Abeles. All Rights Reserved.
33
*
44
* This file is part of BoofCV (http://boofcv.org).
55
*
@@ -90,7 +90,7 @@ public void addPoint( int vertex ) throws IOException {
9090
* @param vertexes Index of vertexes in this face. If null then automatic.
9191
*/
9292
public void addLine( @Nullable DogArray_I32 vertexes ) throws IOException {
93-
writeObject('l', vertexes);
93+
writeObject('l', vertexes, 1);
9494
}
9595

9696
/**
@@ -99,13 +99,21 @@ public void addLine( @Nullable DogArray_I32 vertexes ) throws IOException {
9999
*
100100
* <p>NOTE: Vertexes indexes are 0-indexed. Not 1-indexed like they are in OBJ files.</p>
101101
*
102+
*
103+
* @param count Number of different vertex types, i.e. 3D, texture, normal. All are assumed to
104+
* reference a point with the same index.
102105
* @param vertexes Index of vertexes in this face. If null then automatic.
103106
*/
104-
public void addFace( @Nullable DogArray_I32 vertexes ) throws IOException {
105-
writeObject('f', vertexes);
107+
public void addFace( @Nullable DogArray_I32 vertexes, int count ) throws IOException {
108+
writeObject('f', vertexes, count);
106109
}
107110

108-
private void writeObject( char name, @Nullable DogArray_I32 vertexes ) throws IOException {
111+
/**
112+
*
113+
* @param count How many times it should duplicate the index. It's assumed all vertexes reference
114+
* objects with the same index values.
115+
*/
116+
private void writeObject( char name, @Nullable DogArray_I32 vertexes, int count ) throws IOException {
109117
writer.write(name);
110118
if (vertexes == null || vertexes.size == 0) {
111119
int v = -1;
@@ -125,7 +133,11 @@ else if (vertIndex <= -vertexCount)
125133
// Write the index and compensate for the file format being 1-indexed.
126134
if (vertIndex >= 0)
127135
vertIndex++;
136+
128137
writer.write(" " + vertIndex);
138+
for (int idxCount = 1; idxCount < count; idxCount++) {
139+
writer.write("/" + vertIndex);
140+
}
129141
}
130142
}
131143
writer.write('\n');

main/boofcv-io/src/main/java/boofcv/io/points/impl/PlyCodec.java

+12-12
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ public static void readMesh( InputStream input, VertexMesh mesh, DogArray_I32 co
431431
colorRGB.reset();
432432
mesh.reset();
433433
mesh.vertexes.reserve(vertexes);
434-
mesh.indexes.reserve(triangles*3);
434+
mesh.faceVertexes.reserve(triangles*3);
435435
}
436436

437437
@Override public void addVertex( double x, double y, double z, int rgb ) {
@@ -440,12 +440,12 @@ public static void readMesh( InputStream input, VertexMesh mesh, DogArray_I32 co
440440
}
441441

442442
@Override public void addVertexNormal( double nx, double ny, double nz ) {
443-
mesh.vertexNormals.append((float)nx, (float)ny, (float)nz);
443+
mesh.normals.append((float)nx, (float)ny, (float)nz);
444444
}
445445

446446
@Override public void addPolygon( int[] indexes, int offset, int length ) {
447-
mesh.offsets.add(mesh.indexes.size + length);
448-
mesh.indexes.addAll(indexes, offset, offset + length);
447+
mesh.faceOffsets.add(mesh.faceVertexes.size + length);
448+
mesh.faceVertexes.addAll(indexes, offset, offset + length);
449449
}
450450

451451
@Override public void setTextureName( String textureName ) {
@@ -688,7 +688,7 @@ private static PlyWriter wrapMeshForWriting( VertexMesh mesh, @Nullable DogArray
688688
return new PlyWriter() {
689689
@Override public int getVertexCount() {return mesh.vertexes.size();}
690690

691-
@Override public int getPolygonCount() {return mesh.offsets.size - 1;}
691+
@Override public int getPolygonCount() {return mesh.faceOffsets.size - 1;}
692692

693693
@Override public boolean isColor() {return colorRGB != null;}
694694

@@ -697,7 +697,7 @@ private static PlyWriter wrapMeshForWriting( VertexMesh mesh, @Nullable DogArray
697697
}
698698

699699
@Override public boolean isVertexNormals() {
700-
return mesh.vertexNormals.size() > 0;
700+
return mesh.normals.size() > 0;
701701
}
702702

703703
@Override public String getTextureName() {
@@ -707,27 +707,27 @@ private static PlyWriter wrapMeshForWriting( VertexMesh mesh, @Nullable DogArray
707707
@Override public void getVertex( int which, Point3D_F64 vertex ) {mesh.vertexes.getCopy(which, vertex);}
708708

709709
@Override public void getVertexNormal( int which, GeoTuple3D_F64<?> normal ) {
710-
Point3D_F32 tmp = mesh.vertexNormals.getTemp(which);
710+
Point3D_F32 tmp = mesh.normals.getTemp(which);
711711
normal.setTo(tmp.x, tmp.y, tmp.z);
712712
}
713713

714714
@SuppressWarnings("NullAway")
715715
@Override public int getColor( int which ) {return colorRGB.get(which);}
716716

717717
@Override public int getIndexes( int which, int[] indexes ) {
718-
int idx0 = mesh.offsets.get(which);
719-
int idx1 = mesh.offsets.get(which + 1);
718+
int idx0 = mesh.faceOffsets.get(which);
719+
int idx1 = mesh.faceOffsets.get(which + 1);
720720

721721
for (int i = idx0; i < idx1; i++) {
722-
indexes[i - idx0] = mesh.indexes.get(i);
722+
indexes[i - idx0] = mesh.faceVertexes.get(i);
723723
}
724724

725725
return idx1 - idx0;
726726
}
727727

728728
@Override public int getTextureCoors( int which, float[] coordinates ) {
729-
int idx0 = mesh.offsets.get(which);
730-
int idx1 = mesh.offsets.get(which + 1);
729+
int idx0 = mesh.faceOffsets.get(which);
730+
int idx1 = mesh.faceOffsets.get(which + 1);
731731

732732
int idxArray = 0;
733733
for (int i = idx0; i < idx1; i++) {

0 commit comments

Comments
 (0)