Lưu ý rằng để biên dịch PyOpenGL_accelerate, bạn sẽ cần phải có một môi trường biên dịch tiện ích mở rộng Python đang hoạt động
Học PyOpenGL
Nếu bạn chưa quen với PyOpenGL, bạn có thể muốn bắt đầu với trang hướng dẫn OpenGLContext. Các hướng dẫn đó yêu cầu OpenGLContext, [là một trình bao bọc lớn bao gồm toàn bộ công cụ tạo cảnh, trình phân tích cú pháp VRML97, nhiều bản trình diễn, v.v.], bạn có thể cài đặt nó với
$ pip2.7 install "OpenGLContext-full==3.1.1"
Hoặc bạn có thể sao chép nó [bao gồm cả các nguồn hướng dẫn] với
$ git clone //github.com/mcfletch/openglcontext.git
hoặc [để sử dụng GitHub]
$ git clone //github.com/mcfletch/pyopengl.git
Các trang tài liệu rất hữu ích để tra cứu các tham số và ngữ nghĩa của lệnh gọi PyOpenGL
Chạy thử nghiệm
Bạn có thể chạy bộ thử nghiệm PyOpenGL từ kiểm tra mã nguồn, bạn sẽ cần
git [để thanh toán]
GLUT [GLUT miễn phí]
Thư viện GLExtrusion [libgle]
GLU [thường khả dụng trên mọi máy hỗ trợ OpenGL]
độc tố [pip cài đặt độc tố]
Chạy bộ thử nghiệm từ thanh toán cấp cao nhất trông giống như
$ tox
Kết quả là rất nhiều thử nghiệm được chạy trong một ma trận các môi trường. Tất cả các môi trường sẽ kéo vào pygame, một số cũng sẽ kéo vào numpy. Một số sẽ tăng tốc, và một số sẽ không
Đối với những người thực sự thiếu kiên nhẫn, bạn có thể thử chạy mã trong hình ảnh giới thiệu ở trên. Nếu điều này hoạt động, một cửa sổ sẽ mở trên màn hình của bạn với nền màu đỏ. Nếu bây giờ bạn muốn hiểu cách thức hoạt động của nó, bạn sẽ phải đọc văn bản bên dưới
Sau khi xem xét một số khái niệm OpenGL quan trọng, đã đến lúc viết mã cho ví dụ quad của chúng ta. Tuy nhiên, trước khi sử dụng OpenGL, chúng ta cần mở một cửa sổ có ngữ cảnh GL hợp lệ. Điều này có thể được thực hiện bằng bộ công cụ như Gtk, Qt hoặc Wx hoặc bất kỳ bộ công cụ gốc nào [Windows, Linux, OSX]. Thật không may, giao diện Tk Python không cho phép tạo ngữ cảnh GL và chúng tôi không thể sử dụng nó. Lưu ý rằng cũng tồn tại các bộ công cụ chuyên dụng như GLFW hoặc GLUT và lợi thế của GLUT là nó đã được cài đặt cùng với OpenGL. Ngay cả khi nó hiện không được dùng nữa, chúng tôi sẽ sử dụng GLUT vì đây là bộ công cụ rất nhẹ và không yêu cầu bất kỳ gói bổ sung nào. Đây là một thiết lập tối thiểu sẽ mở một cửa sổ có rác trên đó [vì chúng tôi thậm chí không xóa cửa sổ]
import sys import OpenGL.GL as gl import OpenGL.GLUT as glut def display[]: glut.glutSwapBuffers[] def reshape[width,height]: gl.glViewport[0, 0, width, height] def keyboard[ key, x, y ]: if key == b'\x1b': sys.exit[ ] glut.glutInit[] glut.glutInitDisplayMode[glut.GLUT_DOUBLE | glut.GLUT_RGBA] glut.glutCreateWindow['Hello world!'] glut.glutReshapeWindow[512,512] glut.glutReshapeFunc[reshape] glut.glutDisplayFunc[display] glut.glutKeyboardFunc[keyboard] glut.glutMainLoop[]
Ghi chú
Bạn sẽ không có quyền truy cập vào bất kỳ lệnh GL nào trước khi
program = gl.glCreateProgram[] vertex = gl.glCreateShader[gl.GL_VERTEX_SHADER] fragment = gl.glCreateShader[gl.GL_FRAGMENT_SHADER]5 được thực thi vì sẽ không có ngữ cảnh OpenGL nào trước khi lệnh này được thực thi
program = gl.glCreateProgram[] vertex = gl.glCreateShader[gl.GL_VERTEX_SHADER] fragment = gl.glCreateShader[gl.GL_FRAGMENT_SHADER]6 cho OpenGL biết thuộc tính ngữ cảnh GL là gì. Ở giai đoạn này, chúng tôi chỉ cần một bộ đệm hoán đổi [chúng tôi vẽ trên một bộ đệm trong khi bộ đệm khác được hiển thị] và chúng tôi sử dụng bộ đệm màu RGBA 32 bit đầy đủ [8 bit cho mỗi kênh]. Hàm gọi lại
program = gl.glCreateProgram[] vertex = gl.glCreateShader[gl.GL_VERTEX_SHADER] fragment = gl.glCreateShader[gl.GL_FRAGMENT_SHADER]7 thông báo cho OpenGL về kích thước cửa sổ mới trong khi phương thức
program = gl.glCreateProgram[] vertex = gl.glCreateShader[gl.GL_VERTEX_SHADER] fragment = gl.glCreateShader[gl.GL_FRAGMENT_SHADER]8 cho OpenGL biết phải làm gì khi cần vẽ lại. Trong trường hợp đơn giản này, chúng tôi chỉ yêu cầu OpenGL hoán đổi bộ đệm [điều này tránh nhấp nháy]. Cuối cùng, cuộc gọi lại bàn phím cho phép chúng tôi thoát bằng cách nhấn phím
program = gl.glCreateProgram[] vertex = gl.glCreateShader[gl.GL_VERTEX_SHADER] fragment = gl.glCreateShader[gl.GL_FRAGMENT_SHADER]9
Bây giờ cửa sổ của bạn đã được tạo, chúng ta có thể bắt đầu viết chương trình của mình, tức là chúng ta cần viết một đỉnh và một trình đổ bóng phân đoạn. Đối với vertex shader, mã rất đơn giản vì chúng ta đã quan tâm đến việc sử dụng tọa độ thiết bị chuẩn hóa để mô tả quad của chúng ta trong phần trước. Điều này có nghĩa là các đỉnh không cần phải được chuyển đổi. Tuy nhiên, chúng tôi phải quan tâm đến việc gửi tọa độ 4D mặc dù chúng tôi sẽ chỉ truyền tọa độ 2D [
$ git clone //github.com/mcfletch/openglcontext.git00] nếu không kết quả cuối cùng sẽ không được xác định. Đối với tọa độ
$ git clone //github.com/mcfletch/openglcontext.git01, chúng tôi sẽ chỉ đặt nó thành
$ git clone //github.com/mcfletch/openglcontext.git02 [nhưng bất kỳ giá trị nào cũng được] và đối với tọa độ
$ git clone //github.com/mcfletch/openglcontext.git03, chúng tôi đặt nó thành
$ git clone //github.com/mcfletch/openglcontext.git04 [xem phần giải thích]. Cũng lưu ý các cách khác [đã nhận xét] để viết trình đổ bóng
Đối với trình đổ bóng phân đoạn, nó thậm chí còn đơn giản hơn. Chúng tôi đặt màu thành màu đỏ được mô tả bởi bộ dữ liệu
$ git clone //github.com/mcfletch/openglcontext.git05 trong ký hiệu RGBA được chuẩn hóa.
$ git clone //github.com/mcfletch/openglcontext.git04 cho kênh alpha có nghĩa là mờ hoàn toàn
Chúng tôi đã viết trình đổ bóng của mình và bây giờ chúng tôi cần xây dựng một chương trình sẽ liên kết đỉnh và trình đổ bóng phân đoạn với nhau. Xây dựng chương trình như vậy tương đối đơn giản [miễn là chúng tôi không kiểm tra lỗi]. Trước tiên, chúng tôi cần yêu cầu các vị trí chương trình và trình đổ bóng từ GPU
program = gl.glCreateProgram[] vertex = gl.glCreateShader[gl.GL_VERTEX_SHADER] fragment = gl.glCreateShader[gl.GL_FRAGMENT_SHADER]
Bây giờ chúng tôi có thể yêu cầu biên dịch các shader của chúng tôi thành các đối tượng GPU và chúng tôi ghi lại bất kỳ lỗi nào từ trình biên dịch [e. g. lỗi cú pháp, biến không xác định, v.v.]
Sau đó, chúng tôi liên kết hai đối tượng của mình vào một chương trình và một lần nữa, chúng tôi kiểm tra lỗi trong quá trình
$ git clone //github.com/mcfletch/openglcontext.git0
và chúng ta có thể loại bỏ các shader, chúng sẽ không được sử dụng lại [bạn có thể coi chúng là các tệp
$ git clone //github.com/mcfletch/openglcontext.git07 trong C]
$ git clone //github.com/mcfletch/pyopengl.git0
Cuối cùng, chúng tôi biến chương trình thành chương trình mặc định được chạy. Chúng tôi có thể làm điều đó ngay bây giờ vì chúng tôi sẽ sử dụng một chương trình duy nhất trong ví dụ này
$ git clone //github.com/mcfletch/pyopengl.git1
Tiếp theo, chúng ta cần xây dựng dữ liệu CPU và bộ đệm GPU tương ứng sẽ chứa một bản sao của dữ liệu CPU [GPU không thể truy cập bộ nhớ CPU]. Trong Python, mọi thứ được hỗ trợ rất nhiều bởi NumPy, cho phép kiểm soát chính xác các biểu diễn số. Điều này rất quan trọng vì GLES 2. 0 float phải dài chính xác 32 bit và float Python thông thường sẽ không hoạt động [chúng thực sự tương đương với C
$ git clone //github.com/mcfletch/openglcontext.git08]. Vì vậy, hãy để chúng tôi chỉ định một mảng NumPy chứa float 4×2 32 bit sẽ tương ứng với các đỉnh 4×[x,y] của chúng tôi
Sau đó, chúng tôi tạo trình giữ chỗ trên GPU mà chưa chỉ định kích thước
Bây giờ chúng ta cần liên kết bộ đệm với chương trình, nghĩa là đối với mỗi thuộc tính có trong chương trình vertex shader, chúng ta cần báo cho OpenGL biết nơi tìm dữ liệu tương ứng [i. e. bộ đệm GPU] và điều này yêu cầu một số tính toán. Chính xác hơn, chúng ta cần cho GPU biết cách đọc bộ đệm để liên kết từng giá trị với thuộc tính có liên quan. Để làm điều này, GPU cần biết bước tiến giữa 2 phần tử liên tiếp là gì và độ lệch để đọc một thuộc tính là gì
$ git clone //github.com/mcfletch/pyopengl.git3
Trong kịch bản quad đơn giản của chúng tôi, điều này tương đối dễ viết vì chúng tôi có một thuộc tính duy nhất ["
$ git clone //github.com/mcfletch/openglcontext.git09"]. Trước tiên, chúng tôi yêu cầu vị trí thuộc tính bên trong chương trình và sau đó chúng tôi liên kết bộ đệm với phần bù có liên quan
$ git clone //github.com/mcfletch/pyopengl.git5
Về cơ bản, chúng tôi đang cho chương trình biết cách liên kết dữ liệu với thuộc tính có liên quan. Điều này được thực hiện bằng cách cung cấp bước tiến của mảng [có bao nhiêu byte giữa mỗi bản ghi] và độ lệch của một thuộc tính nhất định
Bây giờ hãy điền dữ liệu CPU của chúng tôi và tải nó lên bộ đệm GPU mới được tạo
Chúng ta đã hoàn tất, bây giờ chúng ta có thể viết lại chức năng hiển thị
$ git clone //github.com/mcfletch/pyopengl.git6
Nhân vật
Một hình tứ giác màu đỏ được hiển thị bằng Python, các liên kết OpenGL thô và GLUT đáng kính
Các đối số
$ git clone //github.com/mcfletch/pyopengl.git00 trong
$ git clone //github.com/mcfletch/pyopengl.git01 cho OpenGL biết chúng tôi muốn hiển thị 4 đỉnh từ bộ đệm hoạt động hiện tại của chúng tôi và chúng tôi bắt đầu từ đỉnh 0. Bạn sẽ có được hình bên phải với cùng màu đỏ [nhàm chán]. Toàn bộ nguồn có sẵn từ code/chapter-03/glute-quad-solid. py
Tất cả các thao tác này đều cần thiết để hiển thị một ô màu duy nhất trên màn hình và độ phức tạp có thể tăng lên khá nhiều nếu bạn thêm nhiều đối tượng, hình chiếu, ánh sáng, kết cấu, v.v. Đây là lý do tại sao chúng tôi sẽ ngừng sử dụng giao diện OpenGL thô để chuyển sang thư viện. Chúng tôi sẽ sử dụng thư viện gumpy, chủ yếu là vì tôi đã viết nó, nhưng cũng vì nó cung cấp sự tích hợp chặt chẽ với numpy. Tất nhiên, bạn có thể thiết kế thư viện của riêng mình để dễ dàng viết các ứng dụng GL Python
Nhân vật
Hình tứ giác màu xanh lam được hiển thị bằng cách sử dụng biến
$ git clone //github.com/mcfletch/pyopengl.git02 chỉ định màu của hình tứ giác
Trong ví dụ trước, chúng tôi đã mã hóa cứng màu đỏ bên trong mã nguồn trình đổ bóng phân đoạn. Nhưng nếu chúng ta muốn thay đổi màu từ bên trong chương trình Python thì sao? . May mắn thay, có một giải pháp đơn giản do OpenGL cung cấp.
$ git clone //github.com/mcfletch/pyopengl.git02. Đồng phục, không giống như các thuộc tính, không thay đổi từ đỉnh này sang đỉnh khác và đây chính xác là những gì chúng ta cần trong trường hợp của mình. Do đó, chúng tôi cần sửa đổi một chút trình đổ bóng phân đoạn của mình để sử dụng màu đồng nhất này
$ tox1
Tất nhiên, chúng ta cũng cần tải một màu lên vị trí thống nhất mới này và điều này dễ dàng hơn so với thuộc tính vì bộ nhớ đã được cấp phát trên GPU [vì kích thước đã biết và không phụ thuộc vào số lượng đỉnh]
$ tox2
Nếu bạn chạy mã mới/glut-quad-uniform-color. py, bạn sẽ nhận được hình tứ giác màu xanh lam như hình bên phải
Nhân vật
Một quad màu sử dụng màu trên mỗi đỉnh
Cho đến bây giờ, chúng tôi đã sử dụng một màu không đổi cho bốn đỉnh của hình tứ giác của chúng tôi và kết quả là [không ngạc nhiên] một hình tứ giác màu đỏ hoặc xanh đồng nhất nhàm chán. Chúng ta có thể làm cho nó thú vị hơn một chút bằng cách gán các màu khác nhau cho mỗi đỉnh và xem OpenGL sẽ nội suy màu như thế nào. Trình tạo bóng đỉnh mới của chúng tôi sẽ cần phải được viết lại thành
program = gl.glCreateProgram[] vertex = gl.glCreateShader[gl.GL_VERTEX_SHADER] fragment = gl.glCreateShader[gl.GL_FRAGMENT_SHADER]0
Chúng tôi vừa thêm thuộc tính mới
$ git clone //github.com/mcfletch/pyopengl.git04 nhưng chúng tôi cũng đã thêm một loại biến mới.
$ git clone //github.com/mcfletch/pyopengl.git05. Loại này thực sự được sử dụng để truyền một giá trị từ trình tạo bóng đỉnh sang trình tạo bóng phân đoạn. Như bạn có thể đoán, loại
$ git clone //github.com/mcfletch/pyopengl.git05 có nghĩa là giá trị này sẽ không cố định trên các mảnh khác nhau mà sẽ được nội suy tùy thuộc vào vị trí tương đối của mảnh trong tam giác, như tôi đã giải thích trong phần. Lưu ý rằng chúng tôi cũng phải viết lại trình đổ bóng phân đoạn của mình cho phù hợp, nhưng bây giờ
$ git clone //github.com/mcfletch/pyopengl.git07 sẽ là đầu vào
program = gl.glCreateProgram[] vertex = gl.glCreateShader[gl.GL_VERTEX_SHADER] fragment = gl.glCreateShader[gl.GL_FRAGMENT_SHADER]1
Bây giờ chúng ta cần tải màu đỉnh lên GPU. Chúng ta có thể tạo một bộ đệm dành riêng cho đỉnh mới và liên kết nó với thuộc tính mới
$ git clone //github.com/mcfletch/pyopengl.git04, nhưng có một giải pháp thú vị hơn. Thay vào đó, chúng tôi sẽ sử dụng một mảng có nhiều mảng và một bộ đệm duy nhất, tận dụng lợi thế của mảng có cấu trúc NumPy