1301 lines
38 KiB
Python
1301 lines
38 KiB
Python
#!BPY
|
|
""" Registration info for Blender menus:
|
|
Name: 'VRML97 (.wrl)...'
|
|
Blender: 241
|
|
Group: 'Export'
|
|
Tooltip: 'Export to VRML97 file (.wrl)'
|
|
"""
|
|
|
|
__author__ = ("Rick Kimball", "Ken Miller", "Steve Matthews", "Bart")
|
|
__url__ = ["blender", "blenderartists.org",
|
|
"Author's (Rick) homepage, http://kimballsoftware.com/blender",
|
|
"Author's (Bart) homepage, http://www.neeneenee.de/vrml"]
|
|
__email__ = ["Bart, bart:neeneenee*de"]
|
|
__version__ = "2006/01/17"
|
|
__bpydoc__ = """\
|
|
This script exports to VRML97 format.
|
|
|
|
Usage:
|
|
|
|
Run this script from "File->Export" menu. A pop-up will ask whether you
|
|
want to export only selected or all relevant objects.
|
|
"""
|
|
|
|
|
|
# $Id$
|
|
#
|
|
#------------------------------------------------------------------------
|
|
# VRML97 exporter for blender 2.36 or above
|
|
#
|
|
# ***** BEGIN GPL LICENSE BLOCK *****
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation,
|
|
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
#
|
|
# ***** END GPL LICENCE BLOCK *****
|
|
#
|
|
|
|
####################################
|
|
# Library dependancies
|
|
####################################
|
|
|
|
import Blender
|
|
from Blender import Object, Mesh, Lamp, Draw, BGL, \
|
|
Image, Text, sys, Mathutils, Registry
|
|
from Blender.Scene import Render
|
|
|
|
import math
|
|
|
|
####################################
|
|
# Global Variables
|
|
####################################
|
|
|
|
scene = Blender.Scene.getCurrent()
|
|
world = Blender.World.GetCurrent()
|
|
worldmat = Blender.Texture.Get()
|
|
filename = Blender.Get('filename')
|
|
_safeOverwrite = True
|
|
extension = ''
|
|
|
|
# Matrices below are used only when export_rotate_z_to_y.val:
|
|
#
|
|
# Blender is Z up, VRML is Y up, both are right hand coordinate
|
|
# systems, so to go from Blender coords to VRML coords we rotate
|
|
# by 90 degrees around the X axis. In matrix notation, we have a
|
|
# matrix, and it's inverse, as:
|
|
M_blen2vrml = Mathutils.Matrix([1,0,0,0], \
|
|
[0,0,1,0], \
|
|
[0,-1,0,0], \
|
|
[0,0,0,1])
|
|
M_vrml2blen = Mathutils.Matrix([1,0,0,0], \
|
|
[0,0,-1,0], \
|
|
[0,1,0,0], \
|
|
[0,0,0,1])
|
|
|
|
|
|
class DrawTypes:
|
|
"""Object DrawTypes enum values
|
|
BOUNDS - draw only the bounding box of the object
|
|
WIRE - draw object as a wire frame
|
|
SOLID - draw object with flat shading
|
|
SHADED - draw object with OpenGL shading
|
|
"""
|
|
BOUNDBOX = 1
|
|
WIRE = 2
|
|
SOLID = 3
|
|
SHADED = 4
|
|
TEXTURE = 5
|
|
|
|
if not hasattr(Blender.Object,'DrawTypes'):
|
|
Blender.Object.DrawTypes = DrawTypes()
|
|
|
|
##########################################################
|
|
# Functions for writing output file
|
|
##########################################################
|
|
|
|
class VRML2Export:
|
|
|
|
def __init__(self, filename):
|
|
#--- public you can change these ---
|
|
self.wire = 0
|
|
self.proto = 1
|
|
self.facecolors = 0
|
|
self.vcolors = 0
|
|
self.billnode = 0
|
|
self.halonode = 0
|
|
self.collnode = 0
|
|
self.tilenode = 0
|
|
self.wire = 0
|
|
self.twosided = 0
|
|
|
|
# level of verbosity in console 0-none, 1-some, 2-most
|
|
try:
|
|
rt = Blender.Get('rt')
|
|
if (rt == 42):
|
|
self.verbose = 1
|
|
elif (rt == 43):
|
|
self.verbose = 2
|
|
else:
|
|
self.verbose = 0
|
|
except:
|
|
self.verbose = 0
|
|
|
|
# decimals for material color values 0.000 - 1.000
|
|
self.cp=7
|
|
# decimals for vertex coordinate values 0.000 - n.000
|
|
self.vp=7
|
|
# decimals for texture coordinate values 0.000 - 1.000
|
|
self.tp=7
|
|
|
|
#--- class private don't touch ---
|
|
self.texNames={} # dictionary of textureNames
|
|
self.matNames={} # dictionary of materialNames
|
|
self.meshNames={} # dictionary of meshNames
|
|
self.coordNames={} # dictionary of coordNames
|
|
self.indentLevel=0 # keeps track of current indenting
|
|
self.filename=filename
|
|
self.file = open(filename, "w")
|
|
self.bNav=0
|
|
self.nodeID=0
|
|
self.namesReserved=[ "Anchor", "Appearance", "AudioClip",
|
|
"Background","Billboard", "Box",
|
|
"Collision", "Color", "ColorInterpolator",
|
|
"Cone", "Coordinate",
|
|
"CoordinateInterpolator", "Cylinder",
|
|
"CylinderSensor",
|
|
"DirectionalLight",
|
|
"ElevationGrid", "Extrustion",
|
|
"Fog", "FontStyle", "Group",
|
|
"ImageTexture", "IndexedFaceSet",
|
|
"IndexedLineSet", "Inline",
|
|
"LOD", "Material", "MovieTexture",
|
|
"NavigationInfo", "Normal",
|
|
"NormalInterpolator",
|
|
"OrientationInterpolator", "PixelTexture",
|
|
"PlaneSensor", "PointLight", "PointSet",
|
|
"PositionInterpolator", "ProxmimitySensor",
|
|
"ScalarInterpolator", "Script", "Shape",
|
|
"Sound", "Sphere", "SphereSensor",
|
|
"SpotLight", "Switch", "Text",
|
|
"TextureCoordinate", "TextureTransform",
|
|
"TimeSensor", "TouchSensor", "Transform",
|
|
"Viewpoint", "VisibilitySensor", "WorldInfo" ]
|
|
self.namesStandard=[ "Empty", "Empty.000", "Empty.001",
|
|
"Empty.002", "Empty.003", "Empty.004",
|
|
"Empty.005", "Empty.006", "Empty.007",
|
|
"Empty.008", "Empty.009", "Empty.010",
|
|
"Empty.011", "Empty.012",
|
|
"Scene.001", "Scene.002", "Scene.003",
|
|
"Scene.004", "Scene.005", "Scene.06",
|
|
"Scene.013", "Scene.006", "Scene.007",
|
|
"Scene.008", "Scene.009", "Scene.010",
|
|
"Scene.011","Scene.012",
|
|
"World", "World.000", "World.001",
|
|
"World.002", "World.003", "World.004",
|
|
"World.005" ]
|
|
self.namesFog=[ "", "LINEAR"," EXPONENTIAL", "" ]
|
|
|
|
##########################################################
|
|
# Writing nodes routines
|
|
##########################################################
|
|
|
|
def writeHeader(self):
|
|
bfile = sys.expandpath(Blender.Get('filename'))
|
|
self.file.write("#VRML V2.0 utf8\n\n")
|
|
self.file.write("# This file was authored with Blender " \
|
|
"(http://www.blender.org/)\n")
|
|
self.file.write("# Blender version %s\n" % Blender.Get('version'))
|
|
self.file.write("# Blender file %s\n" % sys.basename(bfile))
|
|
self.file.write("# Exported using VRML97 exporter " \
|
|
"v1.55 (2006/01/17)\n\n")
|
|
|
|
def writeInline(self):
|
|
inlines = Blender.Scene.Get()
|
|
allinlines = len(inlines)
|
|
if scene != inlines[0]:
|
|
return
|
|
else:
|
|
for i in xrange(allinlines):
|
|
nameinline=inlines[i].getName()
|
|
if (nameinline not in self.namesStandard) and (i > 0):
|
|
self.writeIndented("DEF %s Inline {\n" % \
|
|
(self.cleanStr(nameinline)), 1)
|
|
nameinline = nameinline+".wrl"
|
|
self.writeIndented("url \"%s\" \n" % nameinline)
|
|
self.writeIndented("}\n", -1)
|
|
self.writeIndented("\n")
|
|
|
|
def writeScript(self):
|
|
textEditor = Blender.Text.Get()
|
|
alltext = len(textEditor)
|
|
for i in xrange(alltext):
|
|
nametext = textEditor[i].getName()
|
|
nlines = textEditor[i].getNLines()
|
|
if (self.proto == 1):
|
|
if (nametext == "proto" or nametext == "proto.js" or \
|
|
nametext == "proto.txt") and (nlines != None):
|
|
nalllines = len(textEditor[i].asLines())
|
|
alllines = textEditor[i].asLines()
|
|
for j in xrange(nalllines):
|
|
self.writeIndented(alllines[j] + "\n")
|
|
elif (self.proto == 0):
|
|
if (nametext == "route" or nametext == "route.js" or \
|
|
nametext == "route.txt") and (nlines != None):
|
|
nalllines = len(textEditor[i].asLines())
|
|
alllines = textEditor[i].asLines()
|
|
for j in xrange(nalllines):
|
|
self.writeIndented(alllines[j] + "\n")
|
|
self.writeIndented("\n")
|
|
|
|
def writeViewpoint(self, thisObj):
|
|
# NOTE: The transform node above this will take care of
|
|
# the position and orientation of the camera
|
|
context = scene.getRenderingContext()
|
|
ratio = float(context.imageSizeY()) / float(context.imageSizeX())
|
|
temp = ratio * 16 / thisObj.data.getLens()
|
|
lens = 2 * math.atan(temp)
|
|
lens = min(lens, math.pi)
|
|
|
|
self.writeIndented("DEF %s Viewpoint {\n" % \
|
|
(self.cleanStr(thisObj.name)), 1)
|
|
self.writeIndented('description "%s" \n' % thisObj.name)
|
|
self.writeIndented("position 0.0 0.0 0.0\n")
|
|
# Need camera to point to -y in local space to accomodate
|
|
# the transforma node above
|
|
self.writeIndented("orientation 1.0 0.0 0.0 %f\n" % (-math.pi/2.0))
|
|
self.writeIndented("fieldOfView %.3f\n" % (lens))
|
|
self.writeIndented("}\n", -1)
|
|
self.writeIndented("\n")
|
|
|
|
def writeFog(self):
|
|
if world:
|
|
mtype = world.getMistype()
|
|
mparam = world.getMist()
|
|
grd = world.getHor()
|
|
grd0, grd1, grd2 = grd[0], grd[1], grd[2]
|
|
else:
|
|
return
|
|
if (mtype == 1 or mtype == 2):
|
|
self.writeIndented("Fog {\n",1)
|
|
self.writeIndented('fogType "%s"\n' % self.namesFog[mtype])
|
|
self.writeIndented("color %s %s %s\n" % \
|
|
(round(grd0,self.cp), \
|
|
round(grd1,self.cp), \
|
|
round(grd2,self.cp)))
|
|
self.writeIndented("visibilityRange %s\n" % \
|
|
round(mparam[2],self.cp))
|
|
self.writeIndented("}\n",-1)
|
|
self.writeIndented("\n")
|
|
else:
|
|
return
|
|
|
|
def writeNavigationInfo(self, scene):
|
|
allObj = []
|
|
allObj = list(scene.objects)
|
|
headlight = "TRUE"
|
|
vislimit = 0.0
|
|
for thisObj in allObj:
|
|
objType=thisObj.type
|
|
if objType == "Camera":
|
|
vislimit = thisObj.data.getClipEnd()
|
|
elif objType == "Lamp":
|
|
headlight = "FALSE"
|
|
self.writeIndented("NavigationInfo {\n",1)
|
|
self.writeIndented("headlight %s\n" % headlight)
|
|
self.writeIndented("visibilityLimit %s\n" % \
|
|
(round(vislimit,self.cp)))
|
|
self.writeIndented("type [\"EXAMINE\", \"ANY\"]\n")
|
|
self.writeIndented("avatarSize [0.25, 1.75, 0.75]\n")
|
|
self.writeIndented("} \n",-1)
|
|
self.writeIndented(" \n")
|
|
|
|
def writeSpotLight(self, object, lamp):
|
|
# Note: location and orientation are handled by the
|
|
# transform node above this object
|
|
if world:
|
|
ambi = world.getAmb()
|
|
ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5
|
|
else:
|
|
ambi = 0
|
|
ambientIntensity = 0
|
|
|
|
# compute cutoff and beamwidth
|
|
intensity=min(lamp.energy/1.75,1.0)
|
|
beamWidth=((lamp.spotSize*math.pi)/180.0)*.37;
|
|
cutOffAngle=beamWidth*1.3
|
|
|
|
radius = lamp.dist*math.cos(beamWidth)
|
|
self.writeIndented("DEF %s SpotLight {\n" % \
|
|
self.cleanStr(object.name),1)
|
|
self.writeIndented("radius %s\n" % (round(radius,self.cp)))
|
|
self.writeIndented("ambientIntensity %s\n" % \
|
|
(round(ambientIntensity,self.cp)))
|
|
self.writeIndented("intensity %s\n" % (round(intensity,self.cp)))
|
|
self.writeIndented("color %s %s %s\n" % \
|
|
(round(lamp.col[0],self.cp), \
|
|
round(lamp.col[1],self.cp), \
|
|
round(lamp.col[2],self.cp)))
|
|
self.writeIndented("beamWidth %s\n" % (round(beamWidth,self.cp)))
|
|
self.writeIndented("cutOffAngle %s\n" % \
|
|
(round(cutOffAngle,self.cp)))
|
|
# Note: point down -Y axis, transform node above will rotate
|
|
self.writeIndented("direction 0.0 -1.0 0.0\n")
|
|
self.writeIndented("location 0.0 0.0 0.0\n")
|
|
self.writeIndented("}\n",-1)
|
|
self.writeIndented("\n")
|
|
|
|
def writeDirectionalLight(self, object, lamp):
|
|
# Note: location and orientation are handled by the
|
|
# transform node above this object
|
|
if world:
|
|
ambi = world.getAmb()
|
|
ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5
|
|
else:
|
|
ambi = 0
|
|
ambientIntensity = 0
|
|
|
|
intensity=min(lamp.energy/1.75,1.0)
|
|
self.writeIndented("DEF %s DirectionalLight {\n" % \
|
|
self.cleanStr(object.name),1)
|
|
self.writeIndented("ambientIntensity %s\n" % \
|
|
(round(ambientIntensity,self.cp)))
|
|
self.writeIndented("color %s %s %s\n" % \
|
|
(round(lamp.col[0],self.cp), \
|
|
round(lamp.col[1],self.cp), \
|
|
round(lamp.col[2],self.cp)))
|
|
self.writeIndented("intensity %s\n" % \
|
|
(round(intensity,self.cp)))
|
|
# Note: point down -Y axis, transform node above will rotate
|
|
self.writeIndented("direction 0.0 -1.0 0.0\n")
|
|
self.writeIndented("}\n",-1)
|
|
self.writeIndented("\n")
|
|
|
|
def writePointLight(self, object, lamp):
|
|
# Note: location is at origin because parent transform node
|
|
# takes care of this
|
|
if world:
|
|
ambi = world.getAmb()
|
|
ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5
|
|
else:
|
|
ambi = 0
|
|
ambientIntensity = 0
|
|
om = object.getMatrix()
|
|
intensity=min(lamp.energy/1.75,1.0)
|
|
radius = lamp.dist
|
|
self.writeIndented("DEF %s PointLight {\n" % \
|
|
self.cleanStr(object.name),1)
|
|
self.writeIndented("ambientIntensity %s\n" % \
|
|
(round(ambientIntensity,self.cp)))
|
|
self.writeIndented("color %s %s %s\n" % \
|
|
(round(lamp.col[0],self.cp), \
|
|
round(lamp.col[1],self.cp), \
|
|
round(lamp.col[2],self.cp)))
|
|
self.writeIndented("intensity %s\n" % (round(intensity,self.cp)))
|
|
self.writeIndented("location 0.0 0.0 0.0\n")
|
|
self.writeIndented("radius %s\n" % radius )
|
|
self.writeIndented("}\n",-1)
|
|
self.writeIndented("\n")
|
|
|
|
def writeNode(self, thisObj):
|
|
# Note: location and orientation are handled by the
|
|
# transform node above this object
|
|
objectname=str(thisObj.getName())
|
|
if objectname in self.namesStandard:
|
|
return
|
|
else:
|
|
self.writeIndented("%s {\n" % objectname,1)
|
|
# May need to check that the direction is done right
|
|
self.writeIndented("direction 0.0 -1.0 0.0\n")
|
|
self.writeIndented("location 0.0 0.0 0.0\n")
|
|
self.writeIndented("}\n",-1)
|
|
self.writeIndented("\n")
|
|
|
|
def secureName(self, name):
|
|
name = name + str(self.nodeID)
|
|
self.nodeID += 1
|
|
if len(name) <= 3:
|
|
newname = "_" + str(self.nodeID)
|
|
return "%s" % (newname)
|
|
else:
|
|
for bad in ['"','#',"'",',','.','[','\\',']','{','}']:
|
|
name=name.replace(bad,'_')
|
|
if name in self.namesReserved:
|
|
newname = name[0:3] + "_" + str(self.nodeID)
|
|
return "%s" % (newname)
|
|
elif name[0].isdigit():
|
|
newname = "_" + name + str(self.nodeID)
|
|
return "%s" % (newname)
|
|
else:
|
|
newname = name
|
|
return "%s" % (newname)
|
|
|
|
def classifyMesh(self, me, ob):
|
|
self.halonode = 0
|
|
self.billnode = 0
|
|
self.facecolors = 0
|
|
self.vcolors = 0
|
|
self.tilenode = 0
|
|
self.colnode = 0
|
|
self.wire = 0
|
|
if me.faceUV:
|
|
for face in me.faces:
|
|
if (face.mode & Mesh.FaceModes['HALO']):
|
|
self.halonode = 1
|
|
if (face.mode & Mesh.FaceModes['BILLBOARD']):
|
|
self.billnode = 1
|
|
if (face.mode & Mesh.FaceModes['OBCOL']):
|
|
self.facecolors = 1
|
|
if (face.mode & Mesh.FaceModes['SHAREDCOL']):
|
|
self.vcolors = 1
|
|
if (face.mode & Mesh.FaceModes['TILES']):
|
|
self.tilenode = 1
|
|
if not (face.mode & Mesh.FaceModes['DYNAMIC']):
|
|
self.collnode = 1
|
|
if (face.mode & Mesh.FaceModes['TWOSIDE']):
|
|
self.twosided = 1
|
|
|
|
# Bit of a crufty trick, but if mesh has vertex colors
|
|
# (as a non-face property) and if first material has
|
|
# vcol paint set, we export the vertex colors
|
|
if (me.vertexColors):
|
|
if len(me.materials) > 0:
|
|
mat = me.materials[0]
|
|
if mat:
|
|
if (mat.mode & Blender.Material.Modes['VCOL_PAINT']):
|
|
self.vcolors = 1
|
|
else:
|
|
self.vcolors = 0
|
|
|
|
# check if object is wireframe only
|
|
if ob.drawType == Blender.Object.DrawTypes.WIRE:
|
|
# user selected WIRE=2 on the Drawtype=Wire on (F9) Edit page
|
|
self.wire = 1
|
|
|
|
###
|
|
### The next few functions nest Collision/Billboard/Halo nodes.
|
|
### For real mesh data export, jump down to writeMeshData()
|
|
###
|
|
def writeMesh(self, ob, normals = 0):
|
|
|
|
imageMap={} # set of used images
|
|
sided={} # 'one':cnt , 'two':cnt
|
|
vColors={} # 'multi':1
|
|
|
|
if (len(ob.modifiers) > 0):
|
|
me = Mesh.New()
|
|
me.getFromObject(ob.name)
|
|
# Careful with the name, the temporary mesh may
|
|
# reuse the default name for other meshes. So we
|
|
# pick our own name.
|
|
me.name = "MOD_%s" % (ob.name)
|
|
else:
|
|
me = ob.getData(mesh = 1)
|
|
|
|
self.classifyMesh(me, ob)
|
|
|
|
if (self.collnode):
|
|
self.writeCollisionMesh(me, ob, normals)
|
|
return
|
|
else:
|
|
self.writeRegularMesh(me, ob, normals)
|
|
return
|
|
|
|
def writeCollisionMesh(self, me, ob, normals = 0):
|
|
self.writeIndented("Collision {\n",1)
|
|
self.writeIndented("collide FALSE\n")
|
|
self.writeIndented("children [\n")
|
|
|
|
self.writeRegularMesh(me, ob, normals)
|
|
|
|
self.writeIndented("]\n", -1)
|
|
self.writeIndented("}\n", -1)
|
|
|
|
def writeRegularMesh(self, me, ob, normals = 0):
|
|
if (self.billnode):
|
|
self.writeBillboardMesh(me, ob, normals)
|
|
elif (self.halonode):
|
|
self.writeHaloMesh(me, ob, normals)
|
|
else:
|
|
self.writeMeshData(me, ob, normals)
|
|
|
|
def writeBillboardMesh(self, me, ob, normals = 0):
|
|
self.writeIndented("Billboard {\n",1)
|
|
self.writeIndented("axisOfRotation 0 1 0\n")
|
|
self.writeIndented("children [\n")
|
|
|
|
self.writeMeshData(me, ob, normals)
|
|
|
|
self.writeIndented("]\n", -1)
|
|
self.writeIndented("}\n", -1)
|
|
|
|
def writeHaloMesh(self, me, ob, normals = 0):
|
|
self.writeIndented("Billboard {\n",1)
|
|
self.writeIndented("axisOfRotation 0 0 0\n")
|
|
self.writeIndented("children [\n")
|
|
|
|
self.writeMeshData(me, ob, normals)
|
|
|
|
self.writeIndented("]\n", -1)
|
|
self.writeIndented("}\n", -1)
|
|
|
|
###
|
|
### Here is where real mesh data is written
|
|
###
|
|
def writeMeshData(self, me, ob, normals = 0):
|
|
meshName = self.cleanStr(me.name)
|
|
|
|
if self.meshNames.has_key(meshName):
|
|
self.writeIndented("USE ME_%s\n" % meshName, 0)
|
|
self.meshNames[meshName]+=1
|
|
if (self.verbose == 1):
|
|
print " Using Mesh %s (Blender mesh: %s)\n" % \
|
|
(meshName, me.name)
|
|
return
|
|
self.meshNames[meshName]=1
|
|
|
|
if (self.verbose == 1):
|
|
print " Writing Mesh %s (Blender mesh: %s)\n" % \
|
|
(meshName, me.name)
|
|
return
|
|
|
|
self.writeIndented("DEF ME_%s Group {\n" % meshName,1)
|
|
self.writeIndented("children [\n", 1)
|
|
|
|
hasImageTexture = 0
|
|
issmooth = 0
|
|
|
|
maters = me.materials
|
|
nummats = len(me.materials)
|
|
|
|
# Vertex and Face colors trump materials and image textures
|
|
if (self.facecolors or self.vcolors):
|
|
if nummats > 0:
|
|
self.writeShape(ob, me, 0, None)
|
|
else:
|
|
self.writeShape(ob, me, -1, None)
|
|
|
|
# Do meshes with materials, possibly with image textures
|
|
elif nummats > 0:
|
|
for matnum in xrange(len(maters)):
|
|
images = []
|
|
if me.faceUV:
|
|
images = self.getImages(me, matnum)
|
|
if len(images) > 0:
|
|
for image in images:
|
|
self.writeShape(ob, me, matnum, image)
|
|
else:
|
|
self.writeShape(ob, me, matnum, None)
|
|
else:
|
|
self.writeShape(ob, me, matnum, None)
|
|
else:
|
|
if me.faceUV:
|
|
images = self.getImages(me, -1)
|
|
if len(images) > 0:
|
|
for image in images:
|
|
self.writeShape(ob, me, -1, image)
|
|
else:
|
|
self.writeShape(ob, me, -1, None)
|
|
else:
|
|
self.writeShape(ob, me, -1, None)
|
|
|
|
|
|
self.writeIndented("]\n", -1)
|
|
self.writeIndented("}\n", -1)
|
|
|
|
def getImages(self, me, matnum):
|
|
imageNames = {}
|
|
images = []
|
|
for face in me.faces:
|
|
if (matnum == -1) or (face.mat == matnum):
|
|
if (face.image):
|
|
imName = self.cleanStr(face.image.name)
|
|
if not imageNames.has_key(imName):
|
|
images.append(face.image)
|
|
imageNames[imName]=1
|
|
return images
|
|
|
|
def writeCoordinates(self, me, meshName):
|
|
coordName = "coord_%s" % (meshName)
|
|
# look up coord name, use it if available
|
|
if self.coordNames.has_key(coordName):
|
|
self.writeIndented("coord USE %s\n" % coordName, 0)
|
|
self.coordNames[coordName]+=1
|
|
return;
|
|
|
|
self.coordNames[coordName]=1
|
|
|
|
#-- vertices
|
|
self.writeIndented("coord DEF %s Coordinate {\n" % (coordName), 1)
|
|
self.writeIndented("point [\n", 1)
|
|
meshVertexList = me.verts
|
|
|
|
for vertex in meshVertexList:
|
|
vrmlvert = blenvert = Mathutils.Vector(vertex.co)
|
|
if export_rotate_z_to_y.val:
|
|
vrmlvert = M_blen2vrml * vrmlvert
|
|
self.writeUnindented("%s %s %s\n " % \
|
|
(vrmlvert[0], \
|
|
vrmlvert[1], \
|
|
vrmlvert[2]))
|
|
self.writeIndented("]\n", -1)
|
|
self.writeIndented("}\n", -1)
|
|
self.writeIndented("\n")
|
|
|
|
def testShape(self, ob, me, matnum, image):
|
|
if ( (matnum == -1) and (image == None) ):
|
|
if ( len(me.faces) > 0 ):
|
|
return True
|
|
# Check if any faces the material or image
|
|
for face in me.faces:
|
|
if (matnum == -1):
|
|
if (face.image == image):
|
|
return True
|
|
elif (image == None):
|
|
if (face.mat == matnum):
|
|
return True
|
|
else:
|
|
if ((face.image == image) and (face.mat == matnum)):
|
|
return True
|
|
|
|
return False
|
|
|
|
def writeShape(self, ob, me, matnum, image):
|
|
# matnum == -1 means don't check the face.mat
|
|
# image == None means don't check face.image
|
|
|
|
if ( not self.testShape(ob, me, matnum, image) ):
|
|
return False
|
|
|
|
self.writeIndented("Shape {\n",1)
|
|
|
|
self.writeIndented("appearance Appearance {\n", 1)
|
|
if (matnum != -1):
|
|
mater = me.materials[matnum]
|
|
if (mater):
|
|
self.writeMaterial(mater, self.cleanStr(mater.name,''))
|
|
if (mater.mode & Blender.Material.Modes['TEXFACE']):
|
|
if image != None:
|
|
self.writeImageTexture(image.name, image.filename)
|
|
else:
|
|
self.writeDefaultMaterial()
|
|
else:
|
|
if image != None:
|
|
self.writeImageTexture(image.name, image.filename)
|
|
|
|
self.writeIndented("}\n", -1)
|
|
|
|
self.writeGeometry(ob, me, matnum, image)
|
|
|
|
self.writeIndented("}\n", -1)
|
|
|
|
return True
|
|
|
|
def writeGeometry(self, ob, me, matnum, image):
|
|
|
|
#-- IndexedFaceSet or IndexedLineSet
|
|
meshName = self.cleanStr(me.name)
|
|
|
|
# check if object is wireframe only
|
|
if (self.wire):
|
|
ifStyle="IndexedLineSet"
|
|
else:
|
|
# user selected BOUNDS=1, SOLID=3, SHARED=4, or TEXTURE=5
|
|
ifStyle="IndexedFaceSet"
|
|
|
|
self.writeIndented("geometry %s {\n" % ifStyle, 1)
|
|
if not self.wire:
|
|
if self.twosided == 1:
|
|
self.writeIndented("solid FALSE\n")
|
|
else:
|
|
self.writeIndented("solid TRUE\n")
|
|
|
|
self.writeCoordinates(me, meshName)
|
|
self.writeCoordIndex(me, meshName, matnum, image)
|
|
self.writeTextureCoordinates(me, meshName, matnum, image)
|
|
if self.facecolors:
|
|
self.writeFaceColors(me)
|
|
elif self.vcolors:
|
|
self.writeVertexColors(me)
|
|
self.writeIndented("}\n", -1)
|
|
|
|
def writeCoordIndex(self, me, meshName, matnum, image):
|
|
meshVertexList = me.verts
|
|
self.writeIndented("coordIndex [\n", 1)
|
|
coordIndexList=[]
|
|
for face in me.faces:
|
|
if (matnum == -1) or (face.mat == matnum):
|
|
if (image == None) or (face.image == image):
|
|
cordStr=""
|
|
for v in face.verts:
|
|
indx=v.index
|
|
cordStr = cordStr + "%s " % indx
|
|
self.writeUnindented(cordStr + "-1, \n")
|
|
self.writeIndented("]\n", -1)
|
|
|
|
def writeTextureCoordinates(self, me, meshName, matnum, image):
|
|
if (image == None):
|
|
return
|
|
|
|
texCoordList=[]
|
|
texIndexList=[]
|
|
j=0
|
|
|
|
for face in me.faces:
|
|
coordStr = ""
|
|
indexStr = ""
|
|
if (matnum == -1) or (face.mat == matnum):
|
|
if (face.image == image):
|
|
for i in xrange(len(face.verts)):
|
|
uv = face.uv[i]
|
|
indexStr += "%s " % (j)
|
|
coordStr += "%s %s, " % \
|
|
(round(uv[0], self.tp), \
|
|
round(uv[1], self.tp))
|
|
j=j+1
|
|
indexStr += "-1"
|
|
texIndexList.append(indexStr)
|
|
texCoordList.append(coordStr)
|
|
|
|
self.writeIndented("texCoord TextureCoordinate {\n", 1)
|
|
self.writeIndented("point [\n", 1)
|
|
for coord in texCoordList:
|
|
self.writeUnindented("%s\n" % (coord))
|
|
self.writeIndented("]\n", -1)
|
|
self.writeIndented("}\n", -1)
|
|
|
|
self.writeIndented("texCoordIndex [\n", 1)
|
|
for ind in texIndexList:
|
|
self.writeUnindented("%s\n" % (ind))
|
|
self.writeIndented("]\n", -1)
|
|
|
|
def writeFaceColors(self, me):
|
|
self.writeIndented("colorPerVertex FALSE\n")
|
|
self.writeIndented("color Color {\n",1)
|
|
self.writeIndented("color [\n", 1)
|
|
|
|
for face in me.faces:
|
|
if face.col:
|
|
c=face.col[0]
|
|
if self.verbose >= 2:
|
|
print "Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b)
|
|
|
|
aColor = self.rgbToFS(c)
|
|
self.writeUnindented("%s,\n" % aColor)
|
|
self.writeIndented("]\n",-1)
|
|
self.writeIndented("}\n",-1)
|
|
|
|
def writeVertexColors(self, me):
|
|
self.writeIndented("colorPerVertex TRUE\n")
|
|
self.writeIndented("color Color {\n",1)
|
|
self.writeIndented("color [\n\t\t\t\t\t\t", 1)
|
|
|
|
cols = [None] * len(me.verts)
|
|
|
|
for face in me.faces:
|
|
for vind in xrange(len(face.v)):
|
|
vertex = face.v[vind]
|
|
i = vertex.index
|
|
if cols[i] == None:
|
|
cols[i] = face.col[vind]
|
|
|
|
for i in xrange(len(me.verts)):
|
|
aColor = self.rgbToFS(cols[i])
|
|
self.writeUnindented("%s\n" % aColor)
|
|
|
|
self.writeIndented("\n", 0)
|
|
self.writeIndented("]\n",-1)
|
|
self.writeIndented("}\n",-1)
|
|
|
|
def writeDefaultMaterial(self):
|
|
matName = "default"
|
|
|
|
# look up material name, use it if available
|
|
if self.matNames.has_key(matName):
|
|
self.writeIndented("material USE MA_%s\n" % matName)
|
|
self.matNames[matName]+=1
|
|
return;
|
|
|
|
self.matNames[matName]=1
|
|
self.writeIndented("material DEF MA_%s Material {\n" % matName, 1)
|
|
self.writeIndented("diffuseColor 0.8 0.8 0.8\n")
|
|
self.writeIndented("specularColor 1.0 1.0 1.0\n")
|
|
self.writeIndented("shininess 0.5\n")
|
|
self.writeIndented("transparency 0.0\n")
|
|
self.writeIndented("}\n",-1)
|
|
|
|
def writeMaterial(self, mat, matName):
|
|
# look up material name, use it if available
|
|
if self.matNames.has_key(matName):
|
|
self.writeIndented("material USE MA_%s\n" % matName)
|
|
self.matNames[matName]+=1
|
|
return;
|
|
|
|
self.matNames[matName]=1
|
|
|
|
ambient = mat.amb/3
|
|
diffuseR, diffuseG, diffuseB = \
|
|
mat.rgbCol[0], mat.rgbCol[1],mat.rgbCol[2]
|
|
if world:
|
|
ambi = world.getAmb()
|
|
ambi0, ambi1, ambi2 = (ambi[0]*mat.amb) * 2, \
|
|
(ambi[1]*mat.amb) * 2, \
|
|
(ambi[2]*mat.amb) * 2
|
|
else:
|
|
ambi0, ambi1, ambi2 = 0, 0, 0
|
|
emisR, emisG, emisB = (diffuseR*mat.emit+ambi0) / 2, \
|
|
(diffuseG*mat.emit+ambi1) / 2, \
|
|
(diffuseB*mat.emit+ambi2) / 2
|
|
|
|
shininess = mat.hard/512.0
|
|
specR = (mat.specCol[0]+0.001) / (1.25/(mat.getSpec()+0.001))
|
|
specG = (mat.specCol[1]+0.001) / (1.25/(mat.getSpec()+0.001))
|
|
specB = (mat.specCol[2]+0.001) / (1.25/(mat.getSpec()+0.001))
|
|
transp = 1 - mat.alpha
|
|
matFlags = mat.getMode()
|
|
if matFlags & Blender.Material.Modes['SHADELESS']:
|
|
ambient = 1
|
|
shine = 1
|
|
specR = emitR = diffuseR
|
|
specG = emitG = diffuseG
|
|
specB = emitB = diffuseB
|
|
self.writeIndented("material DEF MA_%s Material {\n" % matName, 1)
|
|
self.writeIndented("diffuseColor %s %s %s\n" % \
|
|
(round(diffuseR,self.cp), \
|
|
round(diffuseG,self.cp), \
|
|
round(diffuseB,self.cp)))
|
|
self.writeIndented("ambientIntensity %s\n" % \
|
|
(round(ambient,self.cp)))
|
|
self.writeIndented("specularColor %s %s %s\n" % \
|
|
(round(specR,self.cp), \
|
|
round(specG,self.cp), \
|
|
round(specB,self.cp)))
|
|
self.writeIndented("emissiveColor %s %s %s\n" % \
|
|
(round(emisR,self.cp), \
|
|
round(emisG,self.cp), \
|
|
round(emisB,self.cp)))
|
|
self.writeIndented("shininess %s\n" % (round(shininess,self.cp)))
|
|
self.writeIndented("transparency %s\n" % (round(transp,self.cp)))
|
|
self.writeIndented("}\n",-1)
|
|
|
|
def writeImageTexture(self, name, filename):
|
|
if self.texNames.has_key(name):
|
|
self.writeIndented("texture USE %s\n" % self.cleanStr(name))
|
|
self.texNames[name] += 1
|
|
return
|
|
else:
|
|
self.writeIndented("texture DEF %s ImageTexture {\n" % \
|
|
self.cleanStr(name), 1)
|
|
self.writeIndented('url "%s"\n' % \
|
|
filename.split("\\")[-1].split("/")[-1])
|
|
self.writeIndented("}\n",-1)
|
|
self.texNames[name] = 1
|
|
|
|
def writeBackground(self):
|
|
if world:
|
|
worldname = world.getName()
|
|
else:
|
|
return
|
|
blending = world.getSkytype()
|
|
grd = world.getHor()
|
|
grd0, grd1, grd2 = grd[0], grd[1], grd[2]
|
|
sky = world.getZen()
|
|
sky0, sky1, sky2 = sky[0], sky[1], sky[2]
|
|
mix0, mix1, mix2 = grd[0]+sky[0], grd[1]+sky[1], grd[2]+sky[2]
|
|
mix0, mix1, mix2 = mix0/2, mix1/2, mix2/2
|
|
if worldname in self.namesStandard:
|
|
self.writeIndented("Background {\n",1)
|
|
else:
|
|
self.writeIndented("DEF %s Background {\n" % \
|
|
self.secureName(worldname),1)
|
|
# No Skytype - just Hor color
|
|
if blending == 0:
|
|
self.writeIndented("groundColor %s %s %s\n" % \
|
|
(round(grd0,self.cp), \
|
|
round(grd1,self.cp), \
|
|
round(grd2,self.cp)))
|
|
self.writeIndented("skyColor %s %s %s\n" % \
|
|
(round(grd0,self.cp), \
|
|
round(grd1,self.cp), \
|
|
round(grd2,self.cp)))
|
|
# Blend Gradient
|
|
elif blending == 1:
|
|
self.writeIndented("groundColor [ %s %s %s, " % \
|
|
(round(grd0,self.cp), \
|
|
round(grd1,self.cp), \
|
|
round(grd2,self.cp)))
|
|
self.writeIndented("%s %s %s ]\n" % \
|
|
(round(mix0,self.cp), \
|
|
round(mix1,self.cp), \
|
|
round(mix2,self.cp)))
|
|
self.writeIndented("groundAngle [ 1.57, 1.57 ]\n")
|
|
self.writeIndented("skyColor [ %s %s %s, " % \
|
|
(round(sky0,self.cp), \
|
|
round(sky1,self.cp), \
|
|
round(sky2,self.cp)))
|
|
self.writeIndented("%s %s %s ]\n" % \
|
|
(round(mix0,self.cp), \
|
|
round(mix1,self.cp), \
|
|
round(mix2,self.cp)))
|
|
self.writeIndented("skyAngle [ 1.57, 1.57 ]\n")
|
|
# Blend+Real Gradient Inverse
|
|
elif blending == 3:
|
|
self.writeIndented("groundColor [ %s %s %s, " % \
|
|
(round(sky0,self.cp), \
|
|
round(sky1,self.cp), \
|
|
round(sky2,self.cp)))
|
|
self.writeIndented("%s %s %s ]\n" % \
|
|
(round(mix0,self.cp), \
|
|
round(mix1,self.cp), \
|
|
round(mix2,self.cp)))
|
|
self.writeIndented("groundAngle [ 1.57, 1.57 ]\n")
|
|
self.writeIndented("skyColor [ %s %s %s, " % \
|
|
(round(grd0,self.cp), \
|
|
round(grd1,self.cp), \
|
|
round(grd2,self.cp)))
|
|
self.writeIndented("%s %s %s ]\n" % \
|
|
(round(mix0,self.cp), \
|
|
round(mix1,self.cp), \
|
|
round(mix2,self.cp)))
|
|
self.writeIndented("skyAngle [ 1.57, 1.57 ]\n")
|
|
# Paper - just Zen Color
|
|
elif blending == 4:
|
|
self.writeIndented("groundColor %s %s %s\n" % \
|
|
(round(sky0,self.cp), \
|
|
round(sky1,self.cp), \
|
|
round(sky2,self.cp)))
|
|
self.writeIndented("skyColor %s %s %s\n" % \
|
|
(round(sky0,self.cp), \
|
|
round(sky1,self.cp), \
|
|
round(sky2,self.cp)))
|
|
# Blend+Real+Paper - komplex gradient
|
|
elif blending == 7:
|
|
self.writeIndented("groundColor [ %s %s %s, " % \
|
|
(round(sky0,self.cp), \
|
|
round(sky1,self.cp), \
|
|
round(sky2,self.cp)))
|
|
self.writeIndented("%s %s %s ]\n" % \
|
|
(round(grd0,self.cp), \
|
|
round(grd1,self.cp), \
|
|
round(grd2,self.cp)))
|
|
self.writeIndented("groundAngle [ 1.57, 1.57 ]\n")
|
|
self.writeIndented("skyColor [ %s %s %s, " % \
|
|
(round(sky0,self.cp), \
|
|
round(sky1,self.cp), \
|
|
round(sky2,self.cp)))
|
|
self.writeIndented("%s %s %s ]\n" % \
|
|
(round(grd0,self.cp),
|
|
round(grd1,self.cp),
|
|
round(grd2,self.cp)))
|
|
self.writeIndented("skyAngle [ 1.57, 1.57 ]\n")
|
|
# Any Other two colors
|
|
else:
|
|
self.writeIndented("groundColor %s %s %s\n" % \
|
|
(round(grd0,self.cp), \
|
|
round(grd1,self.cp), \
|
|
round(grd2,self.cp)))
|
|
self.writeIndented("skyColor %s %s %s\n" % \
|
|
(round(sky0,self.cp), \
|
|
round(sky1,self.cp), \
|
|
round(sky2,self.cp)))
|
|
alltexture = len(worldmat)
|
|
for i in xrange(alltexture):
|
|
namemat = worldmat[i].getName()
|
|
pic = worldmat[i].getImage()
|
|
if pic:
|
|
# Stripped path.
|
|
pic_path= pic.filename.split('\\')[-1].split('/')[-1]
|
|
if namemat == "back":
|
|
self.writeIndented('backUrl "%s"\n' % pic_path)
|
|
elif namemat == "bottom":
|
|
self.writeIndented('bottomUrl "%s"\n' % pic_path)
|
|
elif namemat == "front":
|
|
self.writeIndented('frontUrl "%s"\n' % pic_path)
|
|
elif namemat == "left":
|
|
self.writeIndented('leftUrl "%s"\n' % pic_path)
|
|
elif namemat == "right":
|
|
self.writeIndented('rightUrl "%s"\n' % pic_path)
|
|
elif namemat == "top":
|
|
self.writeIndented('topUrl "%s"\n' % pic_path)
|
|
self.writeIndented("}",-1)
|
|
self.writeIndented("\n\n")
|
|
|
|
def writeLamp(self, ob):
|
|
la = ob.data
|
|
laType = la.getType()
|
|
|
|
if laType == Lamp.Types.Lamp:
|
|
self.writePointLight(ob, la)
|
|
elif laType == Lamp.Types.Spot:
|
|
self.writeSpotLight(ob, la)
|
|
elif laType == Lamp.Types.Sun:
|
|
self.writeDirectionalLight(ob, la)
|
|
else:
|
|
self.writeDirectionalLight(ob, la)
|
|
|
|
def writeObject(self, ob):
|
|
|
|
obname = self.cleanStr(ob.name)
|
|
|
|
try:
|
|
obtype=ob.getType()
|
|
except AttributeError:
|
|
print "Error: Unable to get type info for %s" % obname
|
|
return
|
|
|
|
if self.verbose >= 1:
|
|
print "++ Writing %s object %s (Blender name: %s)\n" % \
|
|
(obtype, obname, ob.name)
|
|
|
|
# Note: I am leaving empties out for now -- the original
|
|
# script does some really weird stuff with empties
|
|
if ( (obtype != "Camera") and \
|
|
(obtype != "Mesh") and \
|
|
(obtype != "Lamp") ):
|
|
print "Info: Ignoring [%s], object type [%s] " \
|
|
"not handle yet" % (obname, obtype)
|
|
return
|
|
|
|
ob_matrix = Mathutils.Matrix(ob.getMatrix('worldspace'))
|
|
if export_rotate_z_to_y.val:
|
|
matrix = M_blen2vrml * ob_matrix * M_vrml2blen
|
|
else:
|
|
matrix = ob_matrix
|
|
e = matrix.rotationPart().toEuler()
|
|
|
|
v = matrix.translationPart()
|
|
(axis, angle) = self.eulToVecRot(self.deg2rad(e.x), \
|
|
self.deg2rad(e.y), \
|
|
self.deg2rad(e.z))
|
|
|
|
mrot = e.toMatrix().resize4x4()
|
|
try:
|
|
mrot.invert()
|
|
except:
|
|
print "Warning: %s has degenerate transformation!" % (obname)
|
|
return
|
|
|
|
diag = matrix * mrot
|
|
sizeX = diag[0][0]
|
|
sizeY = diag[1][1]
|
|
sizeZ = diag[2][2]
|
|
|
|
if self.verbose >= 1:
|
|
print " Transformation:\n" \
|
|
" loc: %f %f %f\n" \
|
|
" size: %f %f %f\n" \
|
|
" Rot: (%f %f %f), %f\n" % \
|
|
(v.x, v.y, v.z, \
|
|
sizeX, sizeY, sizeZ, \
|
|
axis[0], axis[1], axis[2], angle)
|
|
|
|
self.writeIndented("DEF OB_%s Transform {\n" % (obname), 1)
|
|
self.writeIndented("translation %f %f %f\n" % \
|
|
(v.x, v.y, v.z) )
|
|
|
|
self.writeIndented("rotation %f %f %f %f\n" % \
|
|
(axis[0],axis[1],axis[2],angle) )
|
|
|
|
self.writeIndented("scale %f %f %f\n" % \
|
|
(sizeX, sizeY, sizeZ) )
|
|
|
|
self.writeIndented("children [\n", 1)
|
|
|
|
self.writeObData(ob)
|
|
|
|
self.writeIndented("]\n", -1) # end object
|
|
self.writeIndented("}\n", -1) # end object
|
|
|
|
def writeObData(self, ob):
|
|
|
|
obtype = ob.getType()
|
|
|
|
if obtype == "Camera":
|
|
self.writeViewpoint(ob)
|
|
elif obtype == "Mesh":
|
|
self.writeMesh(ob)
|
|
elif obtype == "Lamp":
|
|
self.writeLamp(ob)
|
|
elif obtype == "Empty":
|
|
self.writeNode(ob)
|
|
|
|
|
|
##########################################################
|
|
# export routine
|
|
##########################################################
|
|
|
|
def export(self, scene, world, worldmat):
|
|
print "Info: starting VRML97 export to " + self.filename + "..."
|
|
self.writeHeader()
|
|
self.writeScript()
|
|
self.writeNavigationInfo(scene)
|
|
self.writeBackground()
|
|
self.writeFog()
|
|
self.proto = 0
|
|
allObj = []
|
|
if export_selection_only.val:
|
|
allObj = list(scene.objects.context)
|
|
else:
|
|
allObj = list(scene.objects)
|
|
self.writeInline()
|
|
|
|
for thisObj in allObj:
|
|
self.writeObject(thisObj)
|
|
|
|
if not export_selection_only.val:
|
|
self.writeScript()
|
|
self.cleanup()
|
|
|
|
##########################################################
|
|
# Utility methods
|
|
##########################################################
|
|
|
|
def cleanup(self):
|
|
self.file.close()
|
|
self.texNames={}
|
|
self.matNames={}
|
|
self.indentLevel=0
|
|
print "Info: finished VRML97 export to %s\n" % self.filename
|
|
|
|
def cleanStr(self, name, prefix='rsvd_'):
|
|
"""cleanStr(name,prefix) - try to create a valid VRML DEF \
|
|
name from object name"""
|
|
|
|
newName=name[:]
|
|
if len(newName) == 0:
|
|
self.nNodeID+=1
|
|
return "%s%d" % (prefix, self.nNodeID)
|
|
|
|
if newName in self.namesReserved:
|
|
newName='%s%s' % (prefix,newName)
|
|
|
|
if newName[0].isdigit():
|
|
newName='%s%s' % ('_',newName)
|
|
|
|
for bad in (' ','"','#',"'",',','.','[','\\',']','{','}'):
|
|
newName=newName.replace(bad,'_')
|
|
return newName
|
|
|
|
def rgbToFS(self, c):
|
|
s = "%s %s %s" % \
|
|
(round(c.r/255.0,self.cp), \
|
|
round(c.g/255.0,self.cp), \
|
|
round(c.b/255.0,self.cp))
|
|
return s
|
|
|
|
def rad2deg(self, v):
|
|
return round(v*180.0/math.pi,4)
|
|
|
|
def deg2rad(self, v):
|
|
return (v*math.pi)/180.0;
|
|
|
|
def eulToVecRot(self, RotX, RotY, RotZ):
|
|
|
|
ti = RotX*0.5
|
|
tj = RotY*0.5
|
|
th = RotZ*0.5
|
|
|
|
ci = math.cos(ti)
|
|
cj = math.cos(tj)
|
|
ch = math.cos(th)
|
|
si = math.sin(ti)
|
|
sj = math.sin(tj)
|
|
sh = math.sin(th)
|
|
cc = ci*ch
|
|
cs = ci*sh
|
|
sc = si*ch
|
|
ss = si*sh
|
|
|
|
q0 = cj*cc + sj*ss
|
|
q1 = cj*sc - sj*cs
|
|
q2 = cj*ss + sj*cc
|
|
q3 = cj*cs - sj*sc
|
|
|
|
angle = 2 * math.acos(q0)
|
|
if (math.fabs(angle) < 0.000001):
|
|
axis = [1.0, 0.0, 0.0]
|
|
else:
|
|
sphi = 1.0/math.sqrt(1.0 - (q0*q0))
|
|
axis = [q1 * sphi, q2 * sphi, q3 * sphi]
|
|
|
|
a = Mathutils.Vector(axis)
|
|
a.normalize()
|
|
return ([a.x, a.y, a.z], angle)
|
|
|
|
|
|
# For writing well formed VRML code
|
|
#----------------------------------
|
|
def writeIndented(self, s, inc=0):
|
|
if inc < 1:
|
|
self.indentLevel = self.indentLevel + inc
|
|
|
|
self.file.write( self.indentLevel*"\t" + s)
|
|
|
|
if inc > 0:
|
|
self.indentLevel = self.indentLevel + inc
|
|
|
|
# Sometimes better to not have too many
|
|
# tab characters in a long list, for file size
|
|
#----------------------------------
|
|
def writeUnindented(self, s):
|
|
self.file.write(s)
|
|
|
|
##########################################################
|
|
# Callbacks, needed before Main
|
|
##########################################################
|
|
|
|
def select_file(filename):
|
|
if sys.exists(filename) and _safeOverwrite:
|
|
result = \
|
|
Draw.PupMenu("File Already Exists, Overwrite?%t|Yes%x1|No%x0")
|
|
if(result != 1):
|
|
return
|
|
|
|
if not filename.endswith(extension):
|
|
filename += extension
|
|
|
|
wrlexport=VRML2Export(filename)
|
|
wrlexport.export(scene, world, worldmat)
|
|
|
|
#########################################################
|
|
# UI and Registry utilities
|
|
#########################################################
|
|
|
|
export_selection_only = Draw.Create(0)
|
|
export_rotate_z_to_y = Draw.Create(1)
|
|
export_compressed = Draw.Create(0)
|
|
|
|
def save_to_registry():
|
|
d = {}
|
|
d['selection_only'] = export_selection_only.val
|
|
d['rotate_z_to_y'] = export_rotate_z_to_y.val
|
|
d['compressed'] = export_compressed.val
|
|
Registry.SetKey('vrml97_export', d, True)
|
|
|
|
def load_from_registry():
|
|
d = Registry.GetKey('vrml97_export', True)
|
|
if d:
|
|
try:
|
|
export_selection_only.val = d['selection_only']
|
|
export_rotate_z_to_y.val = d['rotate_z_to_y']
|
|
export_compressed.val = d['compressed']
|
|
except: save_to_registry() # If data is not valid, rewrite it.
|
|
|
|
def show_popup():
|
|
pup_block = [
|
|
('Selection Only', export_selection_only, 'Only export objects in visible selection. Else export whole scene.'),
|
|
('Rotate +Z to +Y', export_rotate_z_to_y, 'Rotate such that +Z axis (Blender up) becomes +Y (VRML up).'),
|
|
('Compress', export_compressed, 'Generate a .wrz file (normal VRML compressed by gzip).')
|
|
]
|
|
return Draw.PupBlock('Export VRML 97...', pup_block)
|
|
|
|
#########################################################
|
|
# main routine
|
|
#########################################################
|
|
|
|
load_from_registry()
|
|
|
|
# Note that show_popup must be done before Blender.Window.FileSelector,
|
|
# because export_compressed affects the suggested extension of resulting
|
|
# file.
|
|
|
|
if show_popup():
|
|
save_to_registry()
|
|
if export_compressed.val:
|
|
extension=".wrz"
|
|
from gzip import *
|
|
else:
|
|
extension=".wrl"
|
|
Blender.Window.FileSelector(select_file, "Export VRML97", \
|
|
sys.makename(ext=extension))
|