【问题标题】:PyOpenGL on a Macbook retina displayMacbook 视网膜显示器上的 PyOpenGL
【发布时间】:2013-01-24 21:53:45
【问题描述】:

我有一些代码在 glut 窗口中使用 PyOpenGL 显示图形。在视网膜 Macbook Pro 上,此窗口以低分辨率模式显示,一个 OpenGL 像素由四个物理像素表示。如果它以完整的原始分辨率显示会更好。

我的问题
有什么方法可以在 Retina 显示器上使用 glut 或其他方式在 Python 中获得原生分辨率的 OpenGL 上下文?

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

代码如下:

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()

【问题讨论】:

  • 你应该发布一些代码。
  • 您所追求的内容记录在 developer.apple.com/library/mac/#documentation/… 中,更直接地记录在 developer.apple.com/library/mac/#documentation/graphicsimaging/… 中。现在您需要将其映射到 Python。
  • @Nathaniel 所以问题是另一个问题。似乎您不知道需要什么,现在您只需知道如何使用由from AppKit import NSOpenGLView 获得的NSOpenGLView
  • @mmgp 为我草率的评论深表歉意。我根本不知道可以从 Python 调用这个 AppKit 的东西,所以我认为“将它映射到 Python”你只是意味着“以某种方式在 Python 中做同样的事情”。我将很快研究 AppKit 模块。 (如果您可以发布一个更详细的版本作为答案,那就太棒了。)
  • @Nathaniel 我可以提供一个答案,但我没有现成的视网膜 macbook 来测试它。

标签: python osx-lion glut retina-display pyopengl


【解决方案1】:

要正确实现您所追求的分辨率,您需要使用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 将在前面的命令执行后创建)。

【讨论】:

  • 这看起来很棒。我已经给你赏金,一旦我有机会测试它就会接受答案。
  • 所以在长期被实际工作分心后,我终于有机会尝试这个。不幸的是,虽然python test1.py 运行良好(但分辨率低),但在执行open dist/test1.app 时,我得到一个非常有用的错误“test1 错误”的对话。有一个打开控制台的选项,但据我所知,控制台日志中没有任何来自 python 的内容。
【解决方案2】:

您可以从此处获取可选支持 HiDPI 的 GLUT 修补版本: http://iihm.imag.fr/blanch/software/glut-macosx/

如果您使用此 GLUT 框架,您的应用程序可能会选择以实际屏幕像素分辨率获取 OpenGL 上下文。 您只需从以下位置更改代码中的显示初始化(无论是 C、Python/PyOpenGL 还是任何与 GLUT 框架链接的东西):

glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE)

到:

glutInitDisplayString("rgba double hidpi")

修补后的版本可以优雅地处理具有不同后备存储比例因子的多个屏幕,并为各种期望以像素指定大小或尺寸的函数提供一致的行为(即glutInitWindowSize, glutReshapeWindow, glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT) 和传递给事件回调的光标位置)。

此版本的 GLUT 还完全向后兼容其他决定不选择加入 HiDPI 支持的应用程序。 如果您喜欢构建自己的版本,还提供了补丁和自行构建框架的说明。

补丁版本还增加了鼠标滚轮支持,如果您需要的话。

【讨论】:

    【解决方案3】:

    我猜你必须使用一些 PyObjC 绑定来获取 Glut 创建的 NSWindow,然后调整比例因子。以下是有关 Objective C 部分的一些信息:http://supermegaultragroovy.com/2012/10/24/coding-for-high-resolution-on-os-x-read-this/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-19
      • 1970-01-01
      • 2015-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-13
      • 1970-01-01
      相关资源
      最近更新 更多