2017-04-11 35 views
0

我試圖繪製大量的頂點(類似於點雲)。試圖在OpenGL中更新500多個頂點位置會導致讀取訪問衝突?

同時我也在學習如何使用VBOs並將Numpy數組傳遞給GLSL程序併爲頂點位置設置動畫。

我想我已經取得了一些進展,但是我很限於我多大可以設置array_size參數和任何超過500通常會導致一個錯誤:WindowsError: exception: access violation reading 0x0999B000

有時工作(隨機),我只是想知道如果我在分配內存或緩衝數組的方式上犯了一個錯誤?

只是爲了添加備註,未來我希望一次更新2500多個頂點位置。並想知道我能如何做到這一點?

array_size = 100

#!/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() 

[更新]

我相信我已經回答了我的問題,當我意識到我沒有正確鑄件我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() 

回答

2

的問題是,你總體上沒有指定dtype,這導致float64被選爲dtype

print(vertices.dtype) 
print(colors.dtype) 
print(indices.dtype) 

這應該打印"float32", "float32", "uint32"。然而它打印"float64", "float64", "int32"

問題是,現在你的數據是大小的兩倍。 因此,當您撥打glBufferData()時,您告訴您的data是實際尺寸的兩倍(與您實際給出的尺寸相反)。


那是什麼觸發了access violation reading 0x0999B000,因爲你的駕駛人要你給它的數據的邊界之外讀取數據。

來解決這將是建立頂點後做以下最簡單的方法:

vertices = vertices.astype(np.float32) 
colors = colors.astype(np.float32) 
indices = indices.astype(np.uint32) 

現在你就可以儘可能多的頂點添加爲您的RAM和VRAM允許!


最後挽救自己從未來的頭痛,調用glBufferData()vertices之前添加以下內容:

assert vertices.dtype == np.float32 

同樣爲colorsindices(使用np.uint32代替)這樣做。

如果數據類型不是所需的數據類型,則會觸發斷言。


對於指數小於2 您是否使用int32uint32不會做出改變-1。然而,採用預期類型可能是明智的做法,從而避免在未來意外跳閘。 儘管您可能無法達到此數量的指數或任何其他人。但比對不起更安全。

+0

非常感謝您的回答!我也發現了這一點(可能是因爲你正在打字)!我用修改後的代碼更新了我的帖子,完全按照您的建議。我會接受這個答案作爲答案,因爲它具有很好的描述性,並且可以解決原始問題。 – Logic1

+0

不客氣!同樣道具也讓你自己找到答案! :) – Vallentin