Rotating Sphere with Texture iOS - iphone

I know its very basic question but i couldn't find the answer i am looking for. Basically i have to display a rotating 3D sphere on camera overlay. I have got everything except applying texture to that sphere. Here is my code which generate the triangles strips.
int createSphere (GLfloat spherePoints[], GLfloat fRadius, GLfloat step){
int points = 0;
GLfloat uStep = DEGREES_TO_RADIANS (step);
GLfloat vStep = uStep;
for (GLfloat u = 0.0f; u <= (2 * M_PI); u += uStep) {
for (GLfloat v = -M_PI_2; v <= M_PI_2; v += vStep) {
points++;
spherePoints[(points - 1) * 3] = fRadius * cosf(v) * cosf(u); // x
spherePoints[((points - 1) * 3) + 1] = fRadius * cosf(v) * sinf(u); // y
spherePoints[((points - 1) * 3) + 2] = fRadius * sinf(v); // z
points++;
spherePoints[(points - 1) * 3] = fRadius * cosf(v) * cosf(u + uStep); // x
spherePoints[((points - 1) * 3) + 1] = fRadius * cosf(v) * sinf(u + uStep); // y
spherePoints[((points - 1) * 3) + 2] = fRadius * sinf(v); // z
points++;
spherePoints[(points - 1) * 3] = fRadius * cosf(v + vStep) * cosf(u); // x
spherePoints[((points - 1) * 3) + 1] = fRadius * cosf(v + vStep) * sinf(u); // y
spherePoints[((points - 1) * 3) + 2] = fRadius * sinf(v + vStep); // z
points++;
spherePoints[(points - 1) * 3] = fRadius * cosf(v + vStep) * cosf(u + uStep); // x
spherePoints[((points - 1) * 3) + 1] = fRadius * cosf(v + vStep) * sinf(u + uStep); // y
spherePoints[((points - 1) * 3) + 2] = fRadius * sinf(v + vStep); // z
}
}
return points;
}
Can anybody explain how to generate the Texture coordinates and Normals?

Related

Having trouble creating faces on triangle mesh JavaFX 8

I'm trying to create a Toroid mesh, however I cant create the faces properly...
here is my code:
public static Group createToroidMesh(float radius, float tRadius, int tDivs, int rDivs) {
final Group root = new Group();
int numVerts = tDivs * rDivs;
float[] points = new float[numVerts * POINT_SIZE],
texCoords = new float[numVerts * TEXCOORD_SIZE];
int[] faces = new int[numVerts * FACE_SIZE],
smoothingGroups;
int pointIndex = 0, texIndex = 0, faceIndex = 0, smoothIndex = 0;
float tFrac = 1.0f / tDivs;
float rFrac = 1.0f / rDivs;
float x, y, z;
int p0 = 0, p1 = 0, p2 = 0, p3 = 0, t0 = 0, t1 = 0, t2 = 0, t3 = 0;
// create points
for (int vertIndex = 0; vertIndex < tDivs; vertIndex++) {
float radian = tFrac * vertIndex * 2.0f * 3.141592653589793f;
for (int crossSectionIndex = 0; crossSectionIndex < rDivs; crossSectionIndex++) {
float localRadian = rFrac * crossSectionIndex * 2.0f * 3.141592653589793f;
points[pointIndex] = x = (radius + tRadius * ((float) Math.cos(radian))) * ((float) Math.cos(localRadian));
points[pointIndex + 1] = y = (radius + tRadius * ((float) Math.cos(radian))) * ((float) Math.sin(localRadian));
points[pointIndex + 2] = z = (tRadius * (float) Math.sin(radian));
pointIndex += 3;
float r = crossSectionIndex < tDivs ? tFrac * crossSectionIndex * 2.0F * 3.141592653589793f : 0.0f;
texCoords[texIndex] = (0.5F + (float) (Math.sin(r) * 0.5D));;
texCoords[texIndex + 1] = ((float) (Math.cos(r) * 0.5D) + 0.5F);
texIndex += 2;
}
}
//create faces
for (int y1 = 0; y1 < tDivs - 1 ; y1++) {
float radian = tFrac * y1 * 2.0f * 3.141592653589793f;
for (int x1 = 0; x1 < rDivs - 1; x1++) {
float localRadian = rFrac * x1 * 2.0f * 3.141592653589793f;
p0 = y1 * rDivs + x1;
p1 = p0 + 1;
p2 = p0 + rDivs;
p3 = p2 + 1;
t0 = y1 * rDivs + x1;
t1 = t0 + 1;
t2 = t0 + rDivs;
t3 = t1 + 1;
try {
faces[faceIndex] = (p2);
faces[faceIndex + 1] = (t3);
faces[faceIndex + 2] = (p0);
faces[faceIndex + 3] = (t2);
faces[faceIndex + 4] = (p1);
faces[faceIndex + 5] = (t0);
faceIndex += FACE_SIZE;
faces[faceIndex] = (p2);
faces[faceIndex + 1] = (t3);
faces[faceIndex + 2] = (p1);
faces[faceIndex + 3] = (t0);
faces[faceIndex + 4] = (p3);
faces[faceIndex + 5] = (t1);
//faceIndex += FACE_SIZE;
} catch (Exception e) {
break;
}
}
}
TriangleMesh localTriangleMesh = new TriangleMesh();
localTriangleMesh.getPoints().setAll(points);
localTriangleMesh.getTexCoords().setAll(texCoords);
localTriangleMesh.getFaces().setAll(faces);
MeshView view = new MeshView(localTriangleMesh);
view.setMaterial(new PhongMaterial(Color.BLUEVIOLET));
view.setCullFace(CullFace.BACK);
root.getChildren().clear();
root.getChildren().add(view);
//return localTriangleMesh;
System.out.println("objs in group: " + root.getChildren().size()
+ ", \nnum of points in array: " + points.length / POINT_SIZE
+ ", \nnum TexCoords: " + texCoords.length / TEXCOORD_SIZE
+ ", \nface count: " + faces.length / FACE_SIZE);
root.setRotationAxis(Rotate.X_AXIS);
root.setRotate(90);
return root;
}
and here is the result:
can someone help me iterate through this a little better?
my constructor for the mesh is : Group verts = MeshUtils.createToroidMesh(100,15,4,4);
OK, I figured the problem out... The problem was in my faces loop. It was adding values outside the range of points, and texCoords, here is the corrected loop:
//create faces
for (int point = 0; point < (tubeDivisions) ; point++) {
for (int crossSection = 0; crossSection < (radiusDivisions) ; crossSection++) {
p0 = point * radiusDivisions + crossSection;
p1 = p0 >= 0 ? p0 + 1 : p0 - (radiusDivisions);
p1 = p1 % (radiusDivisions) != 0 ? p0 + 1 : p0 - (radiusDivisions - 1);
p2 = (p0 + radiusDivisions) < ((tubeDivisions * radiusDivisions)) ? p0 + radiusDivisions : p0 - (tubeDivisions * radiusDivisions) + radiusDivisions ;
p3 = p2 < ((tubeDivisions * radiusDivisions) - 1) ? p2 + 1 : p2 - (tubeDivisions * radiusDivisions) + 1;
p3 = p3 % (radiusDivisions) != 0 ? p2 + 1 : p2 - (radiusDivisions - 1);
t0 = point * (radiusDivisions) + crossSection;
t1 = t0 >= 0 ? t0 + 1 : t0 - (radiusDivisions);
t1 = t1 % (radiusDivisions) != 0 ? t0 + 1 : t0 - (radiusDivisions - 1);
t2 = (t0 + radiusDivisions) < ((tubeDivisions * radiusDivisions)) ? t0 + radiusDivisions : t0 - (tubeDivisions * radiusDivisions) + radiusDivisions ;
t3 = t2 < ((tubeDivisions * radiusDivisions) - 1) ? t2 + 1 : t2 - (tubeDivisions * radiusDivisions) + 1;
t3 = t3 % (radiusDivisions) != 0 ? t2 + 1 : t2 - (radiusDivisions - 1);
try {
faces[faceIndex] = (p2);
faces[faceIndex + 1] = (t3);
faces[faceIndex + 2] = (p0);
faces[faceIndex + 3] = (t2);
faces[faceIndex + 4] = (p1);
faces[faceIndex + 5] = (t0);
faceIndex += FACE_SIZE;
faces[faceIndex] = (p2);
faces[faceIndex + 1] = (t3);
faces[faceIndex + 2] = (p1);
faces[faceIndex + 3] = (t0);
faces[faceIndex + 4] = (p3);
faces[faceIndex + 5] = (t1);
faceIndex += FACE_SIZE;
} catch (Exception e) {
e.printStackTrace();
}
//System.out.println(" :: " +p0 + " : " + p1 + " : " + p2 + " : " + p3);
}
}
and the results: (square toroid)
(Round toroid)
Hope this can help if you struggle as well!
Please Note I did not assign UV textures as they should have been(if using Image material) since Only Color is used. TexCoords can be anything (0 - 1.0) if only using colors

Unable to Draw Triangles Through glDrawElements in OpenGL ES 2.0

I'm trying to draw a procedural sphere referenced here.
I modified it a bit so that I can use the glDrawElements method of OpenGL ES 2.0
Here's my version of createSphere:
GLfloat sphereVerticies[10000]={0.0};
GLubyte triangleIndices[15000]={0};
int createSphere (GLfloat spherePoints[], GLubyte triangleIndices[], GLfloat fRadius, GLfloat step)
{
int points = 0;
GLfloat uStep = DEGREES_TO_RADIANS (step);
GLfloat vStep = uStep;
unsigned long index=0;
for (GLfloat u = 0.0f; u <= (2 * M_PI); u += uStep)
{
for (GLfloat v = -M_PI_2; v <= M_PI_2; v += vStep)
{
triangleIndices[index++]=points;
triangleIndices[index++]=points+1;
triangleIndices[index++]=points+2;
triangleIndices[index++]=points+2;
triangleIndices[index++]=points+3;
triangleIndices[index++]=points;
points++;
spherePoints[(points - 1) * 3] = fRadius * cosf(v) * cosf(u); // x
spherePoints[((points - 1) * 3) + 1] = fRadius * cosf(v) * sinf(u); // y
spherePoints[((points - 1) * 3) + 2] = fRadius * sinf(v); // z
points++;
spherePoints[(points - 1) * 3] = fRadius * cosf(v) * cosf(u + uStep); // x
spherePoints[((points - 1) * 3) + 1] = fRadius * cosf(v) * sinf(u + uStep); // y
spherePoints[((points - 1) * 3) + 2] = fRadius * sinf(v); // z
points++;
spherePoints[(points - 1) * 3] = fRadius * cosf(v + vStep) * cosf(u); // x
spherePoints[((points - 1) * 3) + 1] = fRadius * cosf(v + vStep) * sinf(u); // y
spherePoints[((points - 1) * 3) + 2] = fRadius * sinf(v + vStep); // z
points++;
spherePoints[(points - 1) * 3] = fRadius * cosf(v + vStep) * cosf(u + uStep); // x
spherePoints[((points - 1) * 3) + 1] = fRadius * cosf(v + vStep) * sinf(u + uStep); // y
spherePoints[((points - 1) * 3) + 2] = fRadius * sinf(v + vStep); // z
}
}
return points;
}
In SetupGL I have:
..
glEnable(GL_CULL_FACE);
..
..
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);
numPoints=createSphere(sphereVerticies, triangleIndices, 30.0f, 20.0f);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(sphereVerticies), sphereVerticies, GL_STATIC_DRAW);
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(triangleIndices), triangleIndices, GL_STATIC_DRAW);
// New lines (were previously in draw)
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) sphereVerticies);
glBindVertexArrayOES(0);
and finally in drawInRect:
glBindVertexArrayOES(_vertexArray);
glDrawElements(GL_TRIANGLES, (int)(numPoints*1.5), GL_UNSIGNED_BYTE, 0);
Now what am I doing wrong here? I don't see any visual output. Any help will be greatly appreciated. Thanks.
I can see two things:
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) sphereVerticies);
the last argument there should be 0, since the vertices are already buffered and bound in the VBO.
OpenGL ES - glVertexAttribPointer documentation
If a non-zero named buffer object is bound to the GL_ARRAY_BUFFER target (see glBindBuffer) while a generic vertex attribute array is specified, pointer is treated as a byte offset into the buffer object's data store...
And,
glDrawElements(GL_TRIANGLES, (int)(numPoints*1.5), GL_UNSIGNED_BYTE, 0);
you should use GL_UNSIGNED_SHORT because you have more than 255 vertices.
As for the indices, this is how you index them:
(0,1,2) (2,3,0)
2 3 2 2 3
o-------o o o-------o
| | | \ | /
| | => | \ | /
| | | \ | /
o-------o o-------o o
0 1 0 1 0
So, from this chart we can see two problems:
1) The triangles do not close up the polygon
2) Notice the winding, the first triangle is CCW, the second CW.
Try this code:
triangleIndices[index++]=points;
triangleIndices[index++]=points+1;
triangleIndices[index++]=points+2;
triangleIndices[index++]=points+3;
triangleIndices[index++]=points+2;
triangleIndices[index++]=points+1;

OpenGL ES: Translate a matrix to a particular point

Hi guys I am working on a app which requires the use of opengl es. However I have some questions. My task at hand is to rotate a matrix about an arbitrary point say (0,0,0). I did some research on google and the most common approach is
translate the matrix to (0,0,0)
Rotate the matrix
Translate the matrix back to its original position
Effectively
glTranslatef(centerX, centerY, centerZ);
glRotatef(angle, 0, 0, 1);
glTranslatef(-centerX, -centerY, -centerZ);
However my problem is I am using opengl es 2.0. The function translatef does not exist in opengl es 2.0. I have a function called as translateBy but I am unable to figure out how to use translateBy function to translate my matrix to a certain point
Thanks any help would be appreciated.
In OpenGL ES 2.0 you have to use vertex shader and just update the modelview matrix in every frame using
GLint modelviewmatrix = glGetUniformLocation(m_simpleProgram, "ModelviewMatrix");
matrx4 modelviewMatrix = rotation * translation;
glUniformMatrix4fv(modelviewmatrix, 1, 0, modelviewMatrix.Pointer());
assuming matrx4 as a matrix class of 4x4. and rotation and translation are the 4x4 matrix objects for rotation and translation.
Just make your own translate and rotate functions,
Translatef(x,y,z) is equivalent to
Matrx4 Translate( x, y, z)
{
Matrx4 m;
m = { 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, z, 1 }
return m;
}
and Rotatef(degree, vector3 axis) is equivalent to
Matrx4 Rotate( float degree, vector3 axis)
{
float radians = degrees * 3.14159f / 180.0f;
float s = std::sin(radians);
float c = std::cos(radians);
Matrx4 m = Identity(); /// load identity matrix
m[0] = c + (1 - c) * axis.x * axis.x;
m[1] = (1 - c) * axis.x * axis.y - axis.z * s;
m[2] = (1 - c) * axis.x * axis.z + axis.y * s;
m[4] = (1 - c) * axis.x * axis.y + axis.z * s;
m[5] = c + (1 - c) * axis.y * axis.y;
m[6] = (1 - c) * axis.y * axis.z - axis.x * s;
m[8] = (1 - c) * axis.x * axis.z - axis.y * s;
m[9] = (1 - c) * axis.y * axis.z + axis.x * s;
m[10] = c + (1 - c) * axis.z * axis.z;
return m;
}

What is kAccelerometerMinStep?

I have been looking at the Accelerometer Graph example in the iOS Developer library and I have a question about one of the variables that is used...
#define kAccelerometerMinStep 0.02
What is the Accelerometer Min Step? and what role does it have?
Here is how it is being used in the Low Pass Filter...
-(void)addAcceleration:(UIAcceleration*)accel
{
double alpha = filterConstant;
if(adaptive)
{
double d = Clamp(fabs(Norm(x, y, z) - Norm(accel.x, accel.y, accel.z)) / kAccelerometerMinStep - 1.0, 0.0, 1.0);
alpha = (1.0 - d) * filterConstant / kAccelerometerNoiseAttenuation + d * filterConstant;
}
x = accel.x * alpha + x * (1.0 - alpha);
y = accel.y * alpha + y * (1.0 - alpha);
z = accel.z * alpha + z * (1.0 - alpha);
}
And here is how it is being used in the High Pass Filter...
-(void)addAcceleration:(UIAcceleration*)accel
{
double alpha = filterConstant;
if(adaptive)
{
double d = Clamp(fabs(Norm(x, y, z) - Norm(accel.x, accel.y, accel.z)) / kAccelerometerMinStep - 1.0, 0.0, 1.0);
alpha = d * filterConstant / kAccelerometerNoiseAttenuation + (1.0 - d) * filterConstant;
}
x = alpha * (x + accel.x - lastX);
y = alpha * (y + accel.y - lastY);
z = alpha * (z + accel.z - lastZ);
lastX = accel.x;
lastY = accel.y;
lastZ = accel.z;
}
If someone could tell me what the min step is responsible for I would be very grateful...
I would like to capture accelerations ranging in magnitude from 0.05 to 2.00 g force with a frequency response of 0.25-2.50 Hz
Thanks.!

OpenGL ES (iPhone) Touch Picking

Looking to do classic OpenGL mouse picking in ES. I'd prefer not to use third party libs, GLU ports and OpenGL name stacks, etc, are out. This pretty much leaves inverse view transformation and ray intersection, correct?
I've gotten pretty far with the help of:
http://trac.bookofhook.com/bookofhook/trac.cgi/wiki/MousePicking
http://eigenclass.blogspot.com/2008/10/opengl-es-picking-using-ray-boundingbox.html
. . .but I'm not there yet. This also reeks of THERE MUST BE AN EASIER WAY!!
Here is some code:
-(void)handleTouch:(CGPoint)point {
GLfloat width = backingWidth;
GLfloat height = backingHeight;
GLfloat x = point.x;
GLfloat y = point.y;
GLfloat z = 0.0f;
//viewport -> normalized dev coord -> clip
GLfloat n[] = {
2 * x / width - 1,
2 * y / height,
2 * z - 1,
1
};
float fov = 45.0f * (M_PI / 180.0f);
float near = 0.01, far = 10.0f;
float aspect = (float)backingWidth / (float)backingHeight;
float top = tan(fov) * near;
//float bottom = -top;
//float left = aspect * bottom;
float right = aspect * top;
//I'm a viewing volume symmetric projection matrix
GLfloat P[] = {
near / right, 0, 0, 0,
0, near / top, 0, 0,
0, 0, -(far + near) / (far - near), (-2 * far * near) / (far - near),
0, 0, -1, 0
};
GLfloat Pminus1[] = {
1/P[0], 0, 0, 0,
0, 1/P[5], 0, 0,
0, 0, 0, 1/P[14],
0, 0, 1/P[11], -(P[10]/ (P[11]*P[14]))
};
//clip -> view
GLfloat v[] = {
Pminus1[0] * n[0] + Pminus1[1] * n[1] + Pminus1[2] * n[2] + Pminus1[3] * n[3],
Pminus1[4] * n[0] + Pminus1[5] * n[1] + Pminus1[6] * n[2] + Pminus1[7] * n[3],
Pminus1[8] * n[0] + Pminus1[9] * n[1] + Pminus1[10] * n[2] + Pminus1[11] * n[3],
Pminus1[12] * n[0] + Pminus1[13] * n[1] + Pminus1[14] * n[2] + Pminus1[15] * n[3]
};
//view -> world
GLfloat Rt[] = {
mv[0], mv[4], mv[8],
mv[1], mv[5], mv[9],
mv[2], mv[6], mv[10]
};
GLfloat tPrime[] = {
Rt[0] * mv[3] + Rt[1] * mv[7] + Rt[2] * mv[11],
Rt[3] * mv[3] + Rt[4] * mv[7] + Rt[5] * mv[11],
Rt[6] * mv[3] + Rt[7] * mv[7] + Rt[8] * mv[11]
};
GLfloat Mminus1[] = {
Rt[0], Rt[1], Rt[2], -(tPrime[0]),
Rt[3], Rt[4], Rt[5], -(tPrime[1]),
Rt[6], Rt[7], Rt[8], -(tPrime[2]),
0, 0, 0, 1
};
//point in world space
GLfloat w[] = {
Mminus1[0] * v[0] + Mminus1[1] * v[1] + Mminus1[2] * v[2] + Mminus1[3] * v[3],
Mminus1[4] * v[0] + Mminus1[5] * v[1] + Mminus1[6] * v[2] + Mminus1[7] * v[3],
Mminus1[8] * v[0] + Mminus1[9] * v[1] + Mminus1[10] * v[2] + Mminus1[11] * v[3],
Mminus1[12] * v[0] + Mminus1[13] * v[1] + Mminus1[14] * v[2] + Mminus1[15] * v[3]
};
//r = a + t(w - a)
GLfloat a[] = {0.0f, -0.1f, 0.0f};
GLfloat wminusa[] = {w[0] - a[0], w[1] - a[1], w[2] - a[2]};
vector[0] = a[0];
vector[1] = a[1],
vector[2] = a[2];
vector[3] = w[0];
vector[4] = w[1];
vector[5] = -10.0f;
//3 non-colinear points on the plane
GLfloat p1[] = {rect.origin.x, rect.origin.y, 0};
GLfloat p2[] = {rect.origin.x + rect.size.width, rect.origin.y, 0};
GLfloat p3[] = {rect.origin.x + rect.size.width, rect.origin.y + rect.size.height, 0};
//location plane normal vector, Ax + By + Cz + D = 0
GLfloat lp[] = {
p1[1] * (p2[2] - p3[2]) + p2[1] * (p3[2] - p1[2]) + p3[1] * (p1[2] - p2[2]),
p1[2] * (p2[0] - p3[0]) + p2[2] * (p3[0] - p1[0]) + p3[2] * (p1[0] - p2[0]),
p1[0] * (p2[1] - p3[1]) + p2[0] * (p3[1] - p1[1]) + p3[0] * (p1[1] - p2[1]),
-(p1[0] * (((p2[1] * p3[2]) - (p3[1] * p2[2]))) + p2[0] * (((p3[1] * p1[2]) - (p1[1] * p3[2]))) + p3[0] * (((p1[1] * p2[2]) - (p2[1] * p1[2]))))
};
GLfloat PnRd = (lp[0] * wminusa[0]) + (lp[1] * wminusa[1]) + (lp[2] * wminusa[2]);
if(PnRd != 0) {
GLfloat PnR0D = -((lp[0] * a[0]) + (lp[1] * a[1]) + (lp[2] * a[2]) + lp[3]);
if(PnR0D != 0) {
GLfloat t = PnR0D / PnRd;
if(t >= 0) {
GLfloat p[] = {
a[0] + wminusa[0] * t,
a[1] + wminusa[1] * t,
a[2] + wminusa[2] * t
};
if(p[0] > rect.origin.x &&
p[0] < rect.origin.x + rect.size.width &&
p[1] > rect.origin.y &&
p[1] < rect.origin.y + rect.size.height)
NSLog(#"BOOM!!!");
}
}
}
}
This post is very hard to follow. I'm attempting to roll my own on iOS 5 with GLKView; I've worked out how to touch detect pixel RGBA as I describe here, now I'm trying to work out how to quickly change the colours of my scene objects to be unique, to accompany this method.
I managed to fix it:
-(void)view2WorldPoint:(CGPoint)point :(GLfloat*)worldPoint {
// this is the inverse translation of the modelview
GLfloat width = (GLfloat)backingWidth;
GLfloat height = (GLfloat)backingHeight;
float clickX = point.x;
float clickY = point.y;
float clickZ = 0.0f;
NSLog(#"click point : x = %f, y = %f, z = %f", clickX, clickY, clickZ);
// NSLog(#"Me : x = %f, y = %f, z = %f", a[0], a[1], a[2]);
// NSLog(#"Dev : x = %f, y = %f, z = %f", squareX, squareY, squareZ);
//viewport -> normalized device coord -> clip
GLfloat n[] = {
2 * clickX / width - 1,
2 * (480-clickY) / height - 1,
2 * clickZ - 1,
1
};
// NSLog(#"Obj : x = %f, y = %f, z = %f", rect.origin.x, rect.origin.y, -0.5);
// NSLog(#"N : x = %f, y = %f, z = %f", n[0], n[1], n[2]);
//I'm a viewing volume symmetric projection matrix
// GLfloat P[] = {
// near / right, 0, 0, 0,
// 0, near / top, 0, 0,
// 0, 0, -(far + near) / (far - near), (-2 * far * near) / (far - near),
// 0, 0, -1, 0
// };
GLfloat P[16];
glGetFloatv(GL_PROJECTION_MATRIX, P);
// [self dumpMatrix:P :#"P"];
GLfloat Pminus1[] = {
1/P[0], 0, 0, 0,
0, 1/P[5], 0, 0,
0, 0, 0, 1/P[11],
0, 0, 1/P[14], -(P[10]/ (P[11]*P[14]))
};
// [self dumpMatrix:Pminus1 :#"P-1"];
//clip -> view
GLfloat v[] = {
(Pminus1[0] * n[0]) + (Pminus1[1] * n[1]) + (Pminus1[2] * n[2]) + (Pminus1[3] * n[3]),
(Pminus1[4] * n[0]) + (Pminus1[5] * n[1]) + (Pminus1[6] * n[2]) + (Pminus1[7] * n[3]),
(Pminus1[8] * n[0]) + (Pminus1[9] * n[1]) + (Pminus1[10] * n[2]) + (Pminus1[11] * n[3]),
(Pminus1[12] * n[0]) + (Pminus1[13] * n[1]) + (Pminus1[14] * n[2]) + (Pminus1[15] * n[3])
};
// NSLog(#"v = [%f, %f, %f, %f]", v[0], v[1], v[2], v[3]);
// [self dumpMatrix:mv :#"mv"];
//view -> world
GLfloat Rt[] = {
mv[0], mv[4], -mv[8],
mv[1], mv[5], -mv[9],
-mv[2], -mv[6], mv[10]
};
// NSLog(#"Rt0 = [%f, %f, %f]", Rt[0], Rt[1], Rt[2]);
// NSLog(#"Rt1 = [%f, %f, %f]", Rt[3], Rt[4], Rt[5]);
// NSLog(#"Rt2 = [%f, %f, %f]", Rt[6], Rt[7], Rt[8]);
GLfloat tPrime[] = {
Rt[0] * mv[12] + Rt[1] * mv[13] + Rt[2] * mv[14],
Rt[3] * mv[12] + Rt[4] * mv[13] + Rt[5] * mv[14],
Rt[6] * mv[12] + Rt[7] * mv[13] + Rt[8] * mv[14]
};
// NSLog(#"tPrime = [%f, %f, %f]", tPrime[0], tPrime[1], tPrime[2]);
GLfloat Mminus1[] = {
Rt[0], Rt[1], Rt[2], -(tPrime[0]),
Rt[3], Rt[4], Rt[5], -(tPrime[1]),
Rt[6], Rt[7], Rt[8], -(tPrime[2]),
0, 0, 0, 1
};
//point in world space
GLfloat w[] = {
Mminus1[0] * v[0] + Mminus1[1] * v[1] + Mminus1[2] * v[2] + Mminus1[3] * v[3],
Mminus1[4] * v[0] + Mminus1[5] * v[1] + Mminus1[6] * v[2] + Mminus1[7] * v[3],
Mminus1[8] * v[0] + Mminus1[9] * v[1] + Mminus1[10] * v[2] + Mminus1[11] * v[3],
Mminus1[12] * v[0] + Mminus1[13] * v[1] + Mminus1[14] * v[2] + Mminus1[15] * v[3]
};
NSLog(#"W : x = %f, y = %f, z = %f", w[0], w[1], w[2]);
worldPoint[0] = w[0];
worldPoint[1] = w[1];
worldPoint[2] = w[2];
}
Okay, okay that was still a bit buggy. Here is what is MOSTLY working now:
-(void)view2WorldPoint:(CGPoint)point :(GLfloat*)worldPoint {
float clickX = point.x;
float clickY = point.y;
float clickZ = -near;
//viewport -> normalized device coord -> clip
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
GLfloat n[] = {
(clickX - (float)viewport[0]) / (float)viewport[2] * 2.0 - 1.0,
-((clickY - (float)viewport[1]) / (float)viewport[3] * 2.0 - 1.0),
2.0 * clickZ - 1.0,
1.0
};
GLfloat MP[16], MPInv[16];
MatMatMultiply(MP, projMat, modelMat);
GenerateInverseMatrix4f(MPInv, MP); // replace this one with the whole 1/p thang?
GLfloat w[] = {
(MPInv[0] * n[0]) + (MPInv[4] * n[1]) + (MPInv[8] * n[2]) + (MPInv[12] * n[3]),
(MPInv[1] * n[0]) + (MPInv[5] * n[1]) + (MPInv[9] * n[2]) + (MPInv[13] * n[3]),
(MPInv[2] * n[0]) + (MPInv[6] * n[1]) + (MPInv[10] * n[2]) + (MPInv[14] * n[3]),
(MPInv[3] * n[0]) + (MPInv[7] * n[1]) + (MPInv[11] * n[2]) + (MPInv[15] * n[3])
};
worldPoint[0] = w[0] / w[3];
worldPoint[1] = w[1] / w[3];
worldPoint[2] = w[2] / w[3];
}
float Determinant4f(const float m[16])
{
return
m[12]*m[9]*m[6]*m[3]-
m[8]*m[13]*m[6]*m[3]-
m[12]*m[5]*m[10]*m[3]+
m[4]*m[13]*m[10]*m[3]+
m[8]*m[5]*m[14]*m[3]-
m[4]*m[9]*m[14]*m[3]-
m[12]*m[9]*m[2]*m[7]+
m[8]*m[13]*m[2]*m[7]+
m[12]*m[1]*m[10]*m[7]-
m[0]*m[13]*m[10]*m[7]-
m[8]*m[1]*m[14]*m[7]+
m[0]*m[9]*m[14]*m[7]+
m[12]*m[5]*m[2]*m[11]-
m[4]*m[13]*m[2]*m[11]-
m[12]*m[1]*m[6]*m[11]+
m[0]*m[13]*m[6]*m[11]+
m[4]*m[1]*m[14]*m[11]-
m[0]*m[5]*m[14]*m[11]-
m[8]*m[5]*m[2]*m[15]+
m[4]*m[9]*m[2]*m[15]+
m[8]*m[1]*m[6]*m[15]-
m[0]*m[9]*m[6]*m[15]-
m[4]*m[1]*m[10]*m[15]+
m[0]*m[5]*m[10]*m[15];
}
BOOL GenerateInverseMatrix4f(float i[16], const float m[16])
{
float x=Determinant4f(m);
if (x==0) return FALSE;
i[0]= (-m[13]*m[10]*m[7] +m[9]*m[14]*m[7] +m[13]*m[6]*m[11]
-m[5]*m[14]*m[11] -m[9]*m[6]*m[15] +m[5]*m[10]*m[15])/x;
i[4]= ( m[12]*m[10]*m[7] -m[8]*m[14]*m[7] -m[12]*m[6]*m[11]
+m[4]*m[14]*m[11] +m[8]*m[6]*m[15] -m[4]*m[10]*m[15])/x;
i[8]= (-m[12]*m[9]* m[7] +m[8]*m[13]*m[7] +m[12]*m[5]*m[11]
-m[4]*m[13]*m[11] -m[8]*m[5]*m[15] +m[4]*m[9]* m[15])/x;
i[12]=( m[12]*m[9]* m[6] -m[8]*m[13]*m[6] -m[12]*m[5]*m[10]
+m[4]*m[13]*m[10] +m[8]*m[5]*m[14] -m[4]*m[9]* m[14])/x;
i[1]= ( m[13]*m[10]*m[3] -m[9]*m[14]*m[3] -m[13]*m[2]*m[11]
+m[1]*m[14]*m[11] +m[9]*m[2]*m[15] -m[1]*m[10]*m[15])/x;
i[5]= (-m[12]*m[10]*m[3] +m[8]*m[14]*m[3] +m[12]*m[2]*m[11]
-m[0]*m[14]*m[11] -m[8]*m[2]*m[15] +m[0]*m[10]*m[15])/x;
i[9]= ( m[12]*m[9]* m[3] -m[8]*m[13]*m[3] -m[12]*m[1]*m[11]
+m[0]*m[13]*m[11] +m[8]*m[1]*m[15] -m[0]*m[9]* m[15])/x;
i[13]=(-m[12]*m[9]* m[2] +m[8]*m[13]*m[2] +m[12]*m[1]*m[10]
-m[0]*m[13]*m[10] -m[8]*m[1]*m[14] +m[0]*m[9]* m[14])/x;
i[2]= (-m[13]*m[6]* m[3] +m[5]*m[14]*m[3] +m[13]*m[2]*m[7]
-m[1]*m[14]*m[7] -m[5]*m[2]*m[15] +m[1]*m[6]* m[15])/x;
i[6]= ( m[12]*m[6]* m[3] -m[4]*m[14]*m[3] -m[12]*m[2]*m[7]
+m[0]*m[14]*m[7] +m[4]*m[2]*m[15] -m[0]*m[6]* m[15])/x;
i[10]=(-m[12]*m[5]* m[3] +m[4]*m[13]*m[3] +m[12]*m[1]*m[7]
-m[0]*m[13]*m[7] -m[4]*m[1]*m[15] +m[0]*m[5]* m[15])/x;
i[14]=( m[12]*m[5]* m[2] -m[4]*m[13]*m[2] -m[12]*m[1]*m[6]
+m[0]*m[13]*m[6] +m[4]*m[1]*m[14] -m[0]*m[5]* m[14])/x;
i[3]= ( m[9]* m[6]* m[3] -m[5]*m[10]*m[3] -m[9]* m[2]*m[7]
+m[1]*m[10]*m[7] +m[5]*m[2]*m[11] -m[1]*m[6]* m[11])/x;
i[7]= (-m[8]* m[6]* m[3] +m[4]*m[10]*m[3] +m[8]* m[2]*m[7]
-m[0]*m[10]*m[7] -m[4]*m[2]*m[11] +m[0]*m[6]* m[11])/x;
i[11]=( m[8]* m[5]* m[3] -m[4]*m[9]* m[3] -m[8]* m[1]*m[7]
+m[0]*m[9]* m[7] +m[4]*m[1]*m[11] -m[0]*m[5]* m[11])/x;
i[15]=(-m[8]* m[5]* m[2] +m[4]*m[9]* m[2] +m[8]* m[1]*m[6]
-m[0]*m[9]* m[6] -m[4]*m[1]*m[10] +m[0]*m[5]* m[10])/x;
return TRUE;
}
void MatMatMultiply(GLfloat *result, GLfloat *matrix1, GLfloat *matrix2)
{
result[0]=matrix1[0]*matrix2[0]+
matrix1[4]*matrix2[1]+
matrix1[8]*matrix2[2]+
matrix1[12]*matrix2[3];
result[4]=matrix1[0]*matrix2[4]+
matrix1[4]*matrix2[5]+
matrix1[8]*matrix2[6]+
matrix1[12]*matrix2[7];
result[8]=matrix1[0]*matrix2[8]+
matrix1[4]*matrix2[9]+
matrix1[8]*matrix2[10]+
matrix1[12]*matrix2[11];
result[12]=matrix1[0]*matrix2[12]+
matrix1[4]*matrix2[13]+
matrix1[8]*matrix2[14]+
matrix1[12]*matrix2[15];
result[1]=matrix1[1]*matrix2[0]+
matrix1[5]*matrix2[1]+
matrix1[9]*matrix2[2]+
matrix1[13]*matrix2[3];
result[5]=matrix1[1]*matrix2[4]+
matrix1[5]*matrix2[5]+
matrix1[9]*matrix2[6]+
matrix1[13]*matrix2[7];
result[9]=matrix1[1]*matrix2[8]+
matrix1[5]*matrix2[9]+
matrix1[9]*matrix2[10]+
matrix1[13]*matrix2[11];
result[13]=matrix1[1]*matrix2[12]+
matrix1[5]*matrix2[13]+
matrix1[9]*matrix2[14]+
matrix1[13]*matrix2[15];
result[2]=matrix1[2]*matrix2[0]+
matrix1[6]*matrix2[1]+
matrix1[10]*matrix2[2]+
matrix1[14]*matrix2[3];
result[6]=matrix1[2]*matrix2[4]+
matrix1[6]*matrix2[5]+
matrix1[10]*matrix2[6]+
matrix1[14]*matrix2[7];
result[10]=matrix1[2]*matrix2[8]+
matrix1[6]*matrix2[9]+
matrix1[10]*matrix2[10]+
matrix1[14]*matrix2[11];
result[14]=matrix1[2]*matrix2[12]+
matrix1[6]*matrix2[13]+
matrix1[10]*matrix2[14]+
matrix1[14]*matrix2[15];
result[3]=matrix1[3]*matrix2[0]+
matrix1[7]*matrix2[1]+
matrix1[11]*matrix2[2]+
matrix1[15]*matrix2[3];
result[7]=matrix1[3]*matrix2[4]+
matrix1[7]*matrix2[5]+
matrix1[11]*matrix2[6]+
matrix1[15]*matrix2[7];
result[11]=matrix1[3]*matrix2[8]+
matrix1[7]*matrix2[9]+
matrix1[11]*matrix2[10]+
matrix1[15]*matrix2[11];
result[15]=matrix1[3]*matrix2[12]+
matrix1[7]*matrix2[13]+
matrix1[11]*matrix2[14]+
matrix1[15]*matrix2[15];
}