4

My vertices are interleaved in a numpy array (dtype = float32) like this: ... tu, tv, nx, ny, nz, vx, vy, vz, ...

When rendering, I'm calling gl*Pointer() like this (I have enabled the arrays before):

stride = (2 + 3 + 3) * 4
glTexCoordPointer( 2, GL_FLOAT, stride, self.vertArray )
glNormalPointer( GL_FLOAT, stride, self.vertArray + 2 )
glVertexPointer( 3, GL_FLOAT, stride, self.vertArray + 5 )
glDrawElements( GL_TRIANGLES, len( self.indices ), GL_UNSIGNED_SHORT, self.indices )

The result is that nothing renders. However, if I organize my array so that the vertex position is the first element ( ... vx, vy, vz, tu, tv, nx, ny, nz, ... ) I get correct positions for vertices while rendering but texture coords and normals aren't rendered correctly.

This leads me to believe that I'm not setting the pointer offset right. How should I set it? I'm using almost the exact same code in my other app in C++ and it works.

SurvivalMachine
  • 7,946
  • 15
  • 57
  • 87
  • I'm not a PyOpenGL user, but from your description, it sounds like the + on arrays does not do what you think it does in that language. Time to check the language spec ? – Bahbar Apr 21 '10 at 14:43
  • @Bahbar: That's what I thought, but I haven't been able to find any information about it. I have googled a lot to no avail. – SurvivalMachine Apr 21 '10 at 15:41

4 Answers4

3

In python, you can't do pointer arithmetic. What you're trying to do only works for C/C++.

With normal Python list:

>>> array = [1, 2, 3, 4]
>>> array
[1, 2, 3, 4]
>>> array + 2
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: can only concatenate list (not "int") to list

With numpy arrays:

>>> import numpy
>>> a = numpy.array([1, 2, 3])
>>> a + 2
array([3, 4, 5])

See how neither does what you want: starting the array at a certain position.

I think you have basically two options:

  1. Don't use interleaved arrays. This does have one advantage: when you only need to update the vertices (like in bone animations), you don't need to update the texture coordinates.
  2. Using slices might work for you.

Like this:

>>> a = numpy.array(range(10))
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a[3:]
array([3, 4, 5, 6, 7, 8, 9])

Combine this with a correct stride, you can probably get it to work.

Xavier Ho
  • 17,011
  • 9
  • 48
  • 52
  • @Xavier Ho: Thanks, using slices did the trick! However, I don't know about its performance, so I must run some tests. – SurvivalMachine Apr 26 '10 at 16:48
  • @SurvivalMachine: The only downside of using slices is that it creates a new copy of your list. I can't think of another way to overcome that at the moment. – Xavier Ho Apr 26 '10 at 16:51
3

I ran into a similar problem and found that casting the offset to ctypes.c_void_p did the trick.

from ctypes import c_void_p

t_size = self.vertArray.itemsize * 2
n_size = self.vertArray.itemsize * 3

t_offset = c_void_p(0)
n_offset = c_void_p(t_size)
v_offset = c_void_p(t_size+n_size)

glTexCoordPointer( 2, GL_FLOAT, stride, t_offset )
glNormalPointer( GL_FLOAT, stride, n_offset )
glVertexPointer( 3, GL_FLOAT, stride, v_offset )
glDrawElements( GL_TRIANGLES, len( self.indices ), GL_UNSIGNED_SHORT, self.indices )
Exide
  • 859
  • 8
  • 24
  • This example looks promising, but the I don't think just passing in the byte offsets as the last parameter in the glPointer will work. The 3rd parameter is intended to be a pointer into an array, not an offset. – ahoffer Jul 25 '11 at 19:12
  • I spent a good chunk of today running into this problem myself, so even though the thread is old I'm chiming in in case it helps anybody else. Exide is correct because, e.g., http://www.opengl.org/sdk/docs/man2/xhtml/glVertexPointer.xml says that glVertexPointer evaluates the fourth argument as an offset when glBindBuffer / glBufferData is in effect. What his code snippet fails to show is how to do that with self.vertArray. – jdowdell Jul 18 '13 at 05:46
  • Like @jdowdell said, the last argument is an offset. I'm not sure what more I could add with regard to ```self.vertArray```. I simply took it from the original question. – Exide Apr 13 '16 at 22:47
0

I'm answering my own question, because I found an alternative way to accomplish the correct result. Instead of calling gl*Pointer(), I called:

glInterleavedArrays( GL_T2F_N3F_V3F, stride, self.vertArray )

I'm still curious to find a solution that works with gl*Pointer().

SurvivalMachine
  • 7,946
  • 15
  • 57
  • 87
0

According to this link: http://www.opengl.org/sdk/docs/man/xhtml/glTexCoordPointer.xml

stride

Specifies the byte offset between consecutive texture coordinate sets. If stride is 0, the array elements are understood to be tightly packed. The initial value is 0.

Are you sure, that in your case stride is (2 + 3 + 3) * 4 ?

Wiseman
  • 1,059
  • 2
  • 13
  • 24
  • I'm quite sure. TexCoords = 2 elements, Normals = 3 elements and Vertices = 3 elements. My array is float32, so the stride's 4 bytes multiplied by the # of elements. I'm using the same stride also in my C++ code and it works there. – SurvivalMachine Apr 22 '10 at 07:21
  • Ok, then why there is no "3" as a first param in your glNormalPointer call? – Wiseman Apr 22 '10 at 08:40
  • And I'm still not sure, that you sholuld this stride. If you are using equal stride while composing array, you still can get right values, but why bother? Zero stride could fit as well (in my opinion). – Wiseman Apr 22 '10 at 08:43
  • Zero stride would definitely not work for an interleaved array. – Xavier Ho Apr 25 '10 at 05:45
  • glNormalPointer doesn't have an element count parameter, it's always 3. – Alex Apr 28 '11 at 03:33