Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
I
imagej-elphel
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
3
Issues
3
List
Board
Labels
Milestones
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Elphel
imagej-elphel
Commits
4e6966e0
Commit
4e6966e0
authored
Sep 25, 2022
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Debugging gltf export
parent
82b27573
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
1299 additions
and
425 deletions
+1299
-425
pom.xml
pom.xml
+12
-0
CLTParameters.java
src/main/java/com/elphel/imagej/cameras/CLTParameters.java
+118
-61
OpticalFlow.java
...ain/java/com/elphel/imagej/tileprocessor/OpticalFlow.java
+1
-1
QuadCLTCPU.java
...main/java/com/elphel/imagej/tileprocessor/QuadCLTCPU.java
+122
-23
TexturedModel.java
...n/java/com/elphel/imagej/tileprocessor/TexturedModel.java
+121
-239
TileCluster.java
...ain/java/com/elphel/imagej/tileprocessor/TileCluster.java
+54
-46
TileProcessor.java
...n/java/com/elphel/imagej/tileprocessor/TileProcessor.java
+214
-55
GlTfExport.java
src/main/java/com/elphel/imagej/x3d/export/GlTfExport.java
+483
-0
TriMesh.java
src/main/java/com/elphel/imagej/x3d/export/TriMesh.java
+140
-0
WavefrontExport.java
...in/java/com/elphel/imagej/x3d/export/WavefrontExport.java
+24
-0
X3dOutput.java
src/main/java/com/elphel/imagej/x3d/export/X3dOutput.java
+10
-0
No files found.
pom.xml
View file @
4e6966e0
...
...
@@ -27,6 +27,18 @@
<description>
A Maven project implementing imagej-elphel plugin
</description>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>
com.google.code.gson
</groupId>
<artifactId>
gson
</artifactId>
<version>
2.9.1
</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple -->
<dependency>
<groupId>
com.googlecode.json-simple
</groupId>
<artifactId>
json-simple
</artifactId>
<version>
1.1
</version>
</dependency>
<!-- ssh support - see https://www.baeldung.com/java-ssh-connection -->
<!-- https://mvnrepository.com/artifact/org.apache.sshd/sshd-core -->
<dependency>
...
...
src/main/java/com/elphel/imagej/cameras/CLTParameters.java
View file @
4e6966e0
...
...
@@ -383,18 +383,18 @@ public class CLTParameters {
public
boolean
photo_debug
=
false
;
// Generate images and text
public
double
tex_disp_adiffo
=
0.35
;
// 0.3; disparity absolute tolerance to connect in ortho directions
public
double
tex_disp_rdiffo
=
0.12
;
// 0.1; disparity relative tolerance to connect in ortho directions
public
double
tex_disp_adiffd
=
0.6
;
// 0.4; disparity absolute tolerance to connect in diagonal directions
public
double
tex_disp_rdiffd
=
0.18
;
// 0.12; disparity relative tolerance to connect in diagonal directions
public
double
tex_disp_adiffo
=
0.
12
;
// 0.
35; // 0.3; disparity absolute tolerance to connect in ortho directions
public
double
tex_disp_rdiffo
=
0.1
;
// 0.1
2; // 0.1; disparity relative tolerance to connect in ortho directions
public
double
tex_disp_adiffd
=
0.
18
;
// 0.
6; // 0.4; disparity absolute tolerance to connect in diagonal directions
public
double
tex_disp_rdiffd
=
0.1
5
;
// 0.1
8; // 0.12; disparity relative tolerance to connect in diagonal directions
public
double
tex_disp_fof
=
1.5
;
// Increase tolerance for friend of a friend
public
double
tex_fg_bg
=
0.1
;
// Minimal FG/BG disparity difference (NaN bg if difference from FG < this)
public
double
tex_distort
=
0.8
;
// Maximal texture distortion to accumulate multiple scenes (0 - any)
public
double
tex_mb
=
1.0
;
// Reduce texture weight if motion blur exceeds this (as square of MB length)
public
boolean
tex_um
=
true
;
// Use unsharp mask filter for textures
public
double
tex_um_sigma
=
10
.0
;
// Unsharp mask sigma for textures
public
double
tex_um_weight
=
0.
97
;
// Unsharp mask weight
public
double
tex_um_sigma
=
2
.0
;
// Unsharp mask sigma for textures
public
double
tex_um_weight
=
0.
8
;
// Unsharp mask weight
public
boolean
tex_lwir_autorange
=
true
;
// Autorange LWIR textures
public
boolean
tex_um_fixed
=
false
;
// Use fixed range after unsharp mask instead of autorange
public
double
tex_um_range
=
500
;
// Full range after unsharp mask
...
...
@@ -403,7 +403,24 @@ public class CLTParameters {
public
int
tex_hist_bins
=
1024
;
// Number of histogram bins to use for texture histograms
public
int
tex_hist_segments
=
32
;
// Number of evenly-spaced percentiles to use for histogram normalization
public
boolean
tex_color
=
true
;
// Use pseudo-colored textures
public
int
tex_palette
=
2
;
// Palette number for pseudo colors
public
int
tex_palette
=
1
;
// Palette number for pseudo colors
public
int
max_clusters
=
5000
;
// Maximal number of clusters to generate for one run
public
boolean
remove_scans
=
true
;
// Remove all unneeded scans when generating x3d output to save memory
public
boolean
output_x3d
=
true
;
// Generate x3d output
public
boolean
output_obj
=
true
;
// Generate Wavefront obj output
public
boolean
output_glTF
=
true
;
// Generate glTF output
public
boolean
correct_distortions
=
true
;
// Correct lens geometric distortions in a model (will need backdrop to be corrected too)
public
boolean
show_triangles
=
false
;
// true; // Show generated triangles
public
boolean
avg_cluster_disp
=
false
;
// Weight-average disparity for the whole cluster
public
double
maxDispTriangle
=
0.0
;
// 0.2; // Maximal relative disparity difference in a triangle face
public
double
maxZtoXY
=
0.0
;
// 30.0; // world dz /sqrt(dx*dx + dz*dz), // 10.0. <=0 - do not use
public
double
maxZ
=
20000
;
// maximal distance to far object
public
boolean
limitZ
=
true
;
// limit Z, if false - remove triangle
public
double
infinityDistance
=
10000
;
// Distance to generate backdrop (0 - use regular backdrop)
public
int
min_bgnd_tiles
=
10
;
// Minimal number of background tiles to generate background
public
boolean
gltf_emissive
=
false
;
// true; // Use emissive textures
public
boolean
show_textures
=
true
;
// show generated textures
public
boolean
debug_filters
=
false
;
// show intermediate results of filtering
...
...
@@ -472,18 +489,7 @@ public class CLTParameters {
public
double
poles_min_strength
=
0.1
;
// Set new pole segment strength to max of horizontal correlation and this value
public
boolean
poles_force_disp
=
true
;
// Set disparity to that of the bottom of existing segment (false - use hor. disparity)
public
int
max_clusters
=
500
;
// Maximal number of clusters to generate for one run
public
boolean
remove_scans
=
true
;
// Remove all unneeded scans when generating x3d output to save memory
public
boolean
output_x3d
=
true
;
// Generate x3d output
public
boolean
output_obj
=
true
;
// Generate Wavefront obj output
public
boolean
correct_distortions
=
false
;
// Correct lens geometric distortions in a model (will need backdrop to be corrected too)
public
boolean
show_triangles
=
true
;
// Show generated triangles
public
boolean
avg_cluster_disp
=
false
;
// Weight-average disparity for the whole cluster
public
double
maxDispTriangle
=
0.2
;
// Maximal relative disparity difference in a triangle face
public
double
infinityDistance
=
10000
;
// Distance to generate backdrop (0 - use regular backdrop)
public
int
min_bgnd_tiles
=
10
;
// Minimal number of background tiles to generate background
public
boolean
shUseFlaps
=
true
;
// Split into shells with flaps
public
boolean
shAggrFade
=
false
;
// true; // Aggressive fade alpha (whole boundary)
public
int
shMinArea
=
1
;
// Minimal shell area (not counting flaps
...
...
@@ -1420,6 +1426,25 @@ public class CLTParameters {
properties
.
setProperty
(
prefix
+
"tex_color"
,
this
.
tex_color
+
""
);
// boolean
properties
.
setProperty
(
prefix
+
"tex_palette"
,
this
.
tex_palette
+
""
);
// int
properties
.
setProperty
(
prefix
+
"max_clusters"
,
this
.
max_clusters
+
""
);
properties
.
setProperty
(
prefix
+
"remove_scans"
,
this
.
remove_scans
+
""
);
properties
.
setProperty
(
prefix
+
"output_x3d"
,
this
.
output_x3d
+
""
);
properties
.
setProperty
(
prefix
+
"output_obj"
,
this
.
output_obj
+
""
);
properties
.
setProperty
(
prefix
+
"output_glTF"
,
this
.
output_glTF
+
""
);
properties
.
setProperty
(
prefix
+
"correct_distortions"
,
this
.
correct_distortions
+
""
);
properties
.
setProperty
(
prefix
+
"show_triangles"
,
this
.
show_triangles
+
""
);
properties
.
setProperty
(
prefix
+
"avg_cluster_disp"
,
this
.
avg_cluster_disp
+
""
);
properties
.
setProperty
(
prefix
+
"maxDispTriangle"
,
this
.
maxDispTriangle
+
""
);
properties
.
setProperty
(
prefix
+
"maxZtoXY"
,
this
.
maxZtoXY
+
""
);
properties
.
setProperty
(
prefix
+
"maxZ"
,
this
.
maxZ
+
""
);
properties
.
setProperty
(
prefix
+
"limitZ"
,
this
.
limitZ
+
""
);
properties
.
setProperty
(
prefix
+
"infinityDistance"
,
this
.
infinityDistance
+
""
);
properties
.
setProperty
(
prefix
+
"min_bgnd_tiles"
,
this
.
min_bgnd_tiles
+
""
);
properties
.
setProperty
(
prefix
+
"gltf_emissive"
,
this
.
gltf_emissive
+
""
);
properties
.
setProperty
(
prefix
+
"show_textures"
,
this
.
show_textures
+
""
);
properties
.
setProperty
(
prefix
+
"debug_filters"
,
this
.
debug_filters
+
""
);
...
...
@@ -1485,18 +1510,6 @@ public class CLTParameters {
properties
.
setProperty
(
prefix
+
"poles_min_strength"
,
this
.
poles_min_strength
+
""
);
properties
.
setProperty
(
prefix
+
"or_maxDisp"
,
this
.
or_maxDisp
+
""
);
properties
.
setProperty
(
prefix
+
"max_clusters"
,
this
.
max_clusters
+
""
);
properties
.
setProperty
(
prefix
+
"remove_scans"
,
this
.
remove_scans
+
""
);
properties
.
setProperty
(
prefix
+
"output_x3d"
,
this
.
output_x3d
+
""
);
properties
.
setProperty
(
prefix
+
"output_obj"
,
this
.
output_obj
+
""
);
properties
.
setProperty
(
prefix
+
"correct_distortions"
,
this
.
correct_distortions
+
""
);
properties
.
setProperty
(
prefix
+
"show_triangles"
,
this
.
show_triangles
+
""
);
properties
.
setProperty
(
prefix
+
"avg_cluster_disp"
,
this
.
avg_cluster_disp
+
""
);
properties
.
setProperty
(
prefix
+
"maxDispTriangle"
,
this
.
maxDispTriangle
+
""
);
properties
.
setProperty
(
prefix
+
"infinityDistance"
,
this
.
infinityDistance
+
""
);
properties
.
setProperty
(
prefix
+
"min_bgnd_tiles"
,
this
.
min_bgnd_tiles
+
""
);
properties
.
setProperty
(
prefix
+
"shUseFlaps"
,
this
.
shUseFlaps
+
""
);
properties
.
setProperty
(
prefix
+
"shAggrFade"
,
this
.
shAggrFade
+
""
);
properties
.
setProperty
(
prefix
+
"shMinArea"
,
this
.
shMinArea
+
""
);
...
...
@@ -2313,6 +2326,25 @@ public class CLTParameters {
if
(
properties
.
getProperty
(
prefix
+
"tex_color"
)!=
null
)
this
.
tex_color
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"tex_color"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_palette"
)!=
null
)
this
.
tex_palette
=
Integer
.
parseInt
(
properties
.
getProperty
(
prefix
+
"tex_palette"
));
if
(
properties
.
getProperty
(
prefix
+
"max_clusters"
)!=
null
)
this
.
max_clusters
=
Integer
.
parseInt
(
properties
.
getProperty
(
prefix
+
"max_clusters"
));
if
(
properties
.
getProperty
(
prefix
+
"remove_scans"
)!=
null
)
this
.
remove_scans
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"remove_scans"
));
if
(
properties
.
getProperty
(
prefix
+
"output_x3d"
)!=
null
)
this
.
output_x3d
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"output_x3d"
));
if
(
properties
.
getProperty
(
prefix
+
"output_obj"
)!=
null
)
this
.
output_obj
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"output_obj"
));
if
(
properties
.
getProperty
(
prefix
+
"output_glTF"
)!=
null
)
this
.
output_glTF
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"output_glTF"
));
if
(
properties
.
getProperty
(
prefix
+
"correct_distortions"
)!=
null
)
this
.
correct_distortions
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"correct_distortions"
));
if
(
properties
.
getProperty
(
prefix
+
"show_triangles"
)!=
null
)
this
.
show_triangles
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"show_triangles"
));
if
(
properties
.
getProperty
(
prefix
+
"avg_cluster_disp"
)!=
null
)
this
.
avg_cluster_disp
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"avg_cluster_disp"
));
if
(
properties
.
getProperty
(
prefix
+
"maxDispTriangle"
)!=
null
)
this
.
maxDispTriangle
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"maxDispTriangle"
));
if
(
properties
.
getProperty
(
prefix
+
"maxZtoXY"
)!=
null
)
this
.
maxZtoXY
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"maxZtoXY"
));
if
(
properties
.
getProperty
(
prefix
+
"maxZ"
)!=
null
)
this
.
maxZ
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"maxZ"
));
if
(
properties
.
getProperty
(
prefix
+
"limitZ"
)!=
null
)
this
.
limitZ
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"limitZ"
));
if
(
properties
.
getProperty
(
prefix
+
"infinityDistance"
)!=
null
)
this
.
infinityDistance
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"infinityDistance"
));
if
(
properties
.
getProperty
(
prefix
+
"min_bgnd_tiles"
)!=
null
)
this
.
min_bgnd_tiles
=
Integer
.
parseInt
(
properties
.
getProperty
(
prefix
+
"min_bgnd_tiles"
));
if
(
properties
.
getProperty
(
prefix
+
"gltf_emissive"
)!=
null
)
this
.
gltf_emissive
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"gltf_emissive"
));
if
(
properties
.
getProperty
(
prefix
+
"show_textures"
)!=
null
)
this
.
show_textures
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"show_textures"
));
if
(
properties
.
getProperty
(
prefix
+
"debug_filters"
)!=
null
)
this
.
debug_filters
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"debug_filters"
));
...
...
@@ -2378,16 +2410,6 @@ public class CLTParameters {
if
(
properties
.
getProperty
(
prefix
+
"poles_min_strength"
)!=
null
)
this
.
poles_min_strength
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"poles_min_strength"
));
if
(
properties
.
getProperty
(
prefix
+
"poles_force_disp"
)!=
null
)
this
.
poles_force_disp
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"poles_force_disp"
));
if
(
properties
.
getProperty
(
prefix
+
"max_clusters"
)!=
null
)
this
.
max_clusters
=
Integer
.
parseInt
(
properties
.
getProperty
(
prefix
+
"max_clusters"
));
if
(
properties
.
getProperty
(
prefix
+
"remove_scans"
)!=
null
)
this
.
remove_scans
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"remove_scans"
));
if
(
properties
.
getProperty
(
prefix
+
"output_x3d"
)!=
null
)
this
.
output_x3d
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"output_x3d"
));
if
(
properties
.
getProperty
(
prefix
+
"output_obj"
)!=
null
)
this
.
output_obj
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"output_obj"
));
if
(
properties
.
getProperty
(
prefix
+
"correct_distortions"
)!=
null
)
this
.
correct_distortions
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"correct_distortions"
));
if
(
properties
.
getProperty
(
prefix
+
"show_triangles"
)!=
null
)
this
.
show_triangles
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"show_triangles"
));
if
(
properties
.
getProperty
(
prefix
+
"avg_cluster_disp"
)!=
null
)
this
.
avg_cluster_disp
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"avg_cluster_disp"
));
if
(
properties
.
getProperty
(
prefix
+
"maxDispTriangle"
)!=
null
)
this
.
maxDispTriangle
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"maxDispTriangle"
));
if
(
properties
.
getProperty
(
prefix
+
"infinityDistance"
)!=
null
)
this
.
infinityDistance
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"infinityDistance"
));
if
(
properties
.
getProperty
(
prefix
+
"min_bgnd_tiles"
)!=
null
)
this
.
min_bgnd_tiles
=
Integer
.
parseInt
(
properties
.
getProperty
(
prefix
+
"min_bgnd_tiles"
));
if
(
properties
.
getProperty
(
prefix
+
"shUseFlaps"
)!=
null
)
this
.
shUseFlaps
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"shUseFlaps"
));
if
(
properties
.
getProperty
(
prefix
+
"shAggrFade"
)!=
null
)
this
.
shAggrFade
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"shAggrFade"
));
if
(
properties
.
getProperty
(
prefix
+
"shMinArea"
)!=
null
)
this
.
shMinArea
=
Integer
.
parseInt
(
properties
.
getProperty
(
prefix
+
"shMinArea"
));
...
...
@@ -3352,6 +3374,7 @@ public class CLTParameters {
"Maximal texture distortion to accumulate multiple scenes (neighbor tile center offset from the uniform grid. 0 - do not filter"
);
gd
.
addNumericField
(
"Maximal motion blur to reduce weight"
,
this
.
tex_mb
,
5
,
7
,
"pix"
,
"Reduce texture weight if motion blur exceeds this (as square of MB length)."
);
gd
.
addMessage
(
"Textures rendering"
);
gd
.
addCheckbox
(
"Apply unsharp mask"
,
this
.
tex_um
,
"Use unsharp mask filter for texture."
);
...
...
@@ -3378,6 +3401,41 @@ public class CLTParameters {
gd
.
addNumericField
(
"Palette number"
,
this
.
tex_palette
,
0
,
3
,
""
,
"Palette number for pseudo colors."
);
gd
.
addMessage
(
"Triangulation"
);
gd
.
addNumericField
(
"Maximal output meshes"
,
this
.
max_clusters
,
0
,
3
,
""
,
"Maximal number of output meshes to generate."
);
gd
.
addCheckbox
(
"Remove all unneeded scans before x3d"
,
this
.
remove_scans
,
"Remove all unneeded scans when generating x3d output to save memory (old)."
);
gd
.
addCheckbox
(
"Generate x3d"
,
this
.
output_x3d
,
"Generate x3d output."
);
gd
.
addCheckbox
(
"Generate Wavefront obj"
,
this
.
output_obj
,
"Generate Wavefront obj output."
);
gd
.
addCheckbox
(
"Generate glTF output"
,
this
.
output_glTF
,
"Generate glTF output."
);
gd
.
addCheckbox
(
"Correct lens distortions in a model"
,
this
.
correct_distortions
,
"Correct lens geometric distortions in a model (will need backdrop to be corrected too)"
);
gd
.
addCheckbox
(
"Show triangles"
,
this
.
show_triangles
,
"Show generated triangles."
);
gd
.
addCheckbox
(
"Same cluster disparity"
,
this
.
avg_cluster_disp
,
"Weight-average disparity for the whole cluster."
);
gd
.
addNumericField
(
"Maximal relative disparity difference"
,
this
.
maxDispTriangle
,
4
,
6
,
""
,
"Maximal relative disparity difference in a triangle face to show."
);
gd
.
addNumericField
(
"Maximal world dz to dx,dy"
,
this
.
maxZtoXY
,
4
,
6
,
""
,
"Maximal world dz to dx,dy of a triangular face to show"
);
gd
.
addNumericField
(
"Maximal world Z"
,
this
.
maxZ
,
4
,
6
,
"m"
,
"Maximal absolute distance."
);
gd
.
addCheckbox
(
"Clamp Z"
,
this
.
limitZ
,
"Replace too far distance with the maximal one. If false - remove triangle faces that havce too far vertices."
);
gd
.
addNumericField
(
"Distance to a backdrop"
,
this
.
infinityDistance
,
8
,
8
,
"m"
,
"Distance to generate backdrop (0 - use regular backdrop)."
);
gd
.
addNumericField
(
"Minimal background tiles"
,
this
.
min_bgnd_tiles
,
0
,
4
,
""
,
"Minimal number of background tiles to generate background."
);
gd
.
addMessage
(
"glTF export"
);
gd
.
addCheckbox
(
"glTF use emissive textures"
,
this
.
gltf_emissive
);
gd
.
addMessage
(
"Earlier 3D generation parameters"
);
gd
.
addCheckbox
(
"Show generated textures"
,
this
.
show_textures
);
gd
.
addCheckbox
(
"show intermediate results of filtering"
,
this
.
debug_filters
);
...
...
@@ -3456,16 +3514,6 @@ public class CLTParameters {
gd
.
addNumericField
(
"Set new pole segment strength to max of horizontal correlation and this value"
,
this
.
poles_min_strength
,
3
);
gd
.
addCheckbox
(
"Set disparity to that of the bottom of existing segment (false - use hor. disparity)"
,
this
.
poles_force_disp
);
gd
.
addNumericField
(
"Maximal number of output meshes to generate"
,
this
.
max_clusters
,
0
);
gd
.
addCheckbox
(
"Remove all unneeded scans when generating x3d output to save memory"
,
this
.
remove_scans
);
gd
.
addCheckbox
(
"Generate x3d output"
,
this
.
output_x3d
);
gd
.
addCheckbox
(
"Generate Wavefront obj output"
,
this
.
output_obj
);
gd
.
addCheckbox
(
"Correct lens geometric distortions in a model (will need backdrop to be corrected too)"
,
this
.
correct_distortions
);
gd
.
addCheckbox
(
"Show generated triangles"
,
this
.
show_triangles
);
gd
.
addCheckbox
(
"Weight-average disparity for the whole cluster "
,
this
.
avg_cluster_disp
);
gd
.
addNumericField
(
"Maximal disparity difference in a triangle face to show"
,
this
.
maxDispTriangle
,
6
);
gd
.
addNumericField
(
"Distance to generate backdrop (0 - use regular backdrop)"
,
this
.
infinityDistance
,
8
);
gd
.
addNumericField
(
" Minimal number of background tiles to generate background"
,
this
.
min_bgnd_tiles
,
0
);
gd
.
addCheckbox
(
"Split into shells with flaps"
,
this
.
shUseFlaps
);
gd
.
addCheckbox
(
"Aggressive fade alpha (whole boundary)"
,
this
.
shAggrFade
);
...
...
@@ -4407,6 +4455,25 @@ public class CLTParameters {
this
.
tex_color
=
gd
.
getNextBoolean
();
this
.
tex_palette
=
(
int
)
gd
.
getNextNumber
();
this
.
max_clusters
=
(
int
)
gd
.
getNextNumber
();
this
.
remove_scans
=
gd
.
getNextBoolean
();
this
.
output_x3d
=
gd
.
getNextBoolean
();
this
.
output_obj
=
gd
.
getNextBoolean
();
this
.
output_glTF
=
gd
.
getNextBoolean
();
this
.
correct_distortions
=
gd
.
getNextBoolean
();
this
.
show_triangles
=
gd
.
getNextBoolean
();
this
.
avg_cluster_disp
=
gd
.
getNextBoolean
();
this
.
maxDispTriangle
=
gd
.
getNextNumber
();
this
.
maxZtoXY
=
gd
.
getNextNumber
();
this
.
maxZ
=
gd
.
getNextNumber
();
this
.
limitZ
=
gd
.
getNextBoolean
();
this
.
infinityDistance
=
gd
.
getNextNumber
();
this
.
min_bgnd_tiles
=
(
int
)
gd
.
getNextNumber
();
this
.
gltf_emissive
=
gd
.
getNextBoolean
();
this
.
show_textures
=
gd
.
getNextBoolean
();
this
.
debug_filters
=
gd
.
getNextBoolean
();
this
.
min_smth
=
gd
.
getNextNumber
();
...
...
@@ -4471,16 +4538,6 @@ public class CLTParameters {
this
.
poles_min_strength
=
gd
.
getNextNumber
();
this
.
poles_force_disp
=
gd
.
getNextBoolean
();
this
.
max_clusters
=
(
int
)
gd
.
getNextNumber
();
this
.
remove_scans
=
gd
.
getNextBoolean
();
this
.
output_x3d
=
gd
.
getNextBoolean
();
this
.
output_obj
=
gd
.
getNextBoolean
();
this
.
correct_distortions
=
gd
.
getNextBoolean
();
this
.
show_triangles
=
gd
.
getNextBoolean
();
this
.
avg_cluster_disp
=
gd
.
getNextBoolean
();
this
.
maxDispTriangle
=
gd
.
getNextNumber
();
this
.
infinityDistance
=
gd
.
getNextNumber
();
this
.
min_bgnd_tiles
=
(
int
)
gd
.
getNextNumber
();
this
.
shUseFlaps
=
gd
.
getNextBoolean
();
this
.
shAggrFade
=
gd
.
getNextBoolean
();
this
.
shMinArea
=
(
int
)
gd
.
getNextNumber
();
...
...
src/main/java/com/elphel/imagej/tileprocessor/OpticalFlow.java
View file @
4e6966e0
...
...
@@ -903,7 +903,7 @@ public class OpticalFlow {
* @param debug_level if > 0; print number of tiles to correlate
* @return flowXY vectors only for tiles to be updated or null if no tiles left
*/
double
[][]
recalculateFlowXY
(
static
double
[][]
recalculateFlowXY
(
final
double
[][]
flowXY
,
// will update
final
double
[][]
flowXY_prev
,
// previous flowXY (may be null for tiles)
final
double
[][]
corr_vectorsXY
,
...
...
src/main/java/com/elphel/imagej/tileprocessor/QuadCLTCPU.java
View file @
4e6966e0
...
...
@@ -65,6 +65,7 @@ import com.elphel.imagej.correction.EyesisCorrections;
import
com.elphel.imagej.gpu.GpuQuad
;
import
com.elphel.imagej.gpu.TpTask
;
import
com.elphel.imagej.readers.ImagejJp4Tiff
;
import
com.elphel.imagej.x3d.export.TriMesh
;
import
com.elphel.imagej.x3d.export.WavefrontExport
;
import
com.elphel.imagej.x3d.export.X3dOutput
;
...
...
@@ -7552,11 +7553,11 @@ public class QuadCLTCPU {
double
[]
rel_lim
=
{
getMarginFromHist
(
hist
,
// histogram
too_cold
,
// double cumul_val, // cum
m
ulative number of items to be ignored
too_cold
,
// double cumul_val, // cumulative number of items to be ignored
false
),
// boolean high_marg)
getMarginFromHist
(
hist
,
// histogram
too_hot
,
// double cumul_val, // cum
m
ulative number of items to be ignored
too_hot
,
// double cumul_val, // cumulative number of items to be ignored
true
)};
// boolean high_marg)
double
[]
abs_lim
=
{
rel_lim
[
0
]
*
(
hard_hot
-
hard_cold
)
+
hard_cold
,
...
...
@@ -12455,6 +12456,7 @@ public class QuadCLTCPU {
double
infinity_disparity
=
geometryCorrection
.
getDisparityFromZ
(
clt_parameters
.
infinityDistance
);
X3dOutput
x3dOutput
=
null
;
WavefrontExport
wfOutput
=
null
;
ArrayList
<
TriMesh
>
tri_meshes
=
null
;
if
(
clt_parameters
.
remove_scans
){
System
.
out
.
println
(
"Removing all scans but the first(background) and the last to save memory"
);
System
.
out
.
println
(
"Will need to re-start the program to be able to output differently"
);
...
...
@@ -12503,6 +12505,10 @@ public class QuadCLTCPU {
// do nothing, just keep
}
}
if
(
clt_parameters
.
output_glTF
&&
(
x3d_path
!=
null
))
{
tri_meshes
=
new
ArrayList
<
TriMesh
>();
}
if
(
x3dOutput
!=
null
)
{
x3dOutput
.
generateBackground
(
clt_parameters
.
infinityDistance
<=
0.0
);
// needs just first (background) scan
}
...
...
@@ -12579,6 +12585,7 @@ public class QuadCLTCPU {
generateClusterX3d
(
x3dOutput
,
wfOutput
,
// output WSavefront if not null
tri_meshes
,
// ArrayList<TriMesh> tri_meshes,
texturePath
,
"INFINITY"
,
// id (scanIndex - next_pass), // id
"INFINITY"
,
// class
...
...
@@ -12590,7 +12597,11 @@ public class QuadCLTCPU {
showTri
,
// (scanIndex < next_pass + 1) && clt_parameters.show_triangles,
infinity_disparity
,
// 0.3
clt_parameters
.
grow_disp_max
,
// other_range, // 2.0 'other_range - difference from the specified (*_CM)
clt_parameters
.
maxDispTriangle
);
clt_parameters
.
maxDispTriangle
,
clt_parameters
.
maxZtoXY
,
// double maxZtoXY, // 10.0. <=0 - do not use
clt_parameters
.
maxZ
,
clt_parameters
.
limitZ
,
debugLevel
+
1
);
// int debug_level) > 0
}
catch
(
IOException
e
)
{
// TODO Auto-generated catch block
e
.
printStackTrace
();
...
...
@@ -12668,11 +12679,11 @@ public class QuadCLTCPU {
}
}
boolean
showTri
=
!
batch_mode
&&
(
debugLevel
>
-
1
)
&&
(((
scanIndex
<
next_pass
+
1
)
&&
clt_parameters
.
show_triangles
)
||((
scanIndex
-
next_pass
)
==
73
));
try
{
generateClusterX3d
(
x3dOutput
,
wfOutput
,
// output WSavefront if not null
tri_meshes
,
// ArrayList<TriMesh> tri_meshes,
texturePath
,
"shape_id-"
+(
scanIndex
-
next_pass
),
// id
null
,
// class
...
...
@@ -12685,7 +12696,11 @@ public class QuadCLTCPU {
// FIXME: make a separate parameter:
infinity_disparity
,
// 0.25 * clt_parameters.bgnd_range, // 0.3
clt_parameters
.
grow_disp_max
,
// other_range, // 2.0 'other_range - difference from the specified (*_CM)
clt_parameters
.
maxDispTriangle
);
clt_parameters
.
maxDispTriangle
,
clt_parameters
.
maxZtoXY
,
// double maxZtoXY, // 10.0. <=0 - do not use
clt_parameters
.
maxZ
,
clt_parameters
.
limitZ
,
debugLevel
+
1
);
// int debug_level) > 0
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
return
false
;
...
...
@@ -12718,6 +12733,7 @@ public class QuadCLTCPU {
public
void
generateClusterX3d
(
// USED in lwir
X3dOutput
x3dOutput
,
// output x3d if not null
WavefrontExport
wfOutput
,
// output WSavefront if not null
ArrayList
<
TriMesh
>
tri_meshes
,
String
texturePath
,
String
id
,
String
class_name
,
...
...
@@ -12729,18 +12745,23 @@ public class QuadCLTCPU {
boolean
show_triangles
,
double
min_disparity
,
double
max_disparity
,
double
maxDispTriangle
double
maxDispTriangle
,
// relative <=0 - do not use
double
maxZtoXY
,
// 10.0. <=0 - do not use
double
maxZ
,
// far clip (0 - do not clip). Negative - limit by max
boolean
limitZ
,
int
debug_level
)
throws
IOException
{
// int debug_level = 1;
if
(
bounds
==
null
)
{
return
;
// not used in lwir
}
int
[][]
indices
=
tp
.
getCoordIndices
(
// starting with 0, -1 - not selected
int
[][]
indices
=
tp
.
getCoordIndices
(
// starting with 0, -1 - not selected
// updated 09.18.2022
bounds
,
selected
);
double
[][]
texCoord
=
TileProcessor
.
getTexCoords
(
// get texture coordinates for indices
indices
);
double
[][]
worldXYZ
=
tp
.
getCoords
(
// get world XYZ in meters for indices
double
[][]
worldXYZ
=
tp
.
getCoords
(
// get world XYZ in meters for indices
// updated 09.18.2022
disparity
,
min_disparity
,
max_disparity
,
...
...
@@ -12750,7 +12771,7 @@ public class QuadCLTCPU {
correctDistortions
,
// requires backdrop image to be corrected also
this
.
geometryCorrection
);
double
[]
indexedDisparity
=
tp
.
getIndexedDisparities
(
// get disparity for each index
double
[]
indexedDisparity
=
tp
.
getIndexedDisparities
(
// get disparity for each index
// updated 09.18.2022
disparity
,
min_disparity
,
max_disparity
,
...
...
@@ -12761,12 +12782,83 @@ public class QuadCLTCPU {
int
[][]
triangles
=
TileProcessor
.
triangulateCluster
(
indices
);
// double maxZtoXY = 10.0; // maximal delta_z to sqrt(dx^23 + dy^2)
int
num_removed
=
0
;
if
(
maxDispTriangle
>
0.0
)
{
int
pre_num
=
triangles
.
length
;
triangles
=
TileProcessor
.
filterTriangles
(
// remove crazy triangles with large disparity difference
triangles
,
indexedDisparity
,
// disparities per vertex index
maxDispTriangle
);
// maximal disparity difference in a triangle
maxDispTriangle
,
// maximal disparity difference in a triangle
debug_level
+
0
);
// int debug_level);
if
(
triangles
.
length
<
pre_num
)
{
num_removed
+=
pre_num
-
triangles
.
length
;
if
(
debug_level
>
0
)
{
System
.
out
.
println
(
"filterTriangles() removed "
+
(
pre_num
-
triangles
.
length
)+
" triangles"
);
}
}
}
if
((
maxZ
!=
0.0
)
&&
limitZ
)
{
for
(
int
i
=
0
;
i
<
worldXYZ
.
length
;
i
++)
{
if
(
worldXYZ
[
i
][
2
]
<
-
maxZ
)
{
double
k
=
-
maxZ
/
worldXYZ
[
i
][
2
];
worldXYZ
[
i
][
0
]
*=
k
;
worldXYZ
[
i
][
1
]
*=
k
;
worldXYZ
[
i
][
2
]
*=
k
;
}
}
}
if
((
maxZtoXY
>
0.0
)
||
((
maxZ
!=
0
)
&&
!
limitZ
)
)
{
int
pre_num
=
triangles
.
length
;
triangles
=
TileProcessor
.
filterTrianglesWorld
(
triangles
,
worldXYZ
,
// world per vertex index
maxZtoXY
,
maxZ
);
if
(
triangles
.
length
<
pre_num
)
{
num_removed
+=
pre_num
-
triangles
.
length
;
if
(
debug_level
>
0
)
{
System
.
out
.
println
(
"filterTrianglesWorld() removed "
+
(
pre_num
-
triangles
.
length
)+
" triangles"
);
}
}
}
if
(
triangles
.
length
==
0
)
{
if
(
debug_level
>
0
)
{
System
.
out
.
println
(
"generateClusterX3d() no triangles left in a cluster"
);
}
return
;
// all triangles removed
}
if
(
num_removed
>
0
)
{
int
[]
re_index
=
TileProcessor
.
reIndex
(
// Move to TriMesh?
indices
,
// will be modified if needed (if some indices are removed
triangles
);
if
(
re_index
!=
null
)
{
// need to update other arrays: texCoord, worldXYZ. indexedDisparity[] will not be used
int
num_indices_old
=
worldXYZ
.
length
;
int
[]
inv_index
=
new
int
[
num_indices_old
];
Arrays
.
fill
(
inv_index
,-
1
);
// just to get an error
for
(
int
i
=
0
;
i
<
re_index
.
length
;
i
++)
{
inv_index
[
re_index
[
i
]]
=
i
;
}
double
[][]
texCoord_new
=
new
double
[
re_index
.
length
][];
double
[][]
worldXYZ_new
=
new
double
[
re_index
.
length
][];
for
(
int
i
=
0
;
i
<
re_index
.
length
;
i
++)
{
texCoord_new
[
i
]
=
texCoord
[
re_index
[
i
]];
worldXYZ_new
[
i
]
=
worldXYZ
[
re_index
[
i
]];
}
texCoord
=
texCoord_new
;
worldXYZ
=
worldXYZ_new
;
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
triangles
[
i
].
length
;
j
++)
{
triangles
[
i
][
j
]
=
inv_index
[
triangles
[
i
][
j
]];
}
}
}
if
(
debug_level
>
0
)
{
show_triangles
=
true
;
// show after removed
}
}
if
(
show_triangles
)
{
double
[]
ddisp
=
(
disparity
==
null
)?(
new
double
[
1
]):
disparity
;
...
...
@@ -12800,6 +12892,13 @@ public class QuadCLTCPU {
worldXYZ
,
triangles
);
}
if
(
tri_meshes
!=
null
)
{
tri_meshes
.
add
(
new
TriMesh
(
texturePath
,
// String texture_image,
worldXYZ
,
// double [][] worldXYZ,
texCoord
,
// double [][] texCoord,
triangles
));
// int [][] triangles
}
}
...
...
src/main/java/com/elphel/imagej/tileprocessor/TexturedModel.java
View file @
4e6966e0
...
...
@@ -28,6 +28,8 @@ import java.util.ArrayList;
import
java.util.Arrays
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
org.json.JSONException
;
import
com.elphel.imagej.cameras.CLTParameters
;
import
com.elphel.imagej.cameras.ColorProcParameters
;
import
com.elphel.imagej.cameras.EyesisCorrectionParameters
;
...
...
@@ -35,6 +37,8 @@ import com.elphel.imagej.common.ShowDoubleFloatArrays;
import
com.elphel.imagej.correction.EyesisCorrections
;
import
com.elphel.imagej.gpu.GpuQuad
;
import
com.elphel.imagej.gpu.TpTask
;
import
com.elphel.imagej.x3d.export.GlTfExport
;
import
com.elphel.imagej.x3d.export.TriMesh
;
import
com.elphel.imagej.x3d.export.WavefrontExport
;
import
com.elphel.imagej.x3d.export.X3dOutput
;
...
...
@@ -92,7 +96,7 @@ public class TexturedModel {
}
}
final
int
dbg_tile
=
(
debugLevel
>
0
)?
2021
:-
1
;
// 977 : -1;
final
int
dbg_tile
=
(
debugLevel
>
0
)?
1090
:-
1
;
// 977 : -1;
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
...
...
@@ -481,7 +485,7 @@ public class TexturedModel {
for
(
int
i
=
0
;
i
<
comb_clusters
.
length
;
i
++)
{
consolidated_clusters
[
comb_clusters
[
i
]].
add
(
cluster_list
.
get
(
i
));
}
// incorrectly combined - first combo has only one cluster and NaN in the areas where other clusters could fit
if
(
debugLevel
>
0
)
{
double
[][]
dbg_img
=
new
double
[
this_combo
][
tiles
];
double
[][]
dbg_borders
=
new
double
[
this_combo
][
tiles
];
...
...
@@ -538,6 +542,7 @@ public class TexturedModel {
final
int
debugLevel
)
{
final
boolean
batch_mode
=
clt_parameters
.
batch_run
;
final
boolean
gltf_emissive
=
clt_parameters
.
gltf_emissive
;
final
int
ref_index
=
scenes
.
length
-
1
;
final
QuadCLT
ref_scene
=
scenes
[
ref_index
];
final
TileProcessor
tp
=
ref_scene
.
getTileProcessor
();
...
...
@@ -547,6 +552,7 @@ public class TexturedModel {
double
infinity_disparity
=
ref_scene
.
getGeometryCorrection
().
getDisparityFromZ
(
clt_parameters
.
infinityDistance
);
X3dOutput
x3dOutput
=
null
;
WavefrontExport
wfOutput
=
null
;
ArrayList
<
TriMesh
>
tri_meshes
=
null
;
long
startStepTime
=
System
.
nanoTime
();
final
int
tilesX
=
tp
.
getTilesX
();
final
int
tilesY
=
tp
.
getTilesY
();
...
...
@@ -609,15 +615,15 @@ public class TexturedModel {
TileCluster
[]
tileClusters
=
clusterizeFgBg
(
// wrong result type, not decided
tilesX
,
// final int tilesX,
ds_fg_bg
,
// final double [][] disparities, // may have more layers
sky_invert
,
// final boolean [] selected, // to remove sky (pre-filter by caller, like for ML?)
null
,
//
sky_invert, // final boolean [] selected, // to remove sky (pre-filter by caller, like for ML?)
tex_disp_adiffo
,
// final double disp_adiffo,
tex_disp_rdiffo
,
// final double disp_rdiffo,
tex_disp_adiffd
,
// final double disp_adiffd,
tex_disp_rdiffd
,
// final double disp_rdiffd,
tex_disp_fof
,
// final double disp_fof, // enable higher difference (scale) for fried of a friend
debugLevel
);
//1); // 2); // final int debugLevel)
double
[][]
inter_weights
=
new
double
[
tilesY
][
tilesX
];
// per-tile texture weights for inter-scene accumulation;
double
[][][][]
inter_textures
=
new
double
[
tilesY
][
tilesX
][][];
// [channel][256] - non-overlapping textures
//
double [][] inter_weights = new double [tilesY][tilesX]; // per-tile texture weights for inter-scene accumulation;
//
double [][][][] inter_textures= new double [tilesY][tilesX][][]; // [channel][256] - non-overlapping textures
boolean
[]
scenes_sel
=
new
boolean
[
scenes
.
length
];
// for (int i = scenes.length - 10; i < scenes.length; i++) { // start with just one (reference) scene
for
(
int
i
=
0
;
i
<
scenes
.
length
;
i
++)
{
// start with just one (reference) scene
...
...
@@ -638,15 +644,9 @@ public class TexturedModel {
renormalize
,
// final boolean renormalize, // false - use normalizations from previous scenes to keep consistent colors
debugLevel
);
// final int debug_level)
boolean
save_full_textures
=
false
;
// true;
boolean
save_full_textures
=
true
;
//
false; // true;
EyesisCorrectionParameters
.
CorrectionParameters
correctionsParameters
=
ref_scene
.
correctionsParameters
;
String
x3d_dir
=
correctionsParameters
.
selectX3dDirectory
(
//TODO: Which one to use - name or this.image_name ?
correctionsParameters
.
getModelName
(
ref_scene
.
getImageName
()),
// quad timestamp. Will be ignored if correctionsParameters.use_x3d_subdirs is false
correctionsParameters
.
x3dModelVersion
,
true
,
// smart,
true
);
//newAllowed, // save
String
x3d_dir
=
ref_scene
.
getX3dDirectory
();
if
(
save_full_textures
)
{
for
(
int
nslice
=
0
;
nslice
<
combined_textures
.
length
;
nslice
++)
{
EyesisCorrections
.
saveAndShow
(
...
...
@@ -658,8 +658,7 @@ public class TexturedModel {
1
);
//
}
}
boolean
save_individual_textures
=
true
;
if
(
save_individual_textures
)
{
// Maybe will switch to combined textures (less files)
ImagePlus
[]
imp_textures
=
splitCombinedTextures
(
tileClusters
,
// TileCluster [] tileClusters, //should have name <timestamp>-*
transform_size
,
// int transform_size,
...
...
@@ -673,61 +672,28 @@ public class TexturedModel {
-
1
,
// jpegQuality){// <0 - keep current, 0 - force Tiff, >0 use for JPEG
1
);
//
}
}
if
(
debugLevel
>
-
100
)
{
return
true
;
}
ArrayList
<
CLTPass3d
>
clt_3d_passes
=
new
ArrayList
<
CLTPass3d
>();
// will use its own passes
int
next_pass
=
1
;
// temporarily
/*
if (clt_parameters.remove_scans){
System.out.println("Removing all scans but the first(background) and the last to save memory");
System.out.println("Will need to re-start the program to be able to output differently");
CLTPass3d latest_scan = tp.clt_3d_passes.get(tp.clt_3d_passes.size() - 1);
tp.trimCLTPasses(1);
tp.clt_3d_passes.add(latest_scan); // put it back
}
int next_pass = tp.clt_3d_passes.size(); //
// Create tasks to scan, have tasks, disparity and border tiles in tp.clt_3d_passes
tp.thirdPassSetupSurf( // prepare tile tasks for the second pass based on the previous one(s) // needs last scan
clt_parameters,
//FIXME: make a special parameter?
infinity_disparity, //0.25 * clt_parameters.bgnd_range, // double disparity_far,
clt_parameters.grow_disp_max, // other_range, //double disparity_near, //
ref_scene.getGeometryCorrection(),
threadsMax, // maximal number of threads to launch
updateStatus,
0); // final int debugLevel)
*/
// if (debugLevel > -100) {
// return true;
// }
if
(!
batch_mode
&&
(
debugLevel
>
-
1
))
{
tp
.
showScan
(
tp
.
clt_3d_passes
.
get
(
next_pass
-
1
),
// CLTPass3d scan,
"after_pass3-"
+(
next_pass
-
1
));
//String title)
}
String
x3d_path
=
ref_scene
.
getX3dDirectory
();
// create x3d file
if
(
clt_parameters
.
output_x3d
)
{
x3dOutput
=
new
X3dOutput
(
clt_parameters
,
ref_scene
.
correctionsParameters
,
ref_scene
.
getGeometryCorrection
(),
tp
.
clt_3d_passes
);
null
);
//
tp.clt_3d_passes);
}
if
(
clt_parameters
.
output_obj
&&
(
x3d_
path
!=
null
))
{
if
(
clt_parameters
.
output_obj
&&
(
x3d_
dir
!=
null
))
{
try
{
wfOutput
=
new
WavefrontExport
(
x3d_
path
,
x3d_
dir
,
ref_scene
.
correctionsParameters
.
getModelName
(
ref_scene
.
getImageName
()),
clt_parameters
,
ref_scene
.
correctionsParameters
,
ref_scene
.
getGeometryCorrection
(),
tp
.
clt_3d_passes
);
null
);
//
tp.clt_3d_passes);
}
catch
(
IOException
e
)
{
System
.
out
.
println
(
"Failed to open Wavefront files for writing"
);
// TODO Auto-generated catch block
...
...
@@ -735,164 +701,58 @@ public class TexturedModel {
// do nothing, just keep
}
}
if
(
x3dOutput
!=
null
)
{
x3dOutput
.
generateBackground
(
clt_parameters
.
infinityDistance
<=
0.0
);
// needs just first (background) scan
}
int
bgndIndex
=
0
;
// it already exists?
CLTPass3d
bgndScan
=
tp
.
clt_3d_passes
.
get
(
bgndIndex
);
//TODO make it w/o need for bgndScan.texture as GPU will calculate texture right before output
//use selection? or texture_selection instead?
if
(
bgndScan
.
texture
!=
null
)
{
// TODO: same for the backdrop too
if
(
clt_parameters
.
infinityDistance
>
0.0
){
// generate background as a billboard
// grow selection, then grow once more and create border_tiles
// create/rstore, probably not needed
boolean
[]
bg_sel_backup
=
bgndScan
.
getSelected
().
clone
();
boolean
[]
bg_border_backup
=
(
bgndScan
.
getBorderTiles
()
==
null
)
?
null
:
bgndScan
.
getBorderTiles
().
clone
();
boolean
[]
bg_selected
=
bgndScan
.
getSelected
();
boolean
[]
border_tiles
=
bg_selected
.
clone
();
tp
.
growTiles
(
2
,
// grow tile selection by 1 over non-background tiles 1: 4 directions, 2 - 8 directions, 3 - 8 by 1, 4 by 1 more
bg_selected
,
null
);
// prohibit
for
(
int
i
=
0
;
i
<
border_tiles
.
length
;
i
++){
border_tiles
[
i
]
=
!
border_tiles
[
i
]
&&
bg_selected
[
i
];
}
// update texture_tiles (remove what is known not to be background
if
(
bgndScan
.
texture_tiles
!=
null
)
{
// for CPU
for
(
int
ty
=
0
;
ty
<
tilesY
;
ty
++){
for
(
int
tx
=
0
;
tx
<
tilesX
;
tx
++){
if
(!
bg_selected
[
tx
+
tilesX
*
ty
]){
bgndScan
.
texture_tiles
[
ty
][
tx
]
=
null
;
//
if
(
clt_parameters
.
output_glTF
&&
(
x3d_dir
!=
null
))
{
tri_meshes
=
new
ArrayList
<
TriMesh
>();
}
}
}
}
else
{
// for GPU
for
(
int
i
=
0
;
i
<
bg_selected
.
length
;
i
++)
{
if
(!
bg_selected
[
i
])
{
bgndScan
.
setTextureSelection
(
i
,
false
);
}
}
if
(
x3dOutput
!=
null
)
{
// 09.18.2022 For now - skipping background
x3dOutput
.
generateBackground
(
clt_parameters
.
infinityDistance
<=
0.0
);
// needs just first (background) scan
}
//TODO2020: set texture_selection
bgndScan
.
setBorderTiles
(
border_tiles
);
// limit tile_op to selection?
// updates selection from non-null texture tiles
String
texturePath
=
ref_scene
.
getPassImage
(
// get image from a single pass - both CPU and GPU
clt_parameters
,
colorProcParameters
,
rgbParameters
,
ref_scene
.
correctionsParameters
.
getModelName
(
ref_scene
.
getImageName
())+
"-img_infinity"
,
// +scanIndex,
bgndIndex
,
THREADS_MAX
,
// maximal number of threads to launch
updateStatus
,
batch_mode
?
-
5
:
debugLevel
);
if
(
texturePath
!=
null
)
{
// null if empty image
double
[]
scan_disparity
=
new
double
[
tilesX
*
tilesY
];
int
indx
=
0
;
// boolean [] scan_selected = scan.getSelected();
for
(
int
ty
=
0
;
ty
<
tilesY
;
ty
++)
for
(
int
tx
=
0
;
tx
<
tilesX
;
tx
++){
scan_disparity
[
indx
++]
=
infinity_disparity
;
}
// tp.showScan(
// scan, // CLTPass3d scan,
// "infinityDistance");
// 09.18.2022 - skipping background generation
boolean
showTri
=
false
;
// ((scanIndex < next_pass + 1) && clt_parameters.show_triangles) ||((scanIndex - next_pass) == 73);
try
{
ref_scene
.
generateClusterX3d
(
x3dOutput
,
wfOutput
,
// output WSavefront if not null
texturePath
,
"INFINITY"
,
// id (scanIndex - next_pass), // id
"INFINITY"
,
// class
bgndScan
.
getTextureBounds
(),
bgndScan
.
getSelected
(),
// selected,
scan_disparity
,
// scan.disparity_map[ImageDtt.DISPARITY_INDEX_CM],
clt_parameters
.
transform_size
,
clt_parameters
.
correct_distortions
,
// requires backdrop image to be corrected also
showTri
,
// (scanIndex < next_pass + 1) && clt_parameters.show_triangles,
infinity_disparity
,
// 0.3
clt_parameters
.
grow_disp_max
,
// other_range, // 2.0 'other_range - difference from the specified (*_CM)
clt_parameters
.
maxDispTriangle
);
}
catch
(
IOException
e
)
{
// TODO Auto-generated catch block
e
.
printStackTrace
();
return
false
;
}
// maybe not needed
bgndScan
.
setBorderTiles
(
bg_border_backup
);
bgndScan
.
setSelected
(
bg_sel_backup
);
}
}
}
// With GPU - do nothing here or copy selected -> texture_selection?
for
(
int
scanIndex
=
next_pass
;
scanIndex
<
tp
.
clt_3d_passes
.
size
();
scanIndex
++){
if
(
debugLevel
>
0
){
System
.
out
.
println
(
"FPGA processing scan #"
+
scanIndex
);
int
num_clusters
=
-
1
;
for
(
int
nscene
=
0
;
nscene
<
tileClusters
.
length
;
nscene
++)
{
for
(
int
indx:
tileClusters
[
nscene
].
getSubIndices
())
{
if
(
indx
>
num_clusters
)
num_clusters
=
indx
;
}
ref_scene
.
CLTMeasureTextures
(
// has GPU version - will just copy selection
clt_parameters
,
scanIndex
,
THREADS_MAX
,
// maximal number of threads to launch
updateStatus
,
batch_mode
?
-
5
:
debugLevel
);
}
num_clusters
++;
for
(
int
scanIndex
=
next_pass
;
(
scanIndex
<
tp
.
clt_3d_passes
.
size
())
&&
(
scanIndex
<
clt_parameters
.
max_clusters
);
scanIndex
++){
// just temporary limiting
for
(
int
nslice
=
0
;
nslice
<
tileClusters
.
length
;
nslice
++){
if
(
debugLevel
>
-
1
){
System
.
out
.
println
(
"Generating cluster images (limit is set to "
+
clt_parameters
.
max_clusters
+
") largest, scan #"
+
scanIndex
);
}
String
texturePath
=
ref_scene
.
getPassImage
(
// get image from a single pass
clt_parameters
,
colorProcParameters
,
rgbParameters
,
ref_scene
.
correctionsParameters
.
getModelName
(
ref_scene
.
getImageName
())+
"-img"
+
scanIndex
,
scanIndex
,
THREADS_MAX
,
// maximal number of threads to launch
updateStatus
,
batch_mode
?
-
5
:
debugLevel
);
if
(
texturePath
==
null
)
{
// not used in lwir
continue
;
// empty image
}
CLTPass3d
scan
=
tp
.
clt_3d_passes
.
get
(
scanIndex
);
// TODO: use new updated disparity, for now just what was forced for the picture
double
[]
scan_disparity
=
new
double
[
tilesX
*
tilesY
];
int
indx
=
0
;
for
(
int
ty
=
0
;
ty
<
tilesY
;
ty
++)
for
(
int
tx
=
0
;
tx
<
tilesX
;
tx
++){
scan_disparity
[
indx
++]
=
scan
.
disparity
[
ty
][
tx
];
}
if
(
clt_parameters
.
avg_cluster_disp
){
double
sw
=
0.0
,
sdw
=
0.0
;
for
(
int
i
=
0
;
i
<
scan_disparity
.
length
;
i
++){
// if (scan.selected[i] && !scan.border_tiles[i]){
if
(
scan
.
getSelected
()[
i
]
&&
!
scan
.
getBorderTiles
()[
i
]){
double
w
=
scan
.
disparity_map
[
ImageDtt
.
DISPARITY_STRENGTH_INDEX
][
i
];
sw
+=
w
;
sdw
+=
scan_disparity
[
i
]*
w
;
}
}
sdw
/=
sw
;
for
(
int
i
=
0
;
i
<
scan_disparity
.
length
;
i
++){
scan_disparity
[
i
]
=
sdw
;
// System.out.println("Generating cluster images (limit is set to "+clt_parameters.max_clusters+") largest, scan #"+scanIndex);
System
.
out
.
println
(
"Generating cluster images from texture slice "
+
nslice
);
}
int
[]
indices
=
tileClusters
[
nslice
].
getSubIndices
();
Rectangle
[]
bounds
=
tileClusters
[
nslice
].
getSubBounds
();
int
dbg_tri_indx
=
3
;
// showing triangles for cluster 3
for
(
int
sub_i
=
0
;
sub_i
<
indices
.
length
;
sub_i
++)
{
Rectangle
roi
=
bounds
[
sub_i
];
int
cluster_index
=
indices
[
sub_i
];
ImagePlus
imp_texture_cluster
=
imp_textures
[
cluster_index
];
if
(
imp_textures
[
cluster_index
]
==
null
)
{
if
(
debugLevel
>
-
1
){
System
.
out
.
println
(
"Empty cluster #"
+
cluster_index
);
}
continue
;
}
boolean
showTri
=
!
batch_mode
&&
(
debugLevel
>
-
1
)
&&
(((
scanIndex
<
next_pass
+
1
)
&&
clt_parameters
.
show_triangles
)
||((
scanIndex
-
next_pass
)
==
73
));
String
texturePath
=
imp_texture_cluster
.
getTitle
()+
".png"
;
double
[]
scan_disparity
=
tileClusters
[
nslice
].
getSubDisparity
(
sub_i
);
boolean
[]
scan_selected
=
tileClusters
[
nslice
].
getSubSelected
(
sub_i
);
// skipping averaging disparity fro a whole cluster (needs strength and does not seem to be useful)
boolean
showTri
=
!
batch_mode
&&
(
debugLevel
>
-
1
)
&&
(
clt_parameters
.
show_triangles
)
&&
(
cluster_index
==
dbg_tri_indx
);
try
{
ref_scene
.
generateClusterX3d
(
ref_scene
.
generateClusterX3d
(
// also generates wavefront obj
x3dOutput
,
wfOutput
,
// output WSavefront if not null
tri_meshes
,
// ArrayList<TriMesh> tri_meshes,
texturePath
,
"shape_id-"
+(
scanIndex
-
next_pass
)
,
// id
"shape_id-"
+
cluster_index
,
// id
null
,
// class
scan
.
getTextureBounds
(),
scan
.
getSelected
(),
roi
,
//
scan.getTextureBounds(),
scan_selected
,
//
scan.getSelected(),
scan_disparity
,
// scan.disparity_map[ImageDtt.DISPARITY_INDEX_CM],
clt_parameters
.
transform_size
,
clt_parameters
.
correct_distortions
,
// requires backdrop image to be corrected also
...
...
@@ -900,21 +760,43 @@ public class TexturedModel {
// FIXME: make a separate parameter:
infinity_disparity
,
// 0.25 * clt_parameters.bgnd_range, // 0.3
clt_parameters
.
grow_disp_max
,
// other_range, // 2.0 'other_range - difference from the specified (*_CM)
clt_parameters
.
maxDispTriangle
);
clt_parameters
.
maxDispTriangle
,
clt_parameters
.
maxZtoXY
,
// double maxZtoXY, // 10.0. <=0 - do not use
clt_parameters
.
maxZ
,
clt_parameters
.
limitZ
,
debugLevel
+
1
);
// int debug_level) > 0
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
// if (imp_textures[nslice] != null)
}
// for (int nslice = 0; nslice < tileClusters.length; nslice++){
if
((
x3d_
path
!=
null
)
&&
(
x3dOutput
!=
null
)){
x3dOutput
.
generateX3D
(
x3d_
path
+
Prefs
.
getFileSeparator
()
+
ref_scene
.
correctionsParameters
.
getModelName
(
ref_scene
.
getImageName
())+
".x3d"
);
if
((
x3d_
dir
!=
null
)
&&
(
x3dOutput
!=
null
)){
x3dOutput
.
generateX3D
(
x3d_
dir
+
Prefs
.
getFileSeparator
()
+
ref_scene
.
correctionsParameters
.
getModelName
(
ref_scene
.
getImageName
())+
".x3d"
);
}
if
(
wfOutput
!=
null
){
wfOutput
.
close
();
System
.
out
.
println
(
"Wavefront object file saved to "
+
wfOutput
.
obj_path
);
System
.
out
.
println
(
"Wavefront material file saved to "
+
wfOutput
.
mtl_path
);
}
if
(
tri_meshes
!=
null
)
{
try
{
GlTfExport
.
glTFExport
(
x3d_dir
,
// String x3d_dir,
ref_scene
.
correctionsParameters
.
getModelName
(
ref_scene
.
getImageName
()),
// String model_name,
tri_meshes
,
// ArrayList<TriMesh> tri_meshes,
gltf_emissive
,
// boolean gltf_emissive,
1
);
}
catch
(
JSONException
e
)
{
// TODO Auto-generated catch block
e
.
printStackTrace
();
}
catch
(
IOException
e
)
{
// TODO Auto-generated catch block
e
.
printStackTrace
();
}
// int debugLevel
}
// Save KML and ratings files if they do not exist (so not to overwrite edited ones), make them world-writable
ref_scene
.
writeKml
(
null
,
debugLevel
);
...
...
@@ -1209,7 +1091,7 @@ public class TexturedModel {
}
}
else
{
// for UM need to calculate min and max (probably OK for non-UM too !)
double
[]
minmax
=
QuadCLTCPU
.
getMinMaxTextures
(
faded_textures
);
//double [][][] textures // [
n
slices][nchn][i]
faded_textures
);
//double [][][] textures // [slices][nchn][i]
rel_low
=
minmax
[
0
];
rel_high
=
minmax
[
1
];
}
...
...
@@ -1322,19 +1204,19 @@ public class TexturedModel {
int
transform_size
,
ImagePlus
[]
combo_textures
)
{
int
max_cluster
=
-
1
;
for
(
int
ns
cene
=
0
;
nscene
<
tileClusters
.
length
;
nscen
e
++)
{
for
(
int
indx:
tileClusters
[
ns
cen
e
].
getSubIndices
())
{
for
(
int
ns
lice
=
0
;
nslice
<
tileClusters
.
length
;
nslic
e
++)
{
for
(
int
indx:
tileClusters
[
ns
lic
e
].
getSubIndices
())
{
if
(
indx
>
max_cluster
)
max_cluster
=
indx
;
}
}
ImagePlus
[]
tex_clusters
=
new
ImagePlus
[
max_cluster
+
1
];
for
(
int
ns
cene
=
0
;
nscene
<
tileClusters
.
length
;
nscen
e
++)
{
String
basename
=
combo_textures
[
ns
cen
e
].
getTitle
();
for
(
int
ns
lice
=
0
;
nslice
<
tileClusters
.
length
;
nslic
e
++)
{
String
basename
=
combo_textures
[
ns
lic
e
].
getTitle
();
basename
=
basename
.
substring
(
0
,
basename
.
indexOf
(
'-'
));
ImageStack
combo_stack
=
combo_textures
[
ns
cen
e
].
getStack
();
ImageStack
combo_stack
=
combo_textures
[
ns
lic
e
].
getStack
();
int
nSlices
=
combo_stack
.
getSize
();
int
[]
indices
=
tileClusters
[
ns
cen
e
].
getSubIndices
();
Rectangle
[]
bounds
=
tileClusters
[
ns
cen
e
].
getSubBounds
();
int
[]
indices
=
tileClusters
[
ns
lic
e
].
getSubIndices
();
Rectangle
[]
bounds
=
tileClusters
[
ns
lic
e
].
getSubBounds
();
// try to deal with a single-slice stack?
for
(
int
i
=
0
;
i
<
indices
.
length
;
i
++)
{
Rectangle
roi
=
bounds
[
i
];
...
...
src/main/java/com/elphel/imagej/tileprocessor/TileCluster.java
View file @
4e6966e0
...
...
@@ -76,6 +76,60 @@ class TileCluster{
public
Rectangle
getBounds
()
{
return
bounds
;}
public
boolean
[]
getBorder
()
{
return
border
;}
public
double
[]
getDisparity
()
{
return
disparity
;}
public
double
[]
getSubDisparity
(
int
indx
)
{
// disparity should be NaN for unused !
if
(
clust_list
==
null
)
{
return
null
;
}
Rectangle
sub_bounds
=
clust_list
.
get
(
indx
).
bounds
;
double
[]
sub_disparity
=
new
double
[
sub_bounds
.
width
*
sub_bounds
.
height
];
int
src_x
=
sub_bounds
.
x
-
bounds
.
x
;
for
(
int
dst_y
=
0
;
dst_y
<
sub_bounds
.
height
;
dst_y
++)
{
int
src_y
=
dst_y
+
sub_bounds
.
y
-
bounds
.
y
;
System
.
arraycopy
(
disparity
,
src_y
*
bounds
.
width
+
src_x
,
sub_disparity
,
dst_y
*
sub_bounds
.
width
,
sub_bounds
.
width
);
}
return
sub_disparity
;
}
public
boolean
[]
getSubBorder
(
int
indx
)
{
// disparity should be NaN for unused !
if
(
clust_list
==
null
)
{
return
null
;
}
Rectangle
sub_bounds
=
clust_list
.
get
(
indx
).
bounds
;
boolean
[]
sub_border
=
new
boolean
[
sub_bounds
.
width
*
sub_bounds
.
height
];
int
src_x
=
sub_bounds
.
x
-
bounds
.
x
;
for
(
int
dst_y
=
0
;
dst_y
<
sub_bounds
.
height
;
dst_y
++)
{
int
src_y
=
dst_y
+
sub_bounds
.
y
-
bounds
.
y
;
System
.
arraycopy
(
border
,
src_y
*
bounds
.
width
+
src_x
,
sub_border
,
dst_y
*
sub_bounds
.
width
,
sub_bounds
.
width
);
}
return
sub_border
;
}
public
boolean
[]
getSubSelected
(
int
indx
)
{
// disparity should be NaN for unused !
if
(
clust_list
==
null
)
{
return
null
;
}
double
[]
sub_disparity
=
getSubDisparity
(
indx
);
boolean
[]
sub_selection
=
new
boolean
[
sub_disparity
.
length
];
for
(
int
i
=
0
;
i
<
sub_disparity
.
length
;
i
++)
{
sub_selection
[
i
]
=
!
Double
.
isNaN
(
sub_disparity
[
i
]);
}
return
sub_selection
;
}
public
boolean
[]
getSelected
()
{
if
(
disparity
==
null
)
{
return
null
;
...
...
@@ -132,42 +186,6 @@ class TileCluster{
}
/*
public TileCluster combine (TileCluster tileCluster) {
TileCluster outer, inner;
if (bounds.contains(tileCluster.bounds)) {
outer = this;
inner = tileCluster;
} else if (tileCluster.bounds.contains(bounds)) {
outer = tileCluster;
inner = this;
} else {
Rectangle outer_bounds = bounds.union(tileCluster.bounds);
outer = new TileCluster(outer_bounds, null, null);
outer.combine(this); //
inner = tileCluster;
}
int dst_x = inner.bounds.x - outer.bounds.x;
for (int src_y = 0; src_y < bounds.height; src_y++) {
int dst_y = src_y + inner.bounds.y - outer.bounds.y;
System.arraycopy(
inner.border,
src_y * bounds.width,
outer.border,
dst_y * outer.bounds.width + dst_x,
bounds.width);
System.arraycopy(
inner.disparity,
src_y * bounds.width,
outer.disparity,
dst_y * outer.bounds.width + dst_x,
bounds.width);
}
return outer;
}
*/
public
void
add
(
TileCluster
tileCluster
)
{
if
(!
bounds
.
contains
(
tileCluster
.
bounds
))
{
throw
new
IllegalArgumentException
(
"TileCluster.add(): Added cluster should fit into this "
);
...
...
@@ -193,16 +211,6 @@ class TileCluster{
disparity
,
dst_y
*
bounds
.
width
+
dst_x
,
tileCluster
.
bounds
.
width
);
/**
if ((cluster_index != null) && (tileCluster.cluster_index != null)) {
System.arraycopy(
tileCluster.cluster_index,
src_y * tileCluster.bounds.width,
cluster_index,
dst_y * bounds.width + dst_x,
tileCluster.bounds.width);
}
*/
}
return
;
}
...
...
src/main/java/com/elphel/imagej/tileprocessor/TileProcessor.java
View file @
4e6966e0
...
...
@@ -8626,6 +8626,7 @@ ImageDtt.startAndJoin(threads);
{
int
[][]
indices
=
new
int
[
bounds
.
height
][
bounds
.
width
];
int
indx
=
0
;
if
(
selected
.
length
>
(
bounds
.
height
*
bounds
.
width
))
{
// old version - selected is full size
for
(
int
y
=
0
;
y
<
bounds
.
height
;
y
++)
{
for
(
int
x
=
0
;
x
<
bounds
.
width
;
x
++){
if
(
selected
[
this
.
tilesX
*
(
bounds
.
y
+
y
)
+
(
bounds
.
x
+
x
)]){
...
...
@@ -8635,6 +8636,17 @@ ImageDtt.startAndJoin(threads);
}
}
}
}
else
{
// 09.18.2022
for
(
int
y
=
0
;
y
<
bounds
.
height
;
y
++)
{
for
(
int
x
=
0
;
x
<
bounds
.
width
;
x
++){
if
(
selected
[
bounds
.
width
*
y
+
x
]){
indices
[
y
][
x
]
=
indx
++;
}
else
{
indices
[
y
][
x
]
=
-
1
;
}
}
}
}
return
indices
;
}
...
...
@@ -8680,6 +8692,7 @@ ImageDtt.startAndJoin(threads);
int
maxIndex
=
getMaxIndex
(
indices
);
double
[]
indexedDisparity
=
new
double
[
maxIndex
+
1
];
int
indx
=
0
;
if
(
disparity
.
length
>
(
bounds
.
height
*
bounds
.
width
))
{
// old version - selected is full size
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
...
...
@@ -8692,6 +8705,20 @@ ImageDtt.startAndJoin(threads);
}
}
}
}
else
{
// 09.18.2022
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
// center coordinates for 8*8 tile is [3.5,3.5]
double
disp
=
(
disparity
==
null
)?
min_disparity:
(
disparity
[
bounds
.
width
*
y
+
x
]);
if
(
disp
<
min_disparity
)
disp
=
min_disparity
;
else
if
(
disp
>
max_disparity
)
disp
=
max_disparity
;
indexedDisparity
[
indx
]
=
disp
;
indx
++;
}
}
}
}
return
indexedDisparity
;
}
...
...
@@ -8711,6 +8738,7 @@ ImageDtt.startAndJoin(threads);
int
maxIndex
=
getMaxIndex
(
indices
);
double
[][]
coordinate
=
new
double
[
maxIndex
+
1
][];
int
indx
=
0
;
if
(
disparity
.
length
>
(
bounds
.
height
*
bounds
.
width
))
{
// old version - selected is full size
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
...
...
@@ -8729,6 +8757,27 @@ ImageDtt.startAndJoin(threads);
}
}
}
}
else
{
// 09.18.2022
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
// center coordinates for 8*8 tile is [3.5,3.5]
double
px
=
(
bounds
.
x
+
x
+
0.5
)
*
tile_size
-
0.5
;
double
py
=
(
bounds
.
y
+
y
+
0.5
)
*
tile_size
-
0.5
;
double
disp
=
(
disparity
==
null
)?
min_disparity:
(
disparity
[
bounds
.
width
*
y
+
x
]);
if
(
disp
<
min_disparity
)
disp
=
min_disparity
;
else
if
(
disp
>
max_disparity
)
disp
=
max_disparity
;
coordinate
[
indx
]
=
geometryCorrection
.
getWorldCoordinates
(
px
,
py
,
disp
,
correctDistortions
);
indx
++;
}
}
}
}
return
coordinate
;
}
...
...
@@ -8749,9 +8798,10 @@ ImageDtt.startAndJoin(threads);
public
static
int
[][]
filterTriangles
(
int
[][]
triangles
,
double
[]
disparity
,
// disparities per vertex index
double
maxDispDiff
)
// maximal disparity difference in a triangle
{
final
double
min_avg
=
0.5
;
// minimal average disparity to normalize triangle
double
maxDispDiff
,
// maximal relative disparity difference in a triangle
int
debug_level
)
{
final
double
min_avg
=
3.0
;
// 0.5; // minimal average disparity to normalize triangle
class
Triangle
{
int
[]
points
=
new
int
[
3
];
Triangle
(
int
i1
,
int
i2
,
int
i3
){
...
...
@@ -8762,12 +8812,19 @@ ImageDtt.startAndJoin(threads);
}
ArrayList
<
Triangle
>
triList
=
new
ArrayList
<
Triangle
>();
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++){
double
disp_avg
=
(
triangles
[
i
][
0
]
+
triangles
[
i
][
1
]+
triangles
[
i
][
2
])/
3.0
;
double
disp_avg
=
(
disparity
[
triangles
[
i
][
0
]]
+
disparity
[
triangles
[
i
][
1
]]+
disparity
[
triangles
[
i
][
2
]])/
3.0
;
// fixed 09.18.2022!
if
(
disp_avg
<
min_avg
)
disp_avg
=
min_avg
;
loop:
{
for
(
int
j
=
0
;
j
<
3
;
j
++){
int
j1
=
(
j
+
1
)
%
3
;
if
(
Math
.
abs
(
disparity
[
triangles
[
i
][
j
]]
-
disparity
[
triangles
[
i
][
j1
]])
>
(
disp_avg
*
maxDispDiff
))
break
loop
;
if
(
Math
.
abs
(
disparity
[
triangles
[
i
][
j
]]
-
disparity
[
triangles
[
i
][
j1
]])
>
(
disp_avg
*
maxDispDiff
))
{
if
(
debug_level
>
1
)
{
System
.
out
.
println
(
"removed triangle "
+
i
+
": "
+
disparity
[
triangles
[
i
][
0
]]+
". "
+
disparity
[
triangles
[
i
][
1
]]+
". "
+
disparity
[
triangles
[
i
][
2
]]+
". Avg = "
+
disp_avg
);
}
break
loop
;
}
}
triList
.
add
(
new
Triangle
(
triangles
[
i
][
0
],
...
...
@@ -8780,7 +8837,100 @@ ImageDtt.startAndJoin(threads);
filteredTriangles
[
i
]
=
triList
.
get
(
i
).
points
;
}
return
filteredTriangles
;
}
}
public
static
int
[][]
filterTrianglesWorld
(
int
[][]
triangles
,
double
[][]
worldXYZ
,
// world per vertex index
double
maxZtoXY
,
double
maxZ
)
{
final
double
maxZtoXY2
=
maxZtoXY
*
maxZtoXY
;
class
Triangle
{
int
[]
points
=
new
int
[
3
];
Triangle
(
int
i1
,
int
i2
,
int
i3
){
points
[
0
]
=
i1
;
points
[
1
]
=
i2
;
points
[
2
]
=
i3
;
}
}
ArrayList
<
Triangle
>
triList
=
new
ArrayList
<
Triangle
>();
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++){
double
[][]
min_max
=
new
double
[
3
][
2
];
boolean
not_too_far
=
true
;
for
(
int
di
=
0
;
di
<
3
;
di
++)
{
min_max
[
di
][
0
]
=
worldXYZ
[
triangles
[
i
][
0
]][
di
];
min_max
[
di
][
1
]
=
min_max
[
di
][
0
];
// both min and max to the same vertex 0
}
if
(
maxZ
!=
0
)
{
not_too_far
&=
worldXYZ
[
triangles
[
i
][
0
]][
2
]
>
-
maxZ
;
}
for
(
int
vi
=
1
;
vi
<
3
;
vi
++)
{
for
(
int
di
=
0
;
di
<
3
;
di
++)
{
min_max
[
di
][
0
]
=
Math
.
min
(
min_max
[
di
][
0
],
worldXYZ
[
triangles
[
i
][
vi
]][
di
]);
min_max
[
di
][
1
]
=
Math
.
max
(
min_max
[
di
][
1
],
worldXYZ
[
triangles
[
i
][
vi
]][
di
]);
}
}
double
dx
=
min_max
[
0
][
1
]-
min_max
[
0
][
0
];
double
dy
=
min_max
[
1
][
1
]-
min_max
[
1
][
0
];
double
dz
=
min_max
[
2
][
1
]-
min_max
[
2
][
0
];
double
ratio2
=
dz
*
dz
/(
dx
*
dx
+
dy
*
dy
+
0.001
);
if
(
not_too_far
&&
((
maxZtoXY
==
0
)
||
(
ratio2
<
maxZtoXY2
)))
{
triList
.
add
(
new
Triangle
(
triangles
[
i
][
0
],
triangles
[
i
][
1
],
triangles
[
i
][
2
]));
}
}
int
[][]
filteredTriangles
=
new
int
[
triList
.
size
()][
3
];
for
(
int
i
=
0
;
i
<
filteredTriangles
.
length
;
i
++){
filteredTriangles
[
i
]
=
triList
.
get
(
i
).
points
;
}
return
filteredTriangles
;
}
public
static
int
[]
reIndex
(
int
[][]
indices
,
int
[][]
triangles
)
{
int
last_index
=
-
1
;
for
(
int
i
=
0
;
i
<
indices
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
indices
[
i
].
length
;
j
++)
{
if
(
indices
[
i
][
j
]
>
last_index
)
{
last_index
=
indices
[
i
][
j
];
}
}
}
boolean
[]
used_indices
=
new
boolean
[
last_index
+
1
];
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
triangles
[
i
].
length
;
j
++)
{
// always 3
used_indices
[
triangles
[
i
][
j
]]
=
true
;
}
}
int
new_len
=
0
;
for
(
int
i
=
0
;
i
<
used_indices
.
length
;
i
++)
if
(
used_indices
[
i
])
{
new_len
++;
}
if
(
new_len
==
used_indices
.
length
)
{
return
null
;
// no re-indexing is needed
}
int
[]
re_index
=
new
int
[
new_len
];
int
indx
=
0
;
for
(
int
i
=
0
;
i
<
indices
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
indices
[
i
].
length
;
j
++)
{
int
old_index
=
indices
[
i
][
j
];
if
(
old_index
>=
0
)
{
if
(
used_indices
[
old_index
])
{
// keep
re_index
[
indx
]
=
old_index
;
indices
[
i
][
j
]
=
indx
++;
}
else
{
indices
[
i
][
j
]
=
-
1
;
}
}
}
}
return
re_index
;
}
public
static
int
[][]
triangulateCluster
(
...
...
@@ -8851,6 +9001,8 @@ ImageDtt.startAndJoin(threads);
{
String
[]
titles
=
{
"disparity"
,
"triangles"
};
double
[][]
dbg_img
=
new
double
[
titles
.
length
][
tilesX
*
tilesY
*
tile_size
*
tile_size
];
Arrays
.
fill
(
dbg_img
[
0
],
Double
.
NaN
);
if
(
selected
.
length
>
(
bounds
.
height
*
bounds
.
width
))
{
// old version - selected is full size
for
(
int
i
=
0
;
i
<
selected
.
length
;
i
++
){
double
d
=
selected
[
i
]?
((
disparity
.
length
>
1
)
?
disparity
[
i
]
:
disparity
[
0
]):
Double
.
NaN
;
int
y
=
i
/
tilesX
;
...
...
@@ -8861,6 +9013,18 @@ ImageDtt.startAndJoin(threads);
}
}
}
}
else
{
// 09.18.2022
for
(
int
i
=
0
;
i
<
selected
.
length
;
i
++
){
double
d
=
selected
[
i
]?
((
disparity
.
length
>
1
)
?
disparity
[
i
]
:
disparity
[
0
]):
Double
.
NaN
;
int
y
=
i
/
bounds
.
width
+
bounds
.
y
;
int
x
=
i
%
bounds
.
width
+
bounds
.
x
;
for
(
int
dy
=
0
;
dy
<
tile_size
;
dy
++){
for
(
int
dx
=
0
;
dx
<
tile_size
;
dx
++){
dbg_img
[
0
][(
y
*
tile_size
+
dy
)*(
tile_size
*
tilesX
)
+
(
x
*
tile_size
+
dx
)]
=
d
;
}
}
}
}
int
maxIndex
=
getMaxIndex
(
indices
);
int
[][]
pxy
=
new
int
[
maxIndex
+
1
][
2
];
int
height
=
indices
.
length
;
...
...
@@ -8885,12 +9049,7 @@ ImageDtt.startAndJoin(threads);
for
(
int
j
=
0
;
j
<
tile_size
;
j
++){
int
x
=
pxy
[
pntIndx
[
0
]][
0
]
+
dx
*
j
;
int
y
=
pxy
[
pntIndx
[
0
]][
1
]
+
dy
*
j
;
// int indx = y * tile_size * tilesX + x;
// if (indx < dbg_img[1].length) {
dbg_img
[
1
][
y
*
tile_size
*
tilesX
+
x
]
=
10.0
;
//1711748
// } else {
// indx += 0;
// }
}
}
}
...
...
src/main/java/com/elphel/imagej/x3d/export/GlTfExport.java
0 → 100644
View file @
4e6966e0
package
com
.
elphel
.
imagej
.
x3d
.
export
;
/**
**
** GlTfExport - generate glTF representation of the model
**
** Copyright (C) 2022 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
** GlTfExport.java is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
** -----------------------------------------------------------------------------**
**
*/
import
java.io.FileOutputStream
;
import
java.io.FileWriter
;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
import
java.nio.channels.FileChannel
;
import
java.util.ArrayList
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
com.google.gson.Gson
;
import
com.google.gson.GsonBuilder
;
import
com.google.gson.JsonElement
;
import
com.google.gson.JsonParser
;
import
ij.Prefs
;
public
class
GlTfExport
{
public
static
int
NEAREST
=
9728
;
public
static
int
LINEAR
=
9729
;
public
static
int
NEAREST_MIPMAP_NEAREST
=
9984
;
public
static
int
LINEAR_MIPMAP_NEAREST
=
9985
;
public
static
int
NEAREST_MIPMAP_LINEAR
=
9986
;
public
static
int
LINEAR_MIPMAP_LINEAR
=
9986
;
public
static
int
CLAMP_TO_EDGE
=
33071
;
public
static
int
MIRRORED_REPEAT
=
33648
;
public
static
int
REPEAT
=
10497
;
public
static
int
ARRAY_BUFFER
=
34962
;
// for attributes
public
static
int
ELEMENT_ARRAY_BUFFER
=
34963
;
// for indices
public
static
int
COMPONENT_SIGNED_BYTE
=
5120
;
public
static
int
COMPONENT_UNSIGNED_BYTE
=
5121
;
public
static
int
COMPONENT_SIGNED_SHORT
=
5122
;
public
static
int
COMPONENT_UNSIGNED_SHORT
=
5123
;
public
static
int
COMPONENT_UNSIGNED_INT
=
5125
;
public
static
int
COMPONENT_FLOAT
=
5126
;
public
static
String
ALPHAMODE_OPAQUE
=
"OPAQUE"
;
public
static
String
ALPHAMODE_MASK
=
"MASK"
;
public
static
String
ALPHAMODE_BLEND
=
"BLEND"
;
public
static
String
TYPE_SCALAR
=
"SCALAR"
;
// 1
public
static
String
TYPE_VEC2
=
"VEC2"
;
// 2
public
static
String
TYPE_VEC3
=
"VEC3"
;
// 3
public
static
String
TYPE_VEC4
=
"VEC4"
;
// 4
public
static
String
TYPE_MAT2
=
"MAT2"
;
// 4
public
static
String
TYPE_MAT3
=
"MAT3"
;
// 9
public
static
String
TYPE_MAT4
=
"MAT4"
;
// 16
public
static
int
MODE_POINTS
=
0
;
public
static
int
MODE_LINES
=
1
;
public
static
int
MODE_LINE_LOOP
=
2
;
public
static
int
MODE_LINE_STRIP
=
3
;
public
static
int
MODE_TRIANGLES
=
4
;
public
static
int
MODE_TRIANGLE_STRIP
=
5
;
public
static
int
MODE_TRIANGLE_FAN
=
6
;
public
static
void
glTFExport
(
String
x3d_dir
,
String
model_name
,
ArrayList
<
TriMesh
>
tri_meshes
,
boolean
gltf_emissive
,
int
debugLevel
)
throws
IOException
,
JSONException
{
boolean
invert_faces
=
true
;
// false; // true; // false; // true;
boolean
[]
inv_xyz
=
{
false
,
false
,
false
};
boolean
[]
inv_tex
=
{
false
,
true
};
int
[]
triangle
=
{
0
,
1
,
2
};
if
(
invert_faces
)
{
triangle
[
0
]=
2
;
triangle
[
2
]=
0
;
}
String
base_name
=
x3d_dir
+
Prefs
.
getFileSeparator
()
+
model_name
;
String
bin_path
=
base_name
+
".bin"
;
String
bin_name
=
model_name
+
".bin"
;
String
gltf_path
=
base_name
+
".gltf"
;
int
total_meshes
=
tri_meshes
.
size
();
int
total_vertices
=
0
;
// int total_triangles = 0;
int
[]
mesh_vert
=
new
int
[
total_meshes
];
int
[]
mesh_tri
=
new
int
[
total_meshes
];
int
[][]
offset_len_indx
=
new
int
[
total_meshes
][
2
];
int
[][]
offset_len_tex
=
new
int
[
total_meshes
][
2
];
int
[][]
offset_len_coor
=
new
int
[
total_meshes
][
2
];
int
[][]
minmax_indx
=
new
int
[
total_meshes
][
2
];
float
[][][]
minmax_tex
=
new
float
[
total_meshes
][
2
][
2
];
// [][{x,y}[{min, max}]
float
[][][]
minmax_coor
=
new
float
[
total_meshes
][
3
][
2
];
// [][{x,y,z}[{min, max}]
int
index_size
=
4
;
// 2; // 4 bytes per index entry - will use int - probably faster render even if more memory
for
(
int
nmesh
=
0
;
nmesh
<
total_meshes
;
nmesh
++)
{
mesh_vert
[
nmesh
]
=
tri_meshes
.
get
(
nmesh
).
getCoordinates
().
length
;
mesh_tri
[
nmesh
]
=
tri_meshes
.
get
(
nmesh
).
getTriangles
().
length
;
total_vertices
+=
mesh_vert
[
nmesh
];
/// total_triangles += mesh_tri[nmesh];
offset_len_indx
[
nmesh
][
1
]
=
mesh_tri
[
nmesh
]
*
index_size
*
3
;
offset_len_tex
[
nmesh
][
1
]
=
mesh_vert
[
nmesh
]
*
4
*
2
;
// float, VEC2
offset_len_coor
[
nmesh
][
1
]
=
mesh_vert
[
nmesh
]
*
4
*
3
;
// float, VEC3
if
(
nmesh
>
0
)
{
int
index_prev_len4
=
4
*
((
offset_len_indx
[
nmesh
-
1
][
1
]
+
3
)/
4
);
offset_len_indx
[
nmesh
][
0
]
=
offset_len_indx
[
nmesh
-
1
][
0
]
+
index_prev_len4
;
// pad to 4 bytes
offset_len_tex
[
nmesh
][
0
]
=
offset_len_tex
[
nmesh
-
1
][
0
]
+
offset_len_tex
[
nmesh
-
1
][
1
];
offset_len_coor
[
nmesh
][
0
]
=
offset_len_coor
[
nmesh
-
1
][
0
]
+
offset_len_coor
[
nmesh
-
1
][
1
];
}
}
int
buffer_index_bytes
=
offset_len_indx
[
total_meshes
-
1
][
0
]+
offset_len_indx
[
total_meshes
-
1
][
1
];
buffer_index_bytes
=
4
*
((
buffer_index_bytes
+
3
)/
4
);
int
buffer_texture_bytes
=
4
*
total_vertices
*
2
;
// VEC2
int
buffer_coordinate_bytes
=
4
*
total_vertices
*
3
;
// VEC3
int
buffer_total_bytes
=
buffer_index_bytes
+
buffer_texture_bytes
+
buffer_coordinate_bytes
;
if
(
debugLevel
>
-
1
)
{
System
.
out
.
println
(
"glTFExport(): allocating "
+
buffer_total_bytes
+
" bytes buffer"
);
System
.
out
.
println
(
buffer_index_bytes
+
" for indices,\n"
+
buffer_texture_bytes
+
" for texture coordinates, and \n"
+
buffer_coordinate_bytes
+
" for vertice coordinates."
);
}
ByteBuffer
bb0
=
ByteBuffer
.
allocate
(
buffer_total_bytes
);
ByteBuffer
bb
=
bb0
.
order
(
ByteOrder
.
LITTLE_ENDIAN
);
// will be 3 buffer views: 0 for indices, 1 - for texture coordinates and 2 - for coordinates
for
(
int
nmesh
=
0
;
nmesh
<
total_meshes
;
nmesh
++)
{
int
[][]
triangles
=
tri_meshes
.
get
(
nmesh
).
getTriangles
();
if
(
index_size
==
2
)
{
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++)
{
bb
.
putShort
((
short
)
(
triangles
[
i
][
triangle
[
0
]]));
bb
.
putShort
((
short
)
(
triangles
[
i
][
triangle
[
1
]]));
bb
.
putShort
((
short
)
(
triangles
[
i
][
triangle
[
2
]]));
bb
.
putShort
((
short
)
0
);
}
}
else
{
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++)
{
bb
.
putInt
(
triangles
[
i
][
triangle
[
0
]]);
bb
.
putInt
(
triangles
[
i
][
triangle
[
1
]]);
bb
.
putInt
(
triangles
[
i
][
triangle
[
2
]]);
}
}
minmax_indx
[
nmesh
][
0
]
=
triangles
[
0
][
0
];
minmax_indx
[
nmesh
][
1
]
=
minmax_indx
[
nmesh
][
0
];
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
triangles
[
i
].
length
;
j
++)
{
if
(
triangles
[
i
][
j
]
<
minmax_indx
[
nmesh
][
0
])
{
minmax_indx
[
nmesh
][
0
]
=
triangles
[
i
][
j
];
}
else
if
(
triangles
[
i
][
j
]
>
minmax_indx
[
nmesh
][
1
])
{
minmax_indx
[
nmesh
][
1
]
=
triangles
[
i
][
j
];
}
}
}
}
for
(
int
nmesh
=
0
;
nmesh
<
total_meshes
;
nmesh
++)
{
double
[][]
tex_coord
=
tri_meshes
.
get
(
nmesh
).
getTexCoord
();
for
(
int
i
=
0
;
i
<
tex_coord
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
tex_coord
[
i
].
length
;
j
++)
{
if
(
inv_tex
[
j
])
tex_coord
[
i
][
j
]
=
1.0
-
tex_coord
[
i
][
j
];
}
}
for
(
int
j
=
0
;
j
<
tex_coord
[
0
].
length
;
j
++)
{
minmax_tex
[
nmesh
][
j
][
0
]
=
(
float
)
tex_coord
[
0
][
j
];
minmax_tex
[
nmesh
][
j
][
1
]
=
minmax_tex
[
nmesh
][
j
][
0
];
}
for
(
int
i
=
0
;
i
<
tex_coord
.
length
;
i
++)
{
bb
.
putFloat
((
float
)
tex_coord
[
i
][
0
]);
bb
.
putFloat
((
float
)
tex_coord
[
i
][
1
]);
for
(
int
j
=
0
;
j
<
tex_coord
[
i
].
length
;
j
++)
{
float
f
=
(
float
)
tex_coord
[
i
][
j
];
if
(
f
<
minmax_tex
[
nmesh
][
j
][
0
])
{
minmax_tex
[
nmesh
][
j
][
0
]
=
f
;
}
else
if
(
f
>
minmax_tex
[
nmesh
][
j
][
1
])
{
minmax_tex
[
nmesh
][
j
][
1
]
=
f
;
}
}
}
}
for
(
int
nmesh
=
0
;
nmesh
<
total_meshes
;
nmesh
++)
{
double
[][]
coordinates
=
tri_meshes
.
get
(
nmesh
).
getCoordinates
();
for
(
int
i
=
0
;
i
<
coordinates
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
coordinates
[
i
].
length
;
j
++)
{
if
(
inv_xyz
[
j
])
coordinates
[
i
][
j
]
=
-
coordinates
[
i
][
j
];
}
}
for
(
int
j
=
0
;
j
<
coordinates
[
0
].
length
;
j
++)
{
minmax_coor
[
nmesh
][
j
][
0
]
=
(
float
)
coordinates
[
0
][
j
];
minmax_coor
[
nmesh
][
j
][
1
]
=
minmax_coor
[
nmesh
][
j
][
0
];
}
for
(
int
i
=
0
;
i
<
coordinates
.
length
;
i
++)
{
bb
.
putFloat
((
float
)
coordinates
[
i
][
0
]);
bb
.
putFloat
((
float
)
coordinates
[
i
][
1
]);
bb
.
putFloat
((
float
)
coordinates
[
i
][
2
]);
for
(
int
j
=
0
;
j
<
coordinates
[
i
].
length
;
j
++)
{
float
f
=
(
float
)
coordinates
[
i
][
j
];
if
(
f
<
minmax_coor
[
nmesh
][
j
][
0
])
{
minmax_coor
[
nmesh
][
j
][
0
]
=
f
;
}
else
if
(
f
>
minmax_coor
[
nmesh
][
j
][
1
])
{
minmax_coor
[
nmesh
][
j
][
1
]
=
f
;
}
}
}
}
bb
.
flip
();
try
(
// write bb to file
@SuppressWarnings
(
"resource"
)
FileChannel
fc
=
new
FileOutputStream
(
bin_path
).
getChannel
())
{
fc
.
write
(
bb
);
fc
.
close
();
}
if
(
debugLevel
>
-
1
)
{
System
.
out
.
println
(
"glTFExport(): wrote binary data to "
+
bin_path
);
}
// Now generate glTF json
// prepare mesh short names such as "img001"
String
[]
short_names
=
new
String
[
total_meshes
];
for
(
int
nmesh
=
0
;
nmesh
<
total_meshes
;
nmesh
++)
{
String
tex_uri
=
tri_meshes
.
get
(
nmesh
).
getImage
();
short_names
[
nmesh
]
=
tex_uri
.
substring
(
tex_uri
.
indexOf
(
"-"
)+
1
,
tex_uri
.
lastIndexOf
(
"-"
));
}
JSONObject
gltf_json
=
new
JSONObject
();
//create asset
JSONObject
gltf_asset
=
new
JSONObject
();
gltf_asset
.
put
(
"generator"
,
"imagej-elphel"
);
gltf_asset
.
put
(
"copyright"
,
"2022 (C) Elphel, Inc."
);
gltf_asset
.
put
(
"version"
,
"2.0"
);
gltf_json
.
put
(
"asset"
,
gltf_asset
);
// set single scene
gltf_json
.
put
(
"scene"
,
0
);
// Create nodes -> change to a single node, single mesh with multiple primitives
JSONArray
gltf_nodes
=
new
JSONArray
();
JSONObject
gltf_node0
=
new
JSONObject
();
gltf_node0
.
put
(
"name"
,
"all-meshes-node"
);
gltf_node0
.
put
(
"mesh"
,
0
);
// index of a single mesh
gltf_nodes
.
put
(
gltf_node0
);
gltf_json
.
put
(
"nodes"
,
gltf_nodes
);
// Create a single scene0
JSONArray
gltf_scene0_nodes
=
new
JSONArray
();
gltf_scene0_nodes
.
put
(
0
);
JSONObject
gltf_scene0
=
new
JSONObject
();
gltf_scene0
.
put
(
"name"
,
model_name
);
gltf_scene0
.
put
(
"nodes"
,
gltf_scene0_nodes
);
// Crete scenes
JSONArray
gltf_scenes
=
new
JSONArray
();
gltf_scenes
.
put
(
gltf_scene0
);
gltf_json
.
put
(
"scenes"
,
gltf_scenes
);
// Create images
JSONArray
gltf_images
=
new
JSONArray
();
for
(
int
nmesh
=
0
;
nmesh
<
total_meshes
;
nmesh
++)
{
JSONObject
gltf_image
=
new
JSONObject
();
gltf_image
.
put
(
"uri"
,
tri_meshes
.
get
(
nmesh
).
getImage
());
gltf_images
.
put
(
gltf_image
);
}
gltf_json
.
put
(
"images"
,
gltf_images
);
// Create textures
JSONArray
gltf_textures
=
new
JSONArray
();
for
(
int
nmesh
=
0
;
nmesh
<
total_meshes
;
nmesh
++)
{
JSONObject
gltf_texture
=
new
JSONObject
();
gltf_texture
.
put
(
"sampler"
,
0
);
gltf_texture
.
put
(
"source"
,
nmesh
);
gltf_texture
.
put
(
"name"
,
short_names
[
nmesh
]+
"-tex"
);
gltf_textures
.
put
(
gltf_texture
);
}
gltf_json
.
put
(
"textures"
,
gltf_textures
);
// Create sampler0
JSONObject
gltf_sampler0
=
new
JSONObject
();
// page 46 - otherwise needs power-of-two textures
/*
3.8.4.5. Non-power-of-two Textures
Client implementations SHOULD resize non-power-of-two textures (so that their horizontal and
vertical sizes are powers of two) when running on platforms that have limited support for such
texture dimensions.
Implementation Note
Specifically, if the sampler the texture references:
- has a wrapping mode (either wrapS or wrapT) equal to repeat or mirrored repeat,
or
- has a minification filter (minFilter) that uses mipmapping.
*/
gltf_sampler0
.
put
(
"magFilter"
,
LINEAR
);
gltf_sampler0
.
put
(
"minFilter"
,
LINEAR
);
// NEAREST_MIPMAP_LINEAR);
gltf_sampler0
.
put
(
"wrapS"
,
CLAMP_TO_EDGE
);
// REPEAT); // CLAMP_TO_EDGE
gltf_sampler0
.
put
(
"wrapT"
,
CLAMP_TO_EDGE
);
//REPEAT); // CLAMP_TO_EDGE
// Create samplers
JSONArray
gltf_samplers
=
new
JSONArray
();
gltf_samplers
.
put
(
gltf_sampler0
);
gltf_json
.
put
(
"samplers"
,
gltf_samplers
);
// Create materials (material references texture, so each mesh object - new material
JSONArray
gltf_materials
=
new
JSONArray
();
for
(
int
nmesh
=
0
;
nmesh
<
total_meshes
;
nmesh
++)
{
JSONObject
gltf_material
=
new
JSONObject
();
JSONObject
gltf_pbrMetallicRoughness
=
new
JSONObject
();
JSONObject
gltf_baseColorTexture
=
new
JSONObject
();
gltf_baseColorTexture
.
put
(
"index"
,
nmesh
);
// reference corresponding texture
gltf_pbrMetallicRoughness
.
put
(
"baseColorTexture"
,
gltf_baseColorTexture
);
gltf_pbrMetallicRoughness
.
put
(
"metallicFactor"
,
0.0
);
gltf_material
.
put
(
"pbrMetallicRoughness"
,
gltf_pbrMetallicRoughness
);
gltf_material
.
put
(
"name"
,
short_names
[
nmesh
]+
"-mat"
);
gltf_material
.
put
(
"alphaMode"
,
ALPHAMODE_BLEND
);
if
(
gltf_emissive
)
{
JSONObject
gltf_emissiveTexture
=
new
JSONObject
();
gltf_emissiveTexture
.
put
(
"index"
,
nmesh
);
gltf_material
.
put
(
"emissiveTexture"
,
gltf_emissiveTexture
);
JSONArray
gltf_material_emissiveFactor
=
new
JSONArray
();
gltf_material_emissiveFactor
.
put
(
1.0
);
gltf_material_emissiveFactor
.
put
(
1.0
);
gltf_material_emissiveFactor
.
put
(
1.0
);
gltf_material
.
put
(
"emissiveFactor"
,
gltf_material_emissiveFactor
);
}
gltf_materials
.
put
(
gltf_material
);
}
gltf_json
.
put
(
"materials"
,
gltf_materials
);
// create buffer(s) - a single one
// Create buffer0 (only one)
JSONObject
gltf_buffer0
=
new
JSONObject
();
gltf_buffer0
.
put
(
"byteLength"
,
buffer_total_bytes
);
gltf_buffer0
.
put
(
"uri"
,
bin_name
);
// relative
gltf_buffer0
.
put
(
"name"
,
"single-buffer"
);
// Create buffers
JSONArray
gltf_buffers
=
new
JSONArray
();
gltf_buffers
.
put
(
gltf_buffer0
);
gltf_json
.
put
(
"buffers"
,
gltf_buffers
);
// create bufferViews - 3 per mesh: index, tex_coords, coordinates
JSONArray
gltf_bufferViews
=
new
JSONArray
();
// bufferView for triangle indices:
JSONObject
gltf_view_index
=
new
JSONObject
();
gltf_view_index
.
put
(
"buffer"
,
0
);
gltf_view_index
.
put
(
"byteOffset"
,
0
);
gltf_view_index
.
put
(
"byteLength"
,
buffer_index_bytes
);
/// gltf_view_index.put("byteStride", 2*index_size); // Probably not needed ? page 86
gltf_view_index
.
put
(
"target"
,
ELEMENT_ARRAY_BUFFER
);
gltf_view_index
.
put
(
"name"
,
"buffer-view-index"
);
gltf_bufferViews
.
put
(
gltf_view_index
);
// bufferView for texture coordinates
JSONObject
gltf_view_tex
=
new
JSONObject
();
gltf_view_tex
.
put
(
"buffer"
,
0
);
gltf_view_tex
.
put
(
"byteOffset"
,
buffer_index_bytes
);
gltf_view_tex
.
put
(
"byteLength"
,
buffer_texture_bytes
);
gltf_view_tex
.
put
(
"byteStride"
,
2
*
4
);
gltf_view_tex
.
put
(
"target"
,
ARRAY_BUFFER
);
gltf_view_tex
.
put
(
"name"
,
"buffer-view-tex-coor"
);
gltf_bufferViews
.
put
(
gltf_view_tex
);
// bufferView for world coordinates
JSONObject
gltf_view_coor
=
new
JSONObject
();
gltf_view_coor
.
put
(
"buffer"
,
0
);
gltf_view_coor
.
put
(
"byteOffset"
,
buffer_index_bytes
+
buffer_texture_bytes
);
gltf_view_coor
.
put
(
"byteLength"
,
buffer_coordinate_bytes
);
gltf_view_coor
.
put
(
"byteStride"
,
3
*
4
);
gltf_view_coor
.
put
(
"target"
,
ARRAY_BUFFER
);
gltf_view_coor
.
put
(
"name"
,
"buffer-view-world-coor"
);
gltf_bufferViews
.
put
(
gltf_view_coor
);
gltf_json
.
put
(
"bufferViews"
,
gltf_bufferViews
);
// generate accessors - 3 per mesh: index, texture coordinates and world coordinates
JSONArray
gltf_accessors
=
new
JSONArray
();
for
(
int
nmesh
=
0
;
nmesh
<
total_meshes
;
nmesh
++)
{
// accessor for triangle indices
JSONObject
gltf_accessor_index
=
new
JSONObject
();
JSONArray
gltf_accessor_index_min
=
new
JSONArray
();
JSONArray
gltf_accessor_index_max
=
new
JSONArray
();
gltf_accessor_index_min
.
put
(
minmax_indx
[
nmesh
][
0
]);
gltf_accessor_index_max
.
put
(
minmax_indx
[
nmesh
][
1
]);
gltf_accessor_index
.
put
(
"bufferView"
,
0
);
// of 3
gltf_accessor_index
.
put
(
"byteOffset"
,
offset_len_indx
[
nmesh
][
0
]);
// actually it is signed short/signed int
gltf_accessor_index
.
put
(
"componentType"
,
(
index_size
==
2
)?
COMPONENT_UNSIGNED_SHORT
:
COMPONENT_UNSIGNED_INT
);
gltf_accessor_index
.
put
(
"count"
,
3
*
mesh_tri
[
nmesh
]);
gltf_accessor_index
.
put
(
"min"
,
gltf_accessor_index_min
);
gltf_accessor_index
.
put
(
"max"
,
gltf_accessor_index_max
);
gltf_accessor_index
.
put
(
"type"
,
TYPE_SCALAR
);
gltf_accessor_index
.
put
(
"name"
,
short_names
[
nmesh
]+
"-accessor-index-"
+(
3
*
nmesh
+
0
));
gltf_accessors
.
put
(
gltf_accessor_index
);
// accessor for texture coordinates
JSONObject
gltf_accessor_texcoor
=
new
JSONObject
();
JSONArray
gltf_accessor_texcoor_min
=
new
JSONArray
();
JSONArray
gltf_accessor_texcoor_max
=
new
JSONArray
();
gltf_accessor_texcoor_min
.
put
(
minmax_tex
[
nmesh
][
0
][
0
]);
gltf_accessor_texcoor_min
.
put
(
minmax_tex
[
nmesh
][
1
][
0
]);
gltf_accessor_texcoor_max
.
put
(
minmax_tex
[
nmesh
][
0
][
1
]);
gltf_accessor_texcoor_max
.
put
(
minmax_tex
[
nmesh
][
1
][
1
]);
gltf_accessor_texcoor
.
put
(
"bufferView"
,
1
);
// of 3
gltf_accessor_texcoor
.
put
(
"byteOffset"
,
offset_len_tex
[
nmesh
][
0
]);
// actually it is signed short/signed int
gltf_accessor_texcoor
.
put
(
"componentType"
,
COMPONENT_FLOAT
);
gltf_accessor_texcoor
.
put
(
"count"
,
mesh_vert
[
nmesh
]);
gltf_accessor_texcoor
.
put
(
"min"
,
gltf_accessor_texcoor_min
);
gltf_accessor_texcoor
.
put
(
"max"
,
gltf_accessor_texcoor_max
);
gltf_accessor_texcoor
.
put
(
"type"
,
TYPE_VEC2
);
gltf_accessor_texcoor
.
put
(
"name"
,
short_names
[
nmesh
]+
"-accessor-texcoor-"
+(
3
*
nmesh
+
1
));
gltf_accessors
.
put
(
gltf_accessor_texcoor
);
// accessor for world coordinates
JSONObject
gltf_accessor_coor
=
new
JSONObject
();
JSONArray
gltf_accessor_coor_min
=
new
JSONArray
();
JSONArray
gltf_accessor_coor_max
=
new
JSONArray
();
gltf_accessor_coor_min
.
put
(
minmax_coor
[
nmesh
][
0
][
0
]);
gltf_accessor_coor_min
.
put
(
minmax_coor
[
nmesh
][
1
][
0
]);
gltf_accessor_coor_min
.
put
(
minmax_coor
[
nmesh
][
2
][
0
]);
gltf_accessor_coor_max
.
put
(
minmax_coor
[
nmesh
][
0
][
1
]);
gltf_accessor_coor_max
.
put
(
minmax_coor
[
nmesh
][
1
][
1
]);
gltf_accessor_coor_max
.
put
(
minmax_coor
[
nmesh
][
2
][
1
]);
gltf_accessor_coor
.
put
(
"bufferView"
,
2
);
// of 3
gltf_accessor_coor
.
put
(
"byteOffset"
,
offset_len_coor
[
nmesh
][
0
]);
// actually it is signed short/signed int
gltf_accessor_coor
.
put
(
"componentType"
,
COMPONENT_FLOAT
);
gltf_accessor_coor
.
put
(
"count"
,
mesh_vert
[
nmesh
]);
gltf_accessor_coor
.
put
(
"min"
,
gltf_accessor_coor_min
);
gltf_accessor_coor
.
put
(
"max"
,
gltf_accessor_coor_max
);
gltf_accessor_coor
.
put
(
"type"
,
TYPE_VEC3
);
gltf_accessor_coor
.
put
(
"name"
,
short_names
[
nmesh
]+
"-accessor-coor-"
+(
3
*
nmesh
+
2
));
gltf_accessors
.
put
(
gltf_accessor_coor
);
}
gltf_json
.
put
(
"accessors"
,
gltf_accessors
);
// Generate meshes - trying a single mesh with multiple primitives
JSONObject
gltf_mesh0
=
new
JSONObject
();
JSONArray
gltf_mesh0_primitives
=
new
JSONArray
();
for
(
int
nmesh
=
0
;
nmesh
<
total_meshes
;
nmesh
++)
{
JSONObject
gltf_mesh0_primitive
=
new
JSONObject
();
// does not have "name"
JSONObject
gltf_mesh0_primitive_attr
=
new
JSONObject
();
gltf_mesh0_primitive_attr
.
put
(
"POSITION"
,
3
*
nmesh
+
2
);
gltf_mesh0_primitive_attr
.
put
(
"TEXCOORD_0"
,
3
*
nmesh
+
1
);
gltf_mesh0_primitive
.
put
(
"attributes"
,
gltf_mesh0_primitive_attr
);
gltf_mesh0_primitive
.
put
(
"indices"
,
3
*
nmesh
+
0
);
gltf_mesh0_primitive
.
put
(
"mode"
,
MODE_TRIANGLES
);
gltf_mesh0_primitive
.
put
(
"material"
,
nmesh
);
gltf_mesh0_primitives
.
put
(
gltf_mesh0_primitive
);
}
gltf_mesh0
.
put
(
"primitives"
,
gltf_mesh0_primitives
);
gltf_mesh0
.
put
(
"name"
,
"all-model-meshes"
);
JSONArray
gltf_meshes
=
new
JSONArray
();
gltf_meshes
.
put
(
gltf_mesh0
);
// just a single mesh with multiple primitives
gltf_json
.
put
(
"meshes"
,
gltf_meshes
);
Gson
gson
=
new
GsonBuilder
().
setPrettyPrinting
().
create
();
JsonElement
je
=
JsonParser
.
parseString
(
gltf_json
.
toString
());
String
prettyJsonString
=
gson
.
toJson
(
je
);
FileWriter
gltf_writer
;
// f0 = new FileWriter("output.txt");
gltf_writer
=
new
FileWriter
(
gltf_path
);
gltf_writer
.
write
(
prettyJsonString
);
gltf_writer
.
close
();
return
;
}
}
src/main/java/com/elphel/imagej/x3d/export/TriMesh.java
0 → 100644
View file @
4e6966e0
package
com
.
elphel
.
imagej
.
x3d
.
export
;
/**
**
** TriMesh - triangular mesh representation
**
** Copyright (C) 2022 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
** TriMesh.java is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
** -----------------------------------------------------------------------------**
**
*/
public
class
TriMesh
{
public
String
texture_image
;
public
double
[][]
worldXYZ
;
public
double
[][]
texCoord
;
public
int
[][]
triangles
;
public
TriMesh
(
String
texture_image
,
double
[][]
worldXYZ
,
double
[][]
texCoord
,
int
[][]
triangles
)
{
this
.
texture_image
=
texture_image
;
this
.
worldXYZ
=
worldXYZ
;
this
.
texCoord
=
texCoord
;
this
.
triangles
=
triangles
;
}
public
String
getImage
()
{
return
texture_image
;}
int
[][]
getTriangles
()
{
return
triangles
;}
double
[][]
getTexCoord
()
{
return
texCoord
;
}
public
double
[][]
getTexCoord
(
boolean
inv_x
,
boolean
inv_y
,
boolean
swap_xy
)
{
if
(!
inv_x
&&
!
inv_y
&&
!
swap_xy
)
{
return
texCoord
;
}
double
[][]
inv_tex_coord
=
new
double
[
texCoord
.
length
][
2
];
double
scale_x
=
inv_x
?
-
1.0
:
1.0
;
double
scale_y
=
inv_y
?
-
1.0
:
1.0
;
if
(
swap_xy
)
{
for
(
int
i
=
0
;
i
<
texCoord
.
length
;
i
++)
{
inv_tex_coord
[
i
][
0
]
=
scale_y
*
texCoord
[
i
][
1
];
inv_tex_coord
[
i
][
1
]
=
scale_x
*
texCoord
[
i
][
0
];
}
}
else
{
for
(
int
i
=
0
;
i
<
texCoord
.
length
;
i
++)
{
inv_tex_coord
[
i
][
0
]
=
scale_x
*
texCoord
[
i
][
0
];
inv_tex_coord
[
i
][
1
]
=
scale_y
*
texCoord
[
i
][
1
];
}
}
return
inv_tex_coord
;
}
public
double
[][]
getCoordinates
(){
return
worldXYZ
;
}
/**
* 0: XYZ -> XYZ
* 1: XYZ -> YZX
* 2: XYZ -> ZXY
* 3: XYZ -> XZY
* 4: XYZ -> ZYX
* 5: XYZ -> YXZ
* @param inv_x
* @param inv_y
* @param inv_z
* @param swap3
* @return
*/
public
double
[][]
getCoordinates
(
boolean
inv_x
,
boolean
inv_y
,
boolean
inv_z
,
int
swap3
)
{
if
(!
inv_x
&&
!
inv_y
&&
!
inv_y
&&
(
swap3
==
0
))
{
return
worldXYZ
;
}
double
[][]
inv_worldXYZ
=
new
double
[
worldXYZ
.
length
][
3
];
double
scale_x
=
inv_x
?
-
1.0
:
1.0
;
double
scale_y
=
inv_y
?
-
1.0
:
1.0
;
double
scale_z
=
inv_z
?
-
1.0
:
1.0
;
switch
(
swap3
)
{
case
0
:
// XYZ -> XYZ
for
(
int
i
=
0
;
i
<
texCoord
.
length
;
i
++)
{
inv_worldXYZ
[
i
][
0
]
=
scale_x
*
worldXYZ
[
i
][
0
];
inv_worldXYZ
[
i
][
1
]
=
scale_y
*
worldXYZ
[
i
][
1
];
inv_worldXYZ
[
i
][
2
]
=
scale_z
*
worldXYZ
[
i
][
2
];
}
break
;
case
1
:
// XYZ -> YZX
for
(
int
i
=
0
;
i
<
texCoord
.
length
;
i
++)
{
inv_worldXYZ
[
i
][
1
]
=
scale_x
*
worldXYZ
[
i
][
0
];
inv_worldXYZ
[
i
][
2
]
=
scale_y
*
worldXYZ
[
i
][
1
];
inv_worldXYZ
[
i
][
0
]
=
scale_z
*
worldXYZ
[
i
][
2
];
}
break
;
case
2
:
// XYZ -> ZXY
for
(
int
i
=
0
;
i
<
texCoord
.
length
;
i
++)
{
inv_worldXYZ
[
i
][
2
]
=
scale_x
*
worldXYZ
[
i
][
0
];
inv_worldXYZ
[
i
][
0
]
=
scale_y
*
worldXYZ
[
i
][
1
];
inv_worldXYZ
[
i
][
1
]
=
scale_z
*
worldXYZ
[
i
][
2
];
}
break
;
case
3
:
// XYZ -> XZY
for
(
int
i
=
0
;
i
<
texCoord
.
length
;
i
++)
{
inv_worldXYZ
[
i
][
0
]
=
scale_x
*
worldXYZ
[
i
][
0
];
inv_worldXYZ
[
i
][
2
]
=
scale_y
*
worldXYZ
[
i
][
1
];
inv_worldXYZ
[
i
][
1
]
=
scale_z
*
worldXYZ
[
i
][
2
];
}
break
;
case
4
:
// XYZ -> ZYX
for
(
int
i
=
0
;
i
<
texCoord
.
length
;
i
++)
{
inv_worldXYZ
[
i
][
2
]
=
scale_x
*
worldXYZ
[
i
][
0
];
inv_worldXYZ
[
i
][
1
]
=
scale_y
*
worldXYZ
[
i
][
1
];
inv_worldXYZ
[
i
][
0
]
=
scale_z
*
worldXYZ
[
i
][
2
];
}
break
;
case
5
:
// XYZ -> YXZ
for
(
int
i
=
0
;
i
<
texCoord
.
length
;
i
++)
{
inv_worldXYZ
[
i
][
1
]
=
scale_x
*
worldXYZ
[
i
][
0
];
inv_worldXYZ
[
i
][
0
]
=
scale_y
*
worldXYZ
[
i
][
1
];
inv_worldXYZ
[
i
][
2
]
=
scale_z
*
worldXYZ
[
i
][
2
];
}
break
;
default
:
return
null
;
}
return
inv_worldXYZ
;
}
}
src/main/java/com/elphel/imagej/x3d/export/WavefrontExport.java
View file @
4e6966e0
package
com
.
elphel
.
imagej
.
x3d
.
export
;
/**
**
** WavefrontExport - generate Wavefront OBJ representation of the model
**
** Copyright (C) 2018 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
** WavefrontExport.java is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
** -----------------------------------------------------------------------------**
**
*/
import
java.io.FileWriter
;
import
java.io.IOException
;
...
...
src/main/java/com/elphel/imagej/x3d/export/X3dOutput.java
View file @
4e6966e0
...
...
@@ -76,6 +76,7 @@ public class X3dOutput {
this
.
clt_3d_passes
=
clt_3d_passes
;
}
// init document, bounding box, backdrop
// 09.18.2022 - made work w/o background
public
void
generateBackground
(
boolean
use_backdrop
)
{
try
{
...
...
@@ -105,6 +106,11 @@ public class X3dOutput {
el_Scene
.
appendChild
(
el_TopGroup
);
if
(
clt_3d_passes
==
null
)
{
System
.
out
.
println
(
"Not using background without clt_3d_passes"
);
return
;
}
CLTPass3d
bgnd_pass
=
clt_3d_passes
.
get
(
0
);
Element
el_Bgnd
=
x3dDoc
.
createElement
(
"Background"
);
...
...
@@ -167,6 +173,10 @@ public class X3dOutput {
sb_tex_coords
.
append
(
String
.
format
(
"%.4f %.4f"
,
texCoord
[
i
][
0
],
texCoord
[
i
][
1
]));
}
String
sindex
=
sb_coord_index
.
toString
();
// for both coordIndex and texCoordIndex
if
(
sindex
.
length
()
==
0
)
{
System
.
out
.
println
(
"addCluster(): sindex.length() == 0"
);
System
.
out
.
println
(
"addCluster(): sindex.length() == 0"
);
}
String
scoord
=
sb_coords
.
toString
();
String
stcoord
=
sb_tex_coords
.
toString
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment