いまさら 超時空要塞マクロス リガード 3Dモデル 2

前回からの続きです。Open Dynamics Engineでは、任意の三角形は、節点の座標データと、節点の番号データの配列で扱われます。STLデータでは、各三角形の頂点座標と法線ベクトルで構成されているので、少々変換が必要です。下はPyOdeのTutorialから、TriMeshDataの説明です。

前回のコードの読み込む処理を変更しました。

import os
import struct

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import pygame
from pygame.locals import *

import numpy as np
from struct import unpack

NormalV =[]
NodePoint = []
Vertex1 = []
Vertex2 = []
Vertex3 = []
NVertex = [[0,1,2],[0,1,2]]

Eye_from_x = 60.0
Eye_from_y = 50.0
Eye_from_z = 100.0

Center_X =0.
Center_Y =0.
Center_Z =0.

T_Color = [0.5, 0.7, 0.5, 1.0] #Object Color
 
def BinarySTL(fname):
 global NVertex
 #read start of file to determine if its a binay stl file or a ascii stl file
 fp=open(fname,'rb')
 h=fp.read(80)
 type=h[0:5]
 fp.close()

if type=='solid':
 print ( "reading text file"+str(fname))
 return
 else:
 print ("reading binary stl file "+str(fname,))
 fp = open(fname, 'rb')
 Header = fp.read(80)
 nn = fp.read(4)
 Numtri = unpack('i', nn)[0]
 #print nn
 record_dtype = np.dtype([
 ('normals', np.float32,(3,)), 
 ('Vertex1', np.float32,(3,)),
 ('Vertex2', np.float32,(3,)),
 ('Vertex3', np.float32,(3,)) , 
 ('atttr', '<i2',(1,) )
 ])
 data = np.fromfile(fp , dtype = record_dtype , count =Numtri)
 fp.close()
 
 Normals = data['normals']
 Vertex1= data['Vertex1']
 Vertex2= data['Vertex2']
 Vertex3= data['Vertex3']
 
 p = np.append(Vertex1,Vertex2,axis=0)
 p = np.append(p,Vertex3,axis=0) #list(v1)
 Points =np.array(list(set(tuple(p1) for p1 in p)))

NVertex = np.resize(NVertex,(len(Vertex1),3))
 NVertex[0][0] = Points.tolist().index([Vertex1[0][0],Vertex1[0][1],Vertex1[0][2]])
 NVertex[0][1] = Points.tolist().index([Vertex2[0][0],Vertex2[0][1],Vertex2[0][2]])
 NVertex[0][2] = Points.tolist().index([Vertex3[0][0],Vertex3[0][1],Vertex3[0][2]])
 for i in range(1,len(Vertex1)):
# print(i)
 NVertex[i][0] = Points.tolist().index([Vertex1[i][0],Vertex1[i][1],Vertex1[i][2]])
 NVertex[i][1] = Points.tolist().index([Vertex2[i][0],Vertex2[i][1],Vertex2[i][2]])
 NVertex[i][2] = Points.tolist().index([Vertex3[i][0],Vertex3[i][1],Vertex3[i][2]])
 
 return Header,Points,Normals
 
 return
 
def draw_box():
 global NormalV,NodePoint,NVertex

 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, T_Color)
 glPushMatrix()
 glBegin(GL_TRIANGLES)
 for i in range(len(NormalV)):
 glNormal3f(NormalV[i][0],NormalV[i][1],NormalV[i][2])
 glVertex3f(NodePoint[NVertex[i][0]][0],NodePoint[NVertex[i][0]][1],NodePoint[NVertex[i][0]][2])
 glVertex3f(NodePoint[NVertex[i][1]][0],NodePoint[NVertex[i][1]][1],NodePoint[NVertex[i][1]][2])
 glVertex3f(NodePoint[NVertex[i][2]][0],NodePoint[NVertex[i][2]][1],NodePoint[NVertex[i][2]][2])
 glEnd()
 glPopMatrix()

def prepare_GL():
 global quadratic

 quadratic = gluNewQuadric()
 glViewport(0,0,640,480)

 glClearColor(0.8,0.8,0.9,0)
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glDisable(GL_LIGHTING)
 glEnable(GL_LIGHTING)
 glEnable(GL_NORMALIZE)
 glShadeModel(GL_FLAT)

 glMatrixMode(GL_PROJECTION)
 glLoadIdentity()
 gluPerspective (90,1.3333,0.1,1000.)

 glMatrixMode(GL_MODELVIEW)
 glLoadIdentity()

 glLightfv(GL_LIGHT0,GL_POSITION,[0,0,1,0])
 glLightfv(GL_LIGHT0,GL_DIFFUSE,[1,1,1,1])
 glLightfv(GL_LIGHT0,GL_SPECULAR,[1,1,1,1])
 glEnable(GL_LIGHT0)

glDisable(GL_CULL_FACE)

gluLookAt (Eye_from_x, Eye_from_y, Eye_from_z, Center_X, Center_Y, Center_Z, 0.0, 0.0, 1.0)

def init_GL():

 glutInit ([])

 glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH)

 x = 0
 y = 0
 width = 640
 height = 480
 glutInitWindowPosition (x, y);
 glutInitWindowSize (width, height);
 glutCreateWindow ("test".encode("cp932"))
 glEnable(GL_DEPTH_TEST)
 glEnable(GL_CULL_FACE);
 glCullFace(GL_BACK);

def _keyfunc (c, x, y):
 global Eye_from_x ,Eye_from_y, Eye_from_z,Center_Z
 
 if c == "p".encode("cp932"):
 Center_Z = Center_Z + 5.0
 elif c == "l".encode("cp932"):
 Center_Z = Center_Z - 5.0
 elif c == "j".encode("cp932"):
 Eye_from_x = Eye_from_x + 5.0
 elif c == "f".encode("cp932"):
 Eye_from_x = Eye_from_x - 5.0
 elif c == "b".encode("cp932"):
 Eye_from_z = Eye_from_z + 5.0
 elif c == "c".encode("cp932"):
 Eye_from_z = Eye_from_z - 5.0
 elif c == "u".encode("cp932"):
 Eye_from_y = Eye_from_y + 5.0
 elif c == "r".encode("cp932"):
 Eye_from_y = Eye_from_y - 5.0
 elif c == "q".encode("cp932"):
 sys.exit (0)
 else:
 print ("key missed")
 
 glutPostRedisplay()

def _drawfunc ():

    green = [0.2, 0.8, 0.3, 1.0]
    blue = [0.0, 0.0, 1.0, 1.0]
    red = [1.0, 0.0, 0.0, 1.0]
    prepare_GL()

    draw_box()
    glutSwapBuffers ()



def _idlefunc ():
 
 glutPostRedisplay ()



#main program loop
def main():
 global NormalV,Vertex1,Vertex2,Vertex3,NVertex,NodePoint

fname = "Zentradi_Battlepod_-_Low_Poly.stl" # "porsche.stl"

head,NodePoint,NormalV = BinarySTL(fname)

print(NVertex)
 print(len(NVertex))

print(NodePoint)
 print(len(NodePoint))
 
 max_x = -99999999999.
 min_x = 99999999999.
 max_y = -99999999999.
 min_y = 99999999999.
 max_z = -99999999999.
 min_z = 99999999999.
 for i in range(len(NodePoint)):
 if (max_x < NodePoint[i][0]): max_x = NodePoint[i][0]
 if (min_x > NodePoint[i][0]): min_x = NodePoint[i][0]
 if (max_y < NodePoint[i][1]): max_y = NodePoint[i][1]
 if (min_y > NodePoint[i][1]): min_y = NodePoint[i][1]
 if (max_z < NodePoint[i][2]): max_z = NodePoint[i][2]
 if (min_z > NodePoint[i][2]): min_z = NodePoint[i][2]
 print (max_x,min_x)
 print (max_y,min_y)
 print (max_z,min_z)
 Center_X = (max_x+min_x)/2.
 Center_Y = (max_y+min_y)/2.
 Center_Z = (max_z+min_z)/2.
 
 init_GL()
 glutKeyboardFunc (_keyfunc)
 glutDisplayFunc (_drawfunc)
 glutIdleFunc (_idlefunc)

glutMainLoop ()



if __name__ == '__main__':
 main()

貼り付け時にカラムがおかしくなってしまっているかも・・・。

今回が左(色を変えました)、前回が右です。うまくいっているようです。

次回は、ODEにおける質量などの情報の付加です。