I have made a simple class called Vector3.
It's a 3 dimensional vector with some basic math implementions.
Now i want to be able to rotate this single vector, but i get an exception.
I have this:
private static final float[] matrix = new float[16];
private static final float[] inVec = new float[4];
private static final float[] outVec = new float[4];
public Vector3 rotate(float angle, float axisX, float axisY, float axisZ)
{
inVec[0] = x;
inVec[1] = y;
inVec[2] = z;
inVec[3] = 1;
Matrix.setIdentityM(matrix, 0);
Matrix.rotateM(matrix, 0, angle, axisX, axisY, axisZ);
Matrix.multiplyMM(outVec, 0, matrix, 0, inVec, 0);
x = outVec[0];
y = outVec[1];
z = outVec[2];
return this;
}
And i call i by making this:
Vector3 v = new Vector3(1f, 1f, 1f);
v.rotate(90f, 0f, 1f, 0f);
What i get is an IllegalArgumentException at:
Matrix.multiplyMM(outVec, 0, matrix, 0, inVec, 0);
It says that
length - offset < n
Does anyone have a clue about what i am doing wrong?
I didn't wrote this Vector3 function from the beginning, it's borrowed from the book "beggining android games"
You're using multiplyMM method that mutiplies 2 matrices and return a matrix instead of using multiplyMV (MV stands for matrix-vector) that multiplies your rotation matrix with your vector, returning the rotated vector.
Related
I am working on marker AR with native android vuforia what I am trying to do is to move my video object according to camera (it should always face camera) I tried following but its not working but sometime its working but its not persistence
public void renderFrame(State state, float[] projectionMatrix) {
mSampleAppRenderer.renderVideoBackground();
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
isTracking = false;
for (int tIdx = 0; tIdx < state.getNumTrackableResults(); tIdx++) {
TrackableResult trackableResult = state.getTrackableResult(tIdx);
ImageTarget imageTarget = (ImageTarget) trackableResult
.getTrackable();
imageTarget.startExtendedTracking();
isTracking = true;
float[] modelViewMatrixVideo = Tool.convertPose2GLMatrix(
trackableResult.getPose()).getData();
float[] modelViewProjectionVideo = new float[16];
Matrix44F invTranspMV = SampleMath.Matrix44FTranspose(SampleMath.Matrix44FInverse(Tool.convertPose2GLMatrix(trackableResult.getPose())));
Matrix.translateM(modelViewMatrixVideo, 0, 0f, 0f, 1f);
Matrix.rotateM(modelViewMatrixVideo, 0, (float) Math.toDegrees(Math.asin(-invTranspMV.getData()[6])), 0.0f, 0.f, 1.0f);
Matrix.multiplyMM(modelViewProjectionVideo, 0,
projectionMatrix, 0, modelViewMatrixVideo, 0);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
GLES20.glUseProgram(videoPlaybackShaderID);
GLES20.glVertexAttribPointer(videoPlaybackVertexHandle, 3,
GLES20.GL_FLOAT, false, 0, quadVertices);
GLES20.glVertexAttribPointer(videoPlaybackTexCoordHandle,
2, GLES20.GL_FLOAT, false, 0,
fillBuffer(videoQuadTextureCoordsTransformedStones));
GLES20.glEnableVertexAttribArray(videoPlaybackVertexHandle);
GLES20.glEnableVertexAttribArray(videoPlaybackTexCoordHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
videoPlaybackTextureID);
GLES20.glUniformMatrix4fv(videoPlaybackMVPMatrixHandle, 1,
false, modelViewProjectionVideo, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, NUM_QUAD_INDEX,
GLES20.GL_UNSIGNED_SHORT, quadIndices);
GLES20.glDisableVertexAttribArray(videoPlaybackVertexHandle);
GLES20.glDisableVertexAttribArray(videoPlaybackTexCoordHandle);
GLES20.glUseProgram(0);
GLES20.glDisable(GLES20.GL_BLEND);
SampleUtils.checkGLError("VideoPlayback renderFrame");
}
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
Renderer.getInstance().end();
}
I have tried above so far and its working sometime but not properly
Please help me i am trying to do this from a week.
I am trying to do is to move my video object according to camera (it should always face camera)
If you want that a object faces the camera (Billboarding), then you have to use a model matrix which is the inverse view matrix, but without the translation part.
Use Matrix44FInverse, to geht the inverse matrix of a Matrix44F:
public void renderFrame(State state, float[] projectionMatrix) {
.....
// get the view matrix and set translation part to (0, 0, 0)
float[] tempViewMat = Tool.convertPose2GLMatrix(trackableResult.getPose()).getData();
tempViewMat[12] = 0;
tempViewMat[13] = 0;
tempViewMat[14] = 0;
// create the billboard matrix
Matrix44F billboardMatrix = new Matrix44F();
billboardMatrix.setData(tempViewMat);
billboardMatrix = SampleMath.Matrix44FInverse(billboardMatrix);
// calculate the model view projection matrix
float[] viewMatrixVideo = Tool.convertPose2GLMatrix(trackableResult.getPose()).getData();
float[] modelViewVideo = new float[16];
Matrix.multiplyMM(modelViewVideo, 0, viewMatrixVideo, 0, billboardMatrix.getData(), 0);
float[] modelViewProjectionVideo = new float[16];
Matrix.multiplyMM(modelViewProjectionVideo, 0, projectionMatrix, 0, modelViewVideo, 0);
.....
}
I used your code but my AR is rotating in every direction but i want some different thing I have one video that I want to place it vertical on marker and if user move left or right only then i want to rotate it to face camera so that i will see my AR video same that is vertical from any view
What you want to do is to fix the upwards direction, but to orientate the normal vector to the line of sight.
The line of sight is the inverse Z-axis of the view space in a Right-Handed Coordinate System.
Matrix44F inverse_view = SampleMath.Matrix44FInverse(
Tool.convertPose2GLMatrix(trackableResult.getPose()));
// line of sight
Vec3F los = new Vec3F(-inverse_view[8], -inverse_view[9], -inverse_view[10] );
Eiterh the Y-Axis (0, 1, 0) or the Z-Axis (0, 1, 0) of the model has to be the Z-axis of the orientation matrix.
The X-Axis is the cross product (Vec3FCross) the line of sight and the Z-axis of the orientation matrix.
e.g.
Vec3F z_axis = new Vec3F(0, 0, 1);
Vec3F x_axis = Vec3FNormalize(Vec3FCross(los, z_axis));
Vec3F y_axis = Vec3FCross(z_axis, x_axis);
float[] orientationMatrix = new float[]{
x_axis.getData()[0], x_axis.getData()[1], x_axis.getData()[2], 0,
y_axis.getData()[0], y_axis.getData()[1], y_axis.getData()[2], 0,
z_axis.getData()[0], z_axis.getData()[1], z_axis.getData()[2], 0,
0, 0, 0, 1
};
// calculate the model view projection matrix
float[] viewMatrixVideo = Tool.convertPose2GLMatrix(trackableResult.getPose()).getData();
float[] modelViewVideo = new float[16];
Matrix.multiplyMM(modelViewVideo, 0, viewMatrixVideo, 0, orientationMatrix, 0);
float[] modelViewProjectionVideo = new float[16];
Matrix.multiplyMM(modelViewProjectionVideo, 0, projectionMatrix, 0, modelViewVideo, 0);
I am currently working on developing a 3-D game engine for Android, and everything works fine on my Lenovo TAB 10, but rotation about any axis causes the meshes to flatten (skew) during the rotation. I don't know where to start looking since it works on one device. Any ideas?
I rotate everything around arbitrary axes (right, up, and forward) relative to the objects themselves. The rotated axes are then put into a rotation matrix as follows:
mMatRotate = new cMatrix4(
mvRight.mX, mvUp.mX, mvForward.mX, 0.0f,
mvRight.mY, mvUp.mY, mvForward.mY, 0.0f,
mvRight.mZ, mvUp.mZ, mvForward.mZ, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
The actual matrix is defined as follows:
cMatrix4( float a, float b, float c, float d,
float e, float f, float g, float h,
float i, float j, float k, float l,
float m, float n, float o, float p )
{
mfMatrixData[0] = a; mfMatrixData[1] = b; mfMatrixData[2] = c; mfMatrixData[3] = d;
mfMatrixData[4] = e; mfMatrixData[5] = f; mfMatrixData[6] = g; mfMatrixData[7] = h;
mfMatrixData[8] = i; mfMatrixData[9] = j; mfMatrixData[10] = k; mfMatrixData[11] = l;
mfMatrixData[12] = m; mfMatrixData[13] = n; mfMatrixData[14] = o; mfMatrixData[15] = p;
}
Inside my draw() function looks like this:
Matrix.setIdentityM(mMesh.mModelMatrix, 0);
Matrix.translateM(mMesh.mModelMatrix, 0, mvLocation.mX, mvLocation.mY, mvLocation.mZ);
Matrix.scaleM(mMesh.mModelMatrix, 0, mfScale, mfScale, mfScale);
Matrix.multiplyMM(mMesh.mModelMatrix, 0, mMesh.mModelMatrix, 0, mMatRotate.getFloatArray(), 0);
mMesh.draw(viewMatrix, projMatrix, Renderer);
And the final transform looks like this:
Matrix.multiplyMM(mtrx, 0, viewMatrix, 0, mModelMatrix, 0);
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mtrx, 0);
Matrix.multiplyMM(mtrx, 0, projMatrix, 0, mtrx, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mtrx, 0);
I'm kind of stuck on this one. Any suggestions would be helpful.
Okay, I solved the problem myself, and I'll post it here in case anyone else is interested or encounters a similar issue. It all comes down t the fact that the Lenovo TAB 10 relies entirely on hardware, while the Samsung Galaxy Core Prime does not. The issue is in the line:
Matrix.multiplyMM(mMesh.mModelMatrix, 0, mMesh.mModelMatrix, 0, mMatRotate.getFloatArray(), 0);
In hardware, it seems, it is okay to perform a matrix multiply and place the result into one of the input matrices; but the software implementation does not function the same. This makes sense, I guess, because it would take too long to make a copy every time you do a matrix multiply.
I am a newbee to android OpenGL i am trying to draw buttons using OpenGL I have added a Gesture Listener for the GLSurface View now i have motionevent when ever the user touches. My question is how can i convert motionevent.getx and motionevent.gety (which are in pixel range
)to window or Object coordinates of the view?
I Found the solution for this question posting in case if some one requires it.
public float[] convertToObjectCoordinates(MotionEvent event) {
float[] worldPos = new float[2];
float[] invertedMatrix, transformMatrix,
normalizedInPoint, outPoint, mProjMatrix, mVMatrix;
invertedMatrix = new float[16];
transformMatrix = new float[16];
mProjMatrix = new float[16];
mProjMatrix = mRenderer.getmProjMatrix();
mVMatrix = new float[16];
//Change the Proj and ModelView matrix according to your model and view matrix or you can use your mvpMatrix directly instead of transform Matrix
Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0, 0, 0f, 0.0f, 1.0f, 0.0f);
normalizedInPoint = new float[4];
outPoint = new float[4];
float y = screenHeight - event.getY();
setHeightAndWidth();
normalizedInPoint[0] = (float) ((event.getX()) * 2.0f / screenWidth - 1.0);
normalizedInPoint[1] = (float) ((y) * 2.0f / screenHeight - 1.0);
normalizedInPoint[2] = - 1.0f;
normalizedInPoint[3] = 1.0f;
Matrix.multiplyMM( transformMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
Matrix.invertM(invertedMatrix, 0, transformMatrix, 0);
Matrix.multiplyMV(outPoint, 0, invertedMatrix, 0, normalizedInPoint, 0);
if (outPoint[3] != 0.0)
{
worldPos[0] = outPoint[0] / outPoint[3];
worldPos[1] = outPoint[1] / outPoint[3];
} else {
Log.e("Error", "Normalised Zero Error");
}
return worldPos;
}
This is remake from the following post for Android OpenGL2.0 :
Android OpenGL ES 2.0 screen coordinates to world coordinates
EROl's Answer
thanks to EROl for his reply.
public void setHeightAndWidth() {
screenHeight = this.getHeight();
screenWidth = this.getWidth();
}
The above method should be written in the GLSurfaceView class so that it gives the exact view's height and width. If your View occupies complete screen you may also use Display metrics to get complete screen width and height.
I'm starting to learn OpenGL, and are using the following site: http://www.learnopengles.com/android-lesson-one-getting-started/
But it seems that I got a problem at this part (works fine in portrait mode):
private float[] mViewMatrix = new float[16];
/** Store the projection matrix. This is used to project the scene onto a 2D viewport. */
private float[] mProjectionMatrix = new float[16];
/** Allocate storage for the final combined matrix. This will be passed into the shader program. */
private float[] mMVPMatrix = new float[16];
/** This will be used to pass in the transformation matrix. */
private int mMVPMatrixHandle;
/** This will be used to pass in model position information. */
private int mPositionHandle;
/** This will be used to pass in model color information. */
private int mColorHandle;
/** How many bytes per float. */
private final int mBytesPerFloat = 4;
/** How many elements per vertex. */
private final int mStrideBytes = 7 * mBytesPerFloat;
/** Size of the position data in elements. */
private final int mPositionDataSize = 3;
/** Offset of the color data. */
private final int mColorOffset = 3;
/** Size of the color data in elements. */
private final int mColorDataSize = 4;
public void onSurfaceChanged(GL10 gl, int width, int height)
{
GLES20.glViewport(0, 0, width, height);
// Create a new perspective projection matrix. The height will stay the same
// while the width will vary as per aspect ratio.
final float ratio = (float) width / height;
final float left = -ratio;
final float right = ratio;
final float bottom = -1.0f;
final float top = 1.0f;
final float near = 1.0f;
final float far = 10.0f;
System.out.println("Height: " + height);
System.out.println("Width: " + width);
Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
}
public void onDrawFrame(GL10 gl)
{
final float eyeX = 0.0f;
final float eyeY = 0.0f;
final float eyeZ = 1.5f;
final float lookY = 0.0f; //Y direction of what user see
final float lookZ = -5.0f; //Z direction of what user see
// Set our up vector. This is where our head would be pointing were we holding the camera.
final float upX = 0.0f;
final float upY = 1.0f;
final float upZ = 0.0f;
GLES20.glClearColor(red, green, blue, clearcoloralpha);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, xax, lookY, lookZ, upX, upY, upZ);
// Draw the triangle facing straight on.
for(int i = 0; i < Triangles.size(); i++)
{
Matrix.setIdentityM(Triangles.get(i).getModelMatrix(), 0);
if(Triangles.get(i).Rotate())
{
Triangles.get(i).rotation = (360.0f / 10000.0f) * ((int) Triangles.get(i).last);
Triangles.get(i).last+=20;
//Rotates the matrix by rotation degrees
Matrix.rotateM(Triangles.get(i).getModelMatrix(), 0, Triangles.get(i).rotation, 0.0f, 0.0f, 1.0f);
}
else
Matrix.rotateM(Triangles.get(i).getModelMatrix(), 0, Triangles.get(i).rotation, 0.0f, 0.0f, 1.0f);
drawTriangle(Triangles.get(i).getFloatBuffer(),Triangles.get(i));
}
}
private void drawTriangle(final FloatBuffer aTriangleBuffer, Triangle tri)
{
aTriangleBuffer.position(0);
GLES20.glVertexAttribPointer(mPositionHandle, tri.DataSize, GLES20.GL_FLOAT, false, mStrideBytes, aTriangleBuffer);
GLES20.glEnableVertexAttribArray(mPositionHandle);
aTriangleBuffer.position(3);
GLES20.glVertexAttribPointer(mColorHandle, tri.ColorDataSize, GLES20.GL_FLOAT, false, mStrideBytes, aTriangleBuffer);
GLES20.glEnableVertexAttribArray(mColorHandle);
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, tri.getModelMatrix(), 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
}
But when I try to move a triangle (to the left or right) in landscape mode the triangles get "cut off" (does not display the whole triangle) when moving them to far to one of the sides. It seems that they are been acted on as if they were outside the screen when they actually are not. As mentioned it seems to work fine in portrait mode.
Height is 752 and Width 1280 in landscape mode (Galaxy Tab 2).
Does this have something to do with the Project Matrix which is set here?
Thanks for any help!
You were right, the problem was you were moving you camera :D
xax should have stayed as 0.0f
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, xax, lookY, lookZ, upX, upY, upZ);
I need to pass to gluUnProject the winZ value of a pixel. to obtain the winZ value I need to read the depth value at a given pixel, this is a normalised z coordinate.
The way to do it is this with C: glReadPixels(winX, winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
The problem is that I'm programming with Android 1.5 and OpenGL ES 1, then I don't have the possibility to use GL_DEPTH_COMPONENT and glReadPixels.
How can I obtain the depth of a pixel on the screen?
Solved, it is simply impossible to do it on OpenGL ES 1.x
If someone find the way, tell me, but after weeks of searching i simply think that it is impossible.
Check out this nice post I think it has what your looking for:
http://afqa123.com/2012/04/03/fixing-gluunproject-in-android-froyo/
A custom GLunproject which enables you to calculate the near and far vectors:
private boolean unProject(float winx, float winy, float winz,
float[] modelMatrix, int moffset,
float[] projMatrix, int poffset,
int[] viewport, int voffset,
float[] obj, int ooffset) {
float[] finalMatrix = new float[16];
float[] in = new float[4];
float[] out = new float[4];
Matrix.multiplyMM(finalMatrix, 0, projMatrix, poffset,
modelMatrix, moffset);
if (!Matrix.invertM(finalMatrix, 0, finalMatrix, 0))
return false;
in[0] = winx;
in[1] = winy;
in[2] = winz;
in[3] = 1.0f;
// Map x and y from window coordinates
in[0] = (in[0] - viewport[voffset]) / viewport[voffset + 2];
in[1] = (in[1] - viewport[voffset + 1]) / viewport[voffset + 3];
// Map to range -1 to 1
in[0] = in[0] * 2 - 1;
in[1] = in[1] * 2 - 1;
in[2] = in[2] * 2 - 1;
Matrix.multiplyMV(out, 0, finalMatrix, 0, in, 0);
if (out[3] == 0.0f)
return false;
out[0] /= out[3];
out[1] /= out[3];
out[2] /= out[3];
obj[ooffset] = out[0];
obj[ooffset + 1] = out[1];
obj[ooffset + 2] = out[2];
return true;
}
In order to get the 3D coordinates of a point x/y on the screen, you only have to call the new method once for each intersection with the near and far clipping planes:
// near clipping plane intersection
float[] objNear = new float[4];
unProject(screenX, screenY, 0.1f,
viewMatrix, 0, projectionMatrix, 0, view, 0, objNear, 0);
// far clipping plane intersection
float[] objFar = new float[4];
unProject(screenX, screenY, 1.0f,
viewMatrix, 0, projectionMatrix, 0, view, 0, objFar, 0);
You can then calculate the difference vector (objFar - objNear) and check what location in 3D space corresponds to the screen event.
This is a simple function i use to find the distance between the two vectors:
public float distanceBetweenVectors(float[] vec1, float[] vec2){
float distance = 0;
// Simple math
distance = (float) Math.sqrt(
Math.pow((vec1[0]-vec2[0]), 2) +
Math.pow((vec1[1]-vec2[1]), 2) +
Math.pow((vec1[2]-vec2[2]), 2) +
Math.pow((vec1[3]-vec2[3]), 2)
);
return distance;
}