深度缓冲在Android上无效,但在Linux(使用Kivy)上有效

0 投票
1 回答
591 浏览
提问于 2025-04-18 17:39

我写了一个简单的例子来说明这个问题。

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.resources import resource_find
from kivy.graphics.transformation import Matrix
from kivy.graphics import *
from kivy.graphics.opengl import *
import random

class Root(Widget):
    def __init__(self, *larg, **kw):
        super(Root, self).__init__(*larg, **kw)
        self.vertices = [[-1,-1, 0,    1,-1, 0,    1, 1, 0,   -1, 1, 0]]
        kw['shader_file'] = 'shaders.glsl'
        self.canvas = RenderContext(compute_normal_mat=True)
        shader_file = kw.pop('shader_file')
        self.canvas.shader.source = resource_find(shader_file)
        with self.canvas:
            self.cb = Callback(self.setup_gl_context)
            PushMatrix()
            Translate(0, 0, -5)
            for i in xrange(10):
                Translate(.5, 0, -.5)
                self.render(self.vertices, (random.random(), random.random(), random.random()))
            PopMatrix()
            self.cb = Callback(self.reset_gl_context)
        asp = float(Window.width) / Window.height / 2.0
        proj = Matrix().view_clip(-asp, asp, -0.5, 0.5, 1, 100, 1)
        self.canvas['projection_mat'] = proj

    def setup_gl_context(self, *args):
        glEnable(GL_DEPTH_TEST)

    def reset_gl_context(self, *args):
        glDisable(GL_DEPTH_TEST)

    def render(self, vertices, color):
        for i in xrange(len(vertices)):
            ChangeState(Kd=color, Ka=color, Ks=(.3, .3, .3), Tr=1., Ns=1., intensity=1.)
            Mesh(vertices=vertices[i], indices=[0, 1, 2, 3, 0, 2], fmt=[('v_pos', 3, 'float')], mode='triangles')

class TestApp(App): 
    def build(self):
        return Root()

if __name__ == '__main__':
    TestApp().run()

注意:我使用了这个 shaders.glsl

这个例子绘制了10个正方形,它们的大小相同,但颜色是随机的。每个新绘制的正方形都是通过 Translate(.5, 0, -.5) 进行相对移动的,所以最后绘制的正方形是最远的。因为开启了 glEnable(GL_DEPTH_TEST),所以当我在Linux上运行这个程序时,显示效果是正确的:

enter image description here

但是在我用Buildozer创建了一个*.apk文件后(在 buildzer.spec 文件中,我只修改了 titlenameversion,并把 glsl 加入了 include_exts),然后在Android(4.4)上运行时,显示效果却不正确(就像 GL_DEPTH_TEST 被关闭了一样):

enter image description here

这个问题可能是因为OpenGL ES和OpenGL之间的差异,但我认为 GL_DEPTH_TEST 在两者上都应该能正常工作。也可能是打包时出现了问题,但看起来并不是这样。有没有人能帮帮我呢?

1 个回答

1

正如Reto Koradi所建议的,我又仔细查看了Kivy的文档。我发现了Framebuffer(模块kivy.graphics.fbo),它是一个离屏窗口,像Kivy的画布一样工作。它(可能与画布不同)有一个with_depthbuffer参数,默认设置为False

所以解决办法就是在Framebuffer中把with_depthbuffer = True设置为真,然后在画布中使用Framebuffer渲染的纹理来显示它。

我不太确定为什么在Android上需要这样做,而在Linux上却不需要。也可能有更好的选择,不需要创建(有时毫无意义的)Framebuffer,但这个方法至少在这两个平台上都能用。

我修改了示例代码:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.resources import resource_find
from kivy.graphics.transformation import Matrix
from kivy.graphics import *
from kivy.graphics.opengl import *
import random

class Root(Widget):
    def __init__(self, *larg, **kw):
        super(Root, self).__init__(*larg, **kw)     
        self.vertices = [[-1,-1, 0,    1,-1, 0,    1, 1, 0,   -1, 1, 0]]
        with self.canvas:
             self.fbo = Fbo(with_depthbuffer = True, size = Window.size)
             Rectangle(size=Window.size, texture=self.fbo.texture)

        kw['shader_file'] = 'shaders.glsl'
        shader_file = kw.pop('shader_file')   
        self.fbo.shader.source = resource_find(shader_file)
        with self.fbo:
            self.cb = Callback(self.setup_gl_context)
            PushMatrix()
            Translate(0, 0, -5)
            for i in xrange(10):
                Translate(.5, 0, -.5)
                self.render(self.vertices, (random.random(), random.random(), random.random()))
            PopMatrix()
            self.cb = Callback(self.reset_gl_context)

        asp = float(Window.width) / Window.height / 2.0
        proj = Matrix().view_clip(-asp, asp, -0.5, 0.5, 1, 100, 1)
        self.fbo['projection_mat'] = proj

    def setup_gl_context(self, *args):
        glEnable(GL_DEPTH_TEST)

    def reset_gl_context(self, *args):
        glDisable(GL_DEPTH_TEST)

    def render(self, vertices, color):
        for i in xrange(len(vertices)):
            ChangeState(Kd=color, Ka=color, Ks=(.3, .3, .3), Tr=1., Ns=1., intensity=1.)
            Mesh(vertices=vertices[i], indices=[0, 1, 2, 3, 0, 2], fmt=[('v_pos', 3, 'float')], mode='triangles')

class TestApp(App): 
    def build(self):
        return Root()

if __name__ == '__main__':
    TestApp().run()

撰写回答