2016-04-08 5 views
2

私は、PythonのOpenGL APIに慣れようとしています。私は、テクスチャクォードができるポイントに達しました。今度は異なるテクスチャを別のクワッドに配置したいので、クワッド要素のサブセットをレンダリングし、テクスチャを変更し、残りのクワッドをレンダリングする必要があります。pythonのOpenGL APIを使用して、要素インデックス配列のサブセットでどのようにglDrawElementsを実行しますか?

# based on http://www.pygame.org/wiki/GLSLExample 


import sys 

import pygame 

import OpenGL.GL as gl 
import OpenGL.GLU as glu 
import OpenGL.GLUT as glut 
from OpenGL.arrays import vbo 
import numpy 
from math import * 
from PIL import Image 


def compile_shader(source, shader_type): 
    shader = gl.glCreateShader(shader_type) 
    #source = c_char_p(source) 
    length = -1 #c_int(-1) 
    gl.glShaderSource(shader, source) 
    gl.glCompileShader(shader) 

    status = gl.glGetShaderiv(shader, gl.GL_COMPILE_STATUS) 
    if not status: 
     print_log(shader) 
     gl.glDeleteShader(shader) 
     raise ValueError('Shader compilation failed') 
    return shader 


def compile_program(vertex_source, fragment_source): 
    vertex_shader = None 
    fragment_shader = None 
    program = gl.glCreateProgram() 

    if vertex_source: 
     vertex_shader = compile_shader(vertex_source, gl.GL_VERTEX_SHADER) 
     gl.glAttachShader(program, vertex_shader) 
    if fragment_source: 
     fragment_shader = compile_shader(fragment_source, gl.GL_FRAGMENT_SHADER) 
     gl.glAttachShader(program, fragment_shader) 

    gl.glLinkProgram(program) 

    if vertex_shader: 
     gl.glDeleteShader(vertex_shader) 
    if fragment_shader: 
     gl.glDeleteShader(fragment_shader) 

    return program 


def load_texture(file_name): 
    image = Image.open(file_name) 
    width = image.size[0] 
    height = image.size[1] 
    image_bytes = image.convert("RGBA").tobytes ("raw", "RGBA", 0, -1) 
    texture = gl.glGenTextures(1) 

    gl.glBindTexture  (gl.GL_TEXTURE_2D, texture) 
    gl.glTexParameterf (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_REPEAT) 
    gl.glTexParameterf (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_REPEAT) 
    gl.glTexParameteri (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER,gl.GL_NEAREST) 
    gl.glTexParameteri (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER,gl.GL_LINEAR_MIPMAP_LINEAR) 


    glu.gluBuild2DMipmaps (gl.GL_TEXTURE_2D, gl.GL_RGBA, width, height, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, image_bytes) 

    return texture 

def perspective_matrix(fov, aspect_, near, far): 
    # https://www.opengl.org/discussion_boards/showthread.php/166405-Perspective-Matrix-implementation 

    f = 1/tan(fov/2) 
    #print(f, fov) 
    wiggy = -2 * far * near/(far - near) 
    aspect = aspect_ 
    return numpy.matrix([ 
          [ f/aspect, 0, 0, 0], 
          [0, f, 0, 0], 
          [0, 0, (far+near)/(near-far), wiggy], 
          [0, 0, -1, 0]] , dtype=numpy.float32) 


def print_log(shader): 

    length = gl.glGetShaderiv(shader, gl.GL_INFO_LOG_LENGTH) 

    if length > 0: 

     log = gl.glGetShaderInfoLog(shader) 
     print(log, file=sys.stderr) 

# 
# 
# 

def translation_matrix(x, y, z): 
    return numpy.matrix([[1, 0, 0, x], 
         [0, 1, 0, y], 
         [0, 0, 1, z], 
         [0, 0, 0, 1]], numpy.float32) 


def scale_matrix(scale): 
    return numpy.array([[scale, 0, 0, 0], 
         [0, scale, 0, 0], 
         [0, 0, scale, 0], 
         [0, 0, 0, 1]], numpy.float32) 


def norm4(mat): 
    return [mat, mat/mat[0,3] ] 


def rotation_matrix(radians, axis): 
    len = sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]) 
    x = axis[0]/len 
    y = axis[1]/len 
    z = axis[2]/len 

    c = cos(radians) 
    s = sin(radians) 
    t=1-c 

    # http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/ 
    return numpy.matrix([[ t*x*x + c, t*x*y - z*s, t*x*z + y*s, 0], 
          [ t*x*y + z*s, t*y*y + c, t*y*z - x*s, 0], 
          [ t*x*z - y*s, t*y*z + x*s, t*z*z + c, 0], 
          [0,0,0,1]], dtype=numpy.float32) 


def attributes(handle): 
    # http://nullege.com/codes/show/src%40p%40y%40PyGLy-HEAD%40pygly%40shader.py/210/OpenGL.GL.glGetActiveAttrib/python 
    """Returns an iterator for the attributes of the specified program. 

    Each attribute returns a tuple. 

    :rtype: (name, size, type) 
    :return: A tuple consisting of 3 values: 
     name is the variable name 
     size is the variable size in bytes 
     type is the GL enumeration 
    """ 
    # get number of active uniforms 
    num_attributes = gl.glGetProgramiv(handle, gl.GL_ACTIVE_ATTRIBUTES) 

    for index in range(num_attributes): 
     yield attribute_for_index(handle, index) 

def attribute_for_index(handle, index): 
    """Returns the attribute for the specified attribute index. 

    :rtype: tuple(name, size, type) 
    """ 
    # Constants like GLsizei are only found in OpenGL.constants 
    # for older versions of pyopengl 
    name_length = 30 
    glNameSize = (gl.constants.GLsizei)() 
    glSize = (gl.constants.GLint)() 
    glType = (gl.constants.GLenum)() 
    glName = (gl.constants.GLchar * name_length)() 

    gl.glGetActiveAttrib(
     handle, 
     index, 
     name_length, 
     glNameSize, 
     glSize, 
     glType, 
     glName 
     ) 

    name, size, type = glName.value, glSize.value, glType.value 
    return name, size, type 


def app(): 
    glut.glutInit(sys.argv) 
    width, height = 640, 480 
    pygame.init() 
    pygame.display.set_mode((width, height), pygame.OPENGL | pygame.DOUBLEBUF) 

    program = compile_program(''' 
    // Vertex program 
    attribute vec2 vertex_uv; 
    uniform mat4 mvp; 
    varying vec3 pos; 
    varying vec2 texCoord; 
    void main() { 
     pos = gl_Vertex.xyz; 
     gl_Position = mvp * gl_Vertex; 
     texCoord = vertex_uv; 
    } 
    ''', ''' 
    // Fragment program 
    varying vec3 pos; 
    varying vec2 texCoord; 
    uniform sampler2D tex; 
    void main() { 
     gl_FragColor.rgb = texture(tex, texCoord); 
     //gl_FragColor.r = 0.5; 
    } 
    ''') 

    persp =perspective_matrix(pi/4, 1024/float(768), 0.01, 1000) 


    mat_loc = gl.glGetUniformLocation(program, bytes("mvp", "ascii")) 
    print(mat_loc) 
    uv_loc = gl.glGetAttribLocation(program, bytes("vertex_uv", "ascii")) 
    print(uv_loc) 
    tmp = gl.glGetAttribLocation(program, bytes("gl_Vertex", "ascii")) 
    print([ "gl_Vertex", tmp]) 

    tex_loc = gl.glGetUniformLocation(program, bytes("tex", "ascii")) 
    print(["tex uniform location", tex_loc]) 

    if False: 
     name_length = 30 
     glNameSize = (gl.constants.GLsizei)() 
     glSize = (gl.constants.GLint)() 
     glType = (gl.constants.GLenum)() 
     glName = (gl.constants.GLchar * name_length)() 
     gl.glGetActiveAttrib(program,1, 
          name_length, 
          glNameSize, 
          glSize, 
          glType, 
          glName) 
     print(glName.value) 

     for name,y,z in attributes(program): 
      print([name,y,z, gl.glGetAttribLocation(program, name)]) 


    gl.glEnable(gl.GL_DEPTH_TEST) 


    vertices = [-1, -1, -1, 
       1, -1, -1, 
       1, 1, -1, 
       -1, 1, -1, 

       -1, -1, 1, 
       1, -1, 1, 
       1, 1, 1, 
       -1, 1, 1] 
    uvs = [0,0, 
      1,0, 
      1,1, 
      0,1, 

      0,0, 
      1,0, 
      1,1, 
      0,1, 

      ] 
    indices = [0,1,2,3, 
       4,5,6,7, 
#    8,9,10,11, 
#    12,13,14,15, 
#    16,17,18,19, 
#    20,21,22,23 
    ] 

    vert_buffer = vbo.VBO(numpy.array(vertices, dtype=numpy.float32)) 
    uv_buffer = vbo.VBO(numpy.array(uvs, dtype=numpy.float32)) 
    index_buffer = vbo.VBO(numpy.array(indices, dtype=numpy.uint16), target=gl.GL_ELEMENT_ARRAY_BUFFER) 

    # 

    texture1 = load_texture("bear64.png") 
    texture2 = load_texture("flamingo64.gif") 

    # 

    quit = False 
    angle = 0 

    gl.glUseProgram(program) 

    # bind all our buffers out here because this scene is so static 
    index_buffer.bind() 
    vert_buffer.bind() 
    gl.glEnableVertexAttribArray(0); 
    gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, False, 0, None) 

    if uv_loc>=0: 
     uv_buffer.bind() 
     gl.glEnableVertexAttribArray(uv_loc) 
     gl.glVertexAttribPointer(uv_loc, 2, gl.GL_FLOAT, False, 0, None) 

    import time 
    while not quit: 
     t0 = time.time() 
     for e in pygame.event.get(): 

      if e.type == pygame.QUIT: 
       quit=True 
      elif e.type == pygame.KEYDOWN: 
       print(e.key) 
       if e.key == pygame.K_q: 
        quit = True 


     gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) 
     z = (t0/10)%1 

     mvp = persp*translation_matrix(0,0,-5)* scale_matrix(1) * rotation_matrix(pi*0.4, [-1,0,0]) *rotation_matrix(z*pi*2, [0,0,1]) 
     #print(mvp.dot([0,0,0,1])) 
     mvp_ = numpy.asfortranarray(mvp, dtype=numpy.float32) 
     gl.glUniformMatrix4fv(mat_loc, 1, False, mvp_) 
     gl.glBindTexture(gl.GL_TEXTURE_2D, texture1) 
     gl.glUniform1i(tex_loc, 0) 


     gl.glDrawElements(gl.GL_QUADS, 4, gl.GL_UNSIGNED_SHORT, None) 

     gl.glBindTexture(gl.GL_TEXTURE_2D, texture2) 
     #gl.glDrawElements(gl.GL_QUADS, len(indices)-4, gl.GL_UNSIGNED_SHORT, 4*2) 


     pygame.display.flip() 


if __name__ == '__main__': 
    app() 

この例がどれほど巨大であるかをお詫び申し上げますが、OpenGLはコンパクトではありません。

私の質問は:から構築されたindex_bufferの残りの四角形を描画するように、gl.glDrawElementsを呼び出すにはどうすればよいですか?私が見たすべての例は、ポインタフィールドにNoneを使用しています。これはwebGLと対照的に、0は要素の先頭から、i*2からはi番目のインデックスから開始することができます。

この例を実行するには、bear64.pngとflamingo64.gifが必要です。すべての古いイメージが機能するはずですが、http://www.purplefrog.com/~thoth/wow/bear-64.gifを試すことができます。 OpenGLの4参照(glBindBuffer)から

+0

https://www.opengl.org/sdk/docs/man:あなたのケースではINDEX_TYPEがSHORTで、SHORTサイズはトリックは値がそうのようなCのvoidポインタにキャストしなければならないことである2です/html/glDrawRangeElements.xhtml私は別の活動に走っていますが、これがあなたの答えかもしれません。明日はそれに近づきます。がんばろう。 – Andreas

+0

その呼び出しを試した後、その開始と終了のパラメータは、インデックス配列によって参照される頂点インデックスを束縛すると思います( 'start <= indices [i] <= end'を意味し、' [0..count ) ')、頂点バッファ全体のロードを避けることができます。私は、私の使命を達成するために、何もなしではなく指標に渡すべきものを見つけ出す必要があると考えます。 –

答えて

1

非ゼロのバッファ・オブジェクトが GL_ELEMENT_ARRAY_BUFFER対象、 glDrawElements、glDrawElementsInstanced、glDrawElementsBaseVertex、 glDrawRangeElements、glDrawRangeElementsBaseVertexのインデックスパラメータにバインドされているが、 glMultiDrawElements、またはglMultiDrawElementsBaseVertexは、基本マシン 単位で測定されたバッファオブジェクト内のオフセットとして と解釈されます。

"基本機械単位"にオフセットを入力する必要があります。実際はstart_index * index_type_sizeです。

gl.glDrawElements(gl.GL_QUADS, len(indices)- start, 
        gl.GL_UNSIGNED_SHORT, ctypes.c_void_p(start*2)). 
+0

'None'を' 4 * 2'に変更して、インデックス配列の4番目の短い部分から開始しようとすると、何も描画されません。これはNoneの代わりに0を使うと失敗します。 'gl.glDrawElements(gl.GL_QUADS、4、gl.GL_UNSIGNED_SHORT、0)' –

+0

最後の引数としてc_void_ptrを強制してみてください:gl.glDrawElements(gl.GL_QUADS、4、gl。 GL_UNSIGNED_SHORT、ctypes.c_void_ptr(start * size)) – Andreas

+0

ほぼ。実行した行は 'gl.glDrawElements(gl.GL_QUADS、len(indices) - start、gl.GL_UNSIGNED_SHORT、ctypes.c_void_p(start * 2))でした。'そのコードサンプルをあなたの答えに組み込み、それを受け入れたものとしてマークします。 –

関連する問題