Example #1
0
        /**
         * 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");

            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");
        }
        /**
         * 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");
        }