Я пытаюсь нарисовать игру жизни с opengl. Он отлично работает в обычном pygame, но я читал, что glTexImage2D - это способ быстро нарисовать материал уже в массиве. Я ознакомился с примерами и документами, но не только изрядным количеством ссылок на ссылки, но они были написаны для python 2, поэтому я не могу даже запустить их много, не переведя его. Я заметил, что в отличие от большинства современных графических пакетов, opengl на самом деле ничего не возвращает, поэтому я думаю, что просто не применяю текстуру правильно. (например, в pygame вы создадите поверхность, затем примените возвращаемую поверхность). Код conways работает, принимая живые и мертвые значения и dtype, а затем выполняет всю необходимую проверку, основанную исключительно на аргументах конструктора, что означает, что я могу изменить его с ubyte, чтобы плавать в мгновение ока, поэтому, если это это замечательно.
На данный момент это просто черный экран. Когда pygame.display.flip() удаляется, он просто остается белым, поэтому теоретически что-то рисуется где-то, чтобы изменить его на черный. У меня такое чувство, что проблема кроется в методе glbindtexture, но, честно говоря, я не знаю, что это за решение.
Я положу код conways на всякий случай, если кто-то захочет его запустить. В режиме pygame я масштабирую изображение по переменной масштаба, но для opengl я просто хочу, чтобы он запускался первым, поэтому размер массива контуров теперь будет размером окна, следовательно, 400. Это означает, что это займет немного, но как только заголовок окна будет обновлен, появится индикатор того, что обновление завершено.
выдвижной ящик:
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
from random import random,seed
import numpy as np
from conways3 import Conways
from time import time
size = 400;
scale = 1;
conways = Conways(size,dead=0.0,alive=1.0,dtype=np.ubyte)
pygame.init()
flags = OPENGL|HWSURFACE|DOUBLEBUF
display = pygame.display.set_mode((size*scale, size*scale),flags)
########OPTIMIZATIONS##########
pygame.event.set_allowed([pygame.QUIT]);
###############################
running = True
clock = pygame.time.Clock()
t1 = t2 = t3 = 0
glEnable(GL_TEXTURE_2D)
try:
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
clock.tick()
t1 = time()
Z = conways.update()
t2 = time()
tid = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, tid)
glPixelStorei(GL_UNPACK_ALIGNMENT,1)
glTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE, size,size,0,GL_LUMINANCE, GL_UNSIGNED_BYTE, Z)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
## surf = pygame.surfarray.make_surface(Z)
## display.blit(pygame.transform.scale(surf,(size*scale, size*scale)), (0, 0))
## pygame.display.update()
pygame.display.flip()
t3 = time()
pygame.time.wait(10)
pygame.display.set_caption("fps: {:.4f} calc: {:.4f} draw: {:.4f} tot: {:.4f}".format(clock.get_fps(), t2-t1, t3-t2,t3-t1))
## print(t2-t1)
except Exception as e:
print('-'*20)
print(e)
pygame.quit()
Conways:
from random import random, seed
import numpy as np
from time import time
class Conways:
def __init__(self,size,dead=False,alive=True,dtype = np.bool8):
seed(1)
self.using1 = True;
self.size = size;
self.dead = dead;
self.alive = alive;
self.dtype = dtype;
self.arr1 = np.zeros((self.size,self.size),dtype=self.dtype);
self.arr2 = np.zeros((self.size,self.size),dtype=self.dtype);
for i in range(self.size):
for j in range(self.size):
self.arr1[i][j] = self.alive*(random() < 0.5);
def calcNeighbors(self,arr, i, j):
count = -1*arr[i][j];
for x in range(-1, 2):
for y in range(-1, 2):
count += (arr[(x+i)%self.size][(y+j)%self.size] == self.alive);
return count;
def calcEffi(self,arr, i, j):
count = 0
maxi = self.size - 1
if i > 0:
count += arr[i - 1][j] == self.alive
if i < maxi:
count += arr[i + 1][j] == self.alive
if j > 0:
count += arr[i][j - 1] == self.alive
if i > 0:
count += arr[i - 1][j - 1] == self.alive
if i < maxi:
count += arr[i + 1][j - 1] == self.alive
if j < maxi:
count += arr[i][j + 1] == self.alive
if i > 0:
count += arr[i - 1][j + 1] == self.alive
if i < maxi:
count += arr[i + 1][j + 1] == self.alive
return count;
def calc(self,arr1, arr2):
for i in range(self.size):
for j in range(self.size):
neighbors = self.calcEffi(arr1, i, j);
if neighbors < 2 or neighbors > 3:
arr2[i][j] = self.dead;
elif neighbors == 3:
arr2[i][j] = self.alive;
else:
arr2[i][j] = arr1[i][j];
def update(self):
if self.using1:
self.calc(self.arr1,self.arr2);
else:
self.calc(self.arr2,self.arr1);
self.using1 = not self.using1;
return self.arr2 if self.using1 else self.arr1;
Поскольку значения массива находятся в диапазоне [0, 1], вы должны использовать float32
соответственно GL_FLOAT
:
conways = Conways(size,dead=0.0,alive=1.0,dtype=np.float32)
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, size, size, 0, GL_LUMINANCE, GL_FLOAT, Z)
Но главная проблема заключается в том, что вы ничего не рисуете. Вы должны нарисовать квадрат на весь видовой экран с текстурой, обернутой на нем:
glBindTexture(GL_TEXTURE_2D, tid)
glPixelStorei(GL_UNPACK_ALIGNMENT,1)
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, size,size, 0, GL_LUMINANCE, GL_FLOAT, Z)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glBegin(GL_TRIANGLE_FAN)
glTexCoord2f(0, 1)
glVertex2f(-1, -1)
glTexCoord2f(1, 1)
glVertex2f(1, -1)
glTexCoord2f(1, 0)
glVertex2f(1, 1)
glTexCoord2f(0, 0)
glVertex2f(-1, 1)
glEnd()
Или используйте glEnableClientState
, glVertexPointer
, glTexCoordPointer
и glDrawArrays
для рисования на видовом glDrawArrays
:
vertices = np.array([-1, -1, 1, -1, 1, 1, -1, 1], dtype=np.float32)
tex_coords = np.array([0, 1, 1, 1, 1, 0, 0, 0], dtype=np.float32)
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(2, GL_FLOAT, 0, vertices)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glTexCoordPointer(2, GL_FLOAT, 0, tex_coords)
glDrawArrays(GL_TRIANGLE_FAN, 0, 4)
glDisableClientState(GL_VERTEX_ARRAY)
glDisableClientState(GL_TEXTURE_COORD_ARRAY)
Но обратите внимание, что рисование с помощью glBegin
/glEnd
последовательностей, а также клиентская способность конвейера фиксированной функции OpenGL устарела с десятилетий. Читайте о трубопроводе с фиксированной функциональностью и см. Спецификация вершин и шейдер для современного способа рендеринга.