This is the 19th day of my participation in the August Wenwen Challenge.More challenges in August

Series of articles

Implementation of Android 3D effects (Nuggets first post)


preface

A few days ago, some fans wanted Ji Meng to write a simple tutorial of 3D effect. This effect is available in the official Demo of Android, but it may be difficult for the novice to understand, so I will write a tutorial according to my own understanding and change it into the appearance required by the fans.


The source code will be posted at the end of the article (additional notes for beginners), welcome to leave a comment.

First, look at chat (demand)

Two, achieve the effect

3. Implement

The first five steps are sensor content.

1. Run getSystemService to obtain the SensorManager instance object

mSensorManager = (SensorManager)context.getSystemService(SENSOR_SERVICE);
Copy the code

2. Obtain the desired sensor object from the SensorManager instance object: the parameter determines which sensor to obtain

 mRotationVectorSensor = mSensorManager.getDefaultSensor(
                Sensor.TYPE_ROTATION_VECTOR);
Copy the code

3. Register the sensor when the focus is obtained and have this class implement the SensorEventListener interface

 mSensorManager.registerListener(this, mRotationVectorSensor, 10000);
Copy the code
  • The first parameter: an instance object of the SensorEventListener interface

  • Second parameter: the sensor instance to be registered

  • SensorManager.SENSOR_DELAY_FASTEST = 0: Corresponding to 0 microsecond update interval, fastest, 1 microsecond = 1%1000000 seconds sensorManager.sensor_delay_game = 1: SENSOR_DELAY_UI = 2: sensorManager. SENSOR_DELAY_NORMAL = 3: SensorManager. Update interval for 200000 microseconds: Update interval for x microseconds when typing a custom int value x

4. Two methods must be overridden: onAccuracyChanged and onSensorChanged

  • OnSensorChanged: Callback interface when sensor event values change: The frequency at which this method is executed is related to the frequency at which the sensor was registered.
  • OnAccuracyChanged: callback interface for sensor accuracy changes

5. Unlog the sensor when it loses focus (provides a call to the Activity)

    public void stop(a) {
        mSensorManager.unregisterListener(this);
    }
Copy the code

6. Draw method in the square explanation, this case (OpengL coordinate system is used in 3d coordinates)

  • GlEnable: enables the GL function on the server.
  • GlFrontFace: Defines the front and back sides of a polygon. The direction of the front side of the polygon. GL_CW and GL_CCW are allowed and the initial value is GL_CCW.
  • GlShadeModel: Select constant or smooth shader mode. GL primitives can be in constant or smooth color mode. The default is smooth color mode. When the pixel is rasterized, the color of the inserted vertex will be calculated, and different colors will be evenly distributed to each pixel segment. The allowed values are GL_FLAT and GL_SMOOTH, with an initial value of GL_SMOOTH.
  • GlVertexPointer: Defines a vertex coordinate matrix. (Various parameters and points to note will be posted in the subsequent source code).
  • GlColorPointer: Defines a color matrix. Size specifies the number of elements per color and must be 4. Type indicates the data type of each color element, stride indicates the byte increment from one color to the next allowed vertex, and attribute values are squeezed into simple matrices or stored in separate matrices (simple matrix storage may be more efficient in some versions).
  • GlDrawElements: Render primies from matrix data.

For more advice, see the Official Android documentation.

Iv. Green and yellow parameters in demand

            final float colors[] = {
                      0,  1,  1,  1,  1,  1,  1,  1,
                      1,  1,  0,  1,  1,  1,  1,  1,
                      1,  1,  1,  1,  0,  1,  1,  1,
                      1,  1,  1,  1,  1,  1,  0,  1,
            };
Copy the code

5. The source code

TdRenderer.java

public class TdRenderer implements GLSurfaceView.Renderer.SensorEventListener {
    / / sensor
    private SensorManager mSensorManager;
    private Sensor mRotationVectorSensor;
    private Cube mCube;

    private final float[] mRotationMatrix = new float[16];

    public TdRenderer(Context context) {
        // Step 1: Get the SensorManager instance object with getSystemService
        mSensorManager = (SensorManager)context.getSystemService(SENSOR_SERVICE);
        // Step 2: Get the desired sensor object from the SensorManager instance object: the parameter determines which sensor to get
        mRotationVectorSensor = mSensorManager.getDefaultSensor(
                Sensor.TYPE_ROTATION_VECTOR);

        mCube = new Cube();
        mRotationMatrix[ 0] = 1;
        mRotationMatrix[ 4] = 1;
        mRotationMatrix[ 8] = 1;
        mRotationMatrix[12] = 1;
    }
   // Step 3: Register the sensor when focus is obtained and have this class implement the SensorEventListener interface
    public void start(a) {
        /* * First argument: SensorEventListener instance object of interface * second argument: SensorEventListener instance to register * third argument: SensorEventListener event frequency: * sensorManager. SENSOR_DELAY_FASTEST = 0 microsecond update interval, fastest, 1 microsecond = 1% 1000000 seconds * sensorManager. SENSOR_DELAY_GAME = 1: * sensorManager. SENSOR_DELAY_UI = 2: * sensorManager. SENSOR_DELAY_NORMAL = 3: Update interval for 200000 microseconds * When typing a custom int value x: update interval for x microseconds * */
        mSensorManager.registerListener(this, mRotationVectorSensor, 10000);
    }
    // Step 4: Two methods that must be overridden: onAccuracyChanged, onSensorChanged
    // Step 5: Unplug the sensor when it loses focus (provide a call to the Activity)
    public void stop(a) {
        mSensorManager.unregisterListener(this);
    }
    // Callback interface when sensor event values change: The frequency at which this method is executed is related to the frequency at which the sensor was registered
    public void onSensorChanged(SensorEvent event) {
        // Most sensors will return three axis x,y,x event values
        //float x = event.values[0];
        //float y = event.values[1];
        //float z = event.values[2];
        if(event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { SensorManager.getRotationMatrixFromVector( mRotationMatrix , event.values); }}public void onDrawFrame(GL10 gl) {
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
        gl.glTranslatef(0.0, -3.0 f);
        gl.glMultMatrixf(mRotationMatrix, 0);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

        mCube.draw(gl);
    }

    public void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glViewport(0.0, width, height);
        float ratio = (float) width / height;
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glFrustumf(-ratio, ratio, -1.1.1.10);
    }

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        gl.glDisable(GL10.GL_DITHER);
        // Specifies the clean value of the color buffer
        gl.glClearColor(1.1.1.1);
    }

    public class Cube {
        // OpengL coordinates use 3d coordinates:
        private FloatBuffer mVertexBuffer;
        private FloatBuffer mColorBuffer;
        private ByteBuffer mIndexBuffer;

        public Cube(a) {
            final float vertices[] = {
                    -1, -1, -1.1, -1, -1.1.1, -1,	    -1.1, -1,
                    -1, -1.1.1, -1.1.1.1.1,     -1.1.1};final float colors[] = {
                      0.1.1.1.1.1.1.1.1.1.0.1.1.1.1.1.1.1.1.1.0.1.1.1.1.1.1.1.1.1.0.1};final byte indices[] = {
                    0.4.5.0.5.1.1.5.6.1.6.2.2.6.7.2.7.3.3.7.4.3.4.0.4.7.6.4.6.5.3.0.1.3.1.2
            };

            ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
            vbb.order(ByteOrder.nativeOrder());
            mVertexBuffer = vbb.asFloatBuffer();
            mVertexBuffer.put(vertices);
            mVertexBuffer.position(0);

            ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
            cbb.order(ByteOrder.nativeOrder());
            mColorBuffer = cbb.asFloatBuffer();
            mColorBuffer.put(colors);
            mColorBuffer.position(0);

            mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
            mIndexBuffer.put(indices);
            mIndexBuffer.position(0);
        }

        public void draw(GL10 gl) {
            // Enable server-side GL.
            gl.glEnable(GL10.GL_CULL_FACE);
            // Define the front and back sides of a polygon.
            / / parameters:
            //mode -- The direction of the front of the polygon. GL_CW and GL_CCW are allowed and the initial value is GL_CCW.
            gl.glFrontFace(GL10.GL_CW);
            // Select constant or smooth shader mode.
            //GL primitives can be in constant or smooth coloring mode. The default is smooth coloring mode. When the pixel is rasterized, the color of the inserted vertex will be calculated, and different colors will be evenly distributed to each pixel segment.
            / / parameters:
            //mode -- specifies a symbolic constant to represent the coloring technique to be used. The allowed values are GL_FLAT and GL_SMOOTH, with an initial value of GL_SMOOTH.
            gl.glShadeModel(GL10.GL_SMOOTH);
            // Define a vertex coordinate matrix.
            / / parameters:
            //
            //size -- The coordinate dimension of each vertex, must be 2, 3 or 4, starting with 4.
            //
            //type -- Specifies the data type of each vertex coordinate. The permitted symbolic constants are GL_BYTE, GL_SHORT, GL_FIXED, and GL_FLOAT. The initial value is GL_FLOAT.
            //
            //stride -- Specifies the bit offset between consecutive vertices. If 0, the vertex is considered to be pressed tightly into the matrix, and the initial value is 0.
            //
            //pointer -- A buffer to specify vertex coordinates, if null, no buffer is set.
            gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
            // Define a color matrix.
            //size Specifies the number of elements per color. The value must be 4. Type indicates the data type of each color element, stride indicates the byte increment from one color to the next allowed vertex, and attribute values are squeezed into simple matrices or stored in separate matrices (simple matrix storage may be more efficient in some versions).
            gl.glColorPointer(4, GL10.GL_FLOAT, 0, mColorBuffer);
            // Render primions from matrix data
            // Separate vertex, normal, color, and texture coordinate matrices can be specified in advance and can be used to create sequence primitives by calling the glDrawElements method.
            gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE, mIndexBuffer); }}// Callback interface for sensor accuracy changes
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something when the sensor accuracy changes. Accuracy is the current sensor accuracy}}Copy the code

ThreeDimensionsRotation, Java (Activity remember registration)

public class ThreeDimensionsRotation extends Activity {
    private GLSurfaceView mGLSurfaceView;
    private TdRenderer tdRenderer;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        tdRenderer=new TdRenderer(this);
        // Create a preview view and set it to the content of the Activity
        mGLSurfaceView = new GLSurfaceView(this);
        mGLSurfaceView.setRenderer(tdRenderer);
        setContentView(mGLSurfaceView);
    }

    @Override
    protected void onResume(a) {
        super.onResume();
        tdRenderer.start();
        mGLSurfaceView.onResume();
    }

    @Override
    protected void onPause(a) {
        super.onPause(); tdRenderer.stop(); mGLSurfaceView.onPause(); }}Copy the code