www.jpct.net

jPCT-AE - a 3d engine for Android => Support => Topic started by: sticksen on October 09, 2011, 03:20:19 pm

Title: Scale around a center point?
Post by: sticksen on October 09, 2011, 03:20:19 pm
Hi,

is there any way to scale an Object3D around some arbitrary point? As far as I can see, currently itīs always scaling around the objectīs origin in (0,0,0) , so I would have to calculate something to translate it afterwards? Iīm needing this for correct Pinch-Zooming.

Cheers,
Marc
Title: Re: Scale around a center point?
Post by: K24A3 on October 09, 2011, 04:05:10 pm
One option would be to move the camera to the location of the initial pinch, or translate/move the object at every frame aligned in ratio to the pinch origin.

Or if you want the object pre-translated, you can load the object, translate it into position, then call rotateMesh to update the meshes translation. Not 100% sure if that would work but I imagine it would.

Title: Re: Scale around a center point?
Post by: EgonOlsen on October 09, 2011, 04:25:45 pm
Or if you want the object pre-translated, you can load the object, translate it into position, then call rotateMesh to update the meshes translation. Not 100% sure if that would work but I imagine it would.
Swap "rotateMesh" with "translateMesh" and it should make the translation permanent.
Title: Re: Scale around a center point?
Post by: EgonOlsen on October 09, 2011, 04:26:26 pm
I'm not sure what "scaling around a point" actually means!?
Title: Re: Scale around a center point?
Post by: sticksen on October 09, 2011, 06:02:09 pm
I'm not sure what "scaling around a point" actually means!?

well, currently the object 'grows' to the right and to the bottom, while the upper left corner stays at the same place. I need to 'grow' it in all 4 directions, while only a certain point (given by e.g. a pinch-zoom event) stays at the same place.
Title: Re: Scale around a center point?
Post by: EgonOlsen on October 09, 2011, 08:08:48 pm
The "growing" of the object has to do with it's position in object space and subsequent with it's translation in world space. Scaling is simply done by multiplying the object space vertices with the scale factor. If your model starts at (0,0,0) this point will never change because (0,0,0)*some scalar is still (0,0,0). You can either apply an offset to the world space translation or, and that is what K24A3 suggested, you can translate the object once so that the position in object space fulfills your requirements and make this translation permanent by calling translateMesh() (and clear the translation afterwards).
Title: Re: Scale around a center point?
Post by: sticksen on October 09, 2011, 08:50:24 pm
oh ok...so, just to verify if I understood it correctly: if I have 100 objects, all as a child of an Object 'rootNode', I have to get my point to scale around, read out all Objects, translate them, scale, translate them back? Itīs not possible to just translate my rootNode and then scale, because the object space of the childs doesnīt change, right?
Maybe then Iīm rather going for option 2...

Cheers,
Marc
Title: Re: Scale around a center point?
Post by: EgonOlsen on October 09, 2011, 09:26:35 pm
A said, scaling just multiplies the vertices with a scalar. And translation without any rotations being used is just an addition. So if you have two vertices, like (-10,0,0) and (10,0,0) and scale them by 2, you'll get (-20,0,0) and (20,0,0). Translate them by (100,0,0) and you end up with (80,0,0) and (120,0,0) with your virtual center at (100,0,0)...and i guess that is what you expect. However, if your object's center isn't (0,0,0) (which it obviously isn't), then you'll get different results...for example with (0,0,0) and (20,0,0), you'll end up (doing the operations like above) at (100,0,0) and (140,0,0) and your virtual center is at (120,0,0)...and any subsequent scale won't change that vertex at (100,0,0), so it looks like as if the mesh extends to the left only.
 
Title: Re: Scale around a center point?
Post by: sticksen on October 10, 2011, 09:41:39 pm
Ok, I tried to get it working, but somehow I canīt figure it out.

Code: [Select]
private final static float textureMaxX = 100f;
private final static float textureMaxY = 130f;

//in some init function. this draws a rectangle which is later been filled by a texture
Object3D background = new Object3D(2);
SimpleVector vert1 = new SimpleVector(0, 0, 0);
SimpleVector vert2 = new SimpleVector(textureMaxX, 0, 0);
SimpleVector vert3 = new SimpleVector(textureMaxX, textureMaxY, 0);
SimpleVector vert4 = new SimpleVector(0, textureMaxY, 0);
background.addTriangle(vert3, 1, 1, vert2, 1, 0, vert1, 0, 0);
background.addTriangle(vert3, 1, 1, vert1, 0, 0, vert4, 0, 1);
world.addObject(background);

//in onDrawFrame
background.translate(100, 0, 0);
background.translateMesh();
background.scale(1.01f);
background.translate(-100, 0, 0);
background.translateMesh();

Now whatever values I translate and back-translate the background, it always scales around the center in this example. My first example, which scaled around top left was a 'rootNode', which was instantiated by Object3D.createDummyObj() and is used to group objects. From the above code, I expected to receive a scaling around the right edge of my background rectangle. Am I doing something wrong?

Cheers and thanks for all your efforts!
Marc

Title: Re: Scale around a center point?
Post by: EgonOlsen on October 10, 2011, 10:01:18 pm
Doing it that way will have no visual effect, because you simply undo the translation you did before. What i meant was more like

Code: [Select]
background.translate(100, 0, 0);
background.translateMesh();
background.clearTranslation();
background.scale(1.01f);
Title: Re: Scale around a center point?
Post by: sticksen on October 10, 2011, 10:25:14 pm
Still not the wished effect...it still scales around the center. Does it matter when the object is built? I need to modify the object space coordinates after build() was called. Do I need a VertexController then? I read this:

Code: [Select]
//mesh.setVertexController:
A VertexController is the only way for an application to modify the vertex data of jPCT's meshes after build-time.
Cheers,
Marc
Title: Re: Scale around a center point?
Post by: stownshend on October 10, 2011, 10:37:03 pm
I've been following this thread and still don't understand what it means to scale around an arbitrary point? Are you talking about distorting the original model in any way? Or simple scaling it (around the centre) and translating it to accommodate this point?

By distortion I mean something like (see attached image)

[attachment deleted by admin]
Title: Re: Scale around a center point?
Post by: EgonOlsen on October 10, 2011, 10:39:50 pm
In that case, you could try the following (untested...):

Compile the object in dynamic mode by yourself:

Code: [Select]
background.compile(true, true);
background.build();

Then, after doing the translateMesh(), touch the object like so:

Code: [Select]
background.translate(100, 0, 0);
background.translateMesh();
background.clearTranslation();
background.touch();
background.scale(1.01f);

I've no idea if this will work...if not, a VertexController might be the better option in this case. However, i don't get why you want to do the translateMesh() at runtime. I thought that only the scaling has to happen at runtime, so the idea was to do the translate before calling build() and do only the scale() in onDrawFrame like so:

Code: [Select]

// At load time
background.translate(100, 0, 0);
background.translateMesh();
background.clearTranslation();
background.build();

// At runtime
background.scale(1.01f);
Title: Re: Scale around a center point?
Post by: sticksen on October 11, 2011, 02:00:42 pm
Hi again,

@stownshend: No distortion or anything like that needed.

Sadly that doesnīt work either.
Well, problem is: the 'point to scale around' changes during runtime. As I mentioned, Iīm implementing a pinch-zoom gesture, and every time the user puts 2 fingers on the screen, the scalepoint changes. Thus I have to modify the object at runtime...

I stumbled upon something else: I now donīt call createDummyObj() for my rootNode anymore, instead Iīm just instantiating the exact same rectangle as for the background. Now when I donīt call build on the rootNode and scale it, all children are scaled around top left. After calling build for the root, all childs scale around the center. So build definitely does something that influences the scaling. Damn closed source, it was easier when one could have a look at what itīs doing...:)

Also, javadoc says there's something like unbuild(), but I guess this function isnīt public anymore?

Cheers,
Marc
Title: Re: Scale around a center point?
Post by: EgonOlsen on October 11, 2011, 07:56:24 pm
unbuild() isn't available in jPCT-AE. It's desktop only, because it works only with the hybrid render pipeline that the AE version doesn't feature. But you've finally managed to confuse me...i have a vague idea of what you want, but i'm not really sure how this is supposed to look like. Maybe a rough painting or similar might help to understand this. I'm not sure how the object is supposed to changed if you, for example zoom starting at the lower left corner compared to starting at the upper right. I would think that it doesn't matter as long as you are scaling it around it's center. 
Title: Re: Scale around a center point?
Post by: sticksen on October 26, 2011, 06:50:32 pm
Finally I got it working...first the code:
Code: [Select]
/**
* Scales whole scene via scaleDelta. Note that scale value is handled as
* accumulative, not absolute. Scene is scaled around scaleMidpoint
*
* @param scaleDelta
*            accumulative scale value
* @param scaleMidpoint
*            midpoint in screen coordinates
*/
public void scale(float scaleDelta, Vector3f scaleMidpoint) {

//obtain world coordinates of scaleMidpoint
backgroundMap.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
SimpleVector worldCoord = getCollisionCoordinates(backgroundName, scaleMidpoint);
backgroundMap.setCollisionMode(Object3D.COLLISION_CHECK_NONE);

SimpleVector translation = rootNode.getTranslation();
Matrix mat = rootNode.getRotationMatrix();
mat.translate(-(worldCoord.x - translation.x), -(worldCoord.y - translation.y), 0);
Matrix scale = getScaleMatrix(scaleDelta);
mat.matMul(scale);
mat.translate(worldCoord.x - translation.x, worldCoord.y - translation.y, 0);
}

private Matrix getScaleMatrix(float scale) {
Matrix scaleMat = new Matrix();
scaleMat.setDump(new float[] { scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, 1 });
return scaleMat;
}
Ok, this is kind of a hack, because there's no rootNode.getMatrix() or setMatrix, only getTranslationMatrix and getRotationMatrix. getScaleMatrix also isn't present, so I had to use the rotation matrix and add scale values to it, which don't seem to be stripped afterwards.
The Matrix class itself features .translate, .rotate, but also no .scale, which is another inconsistency.

All other tips mentioned here didn't work for me.

This seems to be the only way things are happening like I want it to, but now another problem arises: Billboarded objects seem to be scaled double. I'm opening a new thread on this.

Thanks for all your help!