最近多次被小伙伴问到 OpenGL 多重采样,其实前面文章里多次讲过了,就是构建2个缓冲区,多重采样缓冲区和目标解析缓冲区。
代码流程
// Framebuffer IDs
private int msaaFBO;
private int msaaColorBuffer;
private int msaaDepthBuffer;
private int resolveFBO;
private int resolveTexture;
public void initFramebuffers(int width, int height) {
// Step 1: Create MSAA FBO
int[] fbo = new int[1];
GLES30.glGenFramebuffers(1, fbo, 0);
msaaFBO = fbo[0];
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, msaaFBO);
// Create MSAA color buffer
int[] renderbuffer = new int[1];
GLES30.glGenRenderbuffers(1, renderbuffer, 0);
msaaColorBuffer = renderbuffer[0];
GLES30.glBindRenderbuffer(GLES30.GL_RENDERBUFFER, msaaColorBuffer);
GLES30.glRenderbufferStorageMultisample(GLES30.GL_RENDERBUFFER, 4, GLES30.GL_RGBA8, width, height); // 4x MSAA
GLES30.glFramebufferRenderbuffer(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_RENDERBUFFER, msaaColorBuffer);
// Create MSAA depth buffer
GLES30.glGenRenderbuffers(1, renderbuffer, 0);
msaaDepthBuffer = renderbuffer[0];
GLES30.glBindRenderbuffer(GLES30.GL_RENDERBUFFER, msaaDepthBuffer);
GLES30.glRenderbufferStorageMultisample(GLES30.GL_RENDERBUFFER, 4, GLES30.GL_DEPTH_COMPONENT16, width, height);
GLES30.glFramebufferRenderbuffer(GLES30.GL_FRAMEBUFFER, GLES30.GL_DEPTH_ATTACHMENT, GLES30.GL_RENDERBUFFER, msaaDepthBuffer);
if (GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER) != GLES30.GL_FRAMEBUFFER_COMPLETE) {
throw new RuntimeException("MSAA Framebuffer is not complete!");
}
// Step 2: Create Resolve FBO
GLES30.glGenFramebuffers(1, fbo, 0);
resolveFBO = fbo[0];
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, resolveFBO);
// Create texture for resolved result
int[] texture = new int[1];
GLES30.glGenTextures(1, texture, 0);
resolveTexture = texture[0];
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, resolveTexture);
GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, width, height, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, resolveTexture, 0);
if (GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER) != GLES30.GL_FRAMEBUFFER_COMPLETE) {
throw new RuntimeException("Resolve Framebuffer is not complete!");
}
// Unbind framebuffer
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
}
public void renderScene() {
// Step 3: Render to MSAA FBO
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, msaaFBO);
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);
// Render your scene here...
// Step 4: Resolve to texture
GLES30.glBindFramebuffer(GLES30.GL_READ_FRAMEBUFFER, msaaFBO);
GLES30.glBindFramebuffer(GLES30.GL_DRAW_FRAMEBUFFER, resolveFBO);
GLES30.glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GLES30.GL_COLOR_BUFFER_BIT, GLES30.GL_NEAREST);
// Step 5: Unbind framebuffers
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
// Step 6: Use resolveTexture for further processing (e.g., render to screen)
renderQuadWithTexture(resolveTexture);
}