/** * Linearly interpolates between this {@link Matrix4} and the given {@link Matrix4} by the given * factor. * * @param matrix {@link Matrix4} The other matrix. * @param t {@code double} The interpolation ratio. The result is weighted to this value on the * {@link Matrix4}. * @return A reference to this {@link Matrix4} to facilitate chaining. */ @NonNull public Matrix4 lerp(@NonNull Matrix4 matrix, double t) { matrix.toArray(mTmp); for (int i = 0; i < 16; ++i) { m[i] = m[i] * (1.0 - t) + t * mTmp[i]; } return this; }
private Matrix4 createLightViewProjectionMatrix(DirectionalLight light) { // // -- Get the frustum corners in world space // mCamera.getFrustumCorners(mFrustumCorners, true); // // -- Get the frustum centroid // mFrustumCentroid.setAll(0, 0, 0); for (int i = 0; i < 8; i++) mFrustumCentroid.add(mFrustumCorners[i]); mFrustumCentroid.divide(8.0); // // -- // BoundingBox lightBox = new BoundingBox(mFrustumCorners); double distance = mFrustumCentroid.distanceTo(lightBox.getMin()); Vector3 lightDirection = light.getDirectionVector().clone(); lightDirection.normalize(); Vector3 lightPosition = Vector3.subtractAndCreate( mFrustumCentroid, Vector3.multiplyAndCreate(lightDirection, distance)); // // -- // mLightViewMatrix.setToLookAt(lightPosition, mFrustumCentroid, Vector3.Y); for (int i = 0; i < 8; i++) mFrustumCorners[i].multiply(mLightViewMatrix); BoundingBox b = new BoundingBox(mFrustumCorners); mLightProjectionMatrix.setToOrthographic( b.getMin().x, b.getMax().x, b.getMin().y, b.getMax().y, -b.getMax().z, -b.getMin().z); mLightModelViewProjectionMatrix.setAll(mLightProjectionMatrix); mLightModelViewProjectionMatrix.multiply(mLightViewMatrix); return mLightModelViewProjectionMatrix; }
public Vector3 calculatePos(int x, int y, Object3D object3D) { Matrix4 mViewMatrix = getCurrentCamera().getViewMatrix(); Matrix4 mProjectionMatrix = getCurrentCamera().getProjectionMatrix(); double[] mNearPos4 = new double[4]; double[] mFarPos4 = new double[4]; Vector3 mNearPos = new Vector3(); Vector3 mFarPos = new Vector3(); Vector3 mNewObjPos = new Vector3(); int[] mViewport = new int[] {0, 0, getViewportWidth(), getViewportHeight()}; GLU.gluUnProject( x, getViewportHeight() - y, 0, mViewMatrix.getDoubleValues(), 0, mProjectionMatrix.getDoubleValues(), 0, mViewport, 0, mNearPos4, 0); GLU.gluUnProject( x, getViewportHeight() - y, 1.f, mViewMatrix.getDoubleValues(), 0, mProjectionMatrix.getDoubleValues(), 0, mViewport, 0, mFarPos4, 0); mNearPos.setAll( mNearPos4[0] / mNearPos4[3], mNearPos4[1] / mNearPos4[3], mNearPos4[2] / mNearPos4[3]); mFarPos.setAll( mFarPos4[0] / mFarPos4[3], mFarPos4[1] / mFarPos4[3], mFarPos4[2] / mFarPos4[3]); double factor = (Math.abs(object3D.getZ()) + mNearPos.z) / (getCurrentCamera().getFarPlane() - getCurrentCamera().getNearPlane()); mNewObjPos.setAll(mFarPos); mNewObjPos.subtract(mNearPos); mNewObjPos.multiply(factor); mNewObjPos.add(mNearPos); return mNewObjPos; }
/** * Subtracts the given {@link Matrix4} to this one. * * @param matrix {@link Matrix4} The matrix to subtract. * @return A reference to this {@link Matrix4} to facilitate chaining. */ @NonNull public Matrix4 subtract(@NonNull Matrix4 matrix) { // @formatter:off matrix.toArray(mTmp); m[0] -= mTmp[0]; m[1] -= mTmp[1]; m[2] -= mTmp[2]; m[3] -= mTmp[3]; m[4] -= mTmp[4]; m[5] -= mTmp[5]; m[6] -= mTmp[6]; m[7] -= mTmp[7]; m[8] -= mTmp[8]; m[9] -= mTmp[9]; m[10] -= mTmp[10]; m[11] -= mTmp[11]; m[12] -= mTmp[12]; m[13] -= mTmp[13]; m[14] -= mTmp[14]; m[15] -= mTmp[15]; return this; // @formatter:on }
/** * Adds the given {@link Matrix4} to this one. * * @param matrix {@link Matrix4} The matrix to add. * @return A reference to this {@link Matrix4} to facilitate chaining. */ @NonNull public Matrix4 add(@NonNull Matrix4 matrix) { // @formatter:off matrix.toArray(mTmp); m[0] += mTmp[0]; m[1] += mTmp[1]; m[2] += mTmp[2]; m[3] += mTmp[3]; m[4] += mTmp[4]; m[5] += mTmp[5]; m[6] += mTmp[6]; m[7] += mTmp[7]; m[8] += mTmp[8]; m[9] += mTmp[9]; m[10] += mTmp[10]; m[11] += mTmp[11]; m[12] += mTmp[12]; m[13] += mTmp[13]; m[14] += mTmp[14]; m[15] += mTmp[15]; return this; // @formatter:on }
public void render( long ellapsedTime, double deltaTime, RenderTarget renderTarget, Material sceneMaterial) { // Scene color-picking requests are relative to the prior frame's render // state, so handle any pending request before applying this frame's updates... if (mPickerInfo != null) { doColorPicking(mPickerInfo); // One-shot, once per frame at most mPickerInfo = null; } performFrameTasks(); // Handle the task queue synchronized (mFrameTaskQueue) { if (mLightsDirty) { updateMaterialsWithLights(); mLightsDirty = false; } } synchronized (mNextSkyboxLock) { // Check if we need to switch the skybox, and if so, do it. if (mNextSkybox != null) { mSkybox = mNextSkybox; mNextSkybox = null; } } synchronized (mNextCameraLock) { // Check if we need to switch the camera, and if so, do it. if (mNextCamera != null) { mCamera = mNextCamera; mCamera.setProjectionMatrix(mRenderer.getViewportWidth(), mRenderer.getViewportHeight()); mNextCamera = null; } } int clearMask = mAlwaysClearColorBuffer ? GLES20.GL_COLOR_BUFFER_BIT : 0; if (renderTarget != null) { renderTarget.bind(); GLES20.glClearColor(mRed, mGreen, mBlue, mAlpha); } else { // GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); GLES20.glClearColor(mRed, mGreen, mBlue, mAlpha); } if (mEnableDepthBuffer) { clearMask |= GLES20.GL_DEPTH_BUFFER_BIT; GLES20.glEnable(GLES20.GL_DEPTH_TEST); GLES20.glDepthFunc(GLES20.GL_LESS); GLES20.glDepthMask(true); GLES20.glClearDepthf(1.0f); } if (mAntiAliasingConfig.equals(ISurface.ANTI_ALIASING_CONFIG.COVERAGE)) { clearMask |= GL_COVERAGE_BUFFER_BIT_NV; } GLES20.glClear(clearMask); // Execute onPreFrame callbacks // We explicitly break out the steps here to help the compiler optimize final int preCount = mPreCallbacks.size(); if (preCount > 0) { synchronized (mPreCallbacks) { for (int i = 0; i < preCount; ++i) { mPreCallbacks.get(i).onPreFrame(ellapsedTime, deltaTime); } } } // Update all registered animations synchronized (mAnimations) { for (int i = 0, j = mAnimations.size(); i < j; ++i) { Animation anim = mAnimations.get(i); if (anim.isPlaying()) anim.update(deltaTime); } } // We are beginning the render process so we need to update the camera matrix before fetching // its values mCamera.onRecalculateModelMatrix(null); // Get the view and projection matrices in advance mVMatrix = mCamera.getViewMatrix(); mPMatrix = mCamera.getProjectionMatrix(); // Pre-multiply View and Projection matrices once for speed mVPMatrix.setAll(mPMatrix).multiply(mVMatrix); mInvVPMatrix.setAll(mVPMatrix).inverse(); mCamera.updateFrustum(mInvVPMatrix); // Update frustum plane // Update the model matrices of all the lights synchronized (mLights) { final int numLights = mLights.size(); for (int i = 0; i < numLights; ++i) { mLights.get(i).onRecalculateModelMatrix(null); } } // Execute onPreDraw callbacks // We explicitly break out the steps here to help the compiler optimize final int preDrawCount = mPreDrawCallbacks.size(); if (preDrawCount > 0) { synchronized (mPreDrawCallbacks) { for (int i = 0; i < preDrawCount; ++i) { mPreDrawCallbacks.get(i).onPreDraw(ellapsedTime, deltaTime); } } } if (mSkybox != null) { GLES20.glDisable(GLES20.GL_DEPTH_TEST); GLES20.glDepthMask(false); mSkybox.setPosition(mCamera.getX(), mCamera.getY(), mCamera.getZ()); // Model matrix updates are deferred to the render method due to parent matrix needs // Render the skybox mSkybox.render(mCamera, mVPMatrix, mPMatrix, mVMatrix, null); if (mEnableDepthBuffer) { GLES20.glEnable(GLES20.GL_DEPTH_TEST); GLES20.glDepthMask(true); } } if (sceneMaterial != null) { sceneMaterial.useProgram(); sceneMaterial.bindTextures(); } synchronized (mChildren) { for (int i = 0, j = mChildren.size(); i < j; ++i) { // Model matrix updates are deferred to the render method due to parent matrix needs mChildren.get(i).render(mCamera, mVPMatrix, mPMatrix, mVMatrix, sceneMaterial); } } if (mDisplaySceneGraph) { mSceneGraph.displayGraph(mCamera, mVPMatrix, mPMatrix, mVMatrix); } if (sceneMaterial != null) { sceneMaterial.unbindTextures(); } synchronized (mPlugins) { for (int i = 0, j = mPlugins.size(); i < j; i++) mPlugins.get(i).render(); } if (renderTarget != null) { renderTarget.unbind(); } // Execute onPostFrame callbacks // We explicitly break out the steps here to help the compiler optimize final int postCount = mPostCallbacks.size(); if (postCount > 0) { synchronized (mPostCallbacks) { for (int i = 0; i < postCount; ++i) { mPostCallbacks.get(i).onPostFrame(ellapsedTime, deltaTime); } } } }
/** * Left multiplies this {@link Matrix4} with the given one, storing the result in this {@link * Matrix}. * * <pre> * A.leftMultiply(B) results in A = BA. * </pre> * * @param matrix {@link Matrix4} The LHS {@link Matrix4}. * @return A reference to this {@link Matrix4} to facilitate chaining. */ @NonNull public Matrix4 leftMultiply(@NonNull Matrix4 matrix) { System.arraycopy(m, 0, mTmp, 0, 16); Matrix.multiplyMM(m, 0, matrix.getDoubleValues(), 0, mTmp, 0); return this; }
/** * Sets the elements of this {@link Matrix4} based on the elements of the provided {@link * Matrix4}. * * @param matrix {@link Matrix4} to copy. * @return A reference to this {@link Matrix4} to facilitate chaining. */ @NonNull public Matrix4 setAll(@NonNull Matrix4 matrix) { matrix.toArray(m); return this; }
/** * Calculates the model matrix for this {@link ATransformable3D} object. * * @param parentMatrix {@link Matrix4} The parent matrix, if any, to apply to this object. */ public void calculateModelMatrix(final Matrix4 parentMatrix) { mMMatrix.setAll(mPosition, mScale, mOrientation); if (parentMatrix != null) { mMMatrix.leftMultiply(parentMatrix); } }