// Bounding box [minX, minY, minZ, maxX, maxY, maxZ]. private void CalculateBoundingBox(FloatBuffer vertices) { if (vertices.Limit() < 3) { mBoundingBoxs[0] = 0.0f; mBoundingBoxs[1] = 0.0f; mBoundingBoxs[2] = 0.0f; mBoundingBoxs[3] = 0.0f; mBoundingBoxs[4] = 0.0f; mBoundingBoxs[5] = 0.0f; return; } else { mBoundingBoxs[0] = vertices.Get(0); mBoundingBoxs[1] = vertices.Get(1); mBoundingBoxs[2] = vertices.Get(2); mBoundingBoxs[3] = vertices.Get(0); mBoundingBoxs[4] = vertices.Get(1); mBoundingBoxs[5] = vertices.Get(2); } // Use the first three pairs as the initial variables and get the three // maximum values and three minimum values. int index = 3; while (index < vertices.Limit() - 2) { if (vertices.Get(index) < mBoundingBoxs[0]) { mBoundingBoxs[0] = vertices.Get(index); } if (vertices.Get(index) > mBoundingBoxs[3]) { mBoundingBoxs[3] = vertices.Get(index); } index++; if (vertices.Get(index) < mBoundingBoxs[1]) { mBoundingBoxs[1] = vertices.Get(index); } if (vertices.Get(index) > mBoundingBoxs[4]) { mBoundingBoxs[4] = vertices.Get(index); } index++; if (vertices.Get(index) < mBoundingBoxs[2]) { mBoundingBoxs[2] = vertices.Get(index); } if (vertices.Get(index) > mBoundingBoxs[5]) { mBoundingBoxs[5] = vertices.Get(index); } index++; } }
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> /// Converts a plane polygon from ARCore into a <see cref="Vector3"/> array. /// </summary> /// <param name="buffer">The float buffer containing 2D vertices of the polygon</param> /// <param name="waveVectorArray">The <see cref="Vector3"/> array with the 3D vertices of the polygon</param> public static void ToWave(this FloatBuffer buffer, ref Vector3[] waveVectorArray) { buffer.Rewind(); var boundaryVertices = buffer.Limit() / 2; if (waveVectorArray == null) { waveVectorArray = new Vector3[boundaryVertices]; } else if (waveVectorArray.Length != boundaryVertices) { Array.Resize(ref waveVectorArray, boundaryVertices); } for (int i = 0; i < boundaryVertices; i++) { waveVectorArray[i].X = buffer.Get(); waveVectorArray[i].Z = buffer.Get(); } }
/** * 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); }
/** * Updates the plane model transform matrix and extents. */ private void updatePlaneParameters(float[] planeMatrix, float extentX, float extentZ, FloatBuffer boundary) { Array.Copy(planeMatrix, 0, mModelMatrix, 0, 16); if (boundary == null) { mVertexBuffer.Limit(0); mIndexBuffer.Limit(0); return; } // Generate a new set of vertices and a corresponding triangle strip index set so that // the plane boundary polygon has a fading edge. This is done by making a copy of the // boundary polygon vertices and scaling it down around center to push it inwards. Then // the index buffer is setup accordingly. boundary.Rewind(); int boundaryVertices = boundary.Limit() / 2; int numVertices; int numIndices; numVertices = boundaryVertices * VERTS_PER_BOUNDARY_VERT; // drawn as GL_TRIANGLE_STRIP with 3n-2 triangles (n-2 for fill, 2n for perimeter). numIndices = boundaryVertices * INDICES_PER_BOUNDARY_VERT; if (mVertexBuffer.Capacity() < numVertices * COORDS_PER_VERTEX) { int size = mVertexBuffer.Capacity(); while (size < numVertices * COORDS_PER_VERTEX) { size *= 2; } mVertexBuffer = ByteBuffer.AllocateDirect(BYTES_PER_FLOAT * size) .Order(ByteOrder.NativeOrder()).AsFloatBuffer(); } mVertexBuffer.Rewind(); mVertexBuffer.Limit(numVertices * COORDS_PER_VERTEX); if (mIndexBuffer.Capacity() < numIndices) { int size = mIndexBuffer.Capacity(); while (size < numIndices) { size *= 2; } mIndexBuffer = ByteBuffer.AllocateDirect(BYTES_PER_SHORT * size) .Order(ByteOrder.NativeOrder()).AsShortBuffer(); } mIndexBuffer.Rewind(); mIndexBuffer.Limit(numIndices); // Note: when either dimension of the bounding box is smaller than 2*FADE_RADIUS_M we // generate a bunch of 0-area triangles. These don't get rendered though so it works // out ok. float xScale = Math.Max((extentX - 2 * FADE_RADIUS_M) / extentX, 0.0f); float zScale = Math.Max((extentZ - 2 * FADE_RADIUS_M) / extentZ, 0.0f); while (boundary.HasRemaining) { float x = boundary.Get(); float z = boundary.Get(); mVertexBuffer.Put(x); mVertexBuffer.Put(z); mVertexBuffer.Put(0.0f); mVertexBuffer.Put(x * xScale); mVertexBuffer.Put(z * zScale); mVertexBuffer.Put(1.0f); } // step 1, perimeter mIndexBuffer.Put((short)((boundaryVertices - 1) * 2)); for (int i = 0; i < boundaryVertices; ++i) { mIndexBuffer.Put((short)(i * 2)); mIndexBuffer.Put((short)(i * 2 + 1)); } mIndexBuffer.Put((short)1); // This leaves us on the interior edge of the perimeter between the inset vertices // for boundary verts n-1 and 0. // step 2, interior: for (int i = 1; i < boundaryVertices / 2; ++i) { mIndexBuffer.Put((short)((boundaryVertices - 1 - i) * 2 + 1)); mIndexBuffer.Put((short)(i * 2 + 1)); } if (boundaryVertices % 2 != 0) { mIndexBuffer.Put((short)((boundaryVertices / 2) * 2 + 1)); } }
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); }