gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Interpreting touchscreen input to a 3d scene (re: Picking?)

#172185 - SatNav - Sat Jan 23, 2010 4:49 pm

This is an odd one (to me at least), so please bear with me. I've tried to find some info myself, but I'm hampered by the fact that I don't even know what terms to search for, so I'll try to explain.

I'm trying to write a Rubik's Cube program. So far, I can draw the cube, and using the touchscreen, rotate it around the X and Y axes, as well as pick individual squares on the face of the cube (and colour them a nice purple).

The problem I'm facing involves grabbing and rotating segments of the cube. Specifically deciding, once I've grabbed a square, *which way* I want to rotate. If the cube is right-way-up, dead-on to the screen, then up/down is up/down and there's no problem, but if the square I'm grabbing is at some odd angle in 3-dimensions, then Up is no longer necessarily Up - so how do I reconcile this with the 2d input from the touchscreen?

The problem (in my mind) is vaguely analogous to how a d-pad or analog stick works in a 3d scene.

I'm not looking for a detailed explanation or anything - just hoping that someone could point me in the direction of a tutorial, or perhaps enlighten me with the name of the technique I'm describing (I'm sure it must have a name), so I can do the research myself.

Cheers,
Mark.

#172191 - Drovor - Sun Jan 24, 2010 7:55 am

There's a demo provided with the devkitPro DS examples (doesn't work in NO$GBA for some reason): examples/ds/Graphics/3D/Picking

Essentially you draw your screen twice.
First draw it normally the way you would display it to the player, then draw with a 1x1 pixel window over the pixel you want to 'pick'. Check whether the 'GFX_POLYGON_RAM_USAGE' register increased. If it does you know that polygon was picked.

I implemented the same algorithm here (search for 'pickMode'):
http://github.com/drovor/DSAnts/blob/master/source/MapDraw.cpp

#172192 - SatNav - Sun Jan 24, 2010 9:30 am

Hi,

thanks for the reply, but that's not exactly what I'm looking for. I'm already using picking in my code, the trouble I'm having is what to do next. I don't know how to explain better than I already have, so I'll reproduce the relevant section here:

SatNav wrote:
The problem I'm facing involves grabbing and rotating segments of the cube. Specifically deciding, once I've grabbed a square, *which way* I want to rotate. If the cube is right-way-up, dead-on to the screen, then up/down is up/down and there's no problem, but if the square I'm grabbing is at some odd angle in 3-dimensions, then Up is no longer necessarily Up - so how do I reconcile this with the 2d input from the touchscreen?


Cheers

#172197 - AntonioND - Sun Jan 24, 2010 1:40 pm

Drovor wrote:
(doesn't work in NO$GBA for some reason)

That reason is that 'GFX_POLYGON_RAM_USAGE' and 'GFX_VERTEX_RAM_USAGE' aren't emulated in NO$GBA.

'GFX_VERTEX_RAM_USAGE' is emulated, if I remember correctly, in iDeaS, but iDeaS emulates 3D worse than NO$GBA or DeSmuME...


Last edited by AntonioND on Sun Jan 24, 2010 1:43 pm; edited 1 time in total

#172198 - TwentySeven - Sun Jan 24, 2010 1:40 pm

Ok so you have picking sorted out - I assume yes.

So you need to figure out the relative motion of the stylus drag to your cube.

eg:

cube is axial in the world, dragging X- to X+ would produce a clockwise rotation.

cube is rotated around the center of the screen 180o, dragging X- to X+ would produce a counterclockwise rotation.


If this is the issue, the you can simply brute force it.

Theres only 6 faces, and 4 orientations per face, so 24 possible combinations of which face is most facing the camera, and then how its rolled.

eg:

the X+ is facing the camera, and it's either Z up, Z right, Z down or Z left.
the X- is facing the camera, and it's either Z up, Z right, Z down or Z left.
the Y+ is facing the camera, and it's either X up, X right, X down or X left.

onwards for all 6 faces.

#172205 - SatNav - Sun Jan 24, 2010 7:26 pm

TwentySeven wrote:
Ok so you have picking sorted out - I assume yes.

So you need to figure out the relative motion of the stylus drag to your cube.


Yes pretty much exactly this. Thing is, most of the time, the cube won't be at some convenient multiple of 90 degrees, but rather at some weird angle that can't be predicted, so the brute force thing won't really work. But thanks for bearing with my terrible explanations :)

Any other ideas out there?

#172209 - elhobbs - Mon Jan 25, 2010 2:15 am

if you think of the movement of the rubiks cube it can be describe as vectors on each face similiar to texture vectors. rotate these vectors into projection space. create a new vector using the stylus drag - you can use 0 for the missing coordinate. then the face surface vector with the largest magnitude along the stylus vector is the move that should be made. this can be accomplished with a dotproduct.

#172214 - zeruda - Mon Jan 25, 2010 5:57 am

When it is a perfect cube you can rotate around all 3 axes. Once you've rotated one segment partially that axis remains free and the other 2 locked so you can't rotate around them until the cube is aligned again. As you are rotating segments, whenever they are realigned you will need to update the global x,y,z axes of rotation.

#172234 - SatNav - Tue Jan 26, 2010 4:51 pm

Thanks elhobbs, that's just what I was looking for - brilliant! Now all I have to do (haha) is actually code it in. Good times!

#172277 - SatNav - Thu Jan 28, 2010 7:01 pm

Well, I've got a bit further, but seem to have a hit a wall again. I've given each face of the cube a vector based on what I know it's initial position will be (eg. the front face is (1, 1, 0)). I then use glGetFixed to get the position matrix, and rotate the vector using this matrix and the following routine:
Code:
void RotateVector (m4x4 &M, VECTOR &V, VECTOR &D)
{
   D.X = (f32tofloat(M.m[0]) * V.X) + (f32tofloat(M.m[4]) * V.Y) + (f32tofloat(M.m[8])  * V.Z);
   D.Y = (f32tofloat(M.m[1]) * V.X) + (f32tofloat(M.m[5]) * V.Y) + (f32tofloat(M.m[9])  * V.Z);
   D.Z = (f32tofloat(M.m[2]) * V.X) + (f32tofloat(M.m[6]) * V.Y) + (f32tofloat(M.m[10]) * V.Z);
}

but on printing my results on the top screen, they don't seem to correspond to what I'm seeing on screen, and from what elhobbs said, I'm sure they should. For example, if a square is right-way-up, and facing the screen, then surely the X and Y components of my resulting vector should both be positive. Or, if a face is angled away from the screen, then the Z component shouldn't be 0.

A lot of this is virgin territory for me, or at least it's my first time applying something I've only studied the theory of before, so thanks for bearing with me, and any help is appreciated.

Cheers.

#172278 - elhobbs - Thu Jan 28, 2010 7:23 pm

(1,1,0) is probably not what you want - typo maybe? you probably want (1,0,0) - in any case the values you are using should be unit vectors - meaning there length is 1.

since you are finding this surface via picking - you already know that it is in front of and facing the view point so the position is not really needed.

maybe you could show the input and output of this rotation function?

#172283 - SatNav - Thu Jan 28, 2010 10:28 pm

Hmm, (1,1,0) is what I meant to type, since the face extends to the right and down, but not into the scene. And this represents it's initial position before any rotation is applied - I take it thats right, since the position matrix will include any glRotates I've done, right? Since the cube can be freely rotated using the stylus, up to three sides can be visible at a time, and unfortunately not much can be inferred about a face's position just from the fact that it can be picked.

Does it have to be a unit vector to work? Cos that's an extra step I'd rather not bother with unless I have to..

As for input and output, here are a few sets. huh - just realised that something odd is happening when I align a face dead-on to the screen. It obviously means something, though I'm smegged if I can figure out what. here:
In:(1,0,-1) - Out:(1,0,1)
In:(1,0,1) - Out:(1,0,-1)
In:(1,1,0) - Out:(1,-1,0)
In:(0,1,1) - Out:(0,-1,-1)
In:(-1,1,0) - Out:(-1,-1,0)
In:(0,1,-1) - Out:(0,-1,1)

And fwiw, All of those outputs ought to be (1,1,0), since they're dead on to the screen when the rotation is performed. Damn, my poor brain.

Cheers.

#172284 - elhobbs - Fri Jan 29, 2010 12:57 am

hmm.. how to make this clearer...
if you have a face of a cube
Code:

0---1
|   |
3---2

with the coordinates:
0 - (0,1,0)
1 - (1,1,0)
2 - (1,0,0)
3 - (0,0,0)

the right vector would be (1,0,0)
the up vector would be (0,1,0)
and the normal would be (0,0,1)

#172340 - SatNav - Mon Feb 01, 2010 7:57 pm

aaah - ok nooow I'm with you. I don't know what I was thinking before. it seemed to make perfect sense at the time...