/// <summary> /// Update the coordinates of hand skeleton points. /// </summary> private void UpdateHandSkeletonsData(float[] handSkeletons) { ShaderUtil.CheckGlError(TAG, "Update hand skeletons data start."); // Each point has a 3D coordinate. The total number of coordinates // is three times the number of skeleton points. int mPointsNum = handSkeletons.Length / 3; Log.Debug(TAG, "ARHand HandSkeletonNumber = " + mPointsNum); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVbo); mNumPoints = mPointsNum; if (mVboSize < mNumPoints * BYTES_PER_POINT) { while (mVboSize < mNumPoints * BYTES_PER_POINT) { // If the size of VBO is insufficient to accommodate the new point cloud, resize the VBO. mVboSize *= 2; } GLES20.GlBufferData(GLES20.GlArrayBuffer, mVboSize, null, GLES20.GlDynamicDraw); } FloatBuffer mSkeletonPoints = FloatBuffer.Wrap(handSkeletons); GLES20.GlBufferSubData(GLES20.GlArrayBuffer, 0, mNumPoints * BYTES_PER_POINT, mSkeletonPoints); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); ShaderUtil.CheckGlError(TAG, "Update hand skeletons data end."); }
/** * Updates the OpenGL buffer contents to the provided point. Repeated calls with the same * point cloud will be ignored. */ public void Update(PointCloud cloud) { if (mLastPointCloud == cloud) { // Redundant call. return; } ShaderUtil.CheckGLError(TAG, "before update"); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVbo); mLastPointCloud = cloud; // If the VBO is not large enough to fit the new point cloud, resize it. mNumPoints = mLastPointCloud.Points.Remaining() / FLOATS_PER_POINT; if (mNumPoints * BYTES_PER_POINT > mVboSize) { while (mNumPoints * BYTES_PER_POINT > mVboSize) { mVboSize *= 2; } GLES20.GlBufferData(GLES20.GlArrayBuffer, mVboSize, null, GLES20.GlDynamicDraw); } GLES20.GlBufferSubData(GLES20.GlArrayBuffer, 0, mNumPoints * BYTES_PER_POINT, mLastPointCloud.Points); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); ShaderUtil.CheckGLError(TAG, "after update"); }
/// <summary> /// Update the coordinates of the hand bounding box. /// </summary> /// <param name="gesturePoints">Gesture hand box data.</param> private void UpdateHandBoxData(float[] gesturePoints) { ShaderUtil.CheckGlError(TAG, "Update hand box data start."); float[] glGesturePoints = { // Get the four coordinates of a rectangular box bounding the hand. gesturePoints[0], gesturePoints[1], gesturePoints[2], gesturePoints[3], gesturePoints[1], gesturePoints[2], gesturePoints[3], gesturePoints[4], gesturePoints[5], gesturePoints[0], gesturePoints[4], gesturePoints[5], }; int gesturePointsNum = glGesturePoints.Length / COORDINATE_DIMENSION; GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVbo); mNumPoints = gesturePointsNum; if (mVboSize < mNumPoints * BYTES_PER_POINT) { while (mVboSize < mNumPoints * BYTES_PER_POINT) { // If the size of VBO is insufficient to accommodate the new point cloud, resize the VBO. mVboSize *= 2; } GLES20.GlBufferData(GLES20.GlArrayBuffer, mVboSize, null, GLES20.GlDynamicDraw); } Log.Debug(TAG, "gesture.getGestureHandPointsNum()" + mNumPoints); FloatBuffer mVertices = FloatBuffer.Wrap(glGesturePoints); GLES20.GlBufferSubData(GLES20.GlArrayBuffer, 0, mNumPoints * BYTES_PER_POINT, mVertices); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); ShaderUtil.CheckGlError(TAG, "Update hand box data end."); }
private void InitializeGlObjectData(Context context) { ObjectData objectData = null; Optional objectDataOptional = ReadObject(context); if (objectDataOptional.IsPresent) { objectData = objectDataOptional.Get().JavaCast <ObjectData>(); } else { Log.Debug(TAG, "Read object error."); return; } mTexCoordsBaseAddress = FLOAT_BYTE_SIZE * objectData.objectIndices.Limit(); mNormalsBaseAddress = mTexCoordsBaseAddress + FLOAT_BYTE_SIZE * objectData.texCoords.Limit(); int totalBytes = mNormalsBaseAddress + FLOAT_BYTE_SIZE * objectData.normals.Limit(); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVertexBufferId); GLES20.GlBufferData(GLES20.GlArrayBuffer, totalBytes, null, GLES20.GlStaticDraw); GLES20.GlBufferSubData( GLES20.GlArrayBuffer, 0, FLOAT_BYTE_SIZE * objectData.objectVertices.Limit(), objectData.objectVertices); GLES20.GlBufferSubData(GLES20.GlArrayBuffer, mTexCoordsBaseAddress, FLOAT_BYTE_SIZE * objectData.texCoords.Limit(), objectData.texCoords); GLES20.GlBufferSubData(GLES20.GlArrayBuffer, mNormalsBaseAddress, FLOAT_BYTE_SIZE * objectData.normals.Limit(), objectData.normals); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, mIndexBufferId); mIndexCount = objectData.indices.Limit(); GLES20.GlBufferData( GLES20.GlElementArrayBuffer, INDEX_COUNT_RATIO * mIndexCount, objectData.indices, GLES20.GlStaticDraw); GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, 0); ShaderUtil.CheckGlError(TAG, "obj buffer load"); }
private void UpdateFaceGeometryData(ARFaceGeometry faceGeometry) { ShaderUtil.CheckGlError(TAG, "Before update data."); FloatBuffer faceVertices = faceGeometry.Vertices; // Obtain the number of geometric vertices of a face. mPointsNum = faceVertices.Limit() / 3; FloatBuffer textureCoordinates = faceGeometry.TextureCoordinates; // Obtain the number of geometric texture coordinates of the // face (the texture coordinates are two-dimensional). int texNum = textureCoordinates.Limit() / 2; Log.Debug(TAG, "Update face geometry data: texture coordinates size:" + texNum); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVerticeId); if (mVerticeBufferSize < (mPointsNum + texNum) * BYTES_PER_POINT) { while (mVerticeBufferSize < (mPointsNum + texNum) * BYTES_PER_POINT) { // If the capacity of the vertex VBO buffer is insufficient, expand the capacity. mVerticeBufferSize *= 2; } GLES20.GlBufferData(GLES20.GlArrayBuffer, mVerticeBufferSize, null, GLES20.GlDynamicDraw); } GLES20.GlBufferSubData(GLES20.GlArrayBuffer, 0, mPointsNum * BYTES_PER_POINT, faceVertices); GLES20.GlBufferSubData(GLES20.GlArrayBuffer, mPointsNum * BYTES_PER_POINT, texNum * BYTES_PER_COORD, textureCoordinates); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); mTrianglesNum = faceGeometry.TriangleCount; IntBuffer faceTriangleIndices = faceGeometry.TriangleIndices; Log.Debug(TAG, "update face geometry data: faceTriangleIndices.size: " + faceTriangleIndices.Limit()); GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, mTriangleId); if (mTriangleBufferSize < mTrianglesNum * BYTES_PER_POINT) { while (mTriangleBufferSize < mTrianglesNum * BYTES_PER_POINT) { // If the capacity of the vertex VBO buffer is insufficient, expand the capacity. mTriangleBufferSize *= 2; } GLES20.GlBufferData(GLES20.GlElementArrayBuffer, mTriangleBufferSize, null, GLES20.GlDynamicDraw); } GLES20.GlBufferSubData(GLES20.GlElementArrayBuffer, 0, mTrianglesNum * BYTES_PER_POINT, faceTriangleIndices); GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, 0); ShaderUtil.CheckGlError(TAG, "After update data."); }
/// <summary> /// This method updates the connection data of skeleton points and is called when any frame is updated. /// </summary> /// <param name="handSkeletons">Bone point data of hand.</param> /// <param name="handSkeletonConnection">Data of connection between bone points of hand.</param> private void UpdateHandSkeletonLinesData(float[] handSkeletons, int[] handSkeletonConnection) { ShaderUtil.CheckGlError(TAG, "Update hand skeleton lines data start."); int pointsLineNum = 0; // Each point is a set of 3D coordinate. Each connection line consists of two points. float[] linePoint = new float[handSkeletonConnection.Length * 3 * 2]; // The format of HandSkeletonConnection data is [p0,p1;p0,p3;p0,p5;p1,p2]. // handSkeletonConnection saves the node indexes. Two indexes obtain a set // of connection point data. Therefore, j = j + 2. This loop obtains related // coordinates and saves them in linePoint. for (int j = 0; j < handSkeletonConnection.Length; j += 2) { linePoint[pointsLineNum * 3] = handSkeletons[3 * handSkeletonConnection[j]]; linePoint[pointsLineNum * 3 + 1] = handSkeletons[3 * handSkeletonConnection[j] + 1]; linePoint[pointsLineNum * 3 + 2] = handSkeletons[3 * handSkeletonConnection[j] + 2]; linePoint[pointsLineNum * 3 + 3] = handSkeletons[3 * handSkeletonConnection[j + 1]]; linePoint[pointsLineNum * 3 + 4] = handSkeletons[3 * handSkeletonConnection[j + 1] + 1]; linePoint[pointsLineNum * 3 + 5] = handSkeletons[3 * handSkeletonConnection[j + 1] + 2]; pointsLineNum += 2; } GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVbo); mPointsNum = pointsLineNum; // If the storage space is insufficient, apply for twice the memory each time. if (mVboSize < mPointsNum * BYTES_PER_POINT) { while (mVboSize < mPointsNum * BYTES_PER_POINT) { mVboSize *= 2; } GLES20.GlBufferData(GLES20.GlArrayBuffer, mVboSize, null, GLES20.GlDynamicDraw); } FloatBuffer linePoints = FloatBuffer.Wrap(linePoint); Log.Debug(TAG, "Skeleton skeleton line points num: " + mPointsNum); Log.Debug(TAG, "Skeleton line points: " + linePoints.ToString()); GLES20.GlBufferSubData(GLES20.GlArrayBuffer, 0, mPointsNum * BYTES_PER_POINT, linePoints); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); ShaderUtil.CheckGlError(TAG, "Update hand skeleton lines data end."); }
/// <summary> /// Update body connection data. /// </summary> private void UpdateBodySkeletonLineData(ARBody body) { FindValidConnectionSkeletonLines(body); ShaderUtil.CheckGlError(TAG, "Update body skeleton line data start."); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVbo); mNumPoints = mPointsLineNum; if (mVboSize < mNumPoints * BYTES_PER_POINT) { while (mVboSize < mNumPoints * BYTES_PER_POINT) { // If the storage space is insufficient, allocate double the space. mVboSize *= 2; } GLES20.GlBufferData(GLES20.GlArrayBuffer, mVboSize, null, GLES20.GlDynamicDraw); } GLES20.GlBufferSubData(GLES20.GlArrayBuffer, 0, mNumPoints * BYTES_PER_POINT, mLinePoints); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); ShaderUtil.CheckGlError(TAG, "Update body skeleton line data end."); }
private void UpdateBodySkeleton() { ShaderUtil.CheckGlError(TAG, "Update Body Skeleton data start."); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVbo); mNumPoints = mPointsNum; if (mVboSize < mNumPoints * BYTES_PER_POINT) { while (mVboSize < mNumPoints * BYTES_PER_POINT) { // If the size of VBO is insufficient to accommodate the new point cloud, resize the VBO. mVboSize *= 2; } GLES20.GlBufferData(GLES20.GlArrayBuffer, mVboSize, null, GLES20.GlDynamicDraw); } GLES20.GlBufferSubData(GLES20.GlArrayBuffer, 0, mNumPoints * BYTES_PER_POINT, mSkeletonPoints); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); ShaderUtil.CheckGlError(TAG, "Update Body Skeleton data end."); }
/// <summary> /// Updates the OpenGL buffer contents to the provided point. Repeated calls with the same /// point cloud will be ignored. /// </summary> public void Update(PointCloud cloud) { if (mLastPointCloud == cloud) { return; } GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVbo); mLastPointCloud = cloud; // If the VBO is not large enough to fit the new point cloud, resize it. mNumPoints = mLastPointCloud.Points.Remaining() / FLOATS_PER_POINT; if (mNumPoints * BYTES_PER_POINT > mVboSize) { while (mNumPoints * BYTES_PER_POINT > mVboSize) { mVboSize *= 2; } GLES20.GlBufferData(GLES20.GlArrayBuffer, mVboSize, null, GLES20.GlDynamicDraw); } GLES20.GlBufferSubData(GLES20.GlArrayBuffer, 0, mNumPoints * BYTES_PER_POINT, mLastPointCloud.Points); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); }
/** * 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"); Android.Opengl.Matrix.SetIdentityM(mModelMatrix, 0); }
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 = JavaGl.Obj.ObjReader.Read(objInputStream); obj = JavaGl.Obj.ObjUtils.ConvertToRenderable(obj); IntBuffer wideIndices = JavaGl.Obj.ObjData.GetFaceVertexIndices(obj, 3); FloatBuffer vertices = JavaGl.Obj.ObjData.GetVertices(obj); FloatBuffer texCoords = JavaGl.Obj.ObjData.GetTexCoords(obj, 2); FloatBuffer normals = JavaGl.Obj.ObjData.GetNormals(obj); 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]; 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); 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"); Android.Opengl.Matrix.SetIdentityM(mModelMatrix, 0); }