如何在GLSurfaceView与CameraView中固定3D模型并多角度旋转
Hey there! Let's figure out how to lock your STL model to a specific spot on the CameraView while keeping that handy touch rotation feature working. I’ve dealt with similar AR overlay setups before, so here’s a step-by-step breakdown:
1. First: Understand the Coordinate Disconnect
Right now, your model is rendering at the GL world origin (0,0,0) which overlays on top of the CameraView. To pin it to a specific screen spot, you need to map CameraView screen coordinates (like a center point or corner) into the 3D world space that your GL renderer uses.
2. Separate Position & Rotation Transforms
The key here is to split your model's transformation into two independent parts:
- A fixed translation that locks the model to your target screen position
- A local rotation that lets users spin the model without moving it from that spot
Matrix order matters here: always apply the translation first, then the rotation. This ensures rotation happens around the model's own center, not the world origin.
3. Modify Your onDrawFrame & Rendering Code
Let’s adjust your existing code to implement this:
Step 1: Calculate the Fixed 3D Position
First, convert your target CameraView screen position (e.g., center) into GL world coordinates. We’ll use normalized device coordinates (NDC) as an intermediary:
// Define your target screen position (example: CameraView center) private float targetScreenX; private float targetScreenY; private float worldX, worldY, worldZ; private float orthoWidth, orthoHeight; // Call this when CameraView size changes (like in onSurfaceChanged) private void updateFixedPosition() { // Get CameraView's current dimensions int camWidth = mCameraView.getWidth(); int camHeight = mCameraView.getHeight(); // Set target to screen center (adjust to your desired spot) targetScreenX = camWidth / 2.0f; targetScreenY = camHeight / 2.0f; // Convert screen coords to GL normalized device coords (-1 to 1 range) float ndcX = (2.0f * targetScreenX) / camWidth - 1.0f; // GL Y-axis is inverted relative to screen Y-axis float ndcY = 1.0f - (2.0f * targetScreenY) / camHeight; // Convert NDC to world coordinates (using orthographic projection) worldX = ndcX * orthoWidth / 2.0f; worldY = ndcY * orthoHeight / 2.0f; worldZ = -5.0f; // Keep model at a fixed depth in front of the camera }
Step 2: Update onDrawFrame to Combine Transforms
Modify your rendering logic to apply translation first, then rotation:
@Override public void onDrawFrame(GL10 gl) { gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); gl.glLoadIdentity(); // 1. Move the model to its fixed screen position first gl.glTranslatef(worldX, worldY, worldZ); // 2. Apply your existing touch rotation logic (rotates around model's center) gl.glRotatef(mAngleX, 1.0f, 0.0f, 0.0f); gl.glRotatef(mAngleY, 0.0f, 1.0f, 0.0f); // Draw your STL model as before mStlRenderer.draw(gl); }
Step 3: Handle CameraView Size Changes
Make sure to recalculate the fixed position when the CameraView or screen rotates:
@Override public void onSurfaceChanged(GL10 gl, int width, int height) { gl.glViewport(0, 0, width, height); // Update orthographic projection (match to screen/CameraView size) gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); orthoWidth = width; orthoHeight = height; gl.glOrthof(-width/2, width/2, -height/2, height/2, 1, 100); gl.glMatrixMode(GL10.GL_MODELVIEW); // Refresh the fixed position when size changes updateFixedPosition(); }
4. Test & Tweak
- First, disable rotation temporarily to confirm the model locks to your target position
- Re-enable rotation and verify the model spins around its own center without moving
- If the position is off, double-check the Y-axis inversion (GL’s Y runs top-to-bottom, unlike screen Y)
内容的提问来源于stack exchange,提问作者Sejpal Pavan

