내 대답은 부분적으로 CodeSurgeon's answer을 기준으로 한 질문의 두 번째 부분입니다.
오프 스크린 렌더링 (표시되는 창 대신 내부 버퍼에 무엇인가를 렌더링하고 렌더링 된 이미지를 파일로 저장하거나 웹 페이지에 표시 할 HTTP 응답으로 저장). PyOpenGL에서 (OpenGL 자체 에서처럼) 약간 까다 롭습니다. 왜냐하면 당신이 표준 GLUT 윈도우를 팝업하거나 깜박일 필요가 없기 때문에 지금까지는 모든 것이 GLUT에 의해 행해졌 기 때문에 (창, init OpenGL 컨텍스트 생성 등) 손으로해야합니다.
그래서는 OpenGL에서 오프 스크린 렌더링을위한 3 가지 방법이 있습니다 :
1) 초기화 GLUT를 사용하지만, 과잉 창을 숨기고 그것을 렌더링합니다. 이 방법은 플랫폼에 독립적입니다. 그러나 GLUT 윈도우는 초기화하는 동안 짧은 시간 동안 나타납니다. 따라서 웹 서버에는 적합하지 않습니다. 그렇지만 시작시에만 초기화를 수행하고 통신 할 별도의 인터페이스를 사용하는 별도의 웹 서버로 설정할 수 있습니다. 그것.
2) 렌더링 할 숨겨진 창, OpenGL 컨텍스트 및 Framebuffer 개체를 모두 수동으로 만듭니다. 이 방법은 모든 것을 제어하고 윈도우는 나타나지 않지만 컨텍스트 생성은 플랫폼에 따라 다릅니다. (아래는 Win64의 예입니다)
3) 세 번째 방법은 방법 2와 비슷하지만 대신 WGL에서 만든 기본 Framebuffer를 사용합니다 손으로 FBO를 만드는 방법. 방법 2와 동일한 효과가 있지만 더 간단합니다.다른 이유로 FBO가 필요하지 않은 경우, FBO가 더 바람직 할 수 있습니다.
이제 방법 2, 하드 코어 1에 대해 설명하겠습니다. 더 많은 샘플은 내 GitHub repository에 있습니다.
그래서 오프 스크린 렌더링 알고리즘은 다음 단계로 구성
- 하는 창을 필요로하기 때문에, 심지어는 OpenGL 컨텍스트를 만들 에 숨겨진 숨겨진 창을 만들기
- 는 OpenGL 컨텍스트를 작성
- 프레임 버퍼 객체를 생성 (FBO)
- 렌더링 버퍼 (색상 및 깊이)를 생성하고 FBO에 첨부하십시오 (자세한 내용은 FBO manual 참조)
- FBO에서 FBO로 바인딩 렌더링을위한 OpenGL 컨텍스트
- 무언가 렌더링. 이 예제에서는 단순화를 위해 2D 프리미티브만을 사용하지만 깊이 테스트를 사용하여 3D 렌더링을위한 버퍼를 준비합니다
- 읽기 용 설정 버퍼, 여기서는 FBO가 하나이므로
에서 읽을 버퍼를 선택하지 않아도됩니다.
- glReadPixels()을 사용하여 색상 렌더링 버퍼에서 렌더링 된 데이터 읽기
- 수신 된 데이터로 원하는대로 수행하십시오. 즉, 수신 된 데이터로 원하는대로 수행하십시오. 즉, PIL 이미지를 만들어 파일에 저장하십시오. 또한 이중 해상도로 렌더링하고 PIL 이미지의 크기를 조정하여 앤티 앨리어스 효과를 적용 할 수 있습니다.
그래서 전체 예제가 있습니다.
중요! 3.1.1 PyOpenGL 구현에는 버그가 있습니다! 인수 7 : : : 그냥 WGL, glReadPixels()
ctypes.ArgumentError과 충돌하기 시작 가져올 때 잘못된 유형을
이 당신의 패키지 디렉토리 \ OpenGL을 \ 원시 \ WGL_types.py로 이동하지 않도록하려면를 찾을 수 다음 줄
HANDLE = POINTER(None) # /home/mcfletch/pylive/OpenGL-ctypes/src/wgl.h:60
# TODO: figure out how to make the handle not appear as a void_p within the code...
HANDLE.final = True
하고 (물론 64를 들면, 86 UINT32에 대한 가정)로 교체
HANDLE = UINT64
HANDLE.final = True
그래서 예를
012,351,641있다
from win32api import *
from win32con import *
from win32gui import *
from OpenGL.WGL import *
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from PIL import Image
from PIL import ImageOps
import uuid
# =========================================
# I left here only necessary constants, it's easy to search for the rest
PFD_TYPE_RGBA = 0
PFD_MAIN_PLANE = 0
PFD_DOUBLEBUFFER = 0x00000001
PFD_DRAW_TO_WINDOW = 0x00000004
PFD_SUPPORT_OPENGL = 0x00000020
# =========================================
# OpenGL context creation helpers
def mywglCreateContext(hWnd):
pfd = PIXELFORMATDESCRIPTOR()
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL
pfd.iPixelType = PFD_TYPE_RGBA
pfd.cColorBits = 32
pfd.cDepthBits = 24
pfd.iLayerType = PFD_MAIN_PLANE
hdc = GetDC(hWnd)
pixelformat = ChoosePixelFormat(hdc, pfd)
SetPixelFormat(hdc, pixelformat, pfd)
oglrc = wglCreateContext(hdc)
wglMakeCurrent(hdc, oglrc)
# check is context created succesfully
# print "OpenGL version:", glGetString(GL_VERSION)
def mywglDeleteContext():
hrc = wglGetCurrentContext()
wglMakeCurrent(0, 0)
if hrc: wglDeleteContext(hrc)
# =========================================
# OpenGL Framebuffer Objects helpers
def myglCreateBuffers(width, height):
fbo = glGenFramebuffers(1)
color_buf = glGenRenderbuffers(1)
depth_buf = glGenRenderbuffers(1)
# binds created FBO to context both for read and draw
glBindFramebuffer(GL_FRAMEBUFFER, fbo)
# bind color render buffer
glBindRenderbuffer(GL_RENDERBUFFER, color_buf)
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color_buf)
# bind depth render buffer - no need for 2D, but necessary for real 3D rendering
glBindRenderbuffer(GL_RENDERBUFFER, depth_buf)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buf)
return fbo, color_buf, depth_buf, width, height
def myglDeleteBuffers(buffers):
fbo, color_buf, depth_buf, width, height = buffers
glBindFramebuffer(GL_FRAMEBUFFER, 0)
glDeleteRenderbuffers(1, color_buf)
glDeleteRenderbuffers(1, depth_buf)
glDeleteFramebuffers(1, fbo)
def myglReadColorBuffer(buffers):
fbo, color_buf, depth_buf, width, height = buffers
glPixelStorei(GL_PACK_ALIGNMENT, 1)
glReadBuffer(GL_COLOR_ATTACHMENT0)
data = glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE)
return data, width, height
# =========================================
# Scene rendering
def renderInit(width, height):
glClearColor(0.5, 0.5, 0.5, 1.0)
glColor(0.0, 1.0, 0.0)
gluOrtho2D(-1.0, 1.0, -1.0, 1.0)
glViewport(0, 0, width, height)
def render():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# draw xy axis with arrows
glBegin(GL_LINES)
# x
glVertex2d(-1, 0)
glVertex2d(1, 0)
glVertex2d(1, 0)
glVertex2d(0.95, 0.05)
glVertex2d(1, 0)
glVertex2d(0.95, -0.05)
# y
glVertex2d(0, -1)
glVertex2d(0, 1)
glVertex2d(0, 1)
glVertex2d(0.05, 0.95)
glVertex2d(0, 1)
glVertex2d(-0.05, 0.95)
glEnd()
glFlush()
# =========================================
# Windows stuff and main steps
def main():
# Create window first with Win32 API
hInstance = GetModuleHandle(None)
wndClass = WNDCLASS()
wndClass.lpfnWndProc = DefWindowProc
wndClass.hInstance = hInstance
wndClass.hbrBackground = GetStockObject(WHITE_BRUSH)
wndClass.hCursor = LoadCursor(0, IDC_ARROW)
wndClass.lpszClassName = str(uuid.uuid4())
wndClass.style = CS_OWNDC
wndClassAtom = RegisterClass(wndClass)
# don't care about window size, couse we will create independent buffers
hWnd = CreateWindow(wndClassAtom, '', WS_POPUP, 0, 0, 1, 1, 0, 0, hInstance, None)
# Ok, window created, now we can create OpenGL context
mywglCreateContext(hWnd)
# In OpenGL context create Framebuffer Object (FBO) and attach Color and Depth render buffers to it
width, height = 300, 300
buffers = myglCreateBuffers(width, height)
# Init our renderer
renderInit(width, height)
# Now everything is ready for job to be done!
# Render something and save it to file
render()
data, width, height = myglReadColorBuffer(buffers)
image = Image.frombytes("RGBA", (width, height), data)
image = ImageOps.flip(image) # in my case image is flipped top-bottom for some reason
# it's easy to achive antialiasing effect by resizing rendered image
# don't forget to increase initial rendered image resolution and line thikness for 2D
#image = image.resize((width/2, height/2), Image.ANTIALIAS)
image.save("fbo.png", "PNG")
# Shutdown everything
myglDeleteBuffers(buffers)
mywglDeleteContext()
main()
안녕하세요! 답변이없는 질문이나 투표를 피하려면 http://stackoverflow.com/help/how-to-ask를 참조하십시오. 귀하의 질문은 매우 광범위하며, 여기서 우리가 중요하게 생각하는 것은 문제를 해결하기위한 사전 노력을하고 보여주는 것입니다. 따라서 지금까지 시도한 것을 보여주는 코드를 추가하는 것이 좋습니다. 아직 무언가를 시도하지 않았다면, 우리는 당신을 위해 당신의 일을하기 위해 여기에 있지 않습니다. 당신은 "너무 광범위합니다"라고 표시 될 수 있습니다. 그러나 충분한 정보를 가진 사람이 이것을보고 길을 안내 할 것입니다. – gelliott181