How to convert screen coordinates to world coordinates after setRotation3D()?

Recently I got a problem. For example, the design resolution in our app is 640x960, and I used setRotation3D(Vec3(-20, 0, 0)) to rotate the layer, and tried to get the touches point coordinate in the rotated layer.

this->setAnchorPoint(0.5, 0);
this->setRotation3D(Vec3(-20, 0, 0));

Void HelloworldScene::onTouchesBegan(touches, event)
{
Point p = touches.at(0)->getLocation(); //Got (90, 780)
P = this->convertToNodeSpace(touches.at(0)->getLocation()); //Got (90, 733)
P = this->convertTouchToNodeSpace(touches.at(0)); //Got (90, 733)

}

None of these is what I expectted!! I touched on the (90, 780) on the screen, it’s supposed to be converted to (0, 960) on the layer. Please check the screenshot.

Anybody knows how to solve this problem?

By refering to the code from stackoverflow, I changed my code like:

Point p = touches.at(0)->getLocation();
Point p2;

projection = Director::getInstance()->getMatrix(cocos2d::MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
modelview = _modelViewTransform;//this->getNodeToWorldTransform();

Mat4 invertedMatrix, transformMatrix;

Vec4 normalizedInPoint, outPoint;

float screenH = DLConfig::getWinSize().height;
float screenW = DLConfig::getWinSize().width;

int oglTouchY = (int) (screenH - p.y);

normalizedInPoint.x = (float) ((p.x) * 2.0f / screenW - 1.0);
normalizedInPoint.y = (float) ((oglTouchY) * 2.0f / screenH - 1.0);
normalizedInPoint.z = - 1.0f;
normalizedInPoint.w = 1.0f;

transformMatrix = projection * modelview;

invertedMatrix = transformMatrix.getInversed();

outPoint = invertedMatrix * normalizedInPoint;

p2.x = outPoint.x / outPoint.w;
p2.y = outPoint.y / outPoint.w;

But it’s still incorrect. This is driving me crazzy… Any idea?

Please help…

This is very critical, I will keep replying myself cause I know there is someone who knows the answer.

up

up

up

need somebody help!!

so are you saying that you rotated the layer and now the touch coordinates are off from what you expect?

if you don’t rotate the layer do the coordinates become what you expect again?

Currently the 3d API is new, there is no mapping from 3d space to 2d space yet…

Yes. I rotated the layer as the “ground” of my 2.5D game, and touched on the screen. I need to know what the converted coordinates are on the roated layer. I think this is called "screen coordinate & world coordinates conversion in 3D games.

If I dont rotate the layer, all the coordinates are correct.

I think this is “2d to 3d conversion” or “unproject”, because the screen is in 2D, and the roated layer is in a 3D world. :smile:

This is the screenshot to describe the problem.

Hi, Sorry for my late reply.

If you have used setRotation3D(), pick concept in 3d is needed for touch handling. Unfortunately, we have not implement this. We will add it on version 3.3 or version 3.4.
However, you can do it manually now.

First, you need a ray in world space. For orthogonal projection in 3d, the start point of the ray could be (x,y, 0), the direction is (0,0,-1).
Second, convert the ray to node space.

ray start = worldToNodeMatrix * (x, y, 0,1)
ray end = worldToNodeMatrix * ((x,y,0,1) + (0,0,-1,0))
ray direct = ray end - ray start

Third, test the intersect point of the ray and the sprite.

BTW, the ray intersect algorithm
http://www.cs.princeton.edu/courses/archive/fall00/cs426/lectures/raycast/sld017.htm
http://www.lighthouse3d.com/tutorials/maths/ray-triangle-intersection/

I hope it could be helpful.
Thanks

1 Like

@dabingnn This is a great reply!

Thanks @dabingnn, I will try your proposal.

@slackmoehrle
Thanks.

@dabingnn, I just translated your idea to the code like this:

Mat4 worldToNodeMatrix = this->getWorldToNodeTransform();
Vec4 start = worldToNodeMatrix * Vec4(p.x, p.y, 0, 1);
Vec4 end = worldToNodeMatrix * Vec4(Vec4(p.x, p.y, 0, 1) + Vec4(0, 0, -1, 0));
Vec4 direct = end - start;

Regarding with the http://www.cs.princeton.edu/courses/archive/fall00/cs426/lectures/raycast/sld017.htm, what is N, d and V in our scenario?

anybody knows?

@mobileharry
In your post, you want to use ray plane intersection to test it.
Here a plane could be represent using a formula P dot N + d = 0.
Here N means the normal of the plane. P dot N equals to (P - O) dot N where O is the zero point.
so d equal -(P - O) dot N.V` is the direction of the ray.