Difference between revisions of "Wfmesh"

From PyMOLWiki
Jump to: navigation, search
(Undo revision 8034 by Cowsandmilk (Talk))
Line 61: Line 61:
 
#  Create openGL objects from a wavefront (obj) file
 
#  Create openGL objects from a wavefront (obj) file
 
###############################################
 
###############################################
+
 
 
import os
 
import os
import string
 
 
import re
 
import re
 
import math
 
import math
 
from pymol.opengl.gl import *
 
from pymol.opengl.gl import *
 
from pymol.callback import Callback
 
from pymol.callback import Callback
+
 
+
 
 
# Wrapper Function, to create a given WFObj with a specific name (flip = 1 if OpenFX + Crossroads used)
 
# Wrapper Function, to create a given WFObj with a specific name (flip = 1 if OpenFX + Crossroads used)
 
def createWFObj(file, name,translate=[0,0,0],flip=0):
 
def createWFObj(file, name,translate=[0,0,0],flip=0):
        obj = WFMesh(file,translate,flip)
+
obj = WFMesh(file,translate,flip)
        cmd.load_callback(obj,name)
+
cmd.load_callback(obj,name)
+
 
+
 
 
# Class for Wavefront Mesh
 
# Class for Wavefront Mesh
 
class WFMesh(Callback):
 
class WFMesh(Callback):
+
 
 
     verts = []        # list of vertices
 
     verts = []        # list of vertices
 
     polys = []        # list of poylgons
 
     polys = []        # list of poylgons
Line 85: Line 84:
 
     vavenorms = []    # list of vertex normals, redundant -- I'm far froma python pro.
 
     vavenorms = []    # list of vertex normals, redundant -- I'm far froma python pro.
 
     sections = {}    # list of sections of mesh
 
     sections = {}    # list of sections of mesh
+
 
 
     # Read mesh into memory
 
     # Read mesh into memory
 
     def readOBJ(self,file):
 
     def readOBJ(self,file):
 
         if os.path.exists(file):
 
         if os.path.exists(file):
            input = open(file,'r')
+
    input = open(file,'r')
            for line in input:
+
    for line in input:
                dat = re.split("\s+", line)
+
dat = re.split("\s+", line)
+
 
                # Find vertex line
+
# Find vertex line
                if line[0] == 'v' and line[1] != 't' and line[1] != 'n':    self.verts.append([dat[1],dat[2],dat[3]])
+
if line[0] == 'v' and line[1] != 't' and line[1] != 'n':    self.verts.append([dat[1],dat[2],dat[3]])
+
 
                # Find polygon line
+
# Find polygon line
                if line[0] == 'f':    self.polys.append([dat[1],dat[2],dat[3]])
+
              if line[0] == 'f':    self.polys.append([dat[1],dat[2],dat[3]])
+
 
                # Find section line
+
# Find section line
                if line[0] == 'g':    self.sections[len(self.polys)] = dat[1]  
+
if line[0] == 'g':    self.sections[len(self.polys)] = dat[1]  
+
 
+
 
     # Compute the normals for each polygon and each vertex            
+
     # Compute the normals for each polygon and each vertex  
 
     def computeNorms(self):
 
     def computeNorms(self):
+
 
        # Compute norms for each polygon
+
# Compute norms for each polygon
        for p in self.polys:
+
for p in self.polys:
                v12 = [float(self.verts[int(p[1])-1][0]) - float(self.verts[int(p[0])-1][0]),\
+
v12 = [float(self.verts[int(p[1])-1][0]) - float(self.verts[int(p[0])-1][0]),\
                      float(self.verts[int(p[1])-1][1]) - float(self.verts[int(p[0])-1][1]),\
+
      float(self.verts[int(p[1])-1][1]) - float(self.verts[int(p[0])-1][1]),\
                      float(self.verts[int(p[1])-1][2]) - float(self.verts[int(p[0])-1][2]) \
+
      float(self.verts[int(p[1])-1][2]) - float(self.verts[int(p[0])-1][2]) \
                      ]
+
      ]
+
                v13 = [float(self.verts[int(p[2])-1][0]) - float(self.verts[int(p[0])-1][0]),\
+
v13 = [float(self.verts[int(p[2])-1][0]) - float(self.verts[int(p[0])-1][0]),\
                      float(self.verts[int(p[2])-1][1]) - float(self.verts[int(p[0])-1][1]),\
+
      float(self.verts[int(p[2])-1][1]) - float(self.verts[int(p[0])-1][1]),\
                      float(self.verts[int(p[2])-1][2]) - float(self.verts[int(p[0])-1][2]) \
+
      float(self.verts[int(p[2])-1][2]) - float(self.verts[int(p[0])-1][2]) \
                      ]  
+
      ]
+
 
                # Compute poly normal
+
# Compute poly normal
                polynorm = self.cross(v12,v13)  
+
polynorm = self.cross(v12,v13)  
                norm = self.normalize(polynorm)
+
norm = self.normalize(polynorm)
+
 
+
 
                # Files created by OpenFX, Crossroads combination need have their normals flipped      
+
# Files created by OpenFX, Crossroads combination need have their normals flipped
                if self.flip:
+
if self.flip:
                        norm[0] = -norm[0]
+
norm[0] = -norm[0]
                        norm[1] = -norm[1]
+
norm[1] = -norm[1]
                        norm[2] = -norm[2]
+
norm[2] = -norm[2]
+
 
                # Append poly norm to polygonal norm array
+
# Append poly norm to polygonal norm array
                self.pnorms.append(norm)
+
self.pnorms.append(norm)
+
 
                # Add norm to each vertexes norm..
+
# Add norm to each vertexes norm..
                try:
+
        try:
                    self.vnorms[int(p[0])-1] = [float(self.vnorms[int(p[0])-1][0]) + norm[0],
+
    self.vnorms[int(p[0])-1] = [float(self.vnorms[int(p[0])-1][0]) + norm[0],
                                            float(self.vnorms[int(p[0])-1][1]) + norm[1],
+
    float(self.vnorms[int(p[0])-1][1]) + norm[1],
                                            float(self.vnorms[int(p[0])-1][2]) + norm[2]
+
    float(self.vnorms[int(p[0])-1][2]) + norm[2]
                                          ]
+
  ]
                except:
+
except:
                    self.vnorms[int(p[0])-1] = [norm[0],norm[1],norm[2]]
+
    self.vnorms[int(p[0])-1] = [norm[0],norm[1],norm[2]]
+
 
                try:                                      
+
        try:  
                    self.vnorms[int(p[1])-1]  = [float(self.vnorms[int(p[1])-1][0]) + norm[0],
+
    self.vnorms[int(p[1])-1]  = [float(self.vnorms[int(p[1])-1][0]) + norm[0],
                                            float(self.vnorms[int(p[1])-1][1]) + norm[1],
+
    float(self.vnorms[int(p[1])-1][1]) + norm[1],
                                            float(self.vnorms[int(p[1])-1][2]) + norm[2]
+
    float(self.vnorms[int(p[1])-1][2]) + norm[2]
                                          ]
+
  ]
                except:
+
except:
                    self.vnorms[int(p[1])-1] = [norm[0],norm[1],norm[2]]
+
    self.vnorms[int(p[1])-1] = [norm[0],norm[1],norm[2]]
+
 
                try:
+
try:
                    self.vnorms[int(p[2])-1]  = [float(self.vnorms[int(p[1])-1][0]) + norm[0],
+
    self.vnorms[int(p[2])-1]  = [float(self.vnorms[int(p[1])-1][0]) + norm[0],
                                            float(self.vnorms[int(p[1])-1][1]) + norm[1],
+
    float(self.vnorms[int(p[1])-1][1]) + norm[1],
                                            float(self.vnorms[int(p[1])-1][2]) + norm[2]
+
    float(self.vnorms[int(p[1])-1][2]) + norm[2]
                                          ]
+
  ]
                except:
+
except:
                    self.vnorms[int(p[2])-1] = [norm[0],norm[1],norm[2]]
+
    self.vnorms[int(p[2])-1] = [norm[0],norm[1],norm[2]]
+
 
+
     
 
         # Average out each vnorm..
 
         # Average out each vnorm..
        index = 0
+
index = 0
        for v in self.vnorms.values():
+
      for v in self.vnorms.values():
                self.vavenorms.append([v[0]/4, v[1]/4, v[2]/4])        
+
self.vavenorms.append([v[0]/4, v[1]/4, v[2]/4])
                index += 1
+
index += 1
+
 
 
     # Utility function to normalize a given vector
 
     # Utility function to normalize a given vector
 
     def normalize(self,v):
 
     def normalize(self,v):
        mag = v[0]*v[0]+v[1]*v[1]+v[2]*v[2]
+
mag = v[0]*v[0]+v[1]*v[1]+v[2]*v[2]
        if mag <= 0:
+
if mag <= 0:
            mag = 1
+
      mag = 1
        else:
+
else:
            mag = math.sqrt(mag)
+
    mag = math.sqrt(mag)
+
        return [v[0]/mag, v[1]/mag,v[2]/mag]
+
return [v[0]/mag, v[1]/mag,v[2]/mag]
+
 
 
     # Utility cross product function
 
     # Utility cross product function
 
     def cross(self,v1,v2):
 
     def cross(self,v1,v2):
        x = 0
+
x = 0
        y = 1
+
y = 1
        z = 2
+
z = 2
+
 
        return [v1[y]*v2[z] - v1[z]*v2[y],\
+
return [v1[y]*v2[z] - v1[z]*v2[y],\
                v1[z]*v2[x] - v1[x]*v2[z],\
+
v1[z]*v2[x] - v1[x]*v2[z],\
                v1[x]*v2[y] - v1[y]*v2[x]
+
v1[x]*v2[y] - v1[y]*v2[x]
                ]
+
]
+
         
 
     # Constructor
 
     # Constructor
 
     def __init__(self, file,translate=[0,0,0],flip=0):
 
     def __init__(self, file,translate=[0,0,0],flip=0):
Line 192: Line 191:
 
         self.vnorms = {}
 
         self.vnorms = {}
 
         self.vavenorms = []
 
         self.vavenorms = []
        self.translate = translate
+
self.translate = translate
        self.flip      = flip  
+
self.flip      = flip  
+
 
 
         print "Read in file: "+str(file)
 
         print "Read in file: "+str(file)
        self.readOBJ(file)
+
self.readOBJ(file)
        print "Done reading in WFMesh, now compute norms"
+
print "Done reading in WFMesh, now compute norms"
        self.computeNorms()
+
self.computeNorms()
        print "Done computing norms, now display WFMesh"
+
print "Done computing norms, now display WFMesh"
+
 
 
     # Draw Function
 
     # Draw Function
 
     def __call__(self):
 
     def __call__(self):
+
        glColorMaterial(GL_FRONT, GL_DIFFUSE);
+
glColorMaterial(GL_FRONT, GL_DIFFUSE);
 
         glEnable(GL_COLOR_MATERIAL);
 
         glEnable(GL_COLOR_MATERIAL);
        glShadeModel(GL_SMOOTH);
+
glShadeModel(GL_SMOOTH);
+
 
        # Color Everything grey
+
# Color Everything grey
 
         glColor3f(0.5,0.5,0.5);
 
         glColor3f(0.5,0.5,0.5);
+
 
        index = 0
+
index = 0
        glPushMatrix()
+
glPushMatrix()
        glTranslated(self.translate[0],self.translate[1],self.translate[2])
+
glTranslated(self.translate[0],self.translate[1],self.translate[2])
        for p in self.polys:
+
for p in self.polys:
                glBegin(GL_POLYGON)
+
glBegin(GL_POLYGON)
                glNormal3f(float(self.pnorms[index][0]),float(self.pnorms[index][1]),float(self.pnorms[index][2]))
+
glNormal3f(float(self.pnorms[index][0]),float(self.pnorms[index][1]),float(self.pnorms[index][2]))
+
                for i in range(0,len(p)):
+
for i in range(0,len(p)):
                        glVertex3f(float(self.verts[int(p[i])-1][0]),float(self.verts[int(p[i])-1][1]),float(self.verts[int(p[i])-1][2]))
+
glVertex3f(float(self.verts[int(p[i])-1][0]),float(self.verts[int(p[i])-1][1]),float(self.verts[int(p[i])-1][2]))
+
 
                        # Vertex Normals - not computed correctly, so commented out for now
+
# Vertex Normals - not computed correctly, so commented out for now
#                       norm = self.vnorms[int(p[i])-1]
+
# norm = self.vnorms[int(p[i])-1]
#                       glNormal3f(float(norm[0]),float(norm[1]),float(norm[2]))
+
# glNormal3f(float(norm[0]),float(norm[1]),float(norm[2]))
                glEnd()
+
glEnd()
                index += 1
+
index += 1
        glPopMatrix()
+
glPopMatrix()
+
 
+
 
+
 
+
 
+
 
 
cmd.extend("createWFObj", createWFObj)
 
cmd.extend("createWFObj", createWFObj)
  

Revision as of 15:09, 14 February 2010

DESCRIPTION

This script will create an object for any Wavefront(.OBJ) mesh file. This is a way to extend the number of objects you can use. Also, you have more control over the coloring, transformations, etc than the CGOs. Although there are a number of these obj files on the web, you can also easily created them with open source tools (OpenFX, Crossroads3D). It takes literally, 2 min to get an object created and then loaded into pymol. Simply open OpenFX Designer, click File->Insert->Model, then choose any of the models (or create your own of course!), then export it as .3ds file. Then open the .3ds file from Crossroads3D and export as Wavefront OBJ.

  • createWFMesh - create a mesh object from Wavefront (*.obj) formated file

IMAGES

Star Wars Anyone?
A Torus, as an example shape you could do. Notice polygon normals are being used...need smoothing!





SETUP

Simply "run WFMesh.py"

NOTES / STATUS

  • Tested on Pymolv0.97, Windows platform, should work on linux as well.
  • Coloring is fixed for grey and sections of mesh are stored, but not used.
  • Simple opengl calls; not optimized (display lists, etc) or anything.
  • Vertex Normal code is broken, so normals are per polygon right now.
  • Post problems in the discussion page, on 'my talk' page or just email me : dwkulp@mail.med.upenn.edu


USAGE

createWFObj file, name [,translate=[0,0,0]] [,flip=0]

EXAMPLES

  createWFObj "ship.obj" "Ship"
  createWFObj "torus.obj" "Torus" flip=1  # Flip = 1, if OBJ created by openFX, crossroads3D combination
  createWFObj "torus.obj" "Torus" translate=[10,10,0] flip=1      
  

REFERENCES

OpenFX Crossroads3D

SCRIPTS (WFMesh.py)

WFMesh.py

###############################################
#  File:          WFObj.py
#  Author:        Dan Kulp
#  Creation Date: 5/13/05
#
#  Notes:
#  Create openGL objects from a wavefront (obj) file
###############################################

import os
import re
import math
from pymol.opengl.gl import *
from pymol.callback import Callback


# Wrapper Function, to create a given WFObj with a specific name (flip = 1 if OpenFX + Crossroads used)
def createWFObj(file, name,translate=[0,0,0],flip=0):
	obj = WFMesh(file,translate,flip)
	cmd.load_callback(obj,name)


# Class for Wavefront Mesh
class WFMesh(Callback):

    verts = []        # list of vertices
    polys = []        # list of poylgons
    pnorms = []       # list of polynomal normals
    vnorms = {}       # dict. of vertex normals
    vavenorms = []    # list of vertex normals, redundant -- I'm far froma python pro.
    sections = {}     # list of sections of mesh

    # Read mesh into memory
    def readOBJ(self,file):
        if os.path.exists(file):
	    input = open(file,'r')
	    for line in input:
		dat = re.split("\s+", line)

		# Find vertex line
		if line[0] == 'v' and line[1] != 't' and line[1] != 'n':    self.verts.append([dat[1],dat[2],dat[3]])

		# Find polygon line
       	        if line[0] == 'f':    self.polys.append([dat[1],dat[2],dat[3]])

		# Find section line
		if line[0] == 'g':    self.sections[len(self.polys)] = dat[1] 


    # Compute the normals for each polygon and each vertex   		
    def computeNorms(self):

	# Compute norms for each polygon
	for p in self.polys:
		v12 = [float(self.verts[int(p[1])-1][0]) - float(self.verts[int(p[0])-1][0]),\
		       float(self.verts[int(p[1])-1][1]) - float(self.verts[int(p[0])-1][1]),\
		       float(self.verts[int(p[1])-1][2]) - float(self.verts[int(p[0])-1][2]) \
		      ]
			
		v13 = [float(self.verts[int(p[2])-1][0]) - float(self.verts[int(p[0])-1][0]),\
		       float(self.verts[int(p[2])-1][1]) - float(self.verts[int(p[0])-1][1]),\
		       float(self.verts[int(p[2])-1][2]) - float(self.verts[int(p[0])-1][2]) \
		      ]	

		# Compute poly normal
		polynorm = self.cross(v12,v13) 
		norm = self.normalize(polynorm)


		# Files created by OpenFX, Crossroads combination need have their normals flipped	
		if self.flip:
			norm[0] = -norm[0]
			norm[1] = -norm[1]
			norm[2] = -norm[2]

		# Append poly norm to polygonal norm array
		self.pnorms.append(norm)

		# Add norm to each vertexes norm..
	        try:
		    self.vnorms[int(p[0])-1] = [float(self.vnorms[int(p[0])-1][0]) + norm[0],
					    float(self.vnorms[int(p[0])-1][1]) + norm[1],
					    float(self.vnorms[int(p[0])-1][2]) + norm[2]
					   ]
		except:
		    self.vnorms[int(p[0])-1] = [norm[0],norm[1],norm[2]]

	        try:					   
		    self.vnorms[int(p[1])-1]  = [float(self.vnorms[int(p[1])-1][0]) + norm[0],
					    float(self.vnorms[int(p[1])-1][1]) + norm[1],
					    float(self.vnorms[int(p[1])-1][2]) + norm[2]
					   ]
		except:
		    self.vnorms[int(p[1])-1] = [norm[0],norm[1],norm[2]]

		try:
		    self.vnorms[int(p[2])-1]  = [float(self.vnorms[int(p[1])-1][0]) + norm[0],
					    float(self.vnorms[int(p[1])-1][1]) + norm[1],
					    float(self.vnorms[int(p[1])-1][2]) + norm[2]
					   ]
		except:
		    self.vnorms[int(p[2])-1] = [norm[0],norm[1],norm[2]]

      
        # Average out each vnorm..
	index = 0
      	for v in self.vnorms.values():
		self.vavenorms.append([v[0]/4, v[1]/4, v[2]/4])		
		index += 1

    # Utility function to normalize a given vector
    def normalize(self,v):
	mag = v[0]*v[0]+v[1]*v[1]+v[2]*v[2]
	if mag <= 0:
  	    mag = 1
	else:
	    mag = math.sqrt(mag)
		
	return [v[0]/mag, v[1]/mag,v[2]/mag]

    # Utility cross product function
    def cross(self,v1,v2):
	x = 0
	y = 1
	z = 2

	return [v1[y]*v2[z] - v1[z]*v2[y],\
		v1[z]*v2[x] - v1[x]*v2[z],\
		v1[x]*v2[y] - v1[y]*v2[x]
		]
		          	
    # Constructor
    def __init__(self, file,translate=[0,0,0],flip=0):
        self.verts = []
        self.polys = [] 
        self.pnorms = []
        self.vnorms = {}
        self.vavenorms = []
	self.translate = translate
	self.flip      = flip 

        print "Read in file: "+str(file)
	self.readOBJ(file)
	print "Done reading in WFMesh, now compute norms"
	self.computeNorms()
	print "Done computing norms, now display WFMesh"

    # Draw Function
    def __call__(self):
	
	glColorMaterial(GL_FRONT, GL_DIFFUSE);	
        glEnable(GL_COLOR_MATERIAL);
	glShadeModel(GL_SMOOTH);

	# Color Everything grey
        glColor3f(0.5,0.5,0.5);

	index = 0
	glPushMatrix()
	glTranslated(self.translate[0],self.translate[1],self.translate[2])
	for p in self.polys:
		glBegin(GL_POLYGON)
		glNormal3f(float(self.pnorms[index][0]),float(self.pnorms[index][1]),float(self.pnorms[index][2]))
		
		for i in range(0,len(p)):
			glVertex3f(float(self.verts[int(p[i])-1][0]),float(self.verts[int(p[i])-1][1]),float(self.verts[int(p[i])-1][2]))

			# Vertex Normals - not computed correctly, so commented out for now
#			norm = self.vnorms[int(p[i])-1]
#			glNormal3f(float(norm[0]),float(norm[1]),float(norm[2]))
		glEnd()
		index += 1
	glPopMatrix()





cmd.extend("createWFObj", createWFObj)

ADDITIONAL RESOURCES

Torus.obj Torus.zip