/** * Updated rotation matrix, aspect ratio etc. */ public void UpdateRotation() { if (MyCamera == null || _sharedData == null) { return; } var orientation = _cameraInfo.Orientation; Matrix.SetRotateM(_sharedData._orientationM, 0, orientation, 0f, 0f, 1f); Camera.Size size = MyCamera.GetParameters().PreviewSize; if (orientation % 90 == 0) { var w = size.Width; size.Width = size.Height; size.Height = w; } _sharedData._aspectRatioPreview [0] = (float)Math.Min(size.Width, size.Height) / size.Width; _sharedData._aspectRatioPreview [1] = (float)Math.Min(size.Width, size.Height) / size.Height; }
/** * Updates the object model matrix and applies scaling. * * @param modelMatrix A 4x4 model-to-world transformation matrix, stored in column-major order. * @param scaleFactor A separate scaling factor to apply before the {@code modelMatrix}. * @see android.opengl.Matrix */ public void updateModelMatrix(float[] modelMatrix, float scaleFactor) { float[] scaleMatrix = new float[16]; Matrix.SetIdentityM(scaleMatrix, 0); scaleMatrix[0] = scaleFactor; scaleMatrix[5] = scaleFactor; scaleMatrix[10] = scaleFactor; Matrix.MultiplyMM(mModelMatrix, 0, modelMatrix, 0, scaleMatrix, 0); }
private void DrawLabel(float[] cameraViews, float[] cameraProjection) { ShaderUtil.CheckGlError(TAG, "Draw label start."); Matrix.MultiplyMM(modelViewMatrix, 0, cameraViews, 0, modelMatrix, 0); Matrix.MultiplyMM(modelViewProjectionMatrix, 0, cameraProjection, 0, modelViewMatrix, 0); float halfWidth = LABEL_WIDTH / 2.0f; float halfHeight = LABEL_HEIGHT / 2.0f; float[] vertices = { -halfWidth, -halfHeight, 1, -halfWidth, halfHeight, 1, halfWidth, halfHeight, 1, halfWidth, -halfHeight, 1, }; // The size of each floating point is 4 bits. FloatBuffer vetBuffer = ByteBuffer.AllocateDirect(4 * vertices.Length) .Order(ByteOrder.NativeOrder()).AsFloatBuffer(); vetBuffer.Rewind(); for (int i = 0; i < vertices.Length; ++i) { vetBuffer.Put(vertices[i]); } vetBuffer.Rewind(); // The size of each floating point is 4 bits. GLES20.GlVertexAttribPointer(glPositionParameter, COORDS_PER_VERTEX, GLES20.GlFloat, false, 4 * COORDS_PER_VERTEX, vetBuffer); // Set the sequence of OpenGL drawing points to generate two triangles that form a plane. short[] indices = { 0, 1, 2, 0, 2, 3 }; // Size of the allocated buffer. ShortBuffer idxBuffer = ByteBuffer.AllocateDirect(2 * indices.Length) .Order(ByteOrder.NativeOrder()).AsShortBuffer(); idxBuffer.Rewind(); for (int i = 0; i < indices.Length; ++i) { idxBuffer.Put(indices[i]); } idxBuffer.Rewind(); GLES20.GlUniformMatrix4fv(glModelViewProjectionMatrix, 1, false, modelViewProjectionMatrix, 0); GLES20.GlDrawElements(GLES20.GlTriangleStrip, idxBuffer.Limit(), GLES20.GlUnsignedShort, idxBuffer); ShaderUtil.CheckGlError(TAG, "Draw label end."); }
/// <summary> /// Draw a virtual object at a specific location on a specified plane. /// This method is called when WorldRenderManager's OnDrawFrame. /// </summary> /// <param name="cameraView">The viewMatrix is a 4 * 4 matrix.</param> /// <param name="cameraProjection">The ProjectionMatrix is a 4 * 4 matrix.</param> /// <param name="lightIntensity">The lighting intensity.</param> /// <param name="obj">The virtual object.</param> public void OnDrawFrame(float[] cameraView, float[] cameraProjection, float lightIntensity, VirtualObject obj) { ShaderUtil.CheckGlError(TAG, "onDrawFrame start."); mModelMatrixs = obj.GetModelAnchorMatrix(); Matrix.MultiplyMM(mModelViewMatrixs, 0, cameraView, 0, mModelMatrixs, 0); Matrix.MultiplyMM(mModelViewProjectionMatrixs, 0, cameraProjection, 0, mModelViewMatrixs, 0); GLES20.GlUseProgram(mGlProgram); Matrix.MultiplyMV(mViewLightDirections, 0, mModelViewMatrixs, 0, LIGHT_DIRECTIONS, 0); MatrixUtil.NormalizeVec3(mViewLightDirections); // Light direction. GLES20.GlUniform4f(mLightingParametersUniform, mViewLightDirections[0], mViewLightDirections[1], mViewLightDirections[2], lightIntensity); float[] objColors = obj.GetColor(); GLES20.GlUniform4fv(mColorUniform, 1, objColors, 0); GLES20.GlActiveTexture(GLES20.GlTexture0); GLES20.GlBindTexture(GLES20.GlTexture2d, mTextures[0]); GLES20.GlUniform1i(mTextureUniform, 0); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVertexBufferId); // The coordinate dimension of the read virtual object is 3. GLES20.GlVertexAttribPointer( mPositionAttribute, 3, GLES20.GlFloat, false, 0, 0); // The dimension of the normal vector is 3. GLES20.GlVertexAttribPointer( mNormalAttribute, 3, GLES20.GlFloat, false, 0, mNormalsBaseAddress); // The dimension of the texture coordinate is 2. GLES20.GlVertexAttribPointer( mTexCoordAttribute, 2, GLES20.GlFloat, false, 0, mTexCoordsBaseAddress); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); GLES20.GlUniformMatrix4fv( mModelViewUniform, 1, false, mModelViewMatrixs, 0); GLES20.GlUniformMatrix4fv( mModelViewProjectionUniform, 1, false, mModelViewProjectionMatrixs, 0); GLES20.GlEnableVertexAttribArray(mPositionAttribute); GLES20.GlEnableVertexAttribArray(mNormalAttribute); GLES20.GlEnableVertexAttribArray(mTexCoordAttribute); GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, mIndexBufferId); GLES20.GlDrawElements(GLES20.GlTriangles, mIndexCount, GLES20.GlUnsignedShort, 0); GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, 0); GLES20.GlDisableVertexAttribArray(mPositionAttribute); GLES20.GlDisableVertexAttribArray(mNormalAttribute); GLES20.GlDisableVertexAttribArray(mTexCoordAttribute); GLES20.GlBindTexture(GLES20.GlTexture2d, 0); ShaderUtil.CheckGlError(TAG, "onDrawFrame end."); }
void Draw(float[] cameraView, float[] cameraPerspective) { // Build the ModelView and ModelViewProjection matrices // for calculating cube position and light. Matrix.MultiplyMM(mModelViewMatrix, 0, cameraView, 0, mModelMatrix, 0); Matrix.MultiplyMM(mModelViewProjectionMatrix, 0, cameraPerspective, 0, mModelViewMatrix, 0); // Set the position of the plane mVertexBuffer.Rewind(); GLES20.GlVertexAttribPointer( mPlaneXZPositionAlphaAttribute, COORDS_PER_VERTEX, GLES20.GlFloat, false, BYTES_PER_FLOAT * COORDS_PER_VERTEX, mVertexBuffer); // Set the Model and ModelViewProjection matrices in the shader. GLES20.GlUniformMatrix4fv(mPlaneModelUniform, 1, false, mModelMatrix, 0); GLES20.GlUniformMatrix4fv( mPlaneModelViewProjectionUniform, 1, false, mModelViewProjectionMatrix, 0); mIndexBuffer.Rewind(); GLES20.GlDrawElements(GLES20.GlTriangleStrip, mIndexBuffer.Limit(), GLES20.GlUnsignedShort, mIndexBuffer); ShaderUtil.CheckGLError(TAG, "Drawing plane"); }
// Convert the input coordinates to the plane coordinate system. private float[] CalculateScreenPos(float coordinateX, float coordinateY, float coordinateZ) { // The coordinates of the point are four-dimensional (x, y, z, w). float[] vecs = new float[4]; vecs[0] = coordinateX; vecs[1] = coordinateY; vecs[2] = coordinateZ; vecs[3] = 1.0f; // Store the coordinate values in the clip coordinate system. float[] rets = new float[4]; Matrix.MultiplyMV(rets, 0, mModelViewProjectionMatrixs, 0, vecs, 0); // Divide by the w component of the coordinates. rets[0] /= rets[3]; rets[1] /= rets[3]; rets[2] /= rets[3]; // In the current coordinate system, left is negative, right is positive, downward // is positive, and upward is negative.Adding 1 to the left of the X coordinate is // equivalent to moving the coordinate system leftwards. Such an operation on the Y // axis is equivalent to moving the coordinate system upwards. rets[0] += 1.0f; rets[1] = 1.0f - rets[1]; // Convert to pixel coordinates. rets[0] *= mWidth; rets[1] *= mHeight; // When the w component is set to 1, the xy component caused by coordinate system // movement is eliminated and doubled. rets[3] = 1.0f; rets[0] /= 2.0f; rets[1] /= 2.0f; return(rets); }
/** * Creates and initializes OpenGL resources needed for rendering the model. * * @param context Context for loading the shader and below-named model and texture assets. * @param objAssetName Name of the OBJ file containing the model geometry. * @param diffuseTextureAssetName Name of the PNG file containing the diffuse texture map. */ public void CreateOnGlThread(Context context, string objAssetName, string diffuseTextureAssetName) { // Read the texture. var textureBitmap = BitmapFactory.DecodeStream(context.Assets.Open(diffuseTextureAssetName)); GLES20.GlActiveTexture(GLES20.GlTexture0); GLES20.GlGenTextures(mTextures.Length, mTextures, 0); GLES20.GlBindTexture(GLES20.GlTexture2d, mTextures[0]); GLES20.GlTexParameteri(GLES20.GlTexture2d, GLES20.GlTextureMinFilter, GLES20.GlLinearMipmapLinear); GLES20.GlTexParameteri(GLES20.GlTexture2d, GLES20.GlTextureMagFilter, GLES20.GlLinear); GLUtils.TexImage2D(GLES20.GlTexture2d, 0, textureBitmap, 0); GLES20.GlGenerateMipmap(GLES20.GlTexture2d); GLES20.GlBindTexture(GLES20.GlTexture2d, 0); textureBitmap.Recycle(); ShaderUtil.CheckGLError(TAG, "Texture loading"); // Read the obj file. var objInputStream = context.Assets.Open(objAssetName); var obj = ObjReader.Read(objInputStream); // Prepare the Obj so that its structure is suitable for // rendering with OpenGL: // 1. Triangulate it // 2. Make sure that texture coordinates are not ambiguous // 3. Make sure that normals are not ambiguous // 4. Convert it to single-indexed data obj = ObjUtils.ConvertToRenderable(obj); // OpenGL does not use Java arrays. ByteBuffers are used instead to provide data in a format // that OpenGL understands. // Obtain the data from the OBJ, as direct buffers: IntBuffer wideIndices = ObjData.GetFaceVertexIndices(obj, 3); FloatBuffer vertices = ObjData.GetVertices(obj); FloatBuffer texCoords = ObjData.GetTexCoords(obj, 2); FloatBuffer normals = ObjData.GetNormals(obj); // Convert int indices to shorts for GL ES 2.0 compatibility ShortBuffer indices = ByteBuffer.AllocateDirect(2 * wideIndices.Limit()) .Order(ByteOrder.NativeOrder()).AsShortBuffer(); while (wideIndices.HasRemaining) { indices.Put((short)wideIndices.Get()); } indices.Rewind(); var buffers = new int[2]; GLES20.GlGenBuffers(2, buffers, 0); mVertexBufferId = buffers[0]; mIndexBufferId = buffers[1]; // Load vertex buffer mVerticesBaseAddress = 0; mTexCoordsBaseAddress = mVerticesBaseAddress + 4 * vertices.Limit(); mNormalsBaseAddress = mTexCoordsBaseAddress + 4 * texCoords.Limit(); int totalBytes = mNormalsBaseAddress + 4 * normals.Limit(); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVertexBufferId); GLES20.GlBufferData(GLES20.GlArrayBuffer, totalBytes, null, GLES20.GlStaticDraw); GLES20.GlBufferSubData( GLES20.GlArrayBuffer, mVerticesBaseAddress, 4 * vertices.Limit(), vertices); GLES20.GlBufferSubData( GLES20.GlArrayBuffer, mTexCoordsBaseAddress, 4 * texCoords.Limit(), texCoords); GLES20.GlBufferSubData( GLES20.GlArrayBuffer, mNormalsBaseAddress, 4 * normals.Limit(), normals); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); // Load index buffer GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, mIndexBufferId); mIndexCount = indices.Limit(); GLES20.GlBufferData( GLES20.GlElementArrayBuffer, 2 * mIndexCount, indices, GLES20.GlStaticDraw); GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, 0); ShaderUtil.CheckGLError(TAG, "OBJ buffer load"); int vertexShader = ShaderUtil.LoadGLShader(TAG, context, GLES20.GlVertexShader, Resource.Raw.object_vertex); int fragmentShader = ShaderUtil.LoadGLShader(TAG, context, GLES20.GlFragmentShader, Resource.Raw.object_fragment); mProgram = GLES20.GlCreateProgram(); GLES20.GlAttachShader(mProgram, vertexShader); GLES20.GlAttachShader(mProgram, fragmentShader); GLES20.GlLinkProgram(mProgram); GLES20.GlUseProgram(mProgram); ShaderUtil.CheckGLError(TAG, "Program creation"); mModelViewUniform = GLES20.GlGetUniformLocation(mProgram, "u_ModelView"); mModelViewProjectionUniform = GLES20.GlGetUniformLocation(mProgram, "u_ModelViewProjection"); mPositionAttribute = GLES20.GlGetAttribLocation(mProgram, "a_Position"); mNormalAttribute = GLES20.GlGetAttribLocation(mProgram, "a_Normal"); mTexCoordAttribute = GLES20.GlGetAttribLocation(mProgram, "a_TexCoord"); mTextureUniform = GLES20.GlGetUniformLocation(mProgram, "u_Texture"); mLightingParametersUniform = GLES20.GlGetUniformLocation(mProgram, "u_LightingParameters"); mMaterialParametersUniform = GLES20.GlGetUniformLocation(mProgram, "u_MaterialParameters"); ShaderUtil.CheckGLError(TAG, "Program parameters"); Matrix.SetIdentityM(mModelMatrix, 0); }
/** * Draws the model. * * @param cameraView A 4x4 view matrix, in column-major order. * @param cameraPerspective A 4x4 projection matrix, in column-major order. * @param lightIntensity Illumination intensity. Combined with diffuse and specular material * properties. * @see #setBlendMode(BlendMode) * @see #updateModelMatrix(float[], float) * @see #setMaterialProperties(float, float, float, float) * @see android.opengl.Matrix */ public void Draw(float[] cameraView, float[] cameraPerspective, float lightIntensity) { ShaderUtil.CheckGLError(TAG, "Before draw"); // Build the ModelView and ModelViewProjection matrices // for calculating object position and light. Matrix.MultiplyMM(mModelViewMatrix, 0, cameraView, 0, mModelMatrix, 0); Matrix.MultiplyMM(mModelViewProjectionMatrix, 0, cameraPerspective, 0, mModelViewMatrix, 0); GLES20.GlUseProgram(mProgram); // Set the lighting environment properties. Matrix.MultiplyMV(mViewLightDirection, 0, mModelViewMatrix, 0, LIGHT_DIRECTION, 0); normalizeVec3(mViewLightDirection); GLES20.GlUniform4f(mLightingParametersUniform, mViewLightDirection[0], mViewLightDirection[1], mViewLightDirection[2], lightIntensity); // Set the object material properties. GLES20.GlUniform4f(mMaterialParametersUniform, mAmbient, mDiffuse, mSpecular, mSpecularPower); // Attach the object texture. GLES20.GlActiveTexture(GLES20.GlTexture0); GLES20.GlBindTexture(GLES20.GlTexture2d, mTextures[0]); GLES20.GlUniform1i(mTextureUniform, 0); // Set the vertex attributes. GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVertexBufferId); GLES20.GlVertexAttribPointer( mPositionAttribute, COORDS_PER_VERTEX, GLES20.GlFloat, false, 0, mVerticesBaseAddress); GLES20.GlVertexAttribPointer( mNormalAttribute, 3, GLES20.GlFloat, false, 0, mNormalsBaseAddress); GLES20.GlVertexAttribPointer( mTexCoordAttribute, 2, GLES20.GlFloat, false, 0, mTexCoordsBaseAddress); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); // Set the ModelViewProjection matrix in the shader. GLES20.GlUniformMatrix4fv( mModelViewUniform, 1, false, mModelViewMatrix, 0); GLES20.GlUniformMatrix4fv( mModelViewProjectionUniform, 1, false, mModelViewProjectionMatrix, 0); // Enable vertex arrays GLES20.GlEnableVertexAttribArray(mPositionAttribute); GLES20.GlEnableVertexAttribArray(mNormalAttribute); GLES20.GlEnableVertexAttribArray(mTexCoordAttribute); if (mBlendMode != BlendMode.Null) { GLES20.GlDepthMask(false); GLES20.GlEnable(GLES20.GlBlend); switch (mBlendMode) { case BlendMode.Shadow: // Multiplicative blending function for Shadow. GLES20.GlBlendFunc(GLES20.GlZero, GLES20.GlOneMinusSrcAlpha); break; case BlendMode.Grid: // Grid, additive blending function. GLES20.GlBlendFunc(GLES20.GlSrcAlpha, GLES20.GlOneMinusSrcAlpha); break; } } GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, mIndexBufferId); GLES20.GlDrawElements(GLES20.GlTriangles, mIndexCount, GLES20.GlUnsignedShort, 0); GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, 0); if (mBlendMode != BlendMode.Null) { GLES20.GlDisable(GLES20.GlBlend); GLES20.GlDepthMask(true); } // Disable vertex arrays GLES20.GlDisableVertexAttribArray(mPositionAttribute); GLES20.GlDisableVertexAttribArray(mNormalAttribute); GLES20.GlDisableVertexAttribArray(mTexCoordAttribute); GLES20.GlBindTexture(GLES20.GlTexture2d, 0); ShaderUtil.CheckGLError(TAG, "After draw"); }
/// <summary> /// Check whether the virtual object is clicked. /// </summary> /// <param name="cameraView">The viewMatrix 4 * 4.</param> /// <param name="cameraPerspective">The ProjectionMatrix 4 * 4.</param> /// <param name="obj">The virtual object data.</param> /// <param name="mEvent">The gesture event.</param> /// <returns>Return the click result for determining whether the input virtual object is clicked</returns> public bool HitTest(float[] cameraView, float[] cameraPerspective, VirtualObject obj, MotionEvent mEvent) { mModelMatrixs = obj.GetModelAnchorMatrix(); Matrix.MultiplyMM(mModelViewMatrixs, 0, cameraView, 0, mModelMatrixs, 0); Matrix.MultiplyMM(mModelViewProjectionMatrixs, 0, cameraPerspective, 0, mModelViewMatrixs, 0); // Calculate the coordinates of the smallest bounding box in the coordinate system of the device screen. float[] screenPos = CalculateScreenPos(mBoundingBoxs[0], mBoundingBoxs[1], mBoundingBoxs[2]); // Record the largest bounding rectangle of an object (minX/minY/maxX/maxY). float[] boundarys = new float[4]; boundarys[0] = screenPos[0]; boundarys[1] = screenPos[0]; boundarys[2] = screenPos[1]; boundarys[3] = screenPos[1]; // Determine whether a screen position corresponding to (maxX, maxY, maxZ) is clicked. boundarys = FindMaximum(boundarys, new int[] { 3, 4, 5 }); if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) && ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3]))) { return(true); } // Determine whether a screen position corresponding to (minX, minY, maxZ) is clicked. boundarys = FindMaximum(boundarys, new int[] { 0, 1, 5 }); if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) && ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3]))) { return(true); } // Determine whether a screen position corresponding to (minX, maxY, minZ) is clicked. boundarys = FindMaximum(boundarys, new int[] { 0, 4, 2 }); if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) && ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3]))) { return(true); } // Determine whether a screen position corresponding to (minX, maxY, maxZ) is clicked. boundarys = FindMaximum(boundarys, new int[] { 0, 4, 5 }); if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) && ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3]))) { return(true); } // Determine whether a screen position corresponding to (maxX, minY, minZ) is clicked. boundarys = FindMaximum(boundarys, new int[] { 3, 1, 2 }); if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) && ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3]))) { return(true); } // Determine whether a screen position corresponding to (maxX, minY, maxZ) is clicked. boundarys = FindMaximum(boundarys, new int[] { 3, 1, 5 }); if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) && ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3]))) { return(true); } // Determine whether a screen position corresponding to (maxX, maxY, maxZ) is clicked. boundarys = FindMaximum(boundarys, new int[] { 3, 4, 2 }); if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) && ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3]))) { return(true); } return(false); }