我试图绘制大量顶点(类似于点云)。
与此同时,我也在尝试学习如何使用VBO并将Numpy数组传递给GLSL程序并为顶点位置设置动画。
我认为我已经取得了一些进展但是我受限于我可以设置array_size
参数的大小,而超过500的任何内容通常会导致错误:WindowsError: exception: access violation reading 0x0999B000
有时它(随机)工作,我只是想知道我在分配内存或缓冲数组方面是否犯了错误?
只是添加一个注释,将来我希望一次更新2500多个顶点位置。并且想知道我怎么能做到这一点?
#!/bin/env python
# coding: utf-8
import time
import numpy as np
from textwrap import dedent
from OpenGL.GL import *
from OpenGL.GL.shaders import compileShader, compileProgram
import pygame
from pygame.locals import *
##############################################################################
# OpenGL funcs
##############################################################################
buffers=None
shader = None
def init_gl():
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE) #allow the program to specify the point size
global shader, buffers
vertex_shader = compileShader(dedent('''
uniform mat4 Projection = mat4(1);
uniform mat4 ModelView = mat4(1);
varying out vec3 _color;
void main() {
_color = gl_Color;
gl_Position = Projection * ModelView * gl_ModelViewProjectionMatrix * gl_Vertex;
vec3 ndc = gl_Position.xyz / gl_Position.w ; // perspective divide.
float zDist = 1.0-ndc.z ; // 1 is close (right up in your face,)
// 0 is far (at the far plane)
gl_PointSize = 25*zDist ; // between 0 and 50 now.
}
'''), GL_VERTEX_SHADER)
fragment_shader = compileShader(dedent('''
in vec3 _color;
void main() {
gl_FragColor = vec4(_color, 1.0); //gl_Color;
}
'''), GL_FRAGMENT_SHADER)
shader = compileProgram(vertex_shader, fragment_shader)
buffers=create_vbo()
yaw=0
pitch=0
def draw():
global yaw, pitch
glClear(GL_COLOR_BUFFER_BIT)# | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
yaw+=0.39
pitch+=0.27
glTranslatef(0.0, 0.0, 0.0)
glRotatef(yaw, 0, 1, 0)
glRotatef(pitch, 1, 0, 0)
setPoints()
glFlush()
##############################################################################
# vertices
##############################################################################
array_size = 1000
scale = 0.15
#create dataset https://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html
theta = np.linspace(-4 * np.pi, 4 * np.pi, array_size)
z = np.linspace(-2, 2, array_size)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
vertices = np.dstack((x,y,z)) * scale
colors = np.tile(np.array([0.0, 1.0, 0.0]), (array_size,1)) #a bunch of green vertices
indices=np.arange(array_size)
def create_vbo():
buffers = glGenBuffers(3)
glBindBuffer(GL_ARRAY_BUFFER, buffers[0])
glBufferData(GL_ARRAY_BUFFER,
vertices.nbytes, # byte size
(ctypes.c_float*len(vertices.flat))(*vertices.flat),
GL_STREAM_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, buffers[1])
glBufferData(GL_ARRAY_BUFFER,
colors.nbytes, # byte size
(ctypes.c_float*len(colors.flat))(*colors.flat),
GL_STATIC_DRAW)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2])
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
indices.nbytes, # byte size
(ctypes.c_uint*len(indices.flat))(*indices.flat),
GL_STATIC_DRAW)
return buffers
def draw_vbo():
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glVertexPointer(3, GL_FLOAT, 0, None);
glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
glColorPointer(3, GL_FLOAT, 0, None);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2]);
glDrawElements(GL_POINTS, indices.size, GL_UNSIGNED_INT, None);
glDisableClientState(GL_COLOR_ARRAY)
glDisableClientState(GL_VERTEX_ARRAY);
def setPoints():
global shader
glUseProgram(shader)
draw_vbo()
projection = np.array([#the matrix generated captured while using HTC Vive
[ 0.75752085, 0. , 0. , 0.],
[ 0. , 0.68160856, 0. , 0.],
[ 0.05516453, -0.00299519, -1.00040019, -1.],
[ 0. , 0. , -0.20008004, 0.]
])
modelview = np.array([#the matrix generated captured while using HTC Vive
[ 0.99030989, 0.04490654, 0.13141415, 0.],
[-0.01430531, 0.9742285 , -0.22510922, 0.],
[-0.13813627, 0.22104797, 0.9654305 , 0.],
[-0.12975544, -0.9294402 , -1.06236947, 1.]
])
glUniformMatrix4fv(glGetUniformLocation(shader, "Projection"), 1, False, projection)
glUniformMatrix4fv(glGetUniformLocation(shader, "ModelView"), 1, False, modelview)
glUseProgram(0)
##############################################################################
if __name__ == '__main__':
pygame.init()
pygame.display.set_mode((800, 600), HWSURFACE|OPENGL|DOUBLEBUF)
init_gl()
start_time = time.time()
while time.time() - start_time < 5: #5 second animation
draw()
pygame.display.flip()
[UPDATE]
我相信当我意识到我没有正确地投射Numpy数组的数据类型时,我已回答了我自己的问题。因此,当我创建它们时,通过向我的数组添加.astype()
,我已经设法获得2000+顶点以显示和动画:)
vertices = (np.dstack((x,y,z)) * scale).astype(np.float32)
colors = (np.tile(np.array([0.0, 1.0, 0.0]), (array_size,1))).astype(np.float32) #a bunch of green vertices
indices = np.arange(array_size).astype(np.uint32)
这是固定的例子:
#!/bin/env python
# coding: utf-8
import time
import numpy as np
from textwrap import dedent
from OpenGL.GL import *
from OpenGL.GL.shaders import compileShader, compileProgram
import pygame
from pygame.locals import *
##############################################################################
# OpenGL funcs
##############################################################################
buffers=None
shader = None
def init_gl():
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE) #allow the program to specify the point size
global shader, buffers
vertex_shader = compileShader(dedent('''
uniform mat4 Projection = mat4(1);
uniform mat4 ModelView = mat4(1);
varying out vec3 _color;
void main() {
_color = gl_Color;
gl_Position = Projection * ModelView * gl_ModelViewProjectionMatrix * gl_Vertex;
vec3 ndc = gl_Position.xyz / gl_Position.w ; // perspective divide.
float zDist = 1.0-ndc.z ; // 1 is close (right up in your face,)
// 0 is far (at the far plane)
gl_PointSize = 25*zDist ; // between 0 and 50 now.
}
'''), GL_VERTEX_SHADER)
fragment_shader = compileShader(dedent('''
in vec3 _color;
void main() {
gl_FragColor = vec4(_color, 1.0); //gl_Color;
}
'''), GL_FRAGMENT_SHADER)
shader = compileProgram(vertex_shader, fragment_shader)
buffers=create_vbo()
yaw=0
pitch=0
def draw():
global yaw, pitch
glClear(GL_COLOR_BUFFER_BIT)# | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
yaw+=0.39
pitch+=0.27
glTranslatef(0.0, 0.0, 0.0)
glRotatef(yaw, 0, 1, 0)
glRotatef(pitch, 1, 0, 0)
setPoints()
glFlush()
##############################################################################
# vertices
##############################################################################
array_size = 2000
scale = 0.15
#create dataset https://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html
theta = np.linspace(-4 * np.pi, 4 * np.pi, array_size)
z = np.linspace(-2, 2, array_size)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
vertices = (np.dstack((x,y,z)) * scale).astype(np.float32)
colors = (np.tile(np.array([0.0, 1.0, 0.0]), (array_size,1))).astype(np.float32) #a bunch of green vertices
indices = np.arange(array_size).astype(np.uint)
def create_vbo():
buffers = glGenBuffers(3)
glBindBuffer(GL_ARRAY_BUFFER, buffers[0])
glBufferData(GL_ARRAY_BUFFER,
vertices.nbytes, # byte size
(ctypes.c_float*len(vertices.flat))(*vertices.flat),
GL_STREAM_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, buffers[1])
glBufferData(GL_ARRAY_BUFFER,
colors.nbytes, # byte size
(ctypes.c_float*len(colors.flat))(*colors.flat),
GL_STATIC_DRAW)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2])
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
indices.nbytes, # byte size
(ctypes.c_uint*len(indices.flat))(*indices.flat),
GL_STATIC_DRAW)
return buffers
def draw_vbo():
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glVertexPointer(3, GL_FLOAT, 0, None);
glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
glColorPointer(3, GL_FLOAT, 0, None);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2]);
glDrawElements(GL_POINTS, indices.size, GL_UNSIGNED_INT, None);
glDisableClientState(GL_COLOR_ARRAY)
glDisableClientState(GL_VERTEX_ARRAY);
def setPoints():
global shader
glUseProgram(shader)
draw_vbo()
projection = np.array([#the matrix generated captured while using HTC Vive
[ 0.75752085, 0. , 0. , 0.],
[ 0. , 0.68160856, 0. , 0.],
[ 0.05516453, -0.00299519, -1.00040019, -1.],
[ 0. , 0. , -0.20008004, 0.]
])
modelview = np.array([#the matrix generated captured while using HTC Vive
[ 0.99030989, 0.04490654, 0.13141415, 0.],
[-0.01430531, 0.9742285 , -0.22510922, 0.],
[-0.13813627, 0.22104797, 0.9654305 , 0.],
[-0.12975544, -0.9294402 , -1.06236947, 1.]
])
glUniformMatrix4fv(glGetUniformLocation(shader, "Projection"), 1, False, projection)
glUniformMatrix4fv(glGetUniformLocation(shader, "ModelView"), 1, False, modelview)
glUseProgram(0)
##############################################################################
if __name__ == '__main__':
pygame.init()
pygame.display.set_mode((800, 600), HWSURFACE|OPENGL|DOUBLEBUF)
init_gl()
start_time = time.time()
while time.time() - start_time < 5: #5 second animation
draw()
pygame.display.flip()
答案 0 :(得分:2)
问题在于,您总体上没有指定dtype
,这导致float64
被选为dtype
。
print(vertices.dtype)
print(colors.dtype)
print(indices.dtype)
应打印"float32", "float32", "uint32"
。但它会打印"float64", "float64", "int32"
。
问题在于现在您的数据是两倍大小。
因此,当您致电glBufferData()
时,您告诉size
data
access violation reading 0x0999B000
的实际尺寸是实际尺寸的两倍(与您实际给出的相比)它)。
这就是触发vertices = vertices.astype(np.float32)
colors = colors.astype(np.float32)
indices = indices.astype(np.uint32)
的原因,因为您的驱动程序正在尝试读取您提供的数据范围之外的数据。
最简单的修复方法是在设置顶点后执行以下操作:
glBufferData()
现在,您可以添加与RAM和VRAM一样多的顶点!
最后为了避免将来头痛,请在使用vertices
致电assert vertices.dtype == np.float32
之前添加以下内容:
colors
对indices
和np.uint32
同样执行此操作(请改用int32
)。
如果数据类型不是所需的数据类型,则会触发断言。
对于小于2 31 -1的指数,无论您使用uint32
还是{{1}}都不会进行更改。然而,采用预期的类型可能是明智的,从而避免在将来意外地绊倒自己。 即使您可能无法达到该数量的指数或任何其他人。但比抱歉更安全。