/** * 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.GetType() != Plane.Type.HorizontalUpwardFacing || plane.GetTrackingState() != Plane.TrackingState.Tracking) { 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.PlanePolygon); // 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"); }