Skip to main content

What do you use to compress large 3D images?

39 replies [Last post]
darrinps
Offline
Joined: 2003-06-12
Points: 0

I have a situation where files in .obj format are just too large to transmit across the Internet.

At first I tried using CompressedGeometry and this worked VERY well, but it has a couple problems:

1) It has been deprecated and will not work with 1.4 as far as the new shaders go.

2) It automatically scales some images (see this thread: http://www.javadesktop.org/forums/thread.jspa?threadID=16401&tstart=0)

So, I'm back to square one.

I've looked at simply zipping the .obj files but that doesn't work anywhere near as well as the compressed geometry did (the zip is about 80% larger).

Does anyone know of anything that takes a .obj (or .stl, oer something else even) and compresses it and then allows you to decompress it on the other end inside of a Java applet/application?

THANKS!

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Mark Hood

[duplicate message deleted]

Message was edited by: kcr

Mark Hood

[duplicate message deleted]

Message was edited by: kcr

darrinps
Offline
Joined: 2003-06-12
Points: 0

Thanks!

May not need to use it, but if I do that info will come in handy.

kcr
Offline
Joined: 2004-03-17
Points: 0

Mark, thanks for the additional information.

> A note about quantization space -- it's not exactly [-1..1]. Its
> actually one quantum away from -1.0 and +1.0 on both sides.
>
> For example, with 16 bits of resolution, the quantization space is
> [(-1.0 + 1/65536) .. (+1.0 - 1/65536)].
> If you need precise scaling, you will need account for those quantums.

Probably better to let CompressedGeometry utilities scale the model and then query the scale (as we discussed yesterday). I think this will require a new method, or at least making an existing package-scope method public.

> With respect to CompressedGeometryFile, it was never intended to be a
> streamable transport mechanism, nor was it designed to encapsulate any
> metadata about the geometry within.

Good point, and as to your following suggestion:

> So I would recommend saving the model and normalized bounds of the
> geometry as you compress it, and then devise your own streamable file
> format that encapsulates the compressed geometry and any metadata you
> would need to display it.

I agree completely. Eventually, if there is enough interest (and an owner), it could be turned into a standard utility.

-- Kevin

darrinps
Offline
Joined: 2003-06-12
Points: 0

> I think this will require a new
> method, or at least making an existing package-scope
> method public.

If I read Mark's reply correctly, and my test does what I THINK it does, then I'm not sure it is needed after all.

Here is what I did:

[code]
private CompressedGeometry compressScene(Scene scene)
{

//TEST
CompressionStream cs = getStream(scene);
CompressedGeometry cg = compressor.compress(cs);
Point3d[] modelBounds = cs.getModelBounds();
Point3d[] normalizedBounds = cs.getNormalizedBounds();
double scale = (modelBounds[1].x - modelBounds[0].x) /
(normalizedBounds[1].x - normalizedBounds[0].x);

System.out.println("New scale: " + scale);

return cg;

//TEST

// return compressor.compress(getStream(scene));

}

[/code]

My thought was that (and I guess I could have viewed the source..but I didn't have it downloaded from CVS) that the CompressionStream was modified by the compress method...and it looks like it was.

Running that code I saw these results (note that some info comes from other methods):

Quality settings:
position = 10
color = 8
normal = 4

Reading/Compressing: UpperModel.obj
New scale: 28.842190557729943
Compressed size is: 239528
Compression complete

Reading/Compressing: LowerModel.obj
New scale: 28.329279467127815
Compressed size is: 243736
Compression complete

Now if I understand all of this correctly, then we would just have to calculate the correction scale using the current (28.842, and 28.33) scale after compression and what it was scaled at before compression.

Does that sound right?

If so, then the question is how do you get the scale of the original obj object?

I know that you can't use the CompressionStream (I tried that...scale was Infinity).

Mark Hood

> Date: Fri, 12 Aug 2005 10:41:43 EDT
> From: java3d-interest@javadesktop.org
>
> Now if I understand all of this correctly, then we would just have
> to calculate the correction scale using the current (28.842, and
> 28.33) scale after compression and what it was scaled at before
> compression.
>
> Does that sound right?
>
> If so, then the question is how do you get the scale of the original
> obj object?

The original uncompressed object isn't scaled, if that's what you're
asking. The compression scale you computed is what you need to scale
the compressed object to the size of the original object.

If you know how to orient and position the original uncompressed
geometry to get what you want in the scene graph, then to replace the
original, use the same transforms and put that scale factor you
computed into a transform directly above the compressed object in the
scene graph.

-- Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

darrinps
Offline
Joined: 2003-06-12
Points: 0

> If you know how to orient and position the original
> uncompressed
> geometry to get what you want in the scene graph,
> then to replace the
> original, use the same transforms and put that scale
> factor you
> computed into a transform directly above the
> compressed object in the
> scene graph.
>
> -- Mark

I must be doing something wrong because this isn't working.

What happens is that the the 4 3D objects all seem to be off in the Z direction.

When I view them as .obj files, all works after I fudge the Y axis (topic for another thread, but long story short they overly each other unless I seperate them by adding a Y value in a transform).

When I view them after compression and applying the scale values that the compression routine specified, they are not only off in the Y direction but also the Z. In short, models 2,3, and 4 all look like they need to move back from the viewer a bit...but how much and how this would be calculated I do not know.

I figure that either I am applying the scale in the wrong place, or that there should be a way to calculate a transform for the Z axis shift based on the scale and the size of the object.

Here is what I am doing. Maybe someone will see what the problem is:

[code]
Transform3D t3dModel1 = new Transform3D();
TransformGroup tgModel1 = new TransformGroup(t3dModel1);
tgModel1.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tgModel1.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
tgModel1.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
tgModel1.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);

Transform3D t3dModel2 = new Transform3D();
TransformGroup tgModel2 = new TransformGroup(t3dModel2);
tgModel2.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tgModel2.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
tgModel2.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
tgModel2.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);

Transform3D t3dModel3 = new Transform3D();
TransformGroup tgModel3 = new TransformGroup(t3dModel3);
tgModel3.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tgModel3.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
tgModel3.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
tgModel3.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);

Transform3D t3dModel4 = new Transform3D();
TransformGroup tgModel4 = new TransformGroup(t3dModel4);
tgModel4.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tgModel4.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
tgModel4.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
tgModel4.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);

//Calculate scaling factors...will be read in but hard coded for test here
float m1Scale = 41.95377476761252f;
float m2Scale = 28.424669824314396f;
float m3Scale = 31.060364187989716f;
float m4Scale = 41.953776678693735f;

m1Scale = m1Scale / 100;
m2Scale = m2Scale / 100;
m3Scale = m3Scale / 100;
m4Scale = m4Scale / 100;

TransformGroup tgModel1Reset = new TransformGroup();
Transform3D t3dModel1Reset = new Transform3D();
t3dModel1Reset.rotX(Math.toRadians(270)); //Correct face down
t3dModel1Reset.setScale(m1Scale);
t3dModel1Reset.setTranslation(new Vector3f(+0.0f, +0.19f, +0.0f));

tgModel1Reset.setTransform(t3dModel1Reset);
tgModel1Reset.addChild(Model1Shape);

TransformGroup tgModel2Reset = new TransformGroup();
Transform3D t3dModel2Reset = new Transform3D();
t3dModel2Reset.rotX(Math.toRadians(270)); //Correct face down
t3dModel2Reset.setScale(m2Scale);
t3dModel2Reset.setTranslation(new Vector3f(+0.0f, +0.05f, +0.0f));

tgModel2Reset.setTransform(t3dModel2Reset);
tgModel2Reset.addChild(Model2Shape);

TransformGroup tgModel3Reset = new TransformGroup();
Transform3D t3dModel3Reset = new Transform3D();
t3dModel3Reset.rotX(Math.toRadians(270)); //Correct face down
t3dModel3Reset.setScale(m3Scale);
t3dModel3Reset.setTranslation(new Vector3f(+0.0f, -0.05f, +0.0f));

tgModel3Reset.setTransform(t3dModel3Reset);
tgModel3Reset.addChild(Model3Shape);

TransformGroup tgModel4Reset = new TransformGroup();
Transform3D t3dModel4Reset = new Transform3D();
t3dModel4Reset.rotX(Math.toRadians(270)); //Correct face down
t3dModel4Reset.setScale(m4Scale);
t3dModel4Reset.setTranslation(new Vector3f(+0.0f, -0.15f, +0.0f));

tgModel4Reset.setTransform(t3dModel4Reset);
tgModel4Reset.addChild(Model4Shape);

tgModel1.addChild(tgModel1Reset);
tgModel2.addChild(tgModel2Reset);
tgModel3.addChild(tgModel3Reset);
tgModel4.addChild(tgModel4Reset);
[/code]

darrinps
Offline
Joined: 2003-06-12
Points: 0

Just a quick update/clarification.

With the OBJ files in "world coordinates" I don't need to fudge the Y offset at all and everything shows up perfectly aligned.

It is only after I run it through the compression routine that I have the problem.

It looks like doing that places it in different coordinates maybe?

darrinps
Offline
Joined: 2003-06-12
Points: 0

Another update.

I found that the scale wasn't doing anything (why?).

I ended up moving this above and now it does affect the scene.

Here is the modified code. Note that the problems still exist (Y and Z orientation problem):

[code]

//Calculate scaling factors...will be read in but hard coded for test here
float m1Scale = 41.95377476761252f;
float m2Scale = 28.424669824314396f;
float m3Scale = 31.060364187989716f;
float m4Scale = 41.953776678693735f;

m1Scale = m1Scale / 100;
m2Scale = m2Scale / 100;
m3Scale = m3Scale / 100;
m4Scale = m4Scale / 100;

Transform3D t3dModel1 = new Transform3D();
t3dModel1.setScale(m1Scale);
TransformGroup tgModel1 = new TransformGroup(t3dModel1);
tgModel1.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tgModel1.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
tgModel1.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
tgModel1.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);

Transform3D t3dModel2 = new Transform3D();
t3dModel2.setScale(m2Scale);
TransformGroup tgModel2 = new TransformGroup(t3dModel2);
tgModel2.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tgModel2.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
tgModel2.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
tgModel2.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);

Transform3D t3dModel3 = new Transform3D();
t3dModel3.setScale(m3Scale);
TransformGroup tgModel3 = new TransformGroup(t3dModel3);
tgModel3.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tgModel3.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
tgModel3.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
tgModel3.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);

Transform3D t3dModel4 = new Transform3D();
t3dModel4.setScale(m4Scale);
TransformGroup tgModel4 = new TransformGroup(t3dModel4);
tgModel4.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tgModel4.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
tgModel4.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
tgModel4.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);

TransformGroup tgModel1Reset = new TransformGroup();
Transform3D t3dModel1Reset = new Transform3D();
t3dModel1Reset.rotX(Math.toRadians(270)); //Correct face down
// t3dModel1Reset.setScale(m1Scale);
t3dModel1Reset.setTranslation(new Vector3f(+0.0f, +0.19f, +0.0f));

tgModel1Reset.setTransform(t3dModel1Reset);
tgModel1Reset.addChild(Model1Shape);

TransformGroup tgModel2Reset = new TransformGroup();
Transform3D t3dModel2Reset = new Transform3D();
t3dModel2Reset.rotX(Math.toRadians(270)); //Correct face down
// t3dModel2Reset.setScale(m2Scale);
t3dModel2Reset.setTranslation(new Vector3f(+0.0f, +0.05f, +0.0f));

tgModel2Reset.setTransform(t3dModel2Reset);
tgModel2Reset.addChild(Model2Shape);

TransformGroup tgModel3Reset = new TransformGroup();
Transform3D t3dModel3Reset = new Transform3D();
t3dModel3Reset.rotX(Math.toRadians(270)); //Correct face down
// t3dModel3Reset.setScale(m3Scale);
t3dModel3Reset.setTranslation(new Vector3f(+0.0f, -0.05f, +0.0f));

tgModel3Reset.setTransform(t3dModel3Reset);
tgModel3Reset.addChild(Model3Shape);

TransformGroup tgModel4Reset = new TransformGroup();
Transform3D t3dModel4Reset = new Transform3D();
t3dModel4Reset.rotX(Math.toRadians(270)); //Correct face down
// t3dModel4Reset.setScale(m4Scale);
t3dModel4Reset.setTranslation(new Vector3f(+0.0f, -0.15f, +0.0f));

tgModel4Reset.setTransform(t3dModel4Reset);
tgModel4Reset.addChild(Model4Shape);

tgModel1.addChild(tgModel1Reset);
tgModel2.addChild(tgModel2Reset);
tgModel3.addChild(tgModel3Reset);
tgModel4.addChild(tgModel4Reset);

[/code]

darrinps
Offline
Joined: 2003-06-12
Points: 0

Still having trouble after converting to this for each model:
[code]
//Calculate scaling factors...will be read in but hard coded for test here
float m1Scale = 41.95377476761252f;
float m2Scale = 28.424669824314396f;
float m3Scale = 31.060364187989716f;
float m4Scale = 41.953776678693735f;

m1Scale = m1Scale / 100;
m2Scale = m2Scale / 100;
m3Scale = m3Scale / 100;
m4Scale = m4Scale / 100;

Transform3D t3dModel1 = new Transform3D();
TransformGroup tgModel1 = new TransformGroup(t3dModel1);
tgModel1.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tgModel1.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
tgModel1.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
tgModel1.setCapability(TransformGroup.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);

//Same thing done for models 2, 3 and 4

Transform3D m1setScale = new Transform3D();
Transform3D m1Rotation = new Transform3D();
Transform3D m1Combined = new Transform3D();

TransformGroup tgModel1Reset = new TransformGroup();
m1setScale.setScale(m1Scale);
m1Rotation.rotX(Math.toRadians(270));
m1Combined.mul(m1Rotation, m1setScale);
tgModel1Reset.setTransform(m1Combined);
tgModel1Reset.addChild(Model1Shape);

//Same thing done for models 2, 3 and 4

[/code]

It acts like the models are no longer in world coordinates and are instead all getting placed at the origin. Is there some flag that needs to be set when compressing the images that keeps the coordinates in tact?

If not, would there be a way to get the original coordinates, save them off, and then calculate what the new ones should be based on the scaling factor?

THANKS!

darrinps
Offline
Joined: 2003-06-12
Points: 0

Well it works now (the CompressedGeometry version...will test out the X3D binary later).

As for the CG stuff, here it what needs to be done:

1) Compress the OBJ models to CG
2) For each compressed model, save off:
a) The CompressedGeometryHeader
b) The scale of the newly compressed model
c) The bounds of the original model
3) Decompress by loading up the CG as normal using the header, then use the scale and bounds like this:

[code]
//Calculate scaling factors...will be read in but hard coded for test here
float model1Scale = 41.95377476761252f;
float model2Scale = 28.424669824314396f;

Transform3D t3dModel1 = new Transform3D();
t3dModel1.rotX(Math.toRadians(270d));
TransformGroup tgModel1 = new TransformGroup(t3dModel1);

Transform3D t3dModel2 = new Transform3D();
t3dModel2.rotX(Math.toRadians(270d));
TransformGroup tgModel2 = new TransformGroup(t3dModel2);

//BOunds will be read in but hard coded for test
Vector3d offset = new Vector3d();
Model1UpperBound = new Point3d(42.92759323120117, 37.80514144897461, 32.51144790649414);
Model1LowerBound = new Point3d(-40.81607437133789, -26.49483871459961, 1.2013089656829834);
Model2UpperBound = new Point3d(29.663230895996094, 21.263938903808594, 12.634425163269043);
Model2LowerBound = new Point3d(-27.01955795288086, -18.983013153076172, -3.275989055633545);

offset.x = (Model1UpperBound.x + Model1LowerBound.x) / 2.0;
offset.y = (Model1UpperBound.y + Model1LowerBound.y) / 2.0;
offset.z = (Model1UpperBound.z + Model1LowerBound.z) / 2.0;

Transform3D model1setScale = new Transform3D();
Transform3D model1Translation = new Transform3D();
Transform3D model1ScaleOffset = new Transform3D();

TransformGroup tgModel1Reset = new TransformGroup();
model1setScale.setScale(model1Scale);
model1Translation.setTranslation(offset);

model1ScaleOffset.mul(model1Translation, model1setScale);
tgModel1Reset.setTransform(model1ScaleOffset);
tgModel1Reset.addChild(Model1Shape);

offset.x = (Model2UpperBound.x + Model2LowerBound.x) / 2.0;
offset.y = (Model2UpperBound.y + Model2LowerBound.y) / 2.0;
offset.z = (Model2UpperBound.z + Model2LowerBound.z) / 2.0;

Transform3D model2setScale = new Transform3D();
Transform3D model2Translation = new Transform3D();
Transform3D model2ScaleOffset = new Transform3D();

TransformGroup tgModel2Reset = new TransformGroup();
model2setScale.setScale(model2Scale);
model2Translation.setTranslation(offset);

model2ScaleOffset.mul(model2Translation, model2setScale);
tgModel2Reset.setTransform(model2ScaleOffset);
tgModel2Reset.addChild(Model2Shape);

[/code]

To calculate the scale and save off the original model's bounds, you need to add some code to your class that extends ObjectFile (at least that is how I did it).

In short, here is what I did:

[code]
private CompressedGeometry compressScene(Scene scene)
{

//TEST
CompressionStream cs = getStream(scene);
CompressedGeometry cg = compressor.compress(cs);

Point3d[] modelBounds = cs.getModelBounds();
Point3d[] normalizedBounds = cs.getNormalizedBounds();
double scale = (modelBounds[1].x - modelBounds[0].x) /
(normalizedBounds[1].x - normalizedBounds[0].x);

System.out.println("Model Bounds: " + modelBounds[1] + "," + modelBounds[0]);
System.out.println("Normalized Bounds: " + normalizedBounds[1] + "," + normalizedBounds[0]);
System.out.println("New scale: " + scale);

return cg;
}
[/code]

Also, [b]MANY[/b] thanks to Mark Hood on helping me solve this.

Hope this helps someone else.

Message was edited by: darrinps

Mark Hood

You can get the compressed scaling info from the public accessor
methods getModelBounds() and getNormalizedBounds() in the
CompressionStream utility class that you used to compress the
geometry.

A note about quantization space -- it's not exactly [-1..1]. Its
actually one quantum away from -1.0 and +1.0 on both sides.

For example, with 16 bits of resolution, the quantization space is
[(-1.0 + 1/65536) .. (+1.0 - 1/65536)]. If you need precise scaling,
you will need account for those quantums.

The arithmetic of signed 2's-complement integers actually allows a
greater range on the negative side -- we could have defined
quantization space to be [-1.0 .. (+1.0 - 1/(2**q))], but then we
thought not having the origin in the middle of the space would be too
confusing.

Also, the quantization scale factor is uniform across all axes -- we
choose the axis with the greatest range, and scale that to the nominal
[-1..1] space, with the other axes scaling appropriately.

With respect to CompressedGeometryFile, it was never intended to be a
streamable transport mechanism, nor was it designed to encapsulate any
metadata about the geometry within. Basically, it was a hack to get
around the horrible file I/O performance that Java had in its earlier
incarnations. At the time we were developing this stuff, we had many
gigabytes of compressed geometry that we needed to display for various
projects and demos, and we simply could not read them in fast enough
with the standard Java API.

So I would recommend saving the model and normalized bounds of the
geometry as you compress it, and then devise your own streamable file
format that encapsulates the compressed geometry and any metadata you
would need to display it.

All this attention to CompressedGeometry! We thought it was dead once
we abandoned the one platform that supported hardware decompression --
the Sun Elite3D -- and we were unable to find the resources to expand
the implementation for texture coordinates. But even with a pure
software implementation, it still is the most compact method of
storing geometry I've ever seen, and the fastest to load into a Java
3D scene graph.

-- Mark Hood

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

darrinps
Offline
Joined: 2003-06-12
Points: 0

> You can get the compressed scaling info from the
> public accessor
> methods getModelBounds() and getNormalizedBounds() in
> the
> CompressionStream utility class that you used to
> compress the
> geometry.

I just looked at these and you get back a Point3D array from each.

I suppose that you could calculate the scale adjustment, but I didn't see any way to automatically get it from these methods.

Assuming that is correct, and all three axis are scaled uniformly (I think that's the way it works if I recall correctly), then how do you use the array? Do you just looks at the 0 index?

I googled for getModelBounds() Java3D, and it only returned two hits...neither one of which explained how to use it!

It would look something like this to start out with...

[code]
//In an class that extends ObjectFile
GeometryCompressor compressor = new GeometryCompressor();
//...
CompressionStream cs = getStream(scene);

Point3d[] originalBoundsArray = cs.getModelBounds();
Point3d[] compressedBoundsArray = cs.getNormalizedBounds();
[/code]

After that though, what do you do with the arrays?

Mark Hood

> Date: Wed, 10 Aug 2005 09:51:47 EDT
> From: java3d-interest@javadesktop.org
>
> > You can get the compressed scaling info from the
> > public accessor
> > methods getModelBounds() and getNormalizedBounds() in
> > the
> > CompressionStream utility class that you used to
> > compress the
> > geometry.
>
> I just looked at these and you get back a Point3D array from each.
>
> I suppose that you could calculate the scale adjustment, but I
> didn't see any way to automatically get it from these methods.

These methods return the lower and upper bounds of the vertex range.
It's in the Javadoc for the utilities, but that bundle is a separate
download.

This is actually more information than you need given that the
compressor as shipped scales uniformly and symmetrically about the
model origin. The Compressed Geometry Specification doesn't mandate
either of those constraints on the scaling though -- the lower and
upper bounds provide the complete scale and offset information you
need for non-uniform, non-symmetric scaling.

So to get the uniform compression scaling, just compute the delta on
one of the axes of the original model bounds -- say X -- and divide by
the delta on the same axis of the normalized bounds:

Point3d[] modelBounds = getModelBounds();
Point3d[] normalizedBounds = getNormalizedBounds();
double scale = (modelBounds[1].x - modelBounds[0].x) /
(normalizedBounds[1].x - normalizedBounds[0].x);

For the best accuracy, choose the axis that has the greatest range.

-- Mark Hood

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Mark Hood

kcr: deleted duplicate post

Message was edited by: kcr

kcr
Offline
Joined: 2004-03-17
Points: 0

Justin pointed out the reasons why a [-1,+1] space is used. What is needed--and I thought was there, but a cursory glance doesn't show it--in the compressed geometry file is the scale value used on the object so that it can be rescaled upon loading. In the absence of this, the scale would need to be stored/transmitted separately.

-- Kevin

darrinps
Offline
Joined: 2003-06-12
Points: 0

> Justin pointed out the reasons why a [-1,+1] space is
> used. What is needed--and I thought was there, but a
> cursory glance doesn't show it--in the compressed
> geometry file is the scale value used on the object
> so that it can be rescaled upon loading. In the
> absence of this, the scale would need to be
> stored/transmitted separately.
>
> -- Kevin

I just checked as well...no scale.

Now (as I just wrote you) exactly how can you obtain the scale to save it off?

It's package private in the CompressionStream and there are no accessors for it anywhere that I could find.

kcr
Offline
Joined: 2004-03-17
Points: 0

> I just checked as well...no scale.
>
> Now (as I just wrote you) exactly how can you obtain the scale to save it off?
>
> It's package private in the CompressionStream and there are no accessors for it anywhere that I could find.

What I was suggesting is that the compressed geometry utilities will need to be enhanced. If the variable is package-private, then public accessor/mutator methods will need to be added. Once the new utility API is added, applications can access the information programatically. Transmitting it between apps or across the network will be more difficult, since we don't want to make an incompatible change to the CompressedGeometryFile format, unless you do it "out of band" (i.e., not part of the file format).

Now all we need is a volunteer.

-- Kevin

darrinps
Offline
Joined: 2003-06-12
Points: 0

Looking at it quickly, I think all that would be needed is to extend two classes:

1) CompressionStream to add getter/setter for the scale.
2) GeometryCompressor to use the extended version of CompressionStream in its compress method.

Again, that's just looking at it quickly, but that should at least allow you to gain access to the scale.

I suppose you could also extend:

3) CompressedGeometryHeader to put in a place holder for the scale.
4) CompressedGeometry to use the extended version of the header.

That probably isn't needed though.

Kyle McDonald

An Alternate solution, for the interim, and probably just for you, would
be to scale the geometry yourself *before* compressing it, and recording
the scale you used.

If you have different pieces of geometry that were being compressed
differently (because of this scaling) then by scaleing all the pieces
identically, the uncompressed geometry would retain it's relative scale.

-Kyle

java3d-interest@javadesktop.org wrote:

>Looking at it quickly, I think all that would be needed is to extend two classes:
>
>1) CompressionStream to add getter/setter for the scale.
>2) GeometryCompressor to use the extended version of CompressionStream in its compress method.
>
>Again, that's just looking at it quickly, but that should at least allow you to gain access to the scale.
>
>I suppose you could also extend:
>
>3) CompressedGeometryHeaderFile to put in a place holder for the scale.
>4) CompressedGeometry to use the extended version of the header.
>
>That probably isn't needed though.
>---
>[Message sent by forum member 'darrinps' (Darrin)]
>
>http://www.javadesktop.org/forums/thread.jspa?messageID=104787𙥓
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
>For additional commands, e-mail: interest-help@java3d.dev.java.net
>
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

darrinps
Offline
Joined: 2003-06-12
Points: 0

> An Alternate solution, for the interim, and probably
> just for you, would
> be to scale the geometry yourself *before*
> compressing it, and recording
> the scale you used.
>
> If you have different pieces of geometry that were
> being compressed
> differently (because of this scaling) then by
> scaleing all the pieces
> identically, the uncompressed geometry would retain
> it's relative scale.

Depending on how Justin's STL to X3D binary converter works, and how getting that across the Internet goes, I think what you mention is the way I'll need to go if going the CG route instead of X3D.

As you said, have the OBJ files all scaled uniformly so that they fit in [-1,1] and then display them without needing to rescale.

Justin Couch

java3d-interest@javadesktop.org wrote:

> Depending on how Justin's STL to X3D binary converter works, and how getting that across the Internet goes, I think what you mention is the way I'll need to go if going the CG route instead of X3D.

It's on the way. Just hacking on some of our existing code in Xj3D to
build it into that. We had a long chat about it here at Yumetech and
some possible future business implications (ie more ways of making money
:) ) and we've decided to do it a little more formally than what I was
talking about yesterday.

Part of the code that I'm working on is basically a munger between some
arbitrary file format and our internal X3D streaming APIs. The nice
thing about this is that we can then feed that into our existing
workflow filter suite. This suite allows us to process the stream on the
way through for all sorts of things (pluggable architecture). For
example, we can have a filter do transform stack reduction applied
before we export the final version of the file. Another use for the
filters is precision reduction or surface simplification - there's
really no limit to what could be done with it.

All this means is that it will take an extra day or two to get finished,
but you should have something very useful at the end of it - and if you
have a Java-based middleware system, you could embed this directly into
that. I'm working on the basic architecture up until lunch and then will
need to spend the afternoon working on Other Stuff. Hopefully this
evening, after training, I'll code up the STL->X3D stream interface and
you should be close to running. One thing I did find out from Alan is
that within that filter architecture, we're still not generating the
spec-compliant binary output. What it has right now is an older
prototype version. We won't be able to get it converted over to the
spec-compliant output until late-ish next week due to other paying
projects needing our attention right now (conference next week that we
need to present at too). However, with the prototype stuff, you should
have a good idea of the rough file sizes that you'll be getting for output.

--
Justin Couch http://www.vlc.com.au/~justin/
Java Architect & Bit Twiddler http://www.yumetech.com/
Author, Java 3D FAQ Maintainer http://www.j3d.org/
-------------------------------------------------------------------
Programming is essentially a markup language surrounding
mathematical formulae and thus, should not be patentable.
-------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

darrinps
Offline
Joined: 2003-06-12
Points: 0

> All this means is that it will take an extra day or
> two to get finished,
> but you should have something very useful at the end
> of it - and if you
> have a Java-based middleware system, you could embed
> this directly into
> that. I'm working on the basic architecture up until

Thanks!

All I need to do with it right now is to use it as a compressor (STL to X3D) and a Java3D loader.

Here is the plan:

1) Run your new code against the four STL files to convert them to binary X3D.

I assume you'll provide an example on how to do this.

2) Use the VRML97Loader (Xj3D) to load up each of the newly minted X3D files.

It will look a little like this for each of the models (upperModel1, upperModel2, lowerModel1, and lowerModel2).

[code]
Loader x3dLoader = new VRML97Loader(Loader.LOAD_ALL);

Scene scene = x3dLoader.load(upperModel1);

Shape3D upperModel1Shape = new Shape3D();
upperModel1Shape = (Shape3D)scene.getSceneGroup().getChild(0);

scene.getSceneGroup().removeAllChildren();
[/code]

3) Add the shapes to my switchgroup and my switchgroup to the branchgroup.

After I get that working, then I'll try to set it up to pull the models from across an Internet connection (what I do today with the CG files and their headers).

The way I do that today (if anyone is interested) looks like this:

[code]
URL urlUpper1 = new URL(tempUpper1);
URL urlUpper1Header = new URL(upperHeader);

DataInputStream hdrStream = new DataInputStream(urlUpper1Header.openStream());
HeaderReader reader = new HeaderReader();

CompressedGeometryHeader upperGeomHeader = reader.read(hdrStream);

//Now read in the compressed file
DataInputStream upperInStream = new DataInputStream(urlUpper1.openStream());

byte[] upperBuffer = new byte[upperGeomHeader.size];

upperInStream.readFully(upperBuffer,0, upperGeomHeader.size);
upperInStream.close();

// Read the compressed geometry.
CompressedGeometry cg = new CompressedGeometry(upperGeomHeader, upperBuffer);

Shape3D upperShape = new Shape3D(cg);
[/code]

The HeaderReader is just a little home grown class.

Justin Couch

java3d-interest@javadesktop.org wrote:

> All I need to do with it right now is to use it as a compressor (STL to X3D) and a Java3D loader.

Understood. We're thinking longer term possibilities than that. We're
already doing a lot of this work internally for projects for our clients
anyway, so doing the extra few cycles to make it into a formal project
within Xj3D is worth it to us.

> 1) Run your new code against the four STL files to convert them to binary X3D.
>
> I assume you'll provide an example on how to do this.

I will. Also, if you are able to, you could send me a representative
file privately and I'll make sure it runs before I point you at the code
(it will all be in the Xj3D CVS, though building an installer shouldn't
be too hard as we have that process automated fairly well now). Not that
STL is anything but a trivial format, but it is always useful to check
against someone's real-world usage too.

> 2) Use the VRML97Loader (Xj3D) to load up each of the newly minted X3D files.

Note that you don't want to use VRML97Loader. That only loads VRML97
files. Instead, you want to use X3DLoader as that only loads X3D files.

--
Justin Couch http://www.vlc.com.au/~justin/
Java Architect & Bit Twiddler http://www.yumetech.com/
Author, Java 3D FAQ Maintainer http://www.j3d.org/
-------------------------------------------------------------------
Programming is essentially a markup language surrounding
mathematical formulae and thus, should not be patentable.
-------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

darrinps
Offline
Joined: 2003-06-12
Points: 0

> I will. Also, if you are able to, you could send me a
> representative
> file privately and I'll make sure it runs before I
> point you at the code

I'll get you four STL files (they form one object of four parts) in a private E-mail within the next few minutes...thanks!

.
.
.

Done. Be warned...it's over 6MB.

Message was edited by: darrinps

darrinps
Offline
Joined: 2003-06-12
Points: 0

>
> I did just look at the STL format and I could write a
> loader/parser for
> that really quickly and maybe hack together a quick
> framework to
> automatically go to the binary output - if you're
> willing to deal with
> some fast-hacked code. I could have a play with that
> tomorrow if you're
> interested.

YOU BET I WOULD BE INTERESTED.

That would be great!

Hong Cao

Hi, All,

I am facing a Java 3D Bug, after setting Anti-alias to true in the
RenderingHint of J3dGraphics2D, the drawings became messed up. Anyone
has an idea how to get around this? Is there any schedule to fix this
bug in future release?

Thanks

Hong

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

kcr
Offline
Joined: 2004-03-17
Points: 0

Another possibility is that someone could extend the current CompressedGeometry utilities to include texture coordinates and shader vertex attributes. You could subclass the existing CompressedGeometry (although you would have to be careful not to use the new subclass in a scene graph, since that wouldn't work). Better yet might be taking the existing classes as a starting point for creating a new utility. That way it wouldn't have to worry about strict compatibility. It would just need to provide compress/decomress methods. It would never go into the scene graph directly -- it would just be used as a transport mechanism.

Of course all of this presumes that someone in the community will get interested enough to pick this up. We don't plan any work on the compressed geometry utilities.

-- Kevin

Alan Hudson

java3d-interest@javadesktop.org wrote:

>Another possibility is that someone could extend the current CompressedGeometry utilities to include texture coordinates and shader vertex attributes. You could subclass the existing CompressedGeometry (although you would have to be careful not to use the new subclass in a scene graph, since that wouldn't work). Better yet might be taking the existing classes as a starting point for creating a new utility. That way it wouldn't have to worry about strict compatibility. It would just need to provide compress/decomress methods. It would never go into the scene graph directly -- it would just be used as a transport mechanism.
>
>Of course all of this presumes that someone in the community will get interested enough to pick this up. We don't plan any work on the compressed geometry utilities.
>
>
>
I will get around to it someday. I'm pretty much done with the general
X3D binary spec. So adding the geometry compression will be the next
step. That said I'm pretty slammed at the moment. I'll try and get a
timeline together for when I might do the generalization work.

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

darrinps
Offline
Joined: 2003-06-12
Points: 0

I'm no expert on 3D math, so please forgive this question if it is very simplistic, but why does the compressed geometry algorithm have to scale the objects to fit in a [-1,1] (world coordinates?) space and need to leave them there?

Couldn't it do the scale to [-1,1], compress, and then rescale to the original size?

This is the issue (along with the deprication) that is causing me to look elsewhere to begin with.

FWIW, the compressed geometry algorithm [b]really[/b] works well, and compresses the files a lot better than just doing a ZIP for example. I ran through about 200 iterations using the various combinations of the quality factors (position, color, normal) and found that 10, 8, 4 reduced my models from about 18MB (that's eighteen megabytes!) to just about 1MB (one!), and you really had to look hard to see the effects of the compression. Any more than that though (going to 9, 8, 4 for example) and the quality degraded a good bit, but at 18 to 1, I was [b]very[/b] pleased.

Justin Couch

java3d-interest@javadesktop.org wrote:

> I'm no expert on 3D math, so please forgive this question if it is very simplistic, but why does the compressed geometry algorithm have to scale the objects to fit in a [-1,1] (world coordinates?) space and need to leave them there?

There are a number of shortcuts you can take when you know that you are
bound in a unit volume. The first is that all floating point numbers no
longer need to keep the mantissa part - all they need is an exponent and
a sign bit. With a little bit of tweaking you can effectively reduce a
32bit number down to less than 16 bits.

Another tweak that can be done is that if the geometry is within a unit
box, there is no difference between a vertex as a position in space and
as a vector. That vertex can also be treated as a vector from the
origin, which allows for some other compression schemes to be used -
notably the Dearing patents on compressing colours and normals through
quantisation.

--
Justin Couch http://www.vlc.com.au/~justin/
Java Architect & Bit Twiddler http://www.yumetech.com/
Author, Java 3D FAQ Maintainer http://www.j3d.org/
-------------------------------------------------------------------
Programming is essentially a markup language surrounding
mathematical formulae and thus, should not be patentable.
-------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Justin Couch

java3d-interest@javadesktop.org wrote:

> I've looked at simply zipping the .obj files but that doesn't work anywhere near as well as the compressed geometry did (the zip is about 80% larger).
>
> Does anyone know of anything that takes a .obj (or .stl, oer something else even) and compresses it and then allows you to decompress it on the other end inside of a Java applet/application?

One option is to use X3D's new binary format. This uses the same
algorithms that the Java3D CompressedGeometry uses - the rights to use
patents were donated by Sun to the Web3D Consortium for specifically
this purpose. Xj3D is the only app/toolkit that supports the binary
format right now (all the prototyping of the spec was done in Xj3D), but
others should be along at some point in the not too distant future.

Not that it will be that readable to you, but here's the ISO CD
standards document text:

http://www.web3d.org/x3d/specifications/ISO-IEC-19776-3-CD-X3DEncodings-...

--
Justin Couch http://www.vlc.com.au/~justin/
Java Architect & Bit Twiddler http://www.yumetech.com/
Author, Java 3D FAQ Maintainer http://www.j3d.org/
-------------------------------------------------------------------
Programming is essentially a markup language surrounding
mathematical formulae and thus, should not be patentable.
-------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

darrinps
Offline
Joined: 2003-06-12
Points: 0

> One option is to use X3D's new binary format. This
> uses the same
> algorithms that the Java3D CompressedGeometry uses -

Thanks for the feedback.

One question though, since X3D uses the same algorithms, wouldn't it have the same problem in that it would auto-scale larger images?

Justin Couch

java3d-interest@javadesktop.org wrote:
> One question though, since X3D uses the same algorithms, wouldn't it have the same problem in that it would auto-scale larger images?

No, because it doesn't touch the images. It only compresses the scene
graph structure. Images are an external object, so the binary format
doesn't touch them. There is a capability of including the images within
the same stream, but nothing is done to them - they're just a binary
blob at the end of the stream.

--
Justin Couch http://www.vlc.com.au/~justin/
Java Architect & Bit Twiddler http://www.yumetech.com/
Author, Java 3D FAQ Maintainer http://www.j3d.org/
-------------------------------------------------------------------
Programming is essentially a markup language surrounding
mathematical formulae and thus, should not be patentable.
-------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

darrinps
Offline
Joined: 2003-06-12
Points: 0

Thanks again.

I'm downloading Python now so I can get Blender to convert my STL images to .X3D. Once I have that in place, I'll look at the using the Xj3D as a Java3D loader (saw a tutorial on that somewhere).

I'll report back once that is all done to let everyone know how well it works.

Justin Couch

java3d-interest@javadesktop.org wrote:
> I'm downloading Python now so I can get Blender to convert my STL images to .X3D. Once I have that in place, I'll look at the using the Xj3D as a Java3D loader (saw a tutorial on that somewhere).
>
> I'll report back once that is all done to let everyone know how well it works.

OK, one thing to be aware of is that Blender doesn't have the binary
export capabilities yet. As far as we know, Xj3D is the only one that
can generate the binary format. There's a standalone utility as part of
Xj3D but it wasn't included in the M10 stable release. To get hold of
it, you'll need to grab the CVS version and look under examples/binary
for the convertor (http://www.xj3d.org/cvs.html). We will need to check
that the Loader interface handles the binary stream correctly, but we
certainly know that the other mechanisms do (such as using the complete
browser or through the programmatic SAI calls).

--
Justin Couch http://www.vlc.com.au/~justin/
Java Architect & Bit Twiddler http://www.yumetech.com/
Author, Java 3D FAQ Maintainer http://www.j3d.org/
-------------------------------------------------------------------
Programming is essentially a markup language surrounding
mathematical formulae and thus, should not be patentable.
-------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

darrinps
Offline
Joined: 2003-06-12
Points: 0

> OK, one thing to be aware of is that Blender doesn't
> have the binary
> export capabilities yet. As far as we know, Xj3D is

Thanks...I just found that out myself! It also looks like AccuTrans doesn't have the ability yet either!

I'll do as you suggest and look at Xj3D and get the stand alone utility.

Justin Couch

java3d-interest@javadesktop.org wrote:

> Thanks...I just found that out myself! It also looks like AccuTrans doesn't have the ability yet either!
>
> I'll do as you suggest and look at Xj3D and get the stand alone utility.

More notes to add: We can't transform any other file formats to X3D, but
if you can get it to the X3D-XML format we can convert from there
(doesn't handle the VRML-encoding right now, we just haven't had the
cycles to fix up the code due to a few internal API changes).

I did just look at the STL format and I could write a loader/parser for
that really quickly and maybe hack together a quick framework to
automatically go to the binary output - if you're willing to deal with
some fast-hacked code. I could have a play with that tomorrow if you're
interested.

--
Justin Couch http://www.vlc.com.au/~justin/
Java Architect & Bit Twiddler http://www.yumetech.com/
Author, Java 3D FAQ Maintainer http://www.j3d.org/
-------------------------------------------------------------------
Programming is essentially a markup language surrounding
mathematical formulae and thus, should not be patentable.
-------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Justin Couch

Justin Couch wrote:

> I did just look at the STL format and I could write a loader/parser for
> that really quickly and maybe hack together a quick framework to
> automatically go to the binary output -

Just replying to myself - I just remembered there's already an STL
parser in j3d.org codebase. That should make generating an output even
easier if you want to either try writing a convertor yourself or if you
want to wait for me to do one.

--
Justin Couch http://www.vlc.com.au/~justin/
Java Architect & Bit Twiddler http://www.yumetech.com/
Author, Java 3D FAQ Maintainer http://www.j3d.org/
-------------------------------------------------------------------
Programming is essentially a markup language surrounding
mathematical formulae and thus, should not be patentable.
-------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net