Macbook retina display 上使用 PyOpenGL

5

我有一些使用PyOpenGL在glut窗口中显示图形的代码。在Retina MacBook Pro上,该窗口以低分辨率模式显示,一个OpenGL像素由四个物理像素表示。如果它能以完整的本地分辨率显示会更好。

我的问题
在Retina显示器上,是否有任何方法可以使用glut或其他方式在Python中获得本地分辨率的OpenGL上下文?

问题示例
以下是一个最小化的PyOpenGL程序示例。它没有什么特别之处 - 任何工作的PyOpenGL代码都会出现这个问题。下面是截图的放大细节。请注意,构成白色三角形的像素是OS X小部件像素的四倍。这是未专门设计用于Retina设备的程序的默认设置。我想知道如何关闭PyOpenGL程序的此功能。

enter image description here

以下是代码:

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *

import os

def initFunc():
    glDisable(GL_DEPTH_TEST)
    glClearColor(0.0, 0.0, 0.0, 0.0)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluOrtho2D(0.0, 400.0, 0.0, 400.0)

def displayFunc():
    glClear(GL_COLOR_BUFFER_BIT)
    glColor3f(1.0, 1.0, 1.0)
    glBegin(GL_TRIANGLES)
    glVertex2f(10.0, 10.0)
    glVertex2f(10.0, 100.0)
    glVertex2f(100.0, 100.0)
    glEnd()
    glFlush()

if __name__ == '__main__':
    glutInit()
    glutInitWindowSize(400,400)
    glutCreateWindow("GL test")
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
    glutDisplayFunc(displayFunc)
    initFunc()
    os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')
        # prevent GL window from appearing behind other applications
    glutMainLoop()

你应该发布一些代码。 - djc
你需要的内容在https://developer.apple.com/library/mac/#documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Introduction/Introduction.html中有记录,更直接的信息可以在http://developer.apple.com/library/mac/#documentation/graphicsimaging/conceptual/opengl-macprogguide/EnablingOpenGLforHighResolution/EnablingOpenGLforHighResolution.html找到。现在你需要将它映射到Python。 - mmgp
@Nathaniel,所以问题是另一个。看起来你不知道需要什么,现在你知道了,只需要知道如何使用from AppKit import NSOpenGLView获取的NSOpenGLView即可。 - mmgp
@mmgp,非常抱歉我之前的匆忙评论。我完全不知道这个AppKit东西居然可以从Python中调用,所以我认为你所说的“将其映射到Python”只是指“以某种方式在Python中完成相同的事情”。我很快就会研究一下AppKit模块。(如果你能发布一个稍微详细一点的版本作为答案,那就太棒了。) - N. Virgo
@Nathaniel 我可以提供一个解决方案,但我没有现成的视网膜 MacBook 来测试它。 - mmgp
@mmgp 嗯,即使你的答案只是给了一个提示让我朝正确的方向前进,那也会很有帮助。(如果你在意这样的事情,还有50点赏金可获得。) - N. Virgo
3个回答

5
为了达到您想要的分辨率,您需要使用一个 NSView 并指示该视图应使用最佳分辨率(这也意味着您不再应使用 GLUT)。由于这超出了 OpenGL 的范围,并且您想使用 Python,因此您需要使用一些可以访问这些对象的软件包以及 py2app(但不需要完整的 py2app build)。
为了访问NSView,或更具体地说是NSOpenGLView,您需要使用 pyobjc。以下代码仅用于清晰起见导入了 Cocoa(由 pyobjc 提供),可以通过 AppKit 访问相同的对象。该代码创建一个 NSWindow,然后创建一个视图,该视图定义了每次需要调用 drawRect 的内容。解决分辨率问题的单行代码是:view.setWantsBestResolutionOpenGLSurface_(True)
import Cocoa
from OpenGL.GL import *
from OpenGL.GLU import *

class GLView(Cocoa.NSOpenGLView):
    def initWithFrame_(self, frame):
        format = Cocoa.NSOpenGLPixelFormat.alloc().initWithAttributes_((0, ))
        view = super(GLView, self).initWithFrame_pixelFormat_(frame, format)
        view.setWantsBestResolutionOpenGLSurface_(True)

        view.openGLContext().makeCurrentContext()
        glDisable(GL_DEPTH_TEST)
        glClearColor(0.0, 0.0, 0.0, 0.0)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluOrtho2D(0.0, 1.0, 0.0, 1.0)
        return view

    def drawRect_(self, bounds):
        glClear(GL_COLOR_BUFFER_BIT)
        glColor3f(1.0, 1.0, 1.0)
        glBegin(GL_TRIANGLES)
        glVertex2f(0.1, 0.1)
        glVertex2f(0.1, 0.9)
        glVertex2f(0.9, 0.9)
        glEnd()
        glFlush()


class AppDelegate(Cocoa.NSObject):
    def windowWillClose_(self, notification):
        app.terminate_(self)

app = Cocoa.NSApplication.sharedApplication()

rect = Cocoa.NSMakeRect(0, 0, 300, 300)
winflags = Cocoa.NSTitledWindowMask | Cocoa.NSClosableWindowMask
win = Cocoa.NSWindow.alloc().initWithContentRect_styleMask_backing_defer_(
        rect, winflags, Cocoa.NSBackingStoreBuffered, False)
delegate = AppDelegate.alloc().init()
win.setDelegate_(delegate)
view = GLView.alloc().initWithFrame_(rect)
win.setContentView_(view)
win.makeKeyAndOrderFront_(None)

app.run()

如果您尝试运行此代码,它将正常运行,但您不会注意到任何关于分辨率问题的差异。为了解决这个问题,您需要构建一个简单的setup.py文件,假设上面的代码保存在名为test1.py的文件中:

from distutils.core import setup
import py2app
setup(app=["test1.py"])

然后运行mypythonexecutable setup.py py2app -A(当然,其中的mypythonexecutable要替换为有意义的内容,例如pythonpython2.7)。现在执行open dist/test1.app即可解决问题(在执行前一个命令后,dist/test1.app将被创建)。


这看起来很棒。我已经授予了您的赏金,并在有机会测试后会接受答案。 - N. Virgo
在被实际工作分心了很长一段时间后,我终于有机会尝试这个。不幸的是,虽然使用 python test1.py 运行良好(但低分辨率),但当执行 open dist/test1.app 时,我会得到一个带有“test1错误”的对话框,这并没有提供太多帮助。有一个打开控制台的选项,但据我所见,控制台日志中没有来自Python的任何信息。 - N. Virgo

3
您可以从这里获取一个修补过的GLUT版本,该版本可选择支持HiDPI: http://iihm.imag.fr/blanch/software/glut-macosx/ 如果您使用此GLUT框架,则应用程序可以选择以真实屏幕像素分辨率获取OpenGL上下文。您只需更改代码中的显示初始化(无论是C、Python/PyOpenGL还是任何与GLUT框架链接的东西),例如:
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE)

to:

glutInitDisplayString("rgba double hidpi")

已修补的版本能够优雅地处理具有不同后备存储器比例的多个屏幕,并为各种需要以像素为单位指定大小或尺寸的功能(即glutInitWindowSize,glutReshapeWindow,glutGet(GLUT_WINDOW_WIDTH),glutGet(GLUT_WINDOW_HEIGHT)和传递给事件回调的光标位置)提供一致的行为。
此版本的GLUT还完全向后兼容其他未选择支持HiDPI的应用程序。如果您希望自己构建版本,则提供了补丁和构建框架的说明。
修补版本还添加了鼠标滚轮支持,如果需要的话。

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接