povray export 0.1x

Hi, At the moment theres no opensource povray exporters.
Hadnt written a render exporter so I gave this a shot- its small and easy to read, feel free to modify- its wip.

not finished but I wanted to write a simple povray exporter that rendered without redoing all your settings. Aim to match blenders internal renderer for lighting and use as many setings as possible.
Exports Lights- point/spot, arealight
Exports 1 material per mesh :confused: - Need some povray howto for switching materials in a mesh2 mesh.
No images/textures yet.
RayMirror, shadow and material settings cross over fairly well.

Should be fairly fast, uses the new mesh wrapper.


update
*added vertex colour export
*smooth/flat faces with normals
*multiple material export per mesh
*raytraced settingsd, reflextions etc


Update
Use getRawFromObject
multiple materials/vertex colours supported.


from math import atan, pi
from Blender import *

def getMeshFromObject(object, name=None, mesh=None):
	if mesh:
		mesh.verts = None # Clear the meshg
	else:
		if not name:
			mesh = Mesh.New()
		else:
			mesh = Mesh.New(name)
	
	
	type = object.getType()
	dataname = object.getData(1)
	
	try:
		mesh.getFromObject(object.name) 
	except:
		return None
	
	if type == 'Mesh':
		tempMe = Mesh.Get( dataname )
		mesh.materials = tempMe.materials
		mesh.degr = tempMe.degr
		mesh.mode = tempMe.mode
	else:
		try:
			data = object.getData()
			materials = data.getMaterials()
			mesh.materials = materials
			print 'assigning materials for non mesh'
		except:
			print 'Cant assign materials to', type
	
	return mesh
	
	'''
	elsetype == 'Curve':
		tempCurve = Curve.Get(dataname)
		mesh.materials = tempCurve.materials
		
	elif type == 'Surf':
		
		
	elif type == 'Mball':
		# metaball materials not accessable
		pass
	'''


def save_pov(filename):
	file = open(filename, 'w')
	scene = Scene.GetCurrent()
	context = scene.getRenderingContext()
	materialTable = {}
	
	# Get the container mesh.
	containerMesh = meshName = tempMesh = None
	for meshName in NMesh.GetNames():
		if meshName.startswith('pov_tmp_mesh'):
			tempMesh = Mesh.Get(meshName)
			if not tempMesh.users:
				containerMesh = tempMesh
	if not containerMesh:
		containerMesh = Mesh.New('pov_tmp_mesh')
	del meshName
	del tempMesh
	
	
	def saneName(name):
		name = name.lower()
		for ch in ' /\\+=-[]{}().,<>\'":;[email protected]#$%^&*|?':
			name = name.replace(ch, '_')
		return name
		
	
	def writeMatrix(matrix):
		file.write('	matrix <%.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f>
' %\
		(matrix[0][0], matrix[0][1], matrix[0][2],  matrix[1][0], matrix[1][1], matrix[1][2],  matrix[2][0], matrix[2][1], matrix[2][2],  matrix[3][0], matrix[3][1], matrix[3][2]) )
	
	def exportCamera():
		camera = scene.getCurrentCamera()
		matrix = camera.matrixWorld
		
		Qsize=float(context.imageSizeX())/float(context.imageSizeY())
		
		file.write('camera {
')
		file.write('	location  <0, 0, 0>
')
		file.write('	look_at  <0, 0, -1>
')
		file.write('	right <%s, 0, 0>
' % -Qsize)
		file.write('	up <0, 1, 0>
')
		file.write('	angle  %f 
' % (360.0*atan(16.0/camera.getData().getLens())/pi))
		
		file.write('	rotate  <%.6f, %.6f, %.6f>
' % tuple(matrix.rotationPart().toEuler()))
		file.write('	translate <%.6f, %.6f, %.6f>
' % (matrix[3][0], matrix[3][1], matrix[3][2]))
		file.write('}
')
	
	
	
	def exportLamps(lamps):
		# Get all lamps
		for ob in lamps:
			lamp = ob.getData()
			
			matrix = ob.matrixWorld
			
			color = tuple([c * lamp.energy for c in lamp.col]) # Colour is modified by energy
			
		
			file.write('light_source')
			file.write('{
')
			file.write('	< 0,0,0 >
')
			file.write('	color red %.6f green %.6f blue %.6f
' % color)
			
			if lamp.type == 0: # Point Lamp 
				pass
			elif lamp.type == 2: # Spot
				file.write('	spotlight
')
				
				# Falloff is the main radius from the centre line
				file.write('	falloff %.2f
' % (lamp.spotSize/2.0) ) # 1 TO 179 FOR BOTH
				file.write('	radius %.6f
' % ((lamp.spotSize/2.0) * (1-lamp.spotBlend)) ) 
				
				# Blender does not have a tightness equivilent, 0 is most like blender default.
				file.write('	tightness 0
') # 0:10f
				
				file.write('	point_at  <0, 0, -1>
')
			elif lamp.type == 4:
				file.write('	area_light <%d,0,0>,<0,0,%d> %d, %d
' % (lamp.areaSizeX, lamp.areaSizeY, lamp.raySamplesX, lamp.raySamplesY))
				file.write('	adaptive 1
')
				file.write('	jitter
')
				
			if lamp.mode & Lamp.Modes['Shadows'] or lamp.mode & Lamp.Modes['RayShadow'] : # Only shadow buffer shadows :p- Should use ray.
				pass
			else:
				file.write('	shadowless
')	
			
			file.write('	fade_distance %.6f
' % lamp.dist)
			file.write('	fade_power %d
' % 1) # Could use blenders lamp quad?
			writeMatrix(matrix)
			
			file.write('}
')
	
	def exportMeshs(sel):
		def bMat2PovString(material):
			povstring = 'finish {'
			if world != None:
				povstring += 'ambient <%.6f, %.6f, %.6f> ' % tuple([c*material.amb for c in world.amb])
			
			povstring += 'diffuse %.6f ' % material.ref
			povstring += 'specular %.6f ' % material.spec
			
			mode = material.mode
			if mode & Material.Modes['RAYMIRROR']:
				#povstring += 'interior { ior %.6f } ' % material.IOR
				if material.rayMirr:
					povstring += 'reflection {'
					povstring += '<%.6f, %.6f, %.6f>' % tuple(material.mirCol) # Should ask for ray mirror flag
					povstring += 'fresnel 1 falloff %.6f exponent %.6f metallic %.6f} ' % (material.fresnelDepth, material.fresnelDepthFac, material.rayMirr)
				
				
					
			if mode & Material.Modes['RAYTRANSP']:
				#povstring += 'interior { ior %.6f } ' % material.IOR
				pass
				#~ finish {
				#~ reflection {
				  #~ [COLOR_REFLECTION_MIN,] COLOR_REFLECTION_MAX
				  #~ [fresnel BOOL_ON_OFF]
				  #~ [falloff FLOAT_FALLOFF]
				  #~ [exponmaterialTableent FLOAT_EXPONENT]
				  #~ [metallic FLOAT_METALLIC]
				#~ }
			#~ }
			#~ [interior { ior IOR }]
			#file.write('		roughness %.6f
' % (material.hard*0.5))
			#file.write('			crand 0.0
') # Sand granyness
			#file.write('			metallic %.6f
' % material.spec)
			#file.write('			phong %.6f
' % material.spec)
			#file.write('			phong_size %.6f
' % material.spec)
			povstring += 'brilliance %.6f ' % (material.hard/256.0) # Like hardness
			povstring += '}'
			#file.write('	}
')
			return povstring
			
			
			
		
		world = World.GetCurrent()
		
		# Convert all materials to strings we can access directly per vertex.
		for material in Material.Get():
			materialTable[material.name] = bMat2PovString(material)
		
		
		
		
		for ob in sel:
			matrix = ob.matrixWorld
			'''
			me = Mesh.Get(ob.getData(name_only=1))
			if me.materials:
				material = me.materials[0]
			else:
				material = Material.New()
			'''
			me = getMeshFromObject(ob, '', containerMesh)
			if not me:
				continue
			
			# quads incur an extra face
			quadCount = len([f for f in me.faces if len(f.v) == 4])
			
			file.write('mesh2 {
')
			file.write('	vertex_vectors {
')
			file.write('		%s' % (len(me.verts))) # vert count
			for v in me.verts:
				file.write(',
		<%.6f, %.6f, %.6f>' % tuple(v.co)) # vert count
			file.write('
  }
')
			
			
			# Build unique Normal list
			uniqueNormals = {}
			for f in me.faces:
				# [-1] is a dummy index, use a list so we can modify in place
				if f.smooth: # Use vertex normals
					for v in f.v:
						key = tuple(v.no)
						uniqueNormals[key] = [-1]
				else: # Use face normal
					key = tuple(f.no)
					uniqueNormals[key] = [-1]
					
			
			file.write('	normal_vectors {
')
			file.write('		%d' % len(uniqueNormals)) # vert count
			idx = 0
			for no, index in uniqueNormals.iteritems():
				file.write(',
		<%.6f, %.6f, %.6f>' % no) # vert count
				index[0] = idx
				idx +=1
			file.write('
  }
')
			
			
			# Vertex colours
			vertCols = {} # Use for material colours also.
			if me.faceUV:
				# Generate unique UV's
				uniqueUVs = {}
				
				
				uv_index = 0
				for f in me.faces:
					for i, uv in enumerate(f.uv): # i is for the vertec colours
						key = uv[0], uv[1]
						uniqueUVs[key] = [-1]
						material = me.materials[f.mat]
						if material.mode & Material.Modes['VCOL_PAINT']:
							key = f.col[i].r, f.col[i].g, f.col[i].b, f.mat # Material index!
						else:
							key = int(material.R*255), int(material.G*255), int(material.B*255), f.mat
						
						vertCols[key] = [-1]
				
				
				file.write('	uv_vectors {
')
				#print unique_uvs
				file.write('		%s' % (len(uniqueUVs))) # vert count
				idx = 0
				for uv, index in uniqueUVs.iteritems():
					file.write(',
		<%.6f, %.6f>' % uv)
					index[0] = idx
					idx +=1
				'''
				else:
					# Just add 1 dummy vector, no real UV's
					file.write('		1') # vert count
					file.write(',
		<0.0, 0.0>')
				'''
				file.write('
  }
')
			else:
				# No vertex colours, so write material colours as vertex colours
				for i, material in enumerate(me.materials):
					print me.materials
					if material: # != None 
						key = int(material.R*255), int(material.G*255), int(material.B*255), i # i == f.mat
						vertCols[key] = [-1]
				
			
			# Vert Colours
			file.write('	texture_list {
')
			file.write('		%s' % (len(vertCols))) # vert count
			idx=0
			for col, index in vertCols.iteritems():
				# texture{pigment{rgb<0.0,0.44,0.66>}finish{Material_001_fsh}}
				#file.write(',
		texture { pigment {rgbf<%.6f, %.6f, %.6f, 0.5>}finish{phong 1}}' % col)
				
				
				if me.materials:
					material = me.materials[col[3]]
					materialString = materialTable[material.name]
				else:
					materialString = '' # Dont write anything
				
				float_col = col[0]/255.0, col[1]/255.0, col[2]/255.0, 1-material.alpha, materialString
				#print material.apl
				file.write(',
		texture { pigment {rgbf<%.6f, %.6f, %.6f, %.6f>}%s}' % float_col)
				index[0] = idx
				idx+=1
			
			file.write( '
  }
' )
			
			# Face indicies
			file.write('	face_indices {
')
			file.write('		%d' % (len(me.faces) + quadCount)) # faces count
			for f in me.faces:
				if len(f.v) == 4:
					indicies = (0,1,2), (0,2,3)
				else:
					indicies = ((0,1,2),)
				
				if not me.materials or me.materials[f.mat] == None: # No materials
					for i1, i2, i3 in indicies:
						file.write(',
		<%d,%d,%d>' %\
						(f.v[i1].index, f.v[i2].index, f.v[i3].index)) # vert count
				else:
					material = me.materials[f.mat]
					for i1, i2, i3 in indicies:
						if me.faceUV and material.mode & Material.Modes['VCOL_PAINT']:
							# Colour per vertex - vertex colour
							col1 = f.col[i1]
							col2 = f.col[i2]
							col3 = f.col[i3]
						
							ci1 = vertCols[col1.r, col1.g, col1.b, f.mat][0]
							ci2 = vertCols[col2.r, col2.g, col2.b, f.mat][0]
							ci3 = vertCols[col3.r, col3.g, col3.b, f.mat][0]
						else:
							# Colour per material - flat material colour
							ci1 = ci2 = ci3 = vertCols[int(material.R*255), int(material.G*255), int(material.B*255), f.mat][0]
						
						file.write(',
		<%d,%d,%d>, %d,%d,%d' %\
						(f.v[i1].index, f.v[i2].index, f.v[i3].index, ci1, ci2, ci3)) # vert count
					
					
					
			file.write('
  }
')
			
			# normal_indices indicies
			file.write('	normal_indices {
')
			file.write('		%d' % (len(me.faces) + quadCount)) # faces count
			for f in me.faces:
				if len(f.v) == 4:
					indicies = (0,1,2), (0,2,3)
				else:
					indicies = ((0,1,2),)
				
				for i1, i2, i3 in indicies:
					if f.smooth:
						file.write(',
		<%d,%d,%d>' %\
						(uniqueNormals[tuple(f.v[i1].no)][0],\
						uniqueNormals[tuple(f.v[i2].no)][0],\
						uniqueNormals[tuple(f.v[i3].no)][0])) # vert count
					else:
						idx = uniqueNormals[tuple(f.no)][0]
						file.write(',
		<%d,%d,%d>' % (idx, idx, idx)) # vert count
						
						
			file.write('
  }
')
			
			
			# normal_indices indicies
			if me.faceUV:
				file.write('	uv_indices {
')
				file.write('		%d' % (len(me.faces) + quadCount)) # faces count
				for f in me.faces:
					if len(f.v) == 4:
						indicies = (0,1,2), (0,2,3)
					else:
						indicies = ((0,1,2),)
					
					for i1, i2, i3 in indicies:
						file.write(',
		<%d,%d,%d>' %\
						(uniqueUVs[tuple(f.uv[i1][0:2])][0],\
						uniqueUVs[tuple(f.uv[i2][0:2])][0],\
						uniqueUVs[tuple(f.uv[i2][0:2])][0])) # vert count
				file.write('
  }
')
			
			if me.materials:
				material = me.materials[0]
				if material:
					file.write('	interior { ior %.6f }
' % material.IOR)
			
			writeMatrix(matrix)
			"""
			# Write material per mesh, not so efficient but we can update later
			#for material in me.materials:
			newName = saneName(material.name)
			#materialNameTable[newName] = 
			
			file.write('	pigment {
')
			file.write('		color rgb <%.6f, %.6f, %.6f>
' % tuple([c * (material.emit+1) for c in material.rgbCol])) 
			file.write('	}
')
			#file.write('		finish {%s
' % newName )
			file.write('		finish {
')
			if world != None:
				file.write('			ambient <%.6f, %.6f, %.6f>
' % tuple([c * material.amb for c in world.amb]) )
			if material.rayMirr:
				file.write('			reflection <%.6f, %.6f, %.6f>
' % tuple([c*material.rayMirr for c in material.mirCol])) # Should ask for ray mirror flag
			file.write('			diffuse %.6f
' % material.ref) 
			file.write('			specular %.6f
' % material.spec)
			
				#~ finish {
				#~ reflection {
				  #~ [COLOR_REFLECTION_MIN,] COLOR_REFLECTION_MAX
				  #~ [fresnel BOOL_ON_OFF]
				  #~ [falloff FLOAT_FALLOFF]
				  #~ [exponent FLOAT_EXPONENT]
				  #~ [metallic FLOAT_METALLIC]
				#~ }
			#~ }
			#~ [interior { ior IOR }]
			#file.write('		roughness %.6f
' % (material.hard*0.5))
			#file.write('			crand 0.0
') # Sand granyness
			#file.write('			metallic %.6f
' % material.spec)
			#file.write('			phong %.6f
' % material.spec)
			#file.write('			phong_size %.6f
' % material.spec)
			file.write('			brilliance %.6f
' % (material.hard/256.0)) # Like hardness
			file.write('		}
')
			#file.write('	}
')
			"""
			file.write('}
')
	
	
	exportCamera()
	#exportMaterials()
	sel = Object.GetSelected()
	lamps = [l for l in sel if l.getType() == 'Lamp']
	exportLamps(lamps)
	exportMeshs(sel)
	
	file.close()  

Window.FileSelector(save_pov, 'Export Povray')

 # Testing with auto render.
'''
save_pov('/usr/share/povray-3.6/scenes/d.pov')
import os
#os.system('povray +W640 +H480 +A +P +X +D0 -V /usr/share/povray-3.6/scenes/d.pov &')
os.system('povray +W320 +H240 +A +P +X +D0 -V /usr/share/povray-3.6/scenes/d.pov &')
'''