Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3d projection is not correctly adjusted with non centre origin #417

Open
raldred opened this issue Aug 6, 2014 · 9 comments
Open

3d projection is not correctly adjusted with non centre origin #417

raldred opened this issue Aug 6, 2014 · 9 comments
Labels

Comments

@raldred
Copy link
Collaborator

raldred commented Aug 6, 2014

Hi,
There is an issue with the _projectionOverlap and a _isBehind methods of IgeEntity
The methods only work when the entity has the standard centre origin.
If the entities origin is adjusted the methods return incorrect results.

I've been trying to resolve this myself, but I'm going round in circles, trying various apporaches but the numbers results get even more confusing. I'm reaching out for some help.

I believe this is the section that's at the root of the issue.

thisMin = {
    x: this._translate.x - thisG3d.x / 2,
    y: this._translate.y - thisG3d.y / 2,
    z: this._translate.z - thisG3d.z
},
thisMax = {
    x: this._translate.x + thisG3d.x / 2,
    y: this._translate.y + thisG3d.y / 2,
    z: this._translate.z + thisG3d.z
},
otherG3d = otherObject._bounds3d,
otherMin = {
    x: otherObject._translate.x - otherG3d.x / 2,
    y: otherObject._translate.y - otherG3d.y / 2,
    z: otherObject._translate.z - otherG3d.z
},
otherMax = {
    x: otherObject._translate.x + otherG3d.x / 2,
    y: otherObject._translate.y + otherG3d.y / 2,
    z: otherObject._translate.z + otherG3d.z
};

Lets look at one of the lines...

this._translate.y - thisG3d.y / 2

This intends to calculate the top left vertex.
That's fine when the origin y is .5, however change that to .7
and it no longer calculates the top left vertex as intended.

Thanks
Rob

@raldred raldred changed the title 3d projection is not correctly adjusted with non centre origin for overlap checking 3d projection is not correctly adjusted with non centre origin Aug 6, 2014
@raldred raldred added the bug label Aug 6, 2014
@Irrelon
Copy link
Owner

Irrelon commented Aug 11, 2014

Hmmmmm. Yes this is an interesting one. Confirmed this is a bug, I can reproduce it.

My math skills are terrible but I think the line you've highlighted looks like the culprit. I would have assumed that multiplying by the origin.y would do it something like:

this._translate.y - thisG3d.y / 2 * (0.5 - origin.y);

Did you already try that?

@raldred
Copy link
Collaborator Author

raldred commented Aug 11, 2014

Yeh I've tried that amongst other things.

screen shot 2014-08-12 at 09 56 48

Video demonstrating how the bounds are effected when adding the adjustment you suggested Rob.
https://dl.dropboxusercontent.com/u/724817/projection-offset.mov

My maths is also pretty poor unfortunately, I've been meaning to post to stack overflow, hopefully there's some mathematicians out there.

I think it has something to do with the 3d bounds having iso coordinates
rather than 2d so the change you suggested moves it in the wrong direction.

@twobob
Copy link

twobob commented Aug 11, 2014

I have zero Idea what I am talking about but it's not something screwy like "their origin taken from the bottom left" and "the other co-ords mapped from the top left" or something similarly really infuriatingly simple is it? Just a thought.

@raldred
Copy link
Collaborator Author

raldred commented Aug 12, 2014

The 3d bounds uses the same translation which is by default .5,.5,.5
I think the origin adjustment needs to happen in a different direction to a different magnitude.
I believe the coordinates need converting into the 3d space.

//An issue with doing that is that this is expensive
//whilst the bounds3dpolygon is cached
//the IgeRect created by the aabb method of IgePoly
//so there's a massive overhead in doing it this way unless we can cached the 3d aabb
obj.bounds3dPolygon().aabb();

It's odd because the debug 3dbounds are drawn correctly but that's calculated from the 3dpoly aabb, this is done in IgeViewport by the paintAabbs method.
I'm thinking the projection might better calculated in the same way.
The only issue is

This is the best I've come up with but it's junk really.

if(this._origin.x !== 0.5 || this._origin.y !== 0.5) {
    thisOrigin = this._origin.rotate(Math.radians(45))
    thisTranslate.x -= (thisG3d.x * (0.5 - thisOrigin.x)) / 2
    thisTranslate.y -= (thisG3d.y * (0.5 - thisOrigin.y)) / 2
}
if(otherObject._origin.x !== 0.5 || otherObject._origin.y !== 0.5) {
    otherOrigin = otherObject._origin.rotate(Math.radians(45))
    otherTranslate.x -= (otherG3d.x * (0.5 - otherOrigin.x)) / 2
    otherTranslate.y -= (otherG3d.y * (0.5 - otherOrigin.y)) / 2
}

I've posted to stackoverflow here: http://stackoverflow.com/questions/25261109/calculating-2d-origin-offset-in-30-60-isometric-world

@ChrisEt
Copy link
Contributor

ChrisEt commented Aug 12, 2014

I also had issues with isometric depth sorting. I left origin at the default [0.5,0.5,0.5] and made all my entities "flat", i.e. size3d(20, 20, 1). I then used the 2d anchor() to correctly position the texture at the entity's origin.

By the way, in case you wonder, I'm using depthSortMode(2), which means simple x+y+z depth sorting. The reason is I couldn't get rid of overlapping 3d bounds and depthSortMode(2) was the fastest and most reliable anyway :-)

@Irrelon
Copy link
Owner

Irrelon commented Sep 3, 2014

@raldred Does the workaround proposed by @ChrisEt work or would that cause issues with your game? I'm still not able to fix this as my tiny brain cannot work out why it's not moving in the correct direction.

@raldred
Copy link
Collaborator Author

raldred commented Sep 3, 2014

Hey sorry I've not got back to your about this, the reason I had for moving the origin is because my scenery is incorrectly placed when comparing with the placement in the Tiled editor. I think that has something to do with the difference in the coordinate system used.
I created a workaround myself which allows me to keep the bounds the correct size and adjust the scenery into place.
The reason I did it this was is because I need the bounds to be correct and to "hug" the entity for depth sorting to work correctly.
If you use the anchor to make the adjustment that only moves the texture, the bounds would remaining in place.

It involved creating a child entity within my SceneryObject class (which extends IgeEntity).
This child entity is then translated by a method.

init: function() {

    //...

    this._model = new IgeEntity()
        .texture(txt)
        .dimensionsFromTexture()
    // etc etc...

    var w = this._model.width(),
        h = this._model.height();
    this._model.bounds3d(w/2,w/2,h);
    this._offsetTo(.5,.7,.5);

    //...

_offsetTo: function() {
    var ao = new IgePoint3d(x,y,z),
        w = this._model.width(),
        h = this._model.height(),
        xoffset = (w/2) - (w * ao.x),
        yoffset = (h/2) - (h * ao.y),
        adjustment = new IgePoint3d(xoffset,yoffset,0).to2d();

    this._model.translateBy(adjustment.x,adjustment.y,0);

I also then added some wrapper methods that forward mouse events from the model to the objects main class.

The normal originTo adjustment I mentioned in my previous post doesn't work I believe because of confusion of coordinates. The origin is adjusted relative to the 2d texture and therefore by a 2d vector. 3d bounds are obviously drawing in iso coordinates with 3d vectors.

I think we just need to figure out the amount of x/y adjustment in pixels and convert it iso world values.
That's the tricky bit that I can't figure out, no combinations of point.toIso.to2d() give me the results i'd expect.

@ChrisEt
Copy link
Contributor

ChrisEt commented Sep 4, 2014

I also came across these problems as I’m also using Tiled for map editor. I understand you have already implemented a working way around this. I’m describing my solution here nevertheless, maybe it can help others avoid these issues.

It took me some time to figure out how Tiled coordinates are based: In isometric Tiled maps the coordinate origin is the top point. X axis increments to the right, Y axis to the left, the coordinates are pixels in each direction. That means going straight down increments x and y by the same amount:
tiled coordinates
If you place an object in Tiled its coordinates are those of the bottom center point. The mouse in the following example therefore has the coordinates (32|32):
tiled object placement
In IGE the coordinates are based on the horizontal and vertical center of the entity. For depth sorting (remember I use x+y+z depth sorting) it is essential the entity’s coordinates are exactly at the point where the feet of the mouse touch the ground.

So what I did is: When someone places a mouse in Tiled at exactly the position from the example above, Tiled stores (32|32) as its coordinates. However, I defined a baseShiftY attribute for each tileset, which in case of the mouse is -3. So when the map is read on the client, an entity is created at (32|29). That way depth sorting will always be correct.

Now you might already know how I manage to place the texture at the right position: I use .anchor() to shift the texture (in screen coordinates) by _cellHeight/2 + baseShiftY.

The code looks like this:

var deco = decoarr[j];
var container = new IgeEntity()
    .isometric(true)
    .translateTo(deco.x, deco.y, 0) 
    .size3d(32, 32, 1)    // z size of 0 causes the depth sorter to get confused
    .mount(objectLayer);         // mount to common object layer

var t = ige.client.mapTextureLookup[deco.gid];

var textureEnt = new IgeEntity()
    .mount(container)
    .texture(t)
    .cell(deco.gid - t._tiledStartingId + 1)
    .dimensionsFromCell()
    // amount of pixels the texture will be shifted
    // this is measured from the center of the entity's bounding box
    .anchor(t.baseShiftX, t._cellHeight / 2 + t.baseShiftY);   // baseShiftY is negative

@ChrisEt
Copy link
Contributor

ChrisEt commented Sep 4, 2014

I tried to understand why the entity was not placed correctly when I set 3D bounds like (32, 32, 32). I found out the texture is always centered at the center of the bounding box on the screen. If you use .anchor() you can adjust the texture position in 2d screen coordinates.

The bug that we are looking for shows when you use origin(0.5, 0.5, 0) or something similar. By the way I wonder how you place your entities correctly because with origin(0.5, 0.5, 0.5) and geometry.z > 1 (set by size3d()) your bounding box extends below the “surface” of the z=0 plane. Could this be the source of your troubles?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants