I'm trying to work through the beginning of the OpenGL redbook for version 2.1 and translate what I learn to the PyOpenGL binding while using Qt for the windowing framework. For some reason though, I can't seem to get my call to glDrawElements() to actually draw anything to the screen. Here are the relevant functions I have so far.
def initializeGL(self):
self.qglClearColor(QtGui.QColor(0,0,150))
self.initGeometry()
GL.glEnable(GL.GL_DEPTH_TEST)
self.buffers = GL.glGenBuffers(2)
def paintGL(self):
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
GL.glLoadIdentity()
GL.glTranslate(0.0, 0.0, -50.0)
GL.glScale(20.0, 20.0, 20.0)
GL.glRotate(self.yRotDeg, 0.2, 1.0, 0.3)
GL.glTranslate(-0.5, -0.5, -0.5)
VERTICES = 0
INDICES = 1
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.buffers[VERTICES])
GL.glBufferData(GL.GL_ARRAY_BUFFER, len(self.cubeVtxArray), self.cubeVtxArray, GL.GL_STATIC_DRAW)
offset = ctypes.c_void_p(0)
GL.glVertexPointer(3, GL.GL_FLOAT, 0, offset)
#GL.glVertexPointerf(self.cubeVtxArray)
GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
GL.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, self.buffers[INDICES])
GL.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, len(self.cubeIdxArray), self.cubeIdxArray, GL.GL_STATIC_DRAW)
GL.glDrawElements(GL.GL_QUADS, 24, GL.GL_UNSIGNED_BYTE, offset)
#GL.glDrawArrays(GL.GL_QUADS, 0, 24)
def initGeometry(self):
self.cubeVtxArray = np.array(
[[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[1.0, 1.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
[1.0, 0.0, 1.0],
[1.0, 1.0, 1.0],
[0.0, 1.0, 1.0]], dtype=np.float32)
self.cubeIdxArray = np.array([
0, 1, 2, 3,
3, 2, 6, 7,
1, 0, 4, 5,
2, 1, 5, 6,
0, 3, 7, 4,
7, 6, 5, 4], dtype=np.uint8)
When I run the program, it does clear the screen to the correct color, but the cube isn't drawn. Interestingly, if I try and render using the glDrawArray() function, it does render (although it doesn't look like a cube since it's rendering the indices). What might be going wrong here?
EDIT:
Here are a couple videos of the results of glDrawElements() and glDrawArrays().
EDIT2:
My problem (as user1118321 pointed out) was that I was passing an array length as the second parameter to glBufferData() where I should have been passing a size in bytes. The solution for python is:
from OpenGL.arrays.arraydatatype import ArrayDatatype
Use ArrayDatatype.arrayByteCount(self.cubeVtxArray) as the second parameter to glBufferData() (and similarly for any other buffers).
EDIT 3:
I'd actually like to make one more edit to this since I just ended up with another related problem from my calls to glBufferData(). I thought naively that I should also be able to use sys.getsizeof() in the same way as ArrayDatatype.arrayByteCount(). This is not the case though if your buffer data is a numpy array as I ended up using. sys.getsizeof() returns the wrong size and will inadvertently chop your array a bit. Goodbye three days of my life....
One thing that looks wrong to me is that you're sending the array size as the second argument to glBufferData. You probably need to send the number of bytes of the data as that argument. So it would be something like:
len(self.cubeVtxArray) * numBytesPerElement
where numBytesPerElement would be 4 bytes per float times 3 floats per vertex = 12 bytes.
In Python, you can get the number of bytes in an array by doing the following:
from OpenGL.arrays.arraydatatype import ArrayDatatype
Use ArrayDatatype.arrayByteCount(self.cubeVtxArray) as the second parameter to glBufferData() (and similarly for any other buffers).
And you'll need to do the same thing for self.cubeIdxArray, though the numBytesPerElement will be 1 in that case.
Related
Using these two library functions:
SimpleITK.Euler3DTransform
scipy.spatial.transform.Rotation.from_euler
to create a simple rotation matrix from Euler Angles:
import numpy as np
import SimpleITK as sitk
from scipy.spatial.transform import Rotation
from math import pi
euler_angles = [pi / 10, pi / 18, pi / 36]
sitk_matrix = sitk.Euler3DTransform((0, 0, 0), *euler_angles).GetMatrix()
sitk_matrix = np.array(sitk_matrix).reshape((3,3))
print(np.array_str(sitk_matrix, precision=3, suppress_small=True))
order = 'XYZ' # Different results for any order in ['XYZ','XZY','YZX','YXZ','ZXY','ZYX','xyz','xzy','yzx','yxz','zxy','zyx']
scipy_matrix = Rotation.from_euler(order, euler_angles).as_matrix()
print(np.array_str(scipy_matrix, precision=3, suppress_small=True))
I get two different results:
[[ 0.976 -0.083 0.2 ]
[ 0.139 0.947 -0.288]
[-0.165 0.309 0.937]]
[[ 0.981 -0.086 0.174]
[ 0.136 0.943 -0.304]
[-0.138 0.322 0.937]]
Why? How can I compute the same matrix as SimpleITK using scipy?
The issue is that the itk.Euler3DTransform class by default applies the rotation matrix multiplications in Z # X # Y order and the Rotation.from_euler function in Z # Y # X order.
Note that this is independent of the order you specified. The order you specify refers to the order of the angles, not the order of the matrix multiplications.
If you are using the itk.Euler3DTransform directly as you showed in your example, you can actually change the default behavior for itk to perform the matrix multiplication in Z # Y # X order.
I never worked with sitk but in theory and based on the documentation, something like this should work:
euler_transform = sitk.Euler3DTransform((0, 0, 0), *euler_angles)
euler_transform.SetComputeZYX(True)
sitk_matrix = euler_transform.GetMatrix()
Alternatively, I wrote a function which is similar to Rotation.from_euler but has the option to specify the rotation order as well:
def build_rotation_3d(radians: NDArray,
radians_oder: str = 'XYZ',
rotation_order: str = 'ZYX',
dims: List[str] = ['X', 'Y', 'Z']) -> NDArray:
x_rad, y_rad, z_rad = radians[(np.searchsorted(dims, list(radians_oder)))]
x_cos, y_cos, z_cos = np.cos([x_rad, y_rad, z_rad], dtype=np.float64)
x_sin, y_sin, z_sin = np.sin([x_rad, y_rad, z_rad], dtype=np.float64)
x_rot = np.asarray([
[1.0, 0.0, 0.0, 0.0],
[0.0, x_cos, -x_sin, 0.0],
[0.0, x_sin, x_cos, 0.0],
[0.0, 0.0, 0.0, 1.0],
])
y_rot = np.asarray([
[y_cos, 0.0, y_sin, 0.0],
[0.0, 1.0, 0.0, 0.0],
[-y_sin, 0.0, y_cos, 0.0],
[0.0, 0.0, 0.0, 1.0],
])
z_rot = np.asarray([
[z_cos, -z_sin, 0.0, 0.0],
[z_sin, z_cos, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
])
rotations = np.asarray([x_rot, y_rot, z_rot])[(np.searchsorted(dims, list(rotation_order)))]
return rotations[0] # rotations[1] # rotations[2]
What is your 'order' string. When I ran your code with order='xyz', I get the same results for SimpleITK and scipy's Rotation.
I need to integrate the area under a curve, but rather than integrating the entire area under the curve at once, I would like to integrate partial areas at a specified interval of 5m. I.e, I would like to know the area under the curve from 0-5m, 5 - 10m, 10 - 15m, etc.
However, the spacing between my x values is irregular (i.e., it does not go [1, 2, 3, 4...] but rather could go, [1, 1.2, 2, 2.3, 3.1, 4...]. So I can't go by index number but rather need to go by values, and I want to create intervals of every 5 meters.
# Here is a sample of the data set (which I do NOT use in the function below, just an example of how irregular the spacing between x values is)
x = [0, 1.0, 2.0, 3.0, 4.3, 5.0, 6.0, 7.0, 8.0, 9.0, 10, 12, 12.5, 12.7, 13, 14.5, 15, 15.5, 16, 16.5]
y = [0, -0.44, -0.83, -0.91, -1.10, -1.16, -1.00, -1.02, -1.05, -1.0, -0.94, - 0.89, -1, -1.39, -1.44, -1.88, -1.9, -1.94, -2.03, -1.9]
I've created a function to get the partial area based on one specific interval (5<x<10), but I need to figure out how to do this for the entire dataframe.
from scipy.integrate import simps
def partial_area (y, x):
x =df.query('5 <= X <= 10')['X']
y =df.query('5 <= X <= 10')['Z']
area = simps(y,x)
return (area)
area = partial_area(y,x)
I'm stuck on the best way to go about this, as I'm not sure how to create intervals by data values rather than index.
i am new to programming and currently working with Python. Can someone explain to me why is it that by changing the order of variable will end up with different results as compared to Euclidean distance obtaining the same results?
Below is the array i used for this experiment to understand the use
u = np.array([[1.0, 0.0], [0.0, 1.0], [-1.0, 0.0], [0.0, -1.0]])
v = np.array([[2.0, 0.0], [0.0, 2.0], [-2.0, 0.0], [0.0, -4.0]])
(directed_hausdorff(u, v)[:])) --> output = (2.23606797749979, 3, 0) and
(directed_hausdorff(v, u)[:])) --> output = v,u = (3.0, 3, 3)
Thank you!
I'm starting to learn PyOpenGL, and I'm following this tutorial. At one point the instructor creates a single array from which he extracts the information to construct a triangle: vetices and their color (I added the Numpy line here):
#-----------|-Vertices pos--|---Colors----|-----------
vertices = [-0.5, -0.5, 0.0, 1.0, 0.0, 0.0,
0.5, -0.5, 0.0, 0.0, 1.0, 0.0,
0.0, 0.5, 0.0, 0.0, 0.0, 1.0]
vertices = np.array(vertices, dtype = np.float32)
The information of this array is passed to glVertexPointer() and glColorPointer() in the display function:
def display():
glClear(GL_COLOR_BUFFER_BIT)
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_COLOR_ARRAY)
glVertexPointer(3, GL_FLOAT, 12, vertices)
glColorPointer(3, GLFLOAT, 12, vertices + 3)
glDrawArrays(GL_TRIANGLES, 0, 3)
glDisableClientState(GL_VERTEX_ARRAY)
glDisableClientState(GL_COLOR_ARRAY)
glutSwapBuffers()
My problem is with the last argument of those functions, in the tutorial (since he is using C++), he can write vertices + 3 in order to tell the program to start reading from the third position of the array, I cannot do this in python.
Can some one guide me on how can I define this pointer? Or how can extract the information from my array.
Note: I'm aware that I can split the information of vertices and colors in differnt arrays, but I want to know if it is possible to do it using one array.
EDIT - Adding the complete code:
from OpenGL.GL import *
from OpenGL.GLUT import *
import numpy as np
import ctypes
#-----------|-Vertices pos--|---Colors----|-----------
vertices = [-0.5, -0.5, 0.0, 1.0, 0.0, 0.0,
0.5, -0.5, 0.0, 0.0, 1.0, 0.0,
0.0, 0.5, 0.0, 0.0, 0.0, 1.0]
vertices = np.array(vertices, dtype = np.float32)
buffer_offset = ctypes.c_void_p
float_size = ctypes.sizeof(ctypes.c_float)
#-----------------------------------------------------
def display():
glClear(GL_COLOR_BUFFER_BIT)
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_COLOR_ARRAY)
glVertexPointer(3, GL_FLOAT, 24, buffer_offset(vertices.ctypes.data))
glColorPointer(3, GL_FLOAT, 24, buffer_offset(vertices.ctypes.data + float_size * 3))
glDrawArrays(GL_TRIANGLES, 0, 3)
glDisableClientState(GL_VERTEX_ARRAY)
glDisableClientState(GL_COLOR_ARRAY)
glutSwapBuffers()
def reshape(w,h):
glViewport(0,0,w,h)
def initOpenGL():
glClearColor(0,0,0,1)
#-----------------------------------------------------
glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH)
glutInitWindowSize(500,500)
glutCreateWindow(b'Test')
glutDisplayFunc(display)
glutIdleFunc(display)
glutReshapeFunc(reshape)
initOpenGL()
glutMainLoop()
This depends on whether you have a vertex buffer bound or not. The last parameter pointer in gl*Pointer() is either.
No Vertex Buffer Bound: It's the address to the vertices
Vertex Buffer Bound: It's a relative offset in relation to the address of the buffer
You can utilize ctypes for this.
import ctypes
buffer_offset = ctypes.c_void_p
float_size = ctypes.sizeof(ctypes.c_float)
Assuming you have a vertex buffer bound, then you'd simply do:
glVertexPointer(3, GL_FLOAT, 12, buffer_offset(0))
glColorPointer(3, GLFLOAT, 12, buffer_offset(float_size * 3))
If you are just using that array and nothing else, then I would assume you could just get the address and equally offset it.
glVertexPointer(3, GL_FLOAT, 12, buffer_offset(vertices.ctypes.data))
glColorPointer(3, GLFLOAT, 12, buffer_offset(vertices.ctypes.data + float_size * 3))
But I have to admit, I've never had the need for this in Python, so I can't confirm it.
I'm trying to create a script for mirroring transforms across the yz plane in Maya.
I was able to set up a node network that gets the desired results. I took a node at the origin with sz set to -1 and a source node from the left side (lf_grp for this test), and fed their worldMatrix attrs into a multMatrix node. Then I passed the output (multMatrix.matrixSum) through a decompose matrix and into my destination node.
I'd really prefer to not create a bunch of nodes to do my mirroring - running a create/connect/disconnect/delete cycle every time is slow and painful... I'd rather just "math the crap out of it" through my script, but I can't seem to figure out how to actually multiply my two matrices...
Oh, I'm using the MTransformationMatrix since it handles a few things for you that the MMatrix does not - like rotation order (at least from what I've read...)
Thank you for any help you can give!
import maya.cmds as mc
import maya.OpenMaya as om
src_xfm = 'lf_grp'
mir_matrix_vals = [-1.0, -0.0, -0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0]
# get src xfm matrix
#
selList = om.MSelectionList()
selList.add(src_xfm)
mDagPath = om.MDagPath()
selList.getDagPath(0, mDagPath)
src_xfmFn = om.MFnTransform(mDagPath)
src_matrix = src_xfmFn.transformation()
# construct mir xfm matrix
#
mir_matrix = om.MTransformationMatrix()
tmp_matrix = om.MMatrix()
om.MScriptUtil().createMatrixFromList(mir_matrix_vals, tmp_matrix)
mir_matrix = om.MTransformationMatrix(tmp_matrix)
# multiply matrices to get mirrored matrix
#
dst_matrix = src_matrix * mir_matrix # HOW DO YOU DO THIS????
Here's how do to it using the openMaya api version 2.
Nowadays this is the preferred method for doing Python api work - among other things it's a lot less wordy and avoids MScriptUtil, which is prone to crashiness if used incorrectly. It's also faster for most things.
This is the plain matrix multiplication:
from maya.api.OpemMaya import MMatrix
mat1 = MMatrix ([0.707107, 0, -0.707107, 0, 0.5, 0.707107, 0.5, 0, 0.5, -0.707107, 0.5, 0, 0, 0, 0, 1])
mat2 = MMatrix([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 100, 200, 300, 1])
print mat1 * mat2
# (((0.707107, 0, -0.707107, 0), (0.5, 0.707107, 0.5, 0), (0.5, -0.707107, 0.5, 0), (100, 200, 300, 1)))
You can't directly multiply an MTransformationMatrix -- that class isn't a linear algebra matrix, it's an accessor for the various position, rotation, scale, shear and pivot data functions of a matrix. You use it if you want get around doing all of the concatenating math yourself on a transform node, like setting its rotation without changing its scale.
You can get the underlyying matrix from an MTransformationMatrix with its asMatrix() function. To apply a matrix to an object :
from maya.api.OpenMaya import MTransformationMatrix, MGlobal, MSelectionList, MFnDagNode
sel = MGlobal.getActiveSelectionList() # selection
dagpath = sel.getDependNode(0) # first node
transform_node = MFnTransform(dagpath) # MFnTransform
xfm= transform_node.transformation().asMatrix() # matrix
new_matrix = mat1 * xfm # math
new_trans = MTransformationMatrix(new_matrix)
transform_node.setTransformation(new_trans)