how to rotating triangle, not Triangular axis in opengl(python)? - python

I am working on rotating a triangle, under the premise that it does not touch the render part(i think this problem can't using camera)
I want the axis that rotates in the above state to be the center (based on world coordinates (0,0)) rather than local space. When the triangle is not at 0,0 .
this is my code
import glfw
from OpenGL.GL import *
from OpenGL.GLU import *
import numpy as np
def render(T):
glClear(GL_COLOR_BUFFER_BIT)
glLoadIdentity()
# draw cooridnate
glBegin(GL_LINES)
glColor3ub(255, 0, 0)
glVertex2fv(np.array([0.,0.]))
glVertex2fv(np.array([1.,0.]))
glColor3ub(0, 255, 0)
glVertex2fv(np.array([0.,0.]))
glVertex2fv(np.array([0.,1.]))
glEnd()
# draw triangle
glBegin(GL_TRIANGLES)
glColor3ub(255, 255, 255)
glVertex2fv( (T # np.array([.0,.5,1.]))[:-1] )
glVertex2fv( (T # np.array([.0,.0,1.]))[:-1] )
glVertex2fv( (T # np.array([.5,.0,1.]))[:-1] )
glEnd()
def main():
if not glfw.init():
return
window = glfw.create_window(480,480,"1234", None,None)
if not window:
glfw.terminate()
return
glfw.make_context_current(window)
glfw.swap_interval(1)
while not glfw.window_should_close(window):
glfw.poll_events()
t = glfw.get_time()
s= np.sin(t)
q = np.array([[np.cos(t),-np.sin(t),.3],
[np.sin(t), np.cos(t),.3],
[0., 0., 0.]])
#th = np.radians(60)
#R = np.array([[np.cos(th), -np.sin(th),0.],
# [np.sin(th), np.cos(th),0.],
# [0., 0., 1.]])
#T = np.array([[1.,0.,.4],
# [0.,1.,.1],
# [0.,0.,1.]])
render(q)
glfw.swap_buffers(window)
glfw.terminate()
if __name__ == "__main__":
main()
-> This is my current state rotate, but not world space (0,0)

If you want to rotate and object around a pivot point:
Move the object so that the pivot point is at (0, 0).
Rotate the object
Move the object to its position in the world.
def main():
# [...]
while not glfw.window_should_close(window):
glfw.poll_events()
t = glfw.get_time()
pivot = (0.15, 0.15)
world_pos = (0.5, 0.5)
trans_pivot = np.array([[1, 0, -pivot[0]], [0, 1, -pivot[1]], [0, 0, 1]])
rotate = np.array([[np.cos(t),-np.sin(t), 0.0],
[np.sin(t), np.cos(t), 0.0],
[0, 0, 1]])
trans_world = np.array([[1, 0, world_pos[0]], [0, 1, world_pos[0]], [0, 0, 1]])
q = trans_world # rotate # trans_pivot
render(q)
glfw.swap_buffers(window)

Related

No shape display pyopengl

So i'm trying to make a function for displaying a circle, here's the function :
def drawCircle(x,y,size):
glColor3f(1,1,1)
glBegin(GL_TRIANGLE_STRIP)
glVertex2f(0,0)
glVertex2f(100,0)
glVertex2f(100,100)
glVertex2f(0,100)
But when i try it, nothing display. If you have the solution, please explain me in detail, I'm not a profesional in opengl or in pyopengl.
Here's the code :
import glfw
from OpenGL.GL import *
from OpenGL.GLUT import *
import numpy as np
import pyrr
from random import *
from math import *
buffer = bytearray(800 * 600 * 3)
display = (800,600)
if not glfw.init():
raise Exception("glfw can not be initialized!")
def CreateWindow(title="Baguette game",width=800,height=600):
display = (width,height)
window = glfw.create_window(width,height,title, None, None)
glfw.set_window_pos(window,400,200)
glfw.make_context_current(window)
return window
def DrawTriangle(pointA=[-0.5, -0.5, 0.0],pointB=[0.5, -0.5,0.0],
pointC=[-0.5, 0, 0.0],color=[1.0,1.0,1.0]):
vertices = [pointA[0], pointA[1], pointA[2],
pointB[0], pointB[1], pointB[2],
pointC[0], pointC[1], pointC[2]]
colors = [color[0], color[1], color[2],
color[0], color[1], color[2],
color[0], color[1], color[2] ]
v = np.array(vertices,dtype=np.float32)
c = np.array(colors, dtype=np.float32)
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT,0,v)
glEnableClientState(GL_COLOR_ARRAY)
glColorPointer(3, GL_FLOAT,0,c)
glDrawArrays(GL_TRIANGLES,0,3)
def DrawRectangle(size=[0.5,0.5],position=[0,0],color=[1.0,1.0,1.0]):
DrawTriangle([position[0]-size[0]/2,position[1]+size[1]/2,0],
[position[0]+size[0]/2,position[1]+size[1]/2,0],
[position[0]+size[0]/2,position[1]-size[1]/2,0],
color)
DrawTriangle([position[0]-size[0]/2,position[1]-size[1]/2,0],
[position[0]+size[0]/2,position[1]-size[1]/2,0],
[position[0]-size[0]/2,position[1]+size[1]/2,0],
color)
def Pixel(x,y):
buffer_data = [randint(0,255), 0, 0] * (x * y)
buffer = (GLubyte * (x * y * 3))(*buffer_data)
glDrawPixels(x, y, GL_RGB, GL_UNSIGNED_BYTE, buffer)
def drawCircle(x,y,size):
glColor3f(1,1,1)
glBegin(GL_TRIANGLE_STRIP)
glVertex2f(0,0)
glVertex2f(100,0)
glVertex2f(100,100)
glVertex2f(0,100)
if __name__=="__main__":
window = CreateWindow()
initialPosition = (0,0,0)
z=1
while not glfw.window_should_close(window):
glfw.poll_events()
#glClear(GL_COLOR_BUFFER_BIT)
DrawRectangle([1,1],[-0.5,0],[1,0,0])
DrawRectangle([1,1],[0.5,0],[0,1,0])
glfw.swap_buffers(window)
glfw.terminate()
You don't use the x, y and size arguments at all. A glBegin/glEnd sequence must be delimited with glEnd. e.g.:
def drawCircle(cx, cy, radius):
glColor3f(1,1,1)
glBegin(GL_TRIANGLE_FAN)
glVertex2f(cx, cy)
for a in range(361):
x = cx + radius * cos(radians(a))
y = cy + radius * sin(radians(a))
glVertex2f(x, y)
glEnd()
For example draw a circle in the center of the viewport:
drawCircle(0, 0, 0.5)
I recommend reading a good OpenGL tutorial. e.g.: LearnOpenGL

pyopengl does not show the intended structure

I am just trying to learn to draw 3d objects with pyopengl. The first thing I am trying to draw is the following code. The coordinates posat, i.e. the positon of atom is supposed to be a bcc lattice, but I am far from getting anything like a cube. The output is added.
Kindly let me know what I am doing wring here:
#!/usr/bin/env python
import math
import sys
import ase
import ase.io.vasp
import pygame
from OpenGL.GL import *
from OpenGL.GLU import *
from pygame.locals import *
# inpfile = sys.argv[1]
# cell = ase.io.vasp.read_vasp(inpfile)
# numat = len(cell.get_positions())
# posat = cell.get_positions()
posat = [[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1], [.5, .5, .5], [1, 1, 0],
[0, 1, 1], [1, 0, 1], [1, 1, 1]]
numat = len(posat)
print(posat)
# print(posat[1][0])
pygame.init()
pygame.display.set_caption('vcrys')
display = (1000, 750)
scree = pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glShadeModel(GL_SMOOTH)
glEnable(GL_COLOR_MATERIAL)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)
glEnable(GL_LIGHT0)
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5, 1])
glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 1.0, 1.0, 1])
sphere = gluNewQuadric()
def atoms(qx, qy, qz, cr, cg, cb, r):
glTranslatef(qx, qy, qz)
glColor4f(cr, cg, cb, 1)
gluSphere(sphere, r, 1080, 1080)
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0] / display[1]), 0.01, 50.0)
glMatrixMode(GL_MODELVIEW)
gluLookAt(0, -10, 0, 0, 0, 0, 0, 0, 1)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
glLoadIdentity()
# init mouse movement and center mouse on screen
displayCenter = [scree.get_size()[i] // 2 for i in range(2)]
mouseMove = [0, 0]
pygame.mouse.set_pos(displayCenter)
up_down_angle = 0.0
paused = False
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE or event.key == pygame.K_RETURN:
run = False
if event.key == pygame.K_PAUSE or event.key == pygame.K_p:
paused = not paused
pygame.mouse.set_pos(displayCenter)
if not paused:
if event.type == pygame.MOUSEMOTION:
mouseMove = [event.pos[i] - displayCenter[i] for i in range(2)]
pygame.mouse.set_pos(displayCenter)
if not paused:
# get keys
keypress = pygame.key.get_pressed()
# mouseMove = pygame.mouse.get_rel()
# init model view matrix
glLoadIdentity()
# apply the look up and down
# up_down_angle += mouseMove[1] * 0.0001
# glRotatef(up_down_angle, .10, 0.0, 0.0)
# init the view matrix
glPushMatrix()
glLoadIdentity()
# apply the movment
if keypress[pygame.K_w]:
glTranslatef(0, 0, 0.1)
if keypress[pygame.K_s]:
glTranslatef(0, 0, -0.1)
if keypress[pygame.K_d]:
glTranslatef(-0.1, 0, 0)
if keypress[pygame.K_a]:
glTranslatef(0.1, 0, 0)
if keypress[pygame.K_u]:
glTranslatef(0.0, 0.1, 0)
if keypress[pygame.K_l]:
glTranslatef(0, -0.1, 0)
# apply the left and right rotation
# glRotatef(mouseMove[0] * 0.01, 0.0, .01, 0.0)
# multiply the current matrix by the get the new view matrix and store the final vie matrix
glMultMatrixf(viewMatrix)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
# apply view matrix
glPopMatrix()
glMultMatrixf(viewMatrix)
glLightfv(GL_LIGHT0, GL_POSITION, [1, -1, 1, 0])
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glPushMatrix()
for a in range(numat):
atoms(posat[a][0], posat[a][1], posat[a][2], 1, 1, 1, 1 / 10)
# atoms(qx=0, cr=0, qy=0, cg=.5, qz=.2, cb=.2, r=1)
# atoms(-3, 0, 0, .2, .2, .5, 1)
glPopMatrix()
pygame.display.flip()
# paused = True
# pygame.time.wait(10)
pygame.quit()
glTranslate defines a translation matrix and multiplies the current matrix with the new translation matrix. Hence all the translations are concatenated.
Use glPushMatrix/glPopMatrx to save the current matrix before specifying the translation and to restore the current matrix after drawing the atom:
def atoms(qx, qy, qz, cr, cg, cb, r):
glPushMatrix()
glTranslatef(qx, qy, qz)
glColor4f(cr, cg, cb, 1)
gluSphere(sphere, r, 1080, 1080)
glPopMatrix()

If i open nrrd file using vtk, only black screen is output

I want to open two nrrd files and then overlap these two files. The first step in this step is to open the nrrd file using vtk's vktImageData or Mapper. I wrote the code to do this, but only black screen appears when I run it.
I've already done this by replacing the Image with a volume and printing the two files over and over. However, when I tried to do color mapping on this result, I noticed that the coordinates of the color mapping did not match the coordinates of the two files. At this time, I did not use the same mapper that rendered the object and the mapper of the color mapping, and I thought that the coordinates were different.
So I start from the beginning to use the same mapper that renders both files and color mapping.
import vtk
def main():
renWin = vtk.vtkRenderWindow()
renderer = vtk.vtkRenderer()
renWin.AddRenderer(renderer)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
reader = vtk.vtkNrrdReader()
reader.SetFileName('Segmentation-label_2.nrrd')
reader.Update()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(reader.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
renderer.AddActor(actor)
iren.Initialize()
renWin.Render()
iren.Start()
if __name__ == "__main__":
main()
When I run this code, only black screen is output. I have searched a lot of data, but I do not know what the problem is.
I would appreciate your reply.
By adjusting the example given in https://vtk.org/Wiki/VTK/Examples/Python/DataManipulation/Cube.py this should load your 3D image data with a 2D slice that you move through.
#!/usr/bin/env python
import vtk
# Start by loading some data.
reader = vtk.vtkNrrdReader()
reader.SetFileName('Segmentation-label_2.nrrd')
reader.Update()
# Calculate the center of the volume
reader.Update()
(xMin, xMax, yMin, yMax, zMin, zMax) = reader.GetExecutive().GetWholeExtent(reader.GetOutputInformation(0))
(xSpacing, ySpacing, zSpacing) = reader.GetOutput().GetSpacing()
(x0, y0, z0) = reader.GetOutput().GetOrigin()
center = [x0 + xSpacing * 0.5 * (xMin + xMax),
y0 + ySpacing * 0.5 * (yMin + yMax),
z0 + zSpacing * 0.5 * (zMin + zMax)]
# Matrices for axial, coronal, sagittal, oblique view orientations
axial = vtk.vtkMatrix4x4()
axial.DeepCopy((1, 0, 0, center[0],
0, 1, 0, center[1],
0, 0, 1, center[2],
0, 0, 0, 1))
coronal = vtk.vtkMatrix4x4()
coronal.DeepCopy((1, 0, 0, center[0],
0, 0, 1, center[1],
0,-1, 0, center[2],
0, 0, 0, 1))
sagittal = vtk.vtkMatrix4x4()
sagittal.DeepCopy((0, 0,-1, center[0],
1, 0, 0, center[1],
0,-1, 0, center[2],
0, 0, 0, 1))
oblique = vtk.vtkMatrix4x4()
oblique.DeepCopy((1, 0, 0, center[0],
0, 0.866025, -0.5, center[1],
0, 0.5, 0.866025, center[2],
0, 0, 0, 1))
# Extract a slice in the desired orientation
reslice = vtk.vtkImageReslice()
reslice.SetInputConnection(reader.GetOutputPort())
reslice.SetOutputDimensionality(2)
reslice.SetResliceAxes(sagittal)
reslice.SetInterpolationModeToLinear()
# Create a greyscale lookup table
table = vtk.vtkLookupTable()
table.SetRange(0, 2000) # image intensity range
table.SetValueRange(0.0, 1.0) # from black to white
table.SetSaturationRange(0.0, 0.0) # no color saturation
table.SetRampToLinear()
table.Build()
# Map the image through the lookup table
color = vtk.vtkImageMapToColors()
color.SetLookupTable(table)
color.SetInputConnection(reslice.GetOutputPort())
# Display the image
actor = vtk.vtkImageActor()
actor.GetMapper().SetInputConnection(color.GetOutputPort())
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
window = vtk.vtkRenderWindow()
window.AddRenderer(renderer)
# Set up the interaction
interactorStyle = vtk.vtkInteractorStyleImage()
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetInteractorStyle(interactorStyle)
window.SetInteractor(interactor)
window.Render()
# Create callbacks for slicing the image
actions = {}
actions["Slicing"] = 0
def ButtonCallback(obj, event):
if event == "LeftButtonPressEvent":
actions["Slicing"] = 1
else:
actions["Slicing"] = 0
def MouseMoveCallback(obj, event):
(lastX, lastY) = interactor.GetLastEventPosition()
(mouseX, mouseY) = interactor.GetEventPosition()
if actions["Slicing"] == 1:
deltaY = mouseY - lastY
reslice.Update()
sliceSpacing = reslice.GetOutput().GetSpacing()[2]
matrix = reslice.GetResliceAxes()
# move the center point that we are slicing through
center = matrix.MultiplyPoint((0, 0, sliceSpacing*deltaY, 1))
matrix.SetElement(0, 3, center[0])
matrix.SetElement(1, 3, center[1])
matrix.SetElement(2, 3, center[2])
window.Render()
else:
interactorStyle.OnMouseMove()
interactorStyle.AddObserver("MouseMoveEvent", MouseMoveCallback)
interactorStyle.AddObserver("LeftButtonPressEvent", ButtonCallback)
interactorStyle.AddObserver("LeftButtonReleaseEvent", ButtonCallback)
# Start interaction
interactor.Start()
del renderer
del window
del interactor

Solar System in OpenGL, Camera position

I want to make simple solar system in OpenGL, with four cameras.
What I want is simple, just locate a camera at earth's one side.
In follow code, I get MODELVIEW_MATRIX by glGetFloatv(GL_MODELVIEW_MATRIX) (line 116)
So I thought that { MODELVIEW_MATRIX multiple [[0],[0],[0],[1]] matrix } get a Origin point of planet in world coordinate system.
But it doesn't work well and so I need some help.
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import math
import numpy as np
WINDOW_WIDTH = 600
WINDOW_HEIGHT = 600
WINDOW_POSITION_X = 0
WINDOW_POSITION_Y = 0
earthRevolveAngle = 180
earthRotateAngle = 0
satelliteRevolveAngle = 180
satellitePlaneAngle = 0
plutoRevolveAngle = 180
plutoRotateAngle = 0
plutoCamera = np.array([0, 0, 0])
earthPosition = np.array([0, 0, 0])
class Camera :
def __init__(self): #constructor
self.loc = np.array([0.0, 50.0, 0.0])
self.tar = np.array([0.0, 0.0, 0.0])
self.up = np.array([1.0, 0.0, 0.0])
self.right = np.array([1.0, 0.0, 0.0])
self.dir = np.array([0.0, 0.0, -1.0])
self.asp = 1.0
self.fov = 70
self.near= 0.1
self.far = 500.0
def setCameraLoc(self, loc):
self.loc = loc
self.tar = self.loc + self.dir
def setCamera(self, loc, tar, up):
self.loc, self.tar, self.up = loc, tar, up
self.dir = self.tar - self.loc
l = np.linalg.norm(self.dir)
if l > 0.0 :
self.dir = self.dir / l
l = np.linalg.norm(self.up)
if l > 0.0 :
self.up = self.up / l
self.right = np.cross(self.dir, self.up)
def setLens(self, fov, asp, near, far):
self.fov, self.asp, self.near, self.far = fov, asp, near, far
def applyCamera(self):
gluLookAt(self.loc[0], self.loc[1], self.loc[2],
self.tar[0], self.tar[1], self.tar[2],
self.up [0], self.up [1], self.up [2])
def applyLens(self):
gluPerspective(self.fov, self.asp, self.near, self.far)
def moveForward(self, step=1.0):
self.tar += self.dir*step
self.loc += self.dir*step
def zoomIn(self, step=1.0):
self.loc += self.dir*step
def zoomOut(self, step=1.0):
self.loc -= self.dir*step
def drawPlanet(semiMajor, semiMinor, revolveAngle, rotateAngle, shape, slope, axisTilt) :
global plutoCamera, earthPosition
a = semiMajor
b = semiMinor
#Orbit's slope
glRotatef(slope, 1, 0, 0)
#Start draw orbit
glBegin(GL_LINE_STRIP)
for i in range(0, 361):
theta = 2.0 * 3.141592 * i / 360.0
x = a*math.cos(theta)
z = b*math.sin(theta)
glVertex3f(x, 0, z)
glEnd()
#End draw orbit
theta = 2.0 * 3.141592 * (revolveAngle%360) / 360.0
x = a * math.cos(theta)
z = b * math.sin(theta)
glRotatef(revolveAngle, 0, 1, 0)
glTranslatef( math.sqrt( x**2 + z**2 ) , 0, 0)
glRotatef(rotateAngle, 0, 1, 0)
glRotatef(axisTilt, 0, 0, 1)
t = glGetFloatv(GL_MODELVIEW_MATRIX)
if(shape == "satellite"):
glScalef(0.4,0.4,0.4)
glutSolidTetrahedron()
glScalef(2.5,2.5,2.5)
elif(shape == "earth"):
glutWireCube(1)
earthPosition = t * np.matrix( [[0],[0],[0],[1]] )
elif(shape == "pluto"):
glScalef(0.4,0.4,0.4)
glutWireOctahedron()
glScalef(2.5,2.5,2.5)
def drawScene() :
global earthRevolveAngle, earthRotateAngle, satelliteAngle, satelliteRevolveAngle, satellitePlaneAngle, plutoRevolveAngle, plutoRotateAngle
# draw solar
glColor3f(1,0,0)
glutWireSphere(1.0, 20, 20)
glPushMatrix()
# draw earth
glColor3f(0,0.5,1.0)
earthRevolveAngle+=0.05 # earth's revolution
earthRotateAngle+=0.2
drawPlanet(5, 5, earthRevolveAngle, earthRotateAngle, "earth",0,15)
# draw satellite
glColor3f(0.7,0.7,0.7)
satelliteRevolveAngle+=1.5
satellitePlaneAngle += 0.25
glRotatef(satellitePlaneAngle, 1, 0, 0)
drawPlanet(1, 1, satelliteRevolveAngle, 1, "satellite",0,0)
# draw pluto
glPopMatrix() # comeback to solar central coordinate
glPushMatrix()
glColor3f(0.9,0.7,0.26)
plutoRevolveAngle+=0.0125 # pluto's revolution
plutoRotateAngle+=0.1 # pluto's rotation
drawPlanet(10, 8, plutoRevolveAngle,plutoRotateAngle, "pluto",0,0)
glPopMatrix()
Cam = Camera()
def disp() :
global plutoCamera, earthPosition, Cam
# reset buffer
glClear(GL_COLOR_BUFFER_BIT)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
# Camera view setting
Cam.setLens(30,1.0,0.1,1000)
Cam.applyLens()
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
# first quadrant
glViewport(int(WINDOW_POSITION_X+WINDOW_WIDTH/2), int(WINDOW_POSITION_Y + WINDOW_HEIGHT/2), int(WINDOW_WIDTH/2), int(WINDOW_HEIGHT/2))
glPushMatrix()
Cam.setCamera( np.array([0,0,1]), np.array([0,0,100]), np.array([0,1,0]))
Cam.applyCamera()
drawScene()
glPopMatrix()
# second quadrant
glViewport(int(WINDOW_POSITION_X), int(WINDOW_POSITION_Y + WINDOW_HEIGHT/2), int(WINDOW_WIDTH/2), int(WINDOW_HEIGHT/2) )
glPushMatrix()
Cam.setCamera( np.array([30,30,30]), np.array([0,0,0]), np.array([0,1,0]))
Cam.applyCamera()
drawScene()
glPopMatrix()
# third quadrant
glViewport(WINDOW_POSITION_X, WINDOW_POSITION_Y, int(WINDOW_WIDTH/2) , int(WINDOW_HEIGHT/2) )
glPushMatrix()
Cam.setCamera( plutoCamera, np.array([0,0,0]), np.array([0,1,0]))
Cam.applyCamera()
drawScene()
glPopMatrix()
# fourth quadrant
glViewport(int(WINDOW_POSITION_X+WINDOW_WIDTH/2), WINDOW_POSITION_Y, int(WINDOW_WIDTH/2), int(WINDOW_HEIGHT/2) )
glPushMatrix()
Cam.setCamera( earthPosition, np.array([0,0,0]) , np.array([0,1,0]))
Cam.applyCamera()
drawScene()
glPopMatrix()
glFlush()
def main():
# windowing
glutInit(sys.argv)
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB)
glutInitWindowSize(WINDOW_WIDTH,WINDOW_HEIGHT)
glutInitWindowPosition(WINDOW_POSITION_X,WINDOW_POSITION_Y)
glutCreateWindow(b"Simple Solar_201624489_ParkChangHae")
glClearColor(0, 0.0, 0.0, 0)
# register callbacks
glutDisplayFunc(disp)
glutIdleFunc(disp)
# enter main infinite-loop
glutMainLoop()
if __name__=="__main__":
main()
The * operator doesn't do what you expect it to do, it is an array multiplication, but not a matrix multiplication. It would perform a componentwise multiplication of the elements. See how does multiplication differ for NumPy Matrix vs Array classes? and Numerical operations on arrays.
Use numpy.dot or numpy.matmul to transform a vector by a matrix.
The result of the transformation of a 4 component vector (Homogeneous coordinates) by 4*4 matrix, is still a 4 component vector. In general you would have to do a perspective divide after the transformation. But the model view matrix is an Orthogonal matrix, so it is sufficient to use the first 3 components of the result, since the 4th component is always 1:
pos = np.array( [0,0,0,1] )
pos = np.dot( pos, t )
earthPosition = pos[0:3]
But note, the view space position of the coordinate (0, 0, 0, 1) is the translation part (the 4th row) of the model view matrix:
earthPosition = t[3][0:3]
Sadly this is not what you want to do, because you want to know the world position of the earth, but not the view position.
Since glGetFloatv(GL_MODELVIEW_MATRIX) returns the model view matrix, the transformation calculates the view position, but not the world position.
You have to transform by the model matrix, but not the model view matrix. Since you can't separated model matrix from the model view matrix, this is not that easy.
What you can get get is the view matrix. With the view matrix and the model view matrix you van get the world position.
A transformation by the model matrix is the same as a transformation by the model view matrix and the inverse view matrix:
p_world = inverse(view_matrix) * model_view_matrix * p_model
I recommend to get the view matrix and to calculate the inverse model view matrix in the Cam class right after setting it by lookAt. The inverse matrix can be calculated by numpy.linalg.inv:
def applyCamera(self):
gluLookAt(self.loc[0], self.loc[1], self.loc[2],
self.tar[0], self.tar[1], self.tar[2],
self.up [0], self.up [1], self.up [2])
self.viewmat = glGetFloatv(GL_MODELVIEW_MATRIX)
self.inv_viewmat = np.linalg.inv(self.viewmat)
Finally the world position is a simple transformation of the 4th row of the model view matrix by the inverse view matrix:
global plutoCamera, earthPosition, Cam
.....
model_view = glGetFloatv(GL_MODELVIEW_MATRIX)
if(shape == "satellite"):
glScalef(0.4,0.4,0.4)
glutSolidTetrahedron()
glScalef(2.5,2.5,2.5)
elif(shape == "earth"):
glutWireCube(1)
pos = np.dot( model_view[3], Cam.inv_viewmat )
earthPosition = pos[0:3]
elif(shape == "pluto"):
glScalef(0.4,0.4,0.4)
glutWireOctahedron()
glScalef(2.5,2.5,2.5)
pos = np.dot( model_view[3], Cam.inv_viewmat )
plutoCamera = pos[0:3]
Preview:

Rendered model disappears at some asymptote

I've been trying to render a simple teapot with PyOpenGL, but have been running into strange issues. I can't seem to figure out exactly where the error originates from, despite the simplicity of the code.
Main.py
import pygame
from pygame.locals import *
from MV import *
import ctypes
from OpenGL.GL import *
from OpenGL.GL import shaders
from OpenGL.GLU import *
import teapot as tp
vertex_shader = '''
#version 420
in vec3 vpos_modelspace;
in vec3 vnorm_modelspace;
uniform mat4 mvp;
out vec4 vertcolor;
void main(){
vertcolor = vec4(vnorm_modelspace, 1.0);
gl_Position = mvp * vec4(vpos_modelspace, 1.0);
}
'''
fragment_shader = '''
#version 420
in vec4 vertcolor;
out vec4 fragcolor;
void main(){
fragcolor = vertcolor;
}
'''
model = tp.teapot
pygame.init()
canvas = pygame.display.set_mode((800, 600), DOUBLEBUF|OPENGL)
pygame.display.set_caption('Test')
glClearColor(.5, .5, .5, 1)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LESS)
glDisable(GL_CULL_FACE)
VERTEXSHADER = shaders.compileShader(vertex_shader, GL_VERTEX_SHADER)
FRAGMENTSHADER = shaders.compileShader(fragment_shader, GL_FRAGMENT_SHADER)
program = shaders.compileProgram(VERTEXSHADER, FRAGMENTSHADER)
glUseProgram(program)
vpos_loc = glGetAttribLocation(program, 'vpos_modelspace')
vnorm_loc = glGetAttribLocation(program, 'vnorm_modelspace')
mvp_loc = glGetUniformLocation(program, 'mvp')
eye = numpy.array([0, 0, 1], dtype=numpy.float32)
at = numpy.array([0, 0, 0], dtype=numpy.float32)
up = numpy.array([0, 1, 0], dtype=numpy.float32)
mvp = frustum(-1, 1, 1, -1, .1, 1000)#lookAt(eye, at, up)
vao = glGenVertexArrays(1)
glBindVertexArray(vao)
vbo_pos = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo_pos)
vbo_norm = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo_norm)
verts = []
normals = []
for i in range(0, len(model.faces), 3):
index = model.faces[i:i+3]
verts.extend(model.vertices[3*index[0]:3*index[0]+3])
verts.extend(model.vertices[3*index[1]:3*index[1]+3])
verts.extend(model.vertices[3*index[2]:3*index[2]+3])
normals.extend(model.normals[3*index[0]:3*index[0]+3])
normals.extend(model.normals[3*index[1]:3*index[1]+3])
normals.extend(model.normals[3*index[2]:3*index[2]+3])
verts = numpy.array(verts, dtype=numpy.float32)
normals = numpy.array(normals, dtype=numpy.float32)
glBindBuffer(GL_ARRAY_BUFFER, vbo_pos)
glBufferData(GL_ARRAY_BUFFER, verts.size * verts.itemsize, verts, GL_STATIC_DRAW)
glVertexAttribPointer(vpos_loc, 3, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0))
glEnableVertexAttribArray(vpos_loc)
glBindBuffer(GL_ARRAY_BUFFER, vbo_norm)
glBufferData(GL_ARRAY_BUFFER, normals.size * normals.itemsize, normals, GL_STATIC_DRAW)
glVertexAttribPointer(vnorm_loc, 3, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0))
glEnableVertexAttribArray(vnorm_loc)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
while(True):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glUseProgram(program)
rotation_matrix = rotate(.01, [0, 1, 0])
mvp = mvp # rotation_matrix
glUniformMatrix4fv(mvp_loc, 1, GL_FALSE, mvp.flatten())
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glBindVertexArray(vao)
glDrawArrays(GL_TRIANGLES, 0, int(verts.size/3))
glBindVertexArray(0)
glUseProgram(0)
pygame.display.flip()
main()
MV.py
import numpy
def normalize(vector):
return vector/numpy.linalg.norm(vector)
def translate(pos):
return numpy.array([[1, 0, 0, pos[0]],
[0, 1, 0, pos[1]],
[0, 0, 1, pos[2]],
[0, 0, 0, 1]], dtype=numpy.float32)
def rotate(angle, axis):
rads = angle * numpy.pi/180
v = normalize(axis)
c = numpy.cos(rads)
omc = 1-c
s = numpy.sin(rads)
return numpy.array([[v[0]*v[0]*omc + c, v[0]*v[1]*omc - v[2]*s, v[0]*v[2]*omc + v[1]*s, 0],
[v[0]*v[1]*omc + v[2]*s, v[1]*v[1]*omc + c, v[1]*v[2]*omc - v[0]*s, 0],
[v[0]*v[2]*omc - v[1]*s, v[1]*v[2]*omc + v[0]*s, v[2]*v[2]*omc + c, 0],
[0, 0, 0, 1]], dtype=numpy.float32)
def lookAt(eye, at, up):
n = normalize(at-eye)
u = normalize(numpy.cross(n, up))
v = normalize(numpy.cross(u, n))
rotate = numpy.array([[u[0], v[0], -n[0], 0],
[u[1], v[1], -n[1], 0],
[u[2], v[2], -n[2], 0],
[0, 0, 0, 1]], dtype=numpy.float32).transpose()
return rotate#translate(-eye)
def frustum(left, right, top, bottom, near, far):
rl = right-left
tb = top-bottom
fn = far-near
return numpy.array([[2*near/rl, 0, (right+left)/rl, 0],
[0, 2*near/tb, (top+bottom)/tb, 0],
[0, 0, -(far+near)/fn, -(2*far*near)/fn],
[0, 0, -1, 0]], dtype=numpy.float32)
The output shows the teapot being rotated (though not about the axis that I expected) and sort of shrinking and disappearing at rotations of 0, pi, 2pi, etc. I believe the teapot vertices are being processed correctly, as it does show up when rotated and is correctly shaded with normal values.
Output at 5 degrees - Model is 'growing'
Output at 30 degrees - Strange culling?
Output at 60 degrees - Relatively normal
Output at 170 degrees - Model is 'shrinking'
Output at 190 degrees - Model is 'growing' on the other side of the plane
At rotations 0, pi, 2pi, etc the model is completely invisible/too small to see.

Categories