/** * 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"); }
/** * Renders the point cloud. * * @param pose the current point cloud pose, from {@link Frame#getPointCloudPose()}. * @param cameraView the camera view matrix for this frame, typically from * {@link Frame#getViewMatrix(float[], int)}. * @param cameraPerspective the camera projection matrix for this frame, typically from * {@link Session#getProjectionMatrix(float[], int, float, float)}. */ public void Draw(Pose pose, float[] cameraView, float[] cameraPerspective) { float[] modelMatrix = new float[16]; pose.ToMatrix(modelMatrix, 0); float[] modelView = new float[16]; float[] modelViewProjection = new float[16]; Matrix.MultiplyMM(modelView, 0, cameraView, 0, modelMatrix, 0); Matrix.MultiplyMM(modelViewProjection, 0, cameraPerspective, 0, modelView, 0); ShaderUtil.CheckGLError(TAG, "Before draw"); GLES20.GlUseProgram(mProgramName); GLES20.GlEnableVertexAttribArray(mPositionAttribute); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVbo); GLES20.GlVertexAttribPointer( mPositionAttribute, 4, GLES20.GlFloat, false, BYTES_PER_POINT, 0); GLES20.GlUniform4f(mColorUniform, 31.0f / 255.0f, 188.0f / 255.0f, 210.0f / 255.0f, 1.0f); GLES20.GlUniformMatrix4fv(mModelViewProjectionUniform, 1, false, modelViewProjection, 0); GLES20.GlUniform1f(mPointSizeUniform, 5.0f); GLES20.GlDrawArrays(GLES20.GlPoints, 0, mNumPoints); GLES20.GlDisableVertexAttribArray(mPositionAttribute); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); ShaderUtil.CheckGLError(TAG, "Draw"); }
/** * Allocates and initializes OpenGL resources needed by the background renderer. Must be * called on the OpenGL thread, typically in * {@link GLSurfaceView.Renderer#onSurfaceCreated(GL10, EGLConfig)}. * * @param context Needed to access shader source. */ public void CreateOnGlThread(Context context) { // Generate the background texture. var textures = new int[1]; GLES20.GlGenTextures(1, textures, 0); TextureId = textures[0]; GLES20.GlBindTexture(mTextureTarget, TextureId); GLES20.GlTexParameteri(mTextureTarget, GLES20.GlTextureWrapS, GLES20.GlClampToEdge); GLES20.GlTexParameteri(mTextureTarget, GLES20.GlTextureWrapT, GLES20.GlClampToEdge); GLES20.GlTexParameteri(mTextureTarget, GLES20.GlTextureMinFilter, GLES20.GlNearest); GLES20.GlTexParameteri(mTextureTarget, GLES20.GlTextureMagFilter, GLES20.GlNearest); int numVertices = 4; if (numVertices != QUAD_COORDS.Length / COORDS_PER_VERTEX) { throw new Exception("Unexpected number of vertices in BackgroundRenderer."); } var bbVertices = ByteBuffer.AllocateDirect(QUAD_COORDS.Length * FLOAT_SIZE); bbVertices.Order(ByteOrder.NativeOrder()); mQuadVertices = bbVertices.AsFloatBuffer(); mQuadVertices.Put(QUAD_COORDS); mQuadVertices.Position(0); var bbTexCoords = ByteBuffer.AllocateDirect(numVertices * TEXCOORDS_PER_VERTEX * FLOAT_SIZE); bbTexCoords.Order(ByteOrder.NativeOrder()); mQuadTexCoord = bbTexCoords.AsFloatBuffer(); mQuadTexCoord.Put(QUAD_TEXCOORDS); mQuadTexCoord.Position(0); var bbTexCoordsTransformed = ByteBuffer.AllocateDirect(numVertices * TEXCOORDS_PER_VERTEX * FLOAT_SIZE); bbTexCoordsTransformed.Order(ByteOrder.NativeOrder()); mQuadTexCoordTransformed = bbTexCoordsTransformed.AsFloatBuffer(); int vertexShader = ShaderUtil.LoadGLShader(TAG, context, GLES20.GlVertexShader, Resource.Raw.screenquad_vertex); int fragmentShader = ShaderUtil.LoadGLShader(TAG, context, GLES20.GlFragmentShader, Resource.Raw.screenquad_fragment_oes); mQuadProgram = GLES20.GlCreateProgram(); GLES20.GlAttachShader(mQuadProgram, vertexShader); GLES20.GlAttachShader(mQuadProgram, fragmentShader); GLES20.GlLinkProgram(mQuadProgram); GLES20.GlUseProgram(mQuadProgram); ShaderUtil.CheckGLError(TAG, "Program creation"); mQuadPositionParam = GLES20.GlGetAttribLocation(mQuadProgram, "a_Position"); mQuadTexCoordParam = GLES20.GlGetAttribLocation(mQuadProgram, "a_TexCoord"); ShaderUtil.CheckGLError(TAG, "Program parameters"); }
/** * Allocates and initializes OpenGL resources needed by the plane renderer. Must be * called on the OpenGL thread, typically in * {@link GLSurfaceView.Renderer#onSurfaceCreated(GL10, EGLConfig)}. * * @param context Needed to access shader source and texture PNG. * @param gridDistanceTextureName Name of the PNG file containing the grid texture. */ public void CreateOnGlThread(Context context, String gridDistanceTextureName) { int vertexShader = ShaderUtil.LoadGLShader(TAG, context, GLES20.GlVertexShader, Resource.Raw.plane_vertex); int passthroughShader = ShaderUtil.LoadGLShader(TAG, context, GLES20.GlFragmentShader, Resource.Raw.plane_fragment); mPlaneProgram = GLES20.GlCreateProgram(); GLES20.GlAttachShader(mPlaneProgram, vertexShader); GLES20.GlAttachShader(mPlaneProgram, passthroughShader); GLES20.GlLinkProgram(mPlaneProgram); GLES20.GlUseProgram(mPlaneProgram); ShaderUtil.CheckGLError(TAG, "Program creation"); // Read the texture. var textureBitmap = Android.Graphics.BitmapFactory.DecodeStream( context.Assets.Open(gridDistanceTextureName)); 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); ShaderUtil.CheckGLError(TAG, "Texture loading"); mPlaneXZPositionAlphaAttribute = GLES20.GlGetAttribLocation(mPlaneProgram, "a_XZPositionAlpha"); mPlaneModelUniform = GLES20.GlGetUniformLocation(mPlaneProgram, "u_Model"); mPlaneModelViewProjectionUniform = GLES20.GlGetUniformLocation(mPlaneProgram, "u_ModelViewProjection"); mTextureUniform = GLES20.GlGetUniformLocation(mPlaneProgram, "u_Texture"); mLineColorUniform = GLES20.GlGetUniformLocation(mPlaneProgram, "u_lineColor"); mDotColorUniform = GLES20.GlGetUniformLocation(mPlaneProgram, "u_dotColor"); mGridControlUniform = GLES20.GlGetUniformLocation(mPlaneProgram, "u_gridControl"); mPlaneUvMatrixUniform = GLES20.GlGetUniformLocation(mPlaneProgram, "u_PlaneUvMatrix"); ShaderUtil.CheckGLError(TAG, "Program parameters"); }
/** * Draws the AR background image. The image will be drawn such that virtual content rendered * with the matrices provided by {@link Frame#getViewMatrix(float[], int)} and * {@link Session#getProjectionMatrix(float[], int, float, float)} will accurately follow * static physical objects. This must be called <b>before</b> drawing virtual content. * * @param frame The last {@code Frame} returned by {@link Session#update()}. */ public void Draw(Frame frame) { // If display rotation changed (also includes view size change), we need to re-query the uv // coordinates for the screen rect, as they may have changed as well. if (frame.HasDisplayGeometryChanged) { frame.TransformDisplayUvCoords(mQuadTexCoord, mQuadTexCoordTransformed); } // No need to test or write depth, the screen quad has arbitrary depth, and is expected // to be drawn first. GLES20.GlDisable(GLES20.GlDepthTest); GLES20.GlDepthMask(false); GLES20.GlBindTexture(GLES11Ext.GlTextureExternalOes, TextureId); GLES20.GlUseProgram(mQuadProgram); // Set the vertex positions. GLES20.GlVertexAttribPointer( mQuadPositionParam, COORDS_PER_VERTEX, GLES20.GlFloat, false, 0, mQuadVertices); // Set the texture coordinates. GLES20.GlVertexAttribPointer(mQuadTexCoordParam, TEXCOORDS_PER_VERTEX, GLES20.GlFloat, false, 0, mQuadTexCoordTransformed); // Enable vertex arrays GLES20.GlEnableVertexAttribArray(mQuadPositionParam); GLES20.GlEnableVertexAttribArray(mQuadTexCoordParam); GLES20.GlDrawArrays(GLES20.GlTriangleStrip, 0, 4); // Disable vertex arrays GLES20.GlDisableVertexAttribArray(mQuadPositionParam); GLES20.GlDisableVertexAttribArray(mQuadTexCoordParam); // Restore the depth state for further drawing. GLES20.GlDepthMask(true); GLES20.GlEnable(GLES20.GlDepthTest); ShaderUtil.CheckGLError(TAG, "Draw"); }
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"); }
/** * Allocates and initializes OpenGL resources needed by the plane renderer. Must be * called on the OpenGL thread, typically in * {@link GLSurfaceView.Renderer#onSurfaceCreated(GL10, EGLConfig)}. * * @param context Needed to access shader source. */ public void CreateOnGlThread(Context context) { ShaderUtil.CheckGLError(TAG, "before create"); var buffers = new int[1]; GLES20.GlGenBuffers(1, buffers, 0); mVbo = buffers[0]; GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVbo); mVboSize = INITIAL_BUFFER_POINTS * BYTES_PER_POINT; GLES20.GlBufferData(GLES20.GlArrayBuffer, mVboSize, null, GLES20.GlDynamicDraw); GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0); ShaderUtil.CheckGLError(TAG, "buffer alloc"); int vertexShader = ShaderUtil.LoadGLShader(TAG, context, GLES20.GlVertexShader, Resource.Raw.point_cloud_vertex); int passthroughShader = ShaderUtil.LoadGLShader(TAG, context, GLES20.GlFragmentShader, Resource.Raw.passthrough_fragment); mProgramName = GLES20.GlCreateProgram(); GLES20.GlAttachShader(mProgramName, vertexShader); GLES20.GlAttachShader(mProgramName, passthroughShader); GLES20.GlLinkProgram(mProgramName); GLES20.GlUseProgram(mProgramName); ShaderUtil.CheckGLError(TAG, "program"); mPositionAttribute = GLES20.GlGetAttribLocation(mProgramName, "a_Position"); mColorUniform = GLES20.GlGetUniformLocation(mProgramName, "u_Color"); mModelViewProjectionUniform = GLES20.GlGetUniformLocation( mProgramName, "u_ModelViewProjection"); mPointSizeUniform = GLES20.GlGetUniformLocation(mProgramName, "u_PointSize"); ShaderUtil.CheckGLError(TAG, "program params"); }
/** * 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); }
/** * 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. Android.Opengl.Matrix.MultiplyMM(mModelViewMatrix, 0, cameraView, 0, mModelMatrix, 0); Android.Opengl.Matrix.MultiplyMM(mModelViewProjectionMatrix, 0, cameraPerspective, 0, mModelViewMatrix, 0); GLES20.GlUseProgram(mProgram); // Set the lighting environment properties. Android.Opengl.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"); }
/** * Draws the collection of tracked planes, with closer planes hiding more distant ones. * * @param allPlanes The collection of planes to draw. * @param cameraPose The pose of the camera, as returned by {@link Frame#getPose()} * @param cameraPerspective The projection matrix, as returned by * {@link Session#getProjectionMatrix(float[], int, float, float)} */ public void DrawPlanes(IEnumerable <Plane> allPlanes, Pose cameraPose, float[] cameraPerspective) { // Planes must be sorted by distance from camera so that we draw closer planes first, and // they occlude the farther planes. List <SortablePlane> sortedPlanes = new List <SortablePlane>(); float[] normal = new float[3]; float cameraX = cameraPose.Tx(); float cameraY = cameraPose.Ty(); float cameraZ = cameraPose.Tz(); foreach (var plane in allPlanes) { if (plane.TrackingState != TrackingState.Tracking || plane.SubsumedBy != null) { continue; } var center = plane.CenterPose; // Get transformed Y axis of plane's coordinate system. center.GetTransformedAxis(1, 1.0f, normal, 0); // Compute dot product of plane's normal with vector from camera to plane center. float distance = (cameraX - center.Tx()) * normal[0] + (cameraY - center.Ty()) * normal[1] + (cameraZ - center.Tz()) * normal[2]; if (distance < 0) { // Plane is back-facing. continue; } sortedPlanes.Add(new SortablePlane(distance, plane)); } sortedPlanes.Sort((x, y) => x.Distance.CompareTo(y.Distance)); var cameraView = new float[16]; cameraPose.Inverse().ToMatrix(cameraView, 0); // Planes are drawn with additive blending, masked by the alpha channel for occlusion. // Start by clearing the alpha channel of the color buffer to 1.0. GLES20.GlClearColor(1, 1, 1, 1); GLES20.GlColorMask(false, false, false, true); GLES20.GlClear(GLES20.GlColorBufferBit); GLES20.GlColorMask(true, true, true, true); // Disable depth write. GLES20.GlDepthMask(false); // Additive blending, masked by alpha chanel, clearing alpha channel. GLES20.GlEnable(GLES20.GlBlend); GLES20.GlBlendFuncSeparate( GLES20.GlDstAlpha, GLES20.GlOne, // RGB (src, dest) GLES20.GlZero, GLES20.GlOneMinusSrcAlpha); // ALPHA (src, dest) // Set up the shader. GLES20.GlUseProgram(mPlaneProgram); // Attach the texture. GLES20.GlActiveTexture(GLES20.GlTexture0); GLES20.GlBindTexture(GLES20.GlTexture2d, mTextures[0]); GLES20.GlUniform1i(mTextureUniform, 0); // Shared fragment uniforms. GLES20.GlUniform4fv(mGridControlUniform, 1, GRID_CONTROL, 0); // Enable vertex arrays GLES20.GlEnableVertexAttribArray(mPlaneXZPositionAlphaAttribute); ShaderUtil.CheckGLError(TAG, "Setting up to draw planes"); foreach (var sortedPlane in sortedPlanes) { var plane = sortedPlane.Plane; float[] planeMatrix = new float[16]; plane.CenterPose.ToMatrix(planeMatrix, 0); UpdatePlaneParameters(planeMatrix, plane.ExtentX, plane.ExtentZ, plane.Polygon); // Get plane index. Keep a map to assign same indices to same planes. int planeIndex = -1; if (!mPlaneIndexMap.TryGetValue(plane, out planeIndex)) { planeIndex = Java.Lang.Integer.ValueOf(mPlaneIndexMap.Count).IntValue(); mPlaneIndexMap.Add(plane, planeIndex); } // Set plane color. Computed deterministically from the Plane index. int colorIndex = planeIndex % PLANE_COLORS_RGBA.Length; ColorRgbaToFloat(mPlaneColor, PLANE_COLORS_RGBA[colorIndex]); GLES20.GlUniform4fv(mLineColorUniform, 1, mPlaneColor, 0); GLES20.GlUniform4fv(mDotColorUniform, 1, mPlaneColor, 0); // Each plane will have its own angle offset from others, to make them easier to // distinguish. Compute a 2x2 rotation matrix from the angle. float angleRadians = planeIndex * 0.144f; float uScale = DOTS_PER_METER; float vScale = DOTS_PER_METER * EQUILATERAL_TRIANGLE_SCALE; mPlaneAngleUvMatrix[0] = +(float)Math.Cos(angleRadians) * uScale; mPlaneAngleUvMatrix[1] = -(float)Math.Sin(angleRadians) * uScale; mPlaneAngleUvMatrix[2] = +(float)Math.Sin(angleRadians) * vScale; mPlaneAngleUvMatrix[3] = +(float)Math.Cos(angleRadians) * vScale; GLES20.GlUniformMatrix2fv(mPlaneUvMatrixUniform, 1, false, mPlaneAngleUvMatrix, 0); Draw(cameraView, cameraPerspective); } // Clean up the state we set GLES20.GlDisableVertexAttribArray(mPlaneXZPositionAlphaAttribute); GLES20.GlBindTexture(GLES20.GlTexture2d, 0); GLES20.GlDisable(GLES20.GlBlend); GLES20.GlDepthMask(true); ShaderUtil.CheckGLError(TAG, "Cleaning up after drawing planes"); }