替换 google arcore 中的 3D 对象

Replace 3D object in google arcore

我是 OpenGL 和 ARCore 的新手,我正在使用 GoogleArCore Sample 作为创建我的应用程序的基础。我可以缩放和缩放 3D 对象,但无法用另一个 3D 对象替换当前 3D 对象。我已经在加载新对象之前检测到着色器了。

基本上,我想重新加载onSurfaceCreated(GL10 gl, EGLConfig config) 但我不知道该怎么做。

这是我的代码

public class MyARActivity extends BaseActivity<MyActivityArBinding> implements GLSurfaceView.Renderer {
    private static final String TAG = DashboardActivity.class.getSimpleName();

    //AR Variables
    private int mWidth;
    private int mHeight;
    private boolean capturePicture = false;
    private boolean installRequested;
    private boolean moving;
    float[] projmtx = new float[16];
    float[] viewmtx = new float[16];
    private Session session;
    private GestureDetector gestureDetector;
    private Snackbar messageSnackbar;
    private DisplayRotationHelper displayRotationHelper;
    private final BackgroundRenderer backgroundRenderer = new BackgroundRenderer();
    private ObjectRenderer virtualObject;// = new ObjectRenderer();
    private ObjectRenderer virtualObjectShadow;// = new ObjectRenderer();
    private final PlaneRenderer planeRenderer = new PlaneRenderer();
    private PointCloudRenderer pointCloud = new PointCloudRenderer();
    private ScaleGestureDetector scaleGestureDetector;
    private MyScaleGestureDetector_1 myScaleGestureDetector;
    // Temporary matrix allocated here to reduce number of allocations for each frame.
    private float[] anchorMatrix = new float[16];
    // Tap handling and UI.
    private ArrayBlockingQueue<MotionEvent> queuedSingleTaps = new ArrayBlockingQueue<>(16);
    private ArrayList<Anchor> anchors = new ArrayList<>();
    private int[] m3DCharacters = new int[]{R.drawable.cat, R.drawable.old_man, R.drawable.bat};
    private SQLiteHelper sqlHelper;
    private boolean isUpdate;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHeaderVisible(false);
        doDefaults();
    }

    private void doDefaults() {
        binding.setPresenter(this);
        sqlHelper = SQLiteHelper.getInstance(this);
        initAR();
    }

    @SuppressLint("ClickableViewAccessibility")
    private void initAR() {
        displayRotationHelper = new DisplayRotationHelper(this);
        myScaleGestureDetector = new MyScaleGestureDetector_1();
        scaleGestureDetector = new ScaleGestureDetector(this, myScaleGestureDetector);

        // Set up tap listener.
        gestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                if (anchors.size() <= 0) {
                    onSingleTap(e);
                }
                return true;
            }

            @Override
            public boolean onDown(MotionEvent e) {
                return true;
            }
        });

        binding.surfaceView.setOnTouchListener(
                new View.OnTouchListener() {
                    @Override
                    public boolean onTouch(View v, MotionEvent event) {

                        switch (event.getAction()) {
                            case MotionEvent.ACTION_DOWN:
                                moving = true;
                                DebugHelper.log("ACTION_DOWN");
                                break;

                            case MotionEvent.ACTION_UP:
                                DebugHelper.log("ACTION_UP");
                                moving = false;
                                DebugHelper.log("SF at ACTION_UP::::", String.valueOf(myScaleGestureDetector.getScaleFactor()));
                                break;
                            case MotionEvent.ACTION_MOVE:
                                if (anchors.size() > 0) {
                                    onSecondTouch(event);
                                }
                                break;
                        }
                        return gestureDetector.onTouchEvent(event);

                    }
                });

        // Set up renderer.
        binding.surfaceView.setPreserveEGLContextOnPause(true);
        binding.surfaceView.setEGLContextClientVersion(2);
        binding.surfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); // Alpha used for plane blending.
        binding.surfaceView.setRenderer(this);
        binding.surfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
        installRequested = false;
    }

    private void onSavePicture() {
        setLoading(true, "Capturing image...");
        Log.e("SavePicture Called", "Yes");
        int pixelData[] = new int[mWidth * mHeight];
        // Read the pixels from the current GL frame.
        IntBuffer buf = IntBuffer.wrap(pixelData);
        buf.position(0);
        GLES20.glReadPixels(0, 0, mWidth, mHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);

        // Convert the pixel data from RGBA to what Android wants, ARGB.
        int bitmapData[] = new int[pixelData.length];
        for (int i = 0; i < mHeight; i++) {
            for (int j = 0; j < mWidth; j++) {
                int p = pixelData[i * mWidth + j];
                int b = (p & 0x00ff0000) >> 16;
                int r = (p & 0x000000ff) << 16;
                int ga = p & 0xff00ff00;
                bitmapData[(mHeight - i - 1) * mWidth + j] = ga | r | b;
            }
        }
        // Create a bitmap.
        Bitmap capturedBitmap = Bitmap.createBitmap(bitmapData, mWidth, mHeight, Bitmap.Config.ARGB_8888);
        Bitmap waterBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.watermark_camar);
        Bitmap waterMarkBitmap = ImageUtil.getInstance().createWaterMaskRightBottom(this, capturedBitmap, waterBitmap, 10, 5);
        sqlHelper.saveToInternalStorage(this, waterMarkBitmap);
        setLoading(false, "");
    }

    /**
     * To capture the current AR Frame
     */
    public void onCaptureClick() {
        if (!ExternalPermissionHelper.hasExtStoragePermission(MyARActivity.this)) {
            ExternalPermissionHelper.requestExtStoragePermission(MyARActivity.this);
            return;
        }
        capturePicture = true;
    }

    /**
     * To open and close the character selection horizontal list
     */
    public void onCharClick() {
        createCharacterScrollView();
    }

    /**
     * To close the entire AR view
     */
    public void closeScreen() {
        finish();
    }

    private void createCharacterScrollView() {
        try {
            binding.LinearTopSlider.setVisibility(View.VISIBLE);
            LayoutInflater inflater = LayoutInflater.from(this);
            binding.charContainer.removeAllViews();
            binding.horizontalChar.scrollTo(0, 0);
            for (int i = 0; i < m3DCharacters.length; i++) {
                View cell = inflater.inflate(R.layout.item_character, null);
                ImageView imgGroup = cell.findViewById(R.id.imgChar);
                View view = cell.findViewById(R.id.view);
                //String name = "cartoon" + (i + 1);
                imgGroup.setImageResource(m3DCharacters[i]); //getResourceId(name)
                view.setVisibility(i < m3DCharacters.length - 1 ? View.VISIBLE : View.GONE);
                binding.charContainer.addView(cell);
                cell.setTag(i);
                cell.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        final int position = (int) view.getTag();
                        switch (position) {
                            case 0:
                                loadObject(0.28f, 3.5f, 0.28f, "cat/cat.obj");
                                break;
                            case 1:
                                loadObject(0.0085f, 5f, 1f, "man/muro.obj");
                                break;
                            case 2:
                                loadObject(0.0009f, 2.75f, 0.25f, "bloodwing/bloodwing.obj");
                                break;
                        }
                    }
                });
            }
            binding.charContainer.setVisibility(View.VISIBLE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private int getResourceId(String drawableName) {
        return getResources().getIdentifier(drawableName, "drawable", getPackageName());
    }

    private void onSecondTouch(MotionEvent e) {
        Log.e("Second Touch", "Executed");
        if (e.getPointerCount() > 1) {
            scaleGestureDetector.onTouchEvent(e);
        } else {
            queuedSingleTaps.offer(e);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (session == null) {
            Exception exception = null;
            String message = null;
            try {
                switch (ArCoreApk.getInstance().requestInstall(this, !installRequested)) {
                    case INSTALL_REQUESTED:
                        installRequested = true;
                        return;
                    case INSTALLED:
                        break;
                }

                // ARCore requires camera permissions to operate. If we did not yet obtain runtime
                // permission on Android M and above, now is a good time to ask the user for it.
                if (!CameraPermissionHelper.hasCameraPermission(this)) {
                    CameraPermissionHelper.requestCameraPermission(this);
                    return;
                }

                session = new Session(/* context= */ this);
            } catch (UnavailableArcoreNotInstalledException
                    | UnavailableUserDeclinedInstallationException e) {
                message = "Please install ARCore";
                exception = e;
            } catch (UnavailableApkTooOldException e) {
                message = "Please update ARCore";
                exception = e;
            } catch (UnavailableSdkTooOldException e) {
                message = "Please update this app";
                exception = e;
            } catch (Exception e) {
                message = "This device does not support AR";
                exception = e;
            }

            if (message != null) {
                showMsg(message);
                Log.e(TAG, "Exception creating session", exception);
                return;
            }

            // Create default config and check if supported.
            Config config = new Config(session);
            if (!session.isSupported(config)) {
                showMsg("This device does not support AR");
            }
            session.configure(config);
        }

        showLoadingMessage();
        // Note that order matters - see the note in onPause(), the reverse applies here.
        session.resume();
        binding.surfaceView.onResume();
        displayRotationHelper.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
        if (session != null) {
            // Note that the order matters - GLSurfaceView is paused first so that it does not try
            // to query the session. If Session is paused before GLSurfaceView, GLSurfaceView may
            // still call session.update() and get a SessionPausedException.
            displayRotationHelper.onPause();
            binding.surfaceView.onPause();
            session.pause();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] results) {
        switch (requestCode) {
            case CameraPermissionHelper.CAMERA_PERMISSION_CODE:
                if (!CameraPermissionHelper.hasCameraPermission(this)) {
                    showMsg("Camera permission is needed to run this application");
                    if (!CameraPermissionHelper.shouldShowRequestPermissionRationale(this)) {
                        // Permission denied with checking "Do not ask again".
                        CameraPermissionHelper.launchPermissionSettings(this);
                    }
                    finish();
                }
                break;

            case ExternalPermissionHelper.EXT_STORAGE_PERMISSION_CODE:
                if (!ExternalPermissionHelper.hasExtStoragePermission(this)) {
                    showMsg("External storage permission is needed to capture the photo");
                    if (!ExternalPermissionHelper.shouldShowRequestPermissionRationale(this)) {
                        // Permission denied with checking "Do not ask again".
                        ExternalPermissionHelper.launchPermissionSettings(this);
                    }
                    finish();
                }
                break;
        }
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus) {
            // Standard Android full-screen functionality.
            getWindow()
                    .getDecorView()
                    .setSystemUiVisibility(
                            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }
    }

    private void onSingleTap(MotionEvent e) {
        // Queue tap if there is space. Tap is lost if queue is full.
        DebugHelper.log("onSingleTap()");
        queuedSingleTaps.offer(e);
    }

    private void loadCatObject() {
        try {
            myScaleGestureDetector.setScaleFactor(0.25f);
            myScaleGestureDetector.setMinValue(3.5f);
            myScaleGestureDetector.setMaxValue(0.25f);
            virtualObject = new ObjectRenderer("cat/cat.obj");
            //virtualObject.createOnGlThread(this, "cat/cat.obj", "cat/cat.png");
            virtualObject.createOnGlThread(this);
            virtualObject.setMaterialProperties(0.0f, 1.0f, 1.0f, 6.0f);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    private void loadBloodwingObject() {
        try {
            myScaleGestureDetector.setScaleFactor(0.0009f);
            myScaleGestureDetector.setMinValue(2.75f);
            myScaleGestureDetector.setMaxValue(0.25f);
            virtualObject = new ObjectRenderer("bloodwing/bloodwing.obj");
            virtualObject.createOnGlThread(this);
            //virtualObject.createOnGlThread(this, "bloodwing/bloodwing.obj", "bloodwing/bloodwing.jpg");
            virtualObject.setMaterialProperties(0.0f, 1.0f, 1.0f, 6.0f);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    private void loadMan() {
        try {
            myScaleGestureDetector.setScaleFactor(0.0085f);
            myScaleGestureDetector.setMinValue(5f);
            myScaleGestureDetector.setMaxValue(1f);
            virtualObject = new ObjectRenderer("man/muro.obj");
            virtualObject.createOnGlThread(this);
            virtualObject.setMaterialProperties(0.0f, 1.0f, 1.0f, 6.0f);
        } catch (Exception ex) {
            ex.printStackTrace();
            finish();
        }
    }

    private void loadObject(float scaleFactor, float minValue, float maxValue, String objectPath) {
        try {
            myScaleGestureDetector.setScaleFactor(scaleFactor);
            myScaleGestureDetector.setMinValue(minValue);
            myScaleGestureDetector.setMaxValue(maxValue);
            if (virtualObject == null) {
                virtualObject = new ObjectRenderer(objectPath);
                virtualObject.createOnGlThread(this);
                virtualObject.setMaterialProperties(0.0f, 1.0f, 1.0f, 6.0f);
            } else {
                isUpdate = true;
                GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
                virtualObject.updateObjectPath(objectPath);
                virtualObject.createOnGlThread(this);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES20.glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
        // Create the texture and pass it to ARCore session to be filled during update().
        backgroundRenderer.createOnGlThread(/*context=*/ this);
        // Prepare the other rendering objects.
        loadObject(0.40f, 3.5f, 0.28f, "cat/cat.obj");
        try {
            planeRenderer.createOnGlThread(/*context=*/ this, "trigrid.png");
        } catch (IOException e) {
            Log.e(TAG, "Failed to read plane texture");
        }
        pointCloud.createOnGlThread(/*context=*/ this);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        displayRotationHelper.onSurfaceChanged(width, height);
        GLES20.glViewport(0, 0, width, height);
        mWidth = width;
        mHeight = height;
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        // Clear screen to notify driver it should not load any pixels from previous frame.
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        if (session == null) {
            return;
        }
        // Notify ARCore session that the view size changed so that the perspective matrix and
        // the video background can be properly adjusted.
        displayRotationHelper.updateSessionIfNeeded(session);

        try {
            session.setCameraTextureName(backgroundRenderer.getTextureId());

            // Obtain the current frame from ARSession. When the configuration is set to
            // UpdateMode.BLOCKING (it is by default), this will throttle the rendering to the
            // camera framerate.
            Frame frame = session.update();
            Camera camera = frame.getCamera();

            // Handle taps. Handling only one tap per frame, as taps are usually low frequency
            // compared to frame rate.
            MotionEvent tap = queuedSingleTaps.poll();
            if (tap != null && camera.getTrackingState() == TrackingState.TRACKING) {
                for (HitResult hit : frame.hitTest(tap)) {
                    // Check if any plane was hit, and if it was hit inside the plane polygon
                    Trackable trackable = hit.getTrackable();
                    // Creates an anchor if a plane or an oriented point was hit.
                    if ((trackable instanceof Plane && ((Plane) trackable).isPoseInPolygon(hit.getHitPose()))
                            || (trackable instanceof Point
                            && ((Point) trackable).getOrientationMode()
                            == Point.OrientationMode.ESTIMATED_SURFACE_NORMAL)) {
                        // Hits are sorted by depth. Consider only closest hit on a plane or oriented point.
                        // Cap the number of objects created. This avoids overloading both the
                        // rendering system and ARCore.
                        //if (!isUpdate) {
                        DebugHelper.log("Anchor size = " + anchors.size());
                        if (anchors.size() >= 1) {
                            anchors.get(0).detach();
                            anchors.remove(0);
                        }
                        // Adding an Anchor tells ARCore that it should track this position in
                        // space. This anchor is created on the Plane to place the 3D model
                        // in the correct position relative both to the world and to the plane.
                        if (isUpdate) {
                            if (anchors.size() > 0) {
                                DebugHelper.log("anchor list has data");
                                for (Anchor anchor : anchors) {
                                    anchor.detach();
                                    anchors.remove(anchor);
                                }
                            }
                        }
                        Anchor anchor = hit.createAnchor();
                        if (anchor != null)
                            anchors.add(anchor);
                        else
                            DebugHelper.log("anchor is null");
                        //}
                        break;
                    }
                }
            }

            // Draw background.
            backgroundRenderer.draw(frame);

            // If not tracking, don't draw 3d objects.
            if (camera.getTrackingState() == TrackingState.PAUSED) {
                return;
            }

            // Get projection matrix.
            camera.getProjectionMatrix(projmtx, 0, 0.1f, 100.0f);

            // Get camera matrix and draw.
            camera.getViewMatrix(viewmtx, 0);

            // Compute lighting from average intensity of the image.
            final float lightIntensity = frame.getLightEstimate().getPixelIntensity();

            // Visualize tracked points.
            PointCloud pointCloud = frame.acquirePointCloud();
            this.pointCloud.update(pointCloud);
            if (!capturePicture)
                this.pointCloud.draw(viewmtx, projmtx);

            // Application is responsible for releasing the point cloud resources after
            // using it.
            pointCloud.release();

            // Check if we detected at least one plane. If so, hide the loading message.
            if (messageSnackbar != null) {
                {
                    for (Plane plane : session.getAllTrackables(Plane.class)) {
                        if (plane.getType() == Plane.Type.HORIZONTAL_UPWARD_FACING
                                && plane.getTrackingState() == TrackingState.TRACKING) {
                            hideLoadingMessage();
                            break;
                        }
                        //xgfgdfgfgd
                        //binding.setCharClick(true);
                    }
                }
                for (Plane plane : session.getAllTrackables(Plane.class)) {
                    if (plane.getType() == Plane.Type.HORIZONTAL_UPWARD_FACING && plane.getTrackingState() == TrackingState.TRACKING) {
                        hideLoadingMessage();
                        break;
                    }
                    //dfgdfgdfgdf
                    //binding.setCharClick(true);
                }
            }


            // Visualize planes.
            if (!capturePicture)
                planeRenderer.drawPlanes(session.getAllTrackables(Plane.class), camera.getDisplayOrientedPose(), projmtx);

            // Visualize anchors created by touch.
            for (Anchor anchor : anchors) {
                if (anchor.getTrackingState() != TrackingState.TRACKING) {
                    continue;
                }
                // Get the current pose of an Anchor in world space. The Anchor pose is updated
                // during calls to session.update() as ARCore refines its estimate of the world.
                anchor.getPose().toMatrix(anchorMatrix, 0);

                // Update and draw the model and its shadow.
                if (virtualObject != null) {
                    virtualObject.updateModelMatrix(anchorMatrix, myScaleGestureDetector.getScaleFactor());
                    if (viewmtx != null && projmtx != null) {
                        virtualObject.draw(viewmtx, projmtx, lightIntensity);
                    }
                }
                if (virtualObjectShadow != null) {
                    virtualObjectShadow.updateModelMatrix(anchorMatrix, myScaleGestureDetector.getScaleFactor());
                    if (viewmtx != null && projmtx != null)
                        virtualObjectShadow.draw(viewmtx, projmtx, lightIntensity);
                }
            }

            if (capturePicture) {
                capturePicture = false;
                onSavePicture();
            }

        } catch (Throwable t) {
            // Avoid crashing the application due to unhandled exceptions.
            Log.e(TAG, "Exception on the OpenGL thread", t);
        }
    }

    private void setLoading(boolean isLoading, String message) {
        binding.setLoading(isLoading);
        binding.setLoadingMessage(message);
    }

    private void showSnackbarMessage(String message, boolean finishOnDismiss) {
        messageSnackbar =
                Snackbar.make(
                        MyARActivity.this.findViewById(android.R.id.content),
                        message,
                        Snackbar.LENGTH_INDEFINITE);
        messageSnackbar.getView().setBackgroundColor(0xbf323232);
        if (finishOnDismiss) {
            messageSnackbar.setAction(
                    "Dismiss",
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            messageSnackbar.dismiss();
                        }
                    });
            messageSnackbar.addCallback(
                    new BaseTransientBottomBar.BaseCallback<Snackbar>() {
                        @Override
                        public void onDismissed(Snackbar transientBottomBar, int event) {
                            super.onDismissed(transientBottomBar, event);
                            finish();
                        }
                    });
        }
        messageSnackbar.show();
    }

    private void showLoadingMessage() {
        runOnUiThread(
                new Runnable() {
                    @Override
                    public void run() {
                        showSnackbarMessage("Searching for surfaces...", false);
                    }
                });
    }

    private void hideLoadingMessage() {
        runOnUiThread(
                new Runnable() {
                    @Override
                    public void run() {
                        if (messageSnackbar != null) {
                            messageSnackbar.dismiss();
                        }
                        messageSnackbar = null;
                    }
                });
    }
}

在我的 ObjectRenderer 和 BackgroundRenderer 中重置了我的代码。

嘻嘻是我的重置密码

BackgroundRenderer.java

public void resetData() {
    GLES20.glDeleteShader(vertexShader);
    GLES20.glDeleteShader(fragmentShader);
    GLES20.glDeleteProgram(quadProgram);
    textureId = -1;
}

ObjectRenderer.java

Public void updateObjectPath(String objectPath) {
    try {
        GLES20.glDeleteShader(vertexShader);
        GLES20.glDeleteShader(fragmentShader);
        GLES20.glDeleteProgram(mProgram);
        reset();
        this.OBJ_PATH = objectPath;
        } 
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void reset() {
        this.OBJ_PATH = null;
        this.mObj = null;
        this.mModelMatrix = null;
        this.mModelViewMatrix = null;
        this.mModelViewProjectionMatrix = null;
        this.mViewLightDirection = null;
        this.mTextures = null;
        this.vectorArrayObjectIds = null;
        this.mMaterialParametersUniform = -1;
        this.mModelViewProjectionUniform = -1;
        this.mVerticesBaseAddress = -1;
        this.mTexCoordsBaseAddress = -1;
        this.mNormalAttribute = -1;
        this.mNormalsBaseAddress = -1;
        this.mIndexBufferId = -1;
        this.mVertexBufferId = -1;
        this.mBlendMode = null;
        this.mProgram = -1;
        this.mLightingParametersUniform = -1;
        this.mIndexCount = -1;
        this.mModelViewUniform = -1;
        this.mPositionAttribute = -1;
        this.mTexCoordAttribute = -1;
        this.vertexShader = -1;
        this.fragmentShader = -1;
        this.mAmbient = 0.3f;
        this.mDiffuse = 1.0f;
        this.mSpecular = 1.0f;
        this.mSpecularPower = 6.0f;
        this.mModelMatrix = new float[16];
        this.mModelViewMatrix = new float[16];
        this.mModelViewProjectionMatrix = new float[16];
        this.mViewLightDirection = new float[4];
    }

任何人都可以指导我吗?

提前致谢。

In OpenGL ES defines the following 6 error values Code:

1280 GL_INVALID_ENUM      
1281 GL_INVALID_VALUE     
1282 GL_INVALID_OPERATION 
1283 GL_STACK_OVERFLOW    
1284 GL_STACK_UNDERFLOW   
1285 GL_OUT_OF_MEMORY

您收到 GL_INVALID_ENUM 错误,这意味着您向 GL 函数传递了不受支持的枚举值。

您需要将新对象名称及其纹理传递给 onDrawFrame 方法,这是因为它仅在 GL 线程上工作。 另请注意,您使用的是 GL 版本 2。

glSurfaceView.setEGLContextClientVersion(2);

    @Override
    public void onDrawFrame(GL10 gl) {

        if (isObjChanged) {
            isObjChanged = false;
            try {
                virtualObject.createOnGlThread(getContext(), objName, textureName);
                virtualObject.setMaterialProperties(0.0f, 2.0f, 0.5f, 6.0f);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;
        }

        // Clear screen to notify driver it should not load any pixels from previous frame.
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
        if (session == null) {
            return;
        }
        // Notify ARCore session that the view size changed so that the perspective matrix and
        // the video background can be properly adjusted.
        displayRotationHelper.updateSessionIfNeeded(session);

        try {
            session.setCameraTextureName(backgroundRenderer.getTextureId());

            // Obtain the current frame from ARSession. When the configuration is set to
            // UpdateMode.BLOCKING (it is by default), this will throttle the rendering to the
            // camera framerate.
            Frame frame = session.update();
            Camera camera = frame.getCamera();

            // Handle taps. Handling only one tap per frame, as taps are usually low frequency
            // compared to frame rate.

            MotionEvent tap = tapHelper.poll();
            if (tap != null && camera.getTrackingState() == TrackingState.TRACKING) {
                for (HitResult hit : frame.hitTest(tap)) {
                    // Check if any plane was hit, and if it was hit inside the plane polygon
                    Trackable trackable = hit.getTrackable();
                    // Creates an anchor if a plane or an oriented point was hit.
                    if ((trackable instanceof Plane && ((Plane) trackable).isPoseInPolygon(hit.getHitPose()))
                            || (trackable instanceof Point
                            && ((Point) trackable).getOrientationMode()
                            == Point.OrientationMode.ESTIMATED_SURFACE_NORMAL)) {
                        // Hits are sorted by depth. Consider only closest hit on a plane or oriented point.
                        // Cap the number of objects created. This avoids overloading both the
                        // rendering system and ARCore.
                        if (anchors.size() >= 1) {
                            anchors.get(0).detach();
                            anchors.remove(0);
                        }
                        // Adding an Anchor tells ARCore that it should track this position in
                        // space. This anchor is created on the Plane to place the 3D model
                        // in the correct position relative both to the world and to the plane.
                        anchors.add(hit.createAnchor());
                        break;
                    }
                }
            }

            // Draw background.
            backgroundRenderer.draw(frame);

            // If not tracking, don't draw 3d objects.
            if (camera.getTrackingState() == TrackingState.PAUSED) {
                return;
            }

            // Get projection matrix.
            float[] projmtx = new float[16];
            camera.getProjectionMatrix(projmtx, 0, 0.1f, 100.0f);

            // Get camera matrix and draw.
            float[] viewmtx = new float[16];
            camera.getViewMatrix(viewmtx, 0);

            // Compute lighting from average intensity of the image.
            // The first three components are color scaling factors.
            // The last one is the average pixel intensity in gamma space.
            final float[] colorCorrectionRgba = new float[4];
            frame.getLightEstimate().getColorCorrection(colorCorrectionRgba, 0);

            // Visualize tracked points.
            PointCloud pointCloud = frame.acquirePointCloud();
            pointCloudRenderer.update(pointCloud);
            pointCloudRenderer.draw(viewmtx, projmtx);

            // Application is responsible for releasing the point cloud resources after
            // using it.
            pointCloud.release();

            // Check if we detected at least one plane. If so, hide the loading message.
            if (messageSnackbarHelper.isShowing()) {
                for (Plane plane : session.getAllTrackables(Plane.class)) {
                    if (plane.getType() == com.google.ar.core.Plane.Type.HORIZONTAL_UPWARD_FACING
                            && plane.getTrackingState() == TrackingState.TRACKING) {
                        messageSnackbarHelper.hide(getActivity());
                        break;
                    }
                }
            }

            // Visualize planes.
            planeRenderer.drawPlanes(
                    session.getAllTrackables(Plane.class), camera.getDisplayOrientedPose(), projmtx);

            // Visualize anchors created by touch.

            for (Anchor anchor : anchors) {
                if (anchor.getTrackingState() != TrackingState.TRACKING) {
                    continue;
                }
                // Get the current pose of an Anchor in world space. The Anchor pose is updated
                // during calls to session.update() as ARCore refines its estimate of the world.
                anchor.getPose().toMatrix(anchorMatrix, 0);

                // Update and draw the model and its shadow.
                virtualObject.updateModelMatrix(anchorMatrix, scaleFactor);
                virtualObject.draw(viewmtx, projmtx, colorCorrectionRgba);
            }

        } catch (Throwable t) {
            // Avoid crashing the application due to unhandled exceptions.
            Log.e(TAG, "Exception on the OpenGL thread", t);
        }
    }