home *** CD-ROM | disk | FTP | other *** search
- # ***** BEGIN LICENSE BLOCK *****
- # Version: MPL 1.1/GPL 2.0/LGPL 2.1
- #
- # The contents of this file are subject to the Mozilla Public License Version
- # 1.1 (the "License"); you may not use this file except in compliance with
- # the License. You may obtain a copy of the License at
- # http://www.mozilla.org/MPL/
- #
- # Software distributed under the License is distributed on an "AS IS" basis,
- # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- # for the specific language governing rights and limitations under the
- # License.
- #
- # The Original Code is the Python Computer Graphics Kit.
- #
- # The Initial Developer of the Original Code is Matthias Baas.
- # Portions created by the Initial Developer are Copyright (C) 2004
- # the Initial Developer. All Rights Reserved.
- #
- # Contributor(s):
- #
- # Alternatively, the contents of this file may be used under the terms of
- # either the GNU General Public License Version 2 or later (the "GPL"), or
- # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- # in which case the provisions of the GPL or the LGPL are applicable instead
- # of those above. If you wish to allow use of your version of this file only
- # under the terms of either the GPL or the LGPL, and not to allow others to
- # use your version of this file under the terms of the MPL, indicate your
- # decision by deleting the provisions above and replace them with the notice
- # and other provisions required by the GPL or the LGPL. If you do not delete
- # the provisions above, a recipient may use your version of this file under
- # the terms of any one of the MPL, the GPL or the LGPL.
- #
- # ***** END LICENSE BLOCK *****
- # $Id: ribexport.py,v 1.17 2006/04/27 16:56:46 mbaas Exp $
-
- import sys, os, os.path, shutil, types
- import protocols
- import pluginmanager
- import lightsource
- #from cgkit import *
- from cgtypes import *
- from targetcamera import TargetCamera
- from scene import getScene
- from geomobject import *
- from boxgeom import BoxGeom
- from spheregeom import SphereGeom
- from ccylindergeom import CCylinderGeom
- from planegeom import PlaneGeom
- from trimeshgeom import TriMeshGeom
- from polyhedrongeom import PolyhedronGeom
- from spotlight3ds import SpotLight3DS
- from glpointlight import GLPointLight
- from gltargetspotlight import GLTargetSpotLight
- from glfreespotlight import GLFreeSpotLight
- from gltargetdistantlight import GLTargetDistantLight
- from glfreedistantlight import GLFreeDistantLight
- from glmaterial import GLMaterial
- from cgkit.Interfaces import *
- from _OpenGL.GL import GL_REPLACE, GL_MODULATE, GL_DECAL, GL_BLEND
- from _OpenGL.GL import *
- import cmds
- from ri import *
- import sl
- from riutil import *
- from math import *
-
- #class IObject(protocols.Interface): pass
- class IGeometry(protocols.Interface): pass
- class ILightSource(protocols.Interface): pass
- class IMaterial(protocols.Interface): pass
-
- # RIBImporter
- class RIBExporter:
- """RIB export class.
- """
-
- _protocols = ["Export"]
-
- # extension
- def extension():
- return ["rib"]
- extension = staticmethod(extension)
-
- # description
- def description(self):
- """Return a short description for the file dialog."""
- return "RenderMan RIB file"
- description = staticmethod(description)
-
- # exportFile
- def exportFile(self,
- filename,
- camera = None,
- output = None,
- output_framebuffer = True,
- bake = False,
- bakemodel = None,
- bakestvar = "st"):
- """Export a RIB file.
-
- \a camera is the camera object to use. If None is passed, the
- first camera found is used.
- \a output is the output file name or a list of output specifiers
- (which contain the parameters for a RiDisplay() call). If
- output is None, no RiDisplay() call is done.
- """
-
- scene = getScene()
- self.timestep = scene.timer().timestep
- self.bake = bake
-
- # A list with all light sources in the scene
- # (the items are the original lights, *not* the adapted lights)
- self.lights = []
-
- # A dictionary that stores lightsource shader names
- # Key is the light class, value is the shader name
- self.light_shader = {}
-
- # A dictionary that stores the passes created by light sources
- # Key is the original light instance, value is the passes list
- # Empty lists are not stored.
- self.light_passes = {}
-
- # A dictionary that stores material shader names
- # Key is the tuple (material class, surface shader name, displacement
- # shader name, interior name), value are the shader names (surface,
- # displacement, interior)
- # (the shader names in the key are not the true file names but
- # the names returned by the material)
- self.material_shaders = {}
-
- # A dictionary that stores the passes created by materials
- # Key is the original material instance, value is the passes list
- # Empty lists are not stored.
- self.material_passes = {}
-
- # A dictionary with map names used so far
- self.mapnames = {}
-
- # The shader names created so far (this dictionary is used to
- # create unique file names)
- self.shader_names = {}
-
- # Key: (geom, matid) Value: File name
- self.geom_file = {}
-
- # The geom file names creates so far
- # (this dictionary is used to create unique file names)
- self.geom_names = {}
-
- # Directory names
- self.shader_path = "shaders"
- self.map_path = "maps"
- self.geom_path = "geoms"
-
- # The list with render passes
- passes = []
-
- # Search for a camera and collect the passes...
- cam = camera
- self.preprocess_called = {}
- for obj in scene.walkWorld():
- if cam==None and ICamera in obj.protocols():
- cam = obj
-
- # Check if the object is a light source
- try:
- explgt = protocols.adapt(obj, ILightSource)
- self.lights.append(obj)
- # Create the RenderPass objects required for this light
- lgtpasses = explgt.createPasses()
- lgtpasses = self.makePassOutputUnique(lgtpasses)
- if lgtpasses!=[]:
- self.light_passes[obj] = lgtpasses
- passes += lgtpasses
- except NotImplementedError:
- # TODO: Use protocols instead of isinstance()
- if isinstance(obj, lightsource.LightSource):
- print 'Unknown light source: "%s"'%obj.name
-
- if obj.geom==None:
- continue
-
- # Collect the material passes
- if obj.visible:
- for i in range(obj.getNumMaterials()):
- mat = obj.getMaterial(i)
- if mat not in self.material_passes:
- try:
- expmat = protocols.adapt(mat, IMaterial)
- # Create the RenderPass objects required for the material
- ps = expmat.createPasses()
- ps = self.makePassOutputUnique(ps)
- if ps!=[]:
- self.material_passes[mat] = ps
- passes += ps
- if mat not in self.preprocess_called:
- expmat.preProcess(self)
- self.preprocess_called[mat] = 1
- except NotImplementedError:
- pass
-
- if cam==None:
- cam = TargetCamera()
-
- # Store the camera so that Pass objects can access it
- self.cam = cam
-
- # Add the map path to the map names
- # (on win32, a backslash is replaced by two backslashes because
- # a renderer might interpret a single backslash as an escape character
- # (such as 3Delight))
- for ps in passes:
- tab = ps.getFilenameTable()
- for vname in tab:
- rname = tab[vname]
- rname = os.path.join(self.map_path, rname)
- if sys.platform=="win32":
- rname = rname.replace('\\', "\\\\")
- tab[vname] = rname
- ps.setFilenameTable(tab)
-
- if len(passes)>0:
- self.checkMapPath()
-
- # Add the final image pass as last pass
- # if output==None:
- # output = scene.getGlobal("output", "out.tif")
- if bake:
- defaultdisplaymode = RI_RGBA
- else:
- defaultdisplaymode = RI_RGB
- mode = scene.getGlobal("displaymode", defaultdisplaymode)
- out = self.outputSpec(output, mode=mode, output_framebuffer=output_framebuffer)
- if bake:
- bakemodel = cmds.worldObject(bakemodel)
- bakepass = BakePass(output=out, bakemodel=bakemodel, bakestvar=bakestvar)
- passes.append(bakepass)
- else:
- imgpass = ImagePass(output=out, cam=cam)
- passes.append(imgpass)
-
- # Initialize the exporter attribute in the passes...
- for p in passes:
- p.exporter = self
-
- # Start export...
- RiBegin(filename)
-
- RiOption("searchpath", "shader", "%s:&"%self.shader_path)
- RiOption("searchpath", "archive", "%s:&"%self.geom_path)
- RiOption("searchpath", "texture", "%s:&"%self.map_path)
- RiHider(RI_HIDDEN, "string depthfilter", "midpoint")
- globalrib = scene.getGlobal("rib", None)
- if globalrib!=None:
- RiArchiveRecord(RI_VERBATIM, globalrib+"\n")
-
- # Do render passes...
- print len(passes),"passes..."
- # nr = 0
- # Tex passes first
- for rpass in passes:
- if isinstance(rpass, TexPass):
- # nr+=1
- # print "\015Pass %d..."%nr,
- rpass.doPass(0)
- rpass._done = True
-
- # Other passes...
- for rpass in passes:
- if isinstance(rpass, TexPass):
- continue
- # nr+=1
- # print "\015Pass %d..."%nr,
- rpass.doPass(0)
- rpass._done = True
-
- RiEnd()
-
- ## protected:
-
- # outputSpec
- def outputSpec(self, output, mode=RI_RGB, output_framebuffer=False):
- """Return the output specification for the final image pass.
-
- output is the parameter passed to exportFile().
- mode and output_framebuffer is only used when output is a string.
- The return value is a list of output specs which can be
- passed as output parameter to the ImagePass.
- """
- # No output?
- if output==None:
- return []
- # Is output a string? (i.e. the output file name)
- elif isinstance(output, types.StringTypes):
- out = [(output, RI_FILE, mode, {})]
- if output_framebuffer:
- out += [(output, RI_FRAMEBUFFER, mode, {})]
- return out
- # User specified output specs? (output must already be a list
- # of specs)
- else:
- return output
-
-
- # isExportable
- def isExportable(self, wobj):
- """Check if a WorldObject can be exported or not.
-
- ??? Geometry?
- """
-
- geom = wobj.geom
- if geom==None:
- return False
-
- try:
- expgeom = protocols.adapt(geom, IGeometry)
- return True
- except NotImplementedError:
- print '"%s" has unknown geometry.'%wobj.name
- return False
-
- # applyViewTransform
- def applyViewTransform(self, V):
- """Apply the view transformation V.
-
- This method corresponds to a RiConcatTransform() call.
- It outputs the view transformation V as a RenderMan transformation.
- The handedness of the scene is taken into account.
-
- \param V (\c mat4) View transformation (world -> camera)
- """
- scene = getScene()
- if scene.handedness=='r':
- RiScale(-1,1,1)
- RiConcatTransform(V.toList())
-
- # applyLightSource
- def applyLightSource(self, lgt):
- """Apply the light source lgt.
-
- This method corresponds to a RiLightSource() call.
-
- \param lgt (\c WorldObject) Light source
- \return Light id or None.
- """
-
- # try:
- explgt = protocols.adapt(lgt, ILightSource)
- # except NotImplementedError:
- # return
-
- # Save the light shader if it wasn't already saved before...
- cls = "%s_%s"%(lgt.__class__, explgt.shaderName())
- if cls not in self.light_shader:
- shadername = self.writeShader(explgt.shaderName(),
- explgt.shaderSource())
- self.light_shader[cls] = shadername
-
- # Get the shader name
- shadername = self.light_shader[cls]
- if shadername==None:
- return None
-
- # Get the parameters for the shader
- passes = self.light_passes.get(lgt, [])
- params = explgt.shaderParams(passes)
-
- lid = RiLightSource(shadername, params)
- return lid
-
- # applyTransformation
- def applyTransformation(self, T, linearvel=None, angularvel=None):
- """Apply the transformation T.
-
- This method corresponds to a RiConcatTransform() call.
- It outputs T as a RenderMan transformation.
-
- \param T (\c mat4) Transformation
- """
- RiConcatTransform(T.toList())
- if linearvel!=None and angularvel!=None:
- try:
- axis = angularvel.normalize()
- except:
- axis = vec3(1,0,0)
- dw = 0.5*self.timestep*degrees(angularvel.length())
- dr = 0.5*self.timestep*linearvel
- if abs(dw)>1E-6:
- RiMotionBegin(0, 1)
- RiRotate(-dw, axis)
- RiRotate( dw, axis)
- RiMotionEnd()
- if dr!=vec3(0):
- RiMotionBegin(0,1)
- RiTranslate(-dr)
- RiTranslate( dr)
- RiMotionEnd()
-
- # applyMaterial
- def applyMaterial(self, mat):
- """Apply a material.
-
- This method corresponds to the calls RiColor(), RiOpacity(),
- RiSurface(), RiDisplacement() and RiInterior().
-
- Evtl. Flags als Parameter, die bestimmten welche der Shader
- wirklich ausgegeben werden sollen (Surface, Displacement, Volume).
- Z.B. koennte Shadow-Pass auf Surface verzichten, evtl. aber nicht
- auf Displacement.
-
- \param mat (\c Material) Material
- """
- if mat==None:
- return
-
- # try:
- expmat = protocols.adapt(mat, IMaterial)
- # except NotImplementedError:
- # return
-
- # Save the shaders if they weren't already saved before...
- cls = (mat.__class__,
- expmat.surfaceShaderName(),
- expmat.displacementShaderName(),
- expmat.interiorShaderName())
- if cls not in self.material_shaders:
- # Prepare the material shaders (save shader source)
- srfshader = self.writeShader(expmat.surfaceShaderName(),
- expmat.surfaceShaderSource())
- dispshader = self.writeShader(expmat.displacementShaderName(),
- expmat.displacementShaderSource())
- intrshader = self.writeShader(expmat.interiorShaderName(),
- expmat.interiorShaderSource())
- self.material_shaders[cls] = (srfshader, dispshader, intrshader)
-
- # Get the shader names
- srfshader, dispshader, intrshader = self.material_shaders[cls]
-
- # Get the parameters for the shader
- passes = self.material_passes.get(mat, [])
- srfparams = expmat.surfaceShaderParams(passes)
- dispparams = expmat.displacementShaderParams(passes)
- interiorparams = expmat.interiorShaderParams(passes)
-
- # Get the shader transforms
- srftransform = expmat.surfaceShaderTransform()
- disptransform = expmat.displacementShaderTransform()
- interiortransform = expmat.interiorShaderTransform()
-
- color = expmat.color()
- opacity = expmat.opacity()
-
- if color!=None:
- RiColor(color)
- if opacity!=None:
- RiOpacity(opacity)
- if srfshader!=None:
- if srftransform!=mat4(1):
- RiTransformBegin()
- RiConcatTransform(srftransform.toList())
- RiSurface(srfshader, srfparams)
- if srftransform!=mat4(1):
- RiTransformEnd()
- if dispshader!=None:
- if disptransform!=mat4(1):
- RiTransformBegin()
- RiConcatTransform(disptransform.toList())
- coordsys, bound = expmat.displacementBound()
- RiAttribute("displacementbound",
- "string coordinatesystem", coordsys,
- "float sphere", bound)
- RiDisplacement(dispshader, dispparams)
- if disptransform!=mat4(1):
- RiTransformEnd()
- if intrshader!=None:
- if interiortransform!=mat4(1):
- RiTransformBegin()
- RiConcatTransform(interiortransform.toList())
- RiInterior(intrshader, interiorparams)
- if interiortransform!=mat4(1):
- RiTransformEnd()
-
-
- # applyGeometry
- def applyGeometry(self, geom, matid=0):
- """Apply a geometry object.
-
- \param geom (\c GeomObject) Geometry or None
- """
- if geom==None:
- return
-
- # Was the geom already exported?
- if (geom, matid) in self.geom_file:
- filename = self.geom_file[geom, matid]
- RiReadArchive(filename)
- return
-
- # The geom was not exported, so do it now...
-
- try:
- expgeom = protocols.adapt(geom, IGeometry)
- except NotImplementedError:
- print 'Warning: Unknown geometry: "%s" (%s)'%(geom.name, geom.__class__.__name__)
- return
-
- # Create the geoms directory if it doesn't exist
- if not os.path.exists(self.geom_path):
- os.mkdir(self.geom_path)
-
- # Determine the output file name (without path)
- n = "%s_id%d_%s.rib"%(geom.__class__.__name__, matid, geom.name)
- filename = self.makeFilenameUnique(n, self.geom_names)
- self.geom_names[filename] = 1
- self.geom_file[geom, matid] = filename
-
- ctx = RiGetContext()
- RiBegin(os.path.join(self.geom_path, filename))
- RiOption(RI_RIBOUTPUT, RI_VERSION, 0)
- expgeom.render(matid)
- RiEnd()
- RiContext(ctx)
- RiReadArchive(filename)
-
-
- # writeShader
- def writeShader(self, name, source):
- """Write a shader source file.
-
- \param name (\c str) Initial shader name or None
- \param source (\c str) Shader source code or None
- \return Shader name
- """
- # No source given? Then just use the specified shader name
- if source==None:
- return name
-
- if name==None:
- name = "shader"
-
- shadername = self.makeFilenameUnique(name, self.shader_names)
- self.shader_names[shadername]=1
-
- # Create the shaders directory if it doesn't exist
- if not os.path.exists(self.shader_path):
- os.mkdir(self.shader_path)
-
- filename = os.path.join(self.shader_path, shadername+".sl")
- f = file(filename, "wt")
- # Add the macros that are used for baking...
- if self.bake:
- f.write("#define BAKE_PASS\n")
- begin = 'varying point _P_bake = transform("world", "current", transform("camera", "object", Pref));\\\n varying point _P_orig = P;\\\n P = _P_bake;'
- end = 'P = _P_orig;'
- normal = 'normalize(n);'
- else:
- begin = ""
- end = ""
- normal = 'faceforward(normalize(n),I);'
- f.write("#define BAKE_BEGIN %s\n"%begin)
- f.write("#define BAKE_END %s\n"%end)
- f.write("#define BAKE_NORMAL(n) %s\n\n"%normal)
-
- f.write(source.replace("$SHADERNAME", shadername))
- f.close()
- return shadername
-
- # checkMapPath
- def checkMapPath(self):
- """Create the map directory if it doesn't already exist.
- """
- if not os.path.exists(self.map_path):
- os.mkdir(self.map_path)
-
-
- # makePassOutputUnique
- def makePassOutputUnique(self, passes):
- res = []
- for rpass in passes:
- tab = rpass.getFilenameTable()
- for vname in tab:
- rname = self.makeFilenameUnique(tab[vname], self.mapnames)
- tab[vname] = rname
- self.mapnames[rname] = 1
- # print tab
- rpass.setFilenameTable(tab)
- res.append(rpass)
-
- return res
-
- # makeFilenameUnique
- def makeFilenameUnique(self, name, names):
- """Modify a file name so that it is unique.
-
- If \a name is already among \a names it is modified by increasing
- a trailing number so that it is unique.
-
- \param name (\c str) File name
- \param names A list or dictionary with existing file names
- \return Unique file name
- """
- base, ext = os.path.splitext(name)
- # Read any trailing number
- # -> base: name without number (and extension) / num: Number
- i = 1
- while i<=len(base) and base[-i:].isdigit():
- i+=1
- i-=1
- if i==0:
- num = 1
- else:
- num = int(base[-i:])
- base = base[:-i]
-
- while name in names:
- name = "%s%d%s"%(base, num, ext)
- num += 1
-
- return name
-
-
-
- ######################################################################
-
- # RenderPass
- class RenderPass:
- """RenderPass.
-
- A pass object can access the exporter (RIBExport) via self.exporter.
- """
- def __init__(self, output, owner=None):
- """Constructor.
-
- output is a list of output specifications that contain the
- output file name, the output type and the output mode (RI_RGB,
- RI_RGBA,...) and optional extra parameters. It's all the
- information that's necessary for a RiDisplay() call.
-
- \param owner (\c Component) The object that requires the result of this pass
- """
- self.owner = owner
- self.output = output
- # A reference to the exporter class (this is initialized in the
- # exporter after the Passes were created)
- self.exporter = None
-
- # done flag (this is set to True in the exporter)
- self._done = False
-
- # Filename table. Key: Logical file name / Value: Real filename
- self.filenametab = {}
- for name,type,mode,params in output:
- self.filenametab[name] = name
-
- # done
- def done(self):
- """Check if this pass is already done or not.
-
- This method is used when shader parameters have to be determined.
- The output of a pass may only be used once the pass is done and
- the output really exists (for example, you can't use a shadow map
- until it was created).
-
- \return True if the pass was already rendered (i.e. the output images exist).
- """
- return self._done
-
- # realFilename
- def realFilename(self, filename):
- """Translate a logical file name into a real file name.
-
- \param filename (\c str) Logical file name
- """
- if filename not in self.filenametab:
- raise ValueError('File name "%s" is not an output file name.'%filename)
-
- return self.filenametab[filename]
-
- # getFilenameTable
- def getFilenameTable(self):
- """Return the filename translation table.
-
- \return The filename translation dictionary.
- """
- return self.filenametab
-
- # setFilenameTable
- def setFilenameTable(self, tab):
- """Set an updated filename table.
-
- \param tab (\c dict) The new filename translation dictionary.
- """
- self.filenametab = tab
-
- # doPass
- def doPass(self, framenr):
- """Write a Frame block.
-
- \param framenr (\c int) Frame number to use
- """
- pass
-
- # initDisplays
- def initDisplays(self):
- """Call RiDisplay() for all outputs stored in the class."""
- # Do RiDisplay() calls...
- append_plus = False
- for name,type,mode,params in self.output:
- name = self.realFilename(name)
- if append_plus:
- name = "+"+name
- RiDisplay(name, type, mode, params)
- append_plus = True
-
-
-
- # ImagePass
- class ImagePass(RenderPass):
- def __init__(self, output, cam):
- RenderPass.__init__(self, output, None)
- self.cam = cam
-
- # doPass
- def doPass(self, framenr):
- scene = getScene()
-
- RiArchiveRecord(RI_COMMENT, "")
- RiArchiveRecord(RI_COMMENT, "Image pass")
- RiArchiveRecord(RI_COMMENT, "")
- RiFrameBegin(framenr)
-
- i,j = scene.getGlobal("pixelsamples", (2,2))
- RiPixelSamples(i,j)
- res = scene.getGlobal("resolution", (640,480))
- try:
- if len(res)==2:
- w,h = res
- aspect = 1
- elif len(res)==3:
- w,h,aspect = res
- else:
- raise Exception
- except:
- print >>sys.stderr, "Error: Invalid resolution setting:",res
- w,h,aspect = 640,480,1
- RiFormat(w,h,aspect)
- RiShadingRate(scene.getGlobal("shadingrate", 1.0))
-
- filterdata = scene.getGlobal("pixelfilter", None)
- if filterdata!=None:
- filter, (xwidth, ywidth) = filterdata
- RiPixelFilter(filter, xwidth, ywidth)
-
- # Do RiDisplay() calls...
- self.initDisplays()
-
- # Camera...
- cam = self.cam
- fstop = getattr(cam, "fstop", 0)
- focallength = getattr(cam, "focallength", 0)
- RiProjection(RI_PERSPECTIVE, fov=cam.fov)
- if fstop!=0 and focallength!=0:
- # XXX: The following line only works with a TargetCamera!
- focaldistance = (cam.target-cam.pos).length()
- RiDepthOfField(fstop, focallength, focaldistance)
- self.exporter.applyViewTransform(cam.viewTransformation())
- RiShutter(0,1)
-
- RiWorldBegin()
-
- # Set light sources...
- for lgt in self.exporter.lights:
- RiAttributeBegin()
- RiAttribute("identifier", "name", lgt.name)
- RiConcatTransform(lgt.worldtransform.toList())
- lid = self.exporter.applyLightSource(lgt)
- RiAttributeEnd()
- if lid!=None:
- RiIlluminate(lid, lgt.enabled)
-
- # shader,params,transform,name = exporter.light_shaders[lgt]
- # lid = RiLightSource(shader, params)
-
- self.renderChilds(scene.worldRoot())
-
- RiWorldEnd()
- RiFrameEnd()
-
- def renderChilds(self, obj):
- exporter = self.exporter
- for child in obj.iterChilds():
- if not child.visible:
- continue
- # No geometry and no children? Then ignore this node
- if child.geom==None and child.lenChilds()==0:
- continue
- # if not exporter.isExportable(child):
- # continue
-
- RiAttributeBegin()
-
- # Store the name of the object
- RiAttribute("identifier", "name", child.name)
- # Transform the object
- exporter.applyTransformation(child.localTransform(), child.linearvel, child.angularvel)
-
- for i in range(child.getNumMaterials()):
- # Set shaders...
- exporter.applyMaterial(child.getMaterial(i))
-
- # Custom RIB
- rib = getattr(child, "rib", None)
- if rib!=None:
- RiArchiveRecord(RI_VERBATIM, rib+"\n")
-
- # Output geometry
- exporter.applyGeometry(child.geom, i)
-
- # Recursively render all childs
- self.renderChilds(child)
-
- RiAttributeEnd()
-
-
- # ShadowPass
- class ShadowPass(RenderPass):
- def __init__(self, output, light, fov, resolution, orientoffset=mat4(1)):
- RenderPass.__init__(self, output, None)
- self.light = light
- self.fov = fov
- self.resolution = resolution
- self.orientoffset = orientoffset
-
- # doPass
- def doPass(self, framenr):
- scene = getScene()
-
- RiArchiveRecord(RI_COMMENT, "")
- RiArchiveRecord(RI_COMMENT, "Shadow pass")
- RiArchiveRecord(RI_COMMENT, "")
- RiFrameBegin(framenr)
-
- RiPixelSamples(1,1)
- RiPixelFilter(RiBoxFilter, 1, 1)
- RiFormat(self.resolution, self.resolution, 1)
- RiShadingRate(2)
-
- # Do RiDisplay() calls...
- self.initDisplays()
-
- # Camera...
- RiProjection(RI_PERSPECTIVE, fov=self.fov)
- V = (self.light.transform*self.orientoffset).inverse()
- self.exporter.applyViewTransform(V)
- RiShutter(0,1)
-
- RiWorldBegin()
-
- self.renderChilds(scene.worldRoot())
-
- RiWorldEnd()
- RiFrameEnd()
- zname = self.realFilename(self.output[0][0])
- mapname = os.path.splitext(zname)[0]+".map"
- RiMakeShadow(zname, mapname)
-
- def renderChilds(self, obj):
- exporter = self.exporter
- for child in obj.iterChilds():
- if not child.visible:
- continue
- # No geometry and no children? Then ignore this node
- if child.geom==None and child.lenChilds()==0:
- continue
- # if not exporter.isExportable(child):
- # continue
-
- RiAttributeBegin()
-
- # Store the name of the object
- RiAttribute("identifier", "name", child.name)
- # Transform the object
- exporter.applyTransformation(child.localTransform())
- for i in range(child.getNumMaterials()):
- # Set shaders...
- exporter.applyMaterial(child.getMaterial(i))
-
- # Custom RIB
- rib = getattr(child, "rib", None)
- if rib!=None:
- RiArchiveRecord(RI_VERBATIM, rib+"\n")
-
- # Output geometry
- exporter.applyGeometry(child.geom, i)
-
- # Recursively render all childs
- self.renderChilds(child)
-
- RiAttributeEnd()
-
- # FlatReflectionPass
- class FlatReflectionPass(RenderPass):
- def __init__(self, output, mirrorobj=None):
- RenderPass.__init__(self, output, None)
- self.mirrorobj = mirrorobj
-
- # doPass
- def doPass(self, framenr):
- scene = getScene()
-
- RiArchiveRecord(RI_COMMENT, "(Flat) Reflection pass")
- RiFrameBegin(framenr)
-
- RiPixelSamples(2,2)
- RiFormat(640,480,1)
- RiShadingRate(1)
-
- # Do RiDisplay() calls...
- self.initDisplays()
-
- # Camera...
- cam = self.exporter.cam
- RiProjection(RI_PERSPECTIVE, fov=cam.fov)
- self.exporter.applyViewTransform(cam.viewTransformation())
- RiScale(1,1,-1)
- RiShutter(0,1)
- # RiTranslate(0,0,1)
-
- RiWorldBegin()
-
- # Set light sources...
- for lgt in self.exporter.lights:
- RiAttributeBegin()
- RiAttribute("identifier", "name", lgt.name)
- RiConcatTransform(lgt.worldtransform.toList())
- lid = self.exporter.applyLightSource(lgt)
- RiAttributeEnd()
- if lid!=None:
- RiIlluminate(lid, RI_TRUE)
-
- # shader,params,transform,name = exporter.light_shaders[lgt]
- # lid = RiLightSource(shader, params)
-
- self.renderChilds(scene.worldRoot())
-
- RiWorldEnd()
- RiFrameEnd()
- tifname = self.realFilename(self.output[0][0])
- texname = os.path.splitext(tifname)[0]+".tex"
- RiMakeTexture(tifname, texname, RI_CLAMP, RI_CLAMP, RiGaussianFilter, 1, 1)
-
-
- def renderChilds(self, obj):
- exporter = self.exporter
- for child in obj.iterChilds():
- if child==self.mirrorobj:
- continue
- if not child.visible:
- continue
- # if not exporter.isExportable(child):
- # continue
-
- RiAttributeBegin()
-
- # Store the name of the object
- RiAttribute("identifier", "name", child.name)
- # Transform the object
- exporter.applyTransformation(child.localTransform(), child.linearvel, child.angularvel)
- for i in range(child.getNumMaterials()):
- # Set shaders...
- exporter.applyMaterial(child.getMaterial(i))
-
- # Custom RIB
- rib = getattr(child, "rib", None)
- if rib!=None:
- RiArchiveRecord(RI_VERBATIM, rib+"\n")
-
- # Output geometry
- exporter.applyGeometry(child.geom, i)
-
- # Recursively render all childs
- self.renderChilds(child)
-
- RiAttributeEnd()
-
- # BakePass
- class BakePass(RenderPass):
- """Create a bake pass.
-
- The class uses the technique described in the "Stupid RAT Tricks 2001":
- "The RenderMan EasyBake Oven" by Jonathan Litt and Dan Goldman.
- http://www.cs.washington.edu/homes/dgoldman/ezbake/EZ_Bake_Oven.htm
-
- Additionally, the original geometry is also stored so that raytracing
- can also be used.
- """
-
- def __init__(self, output, bakemodel, bakestvar="st"):
- """
- bakemodel is the WorldObject whose texture should be baked.
- bakestvar is the name of the variable that holds the texture
- coordinates for baking.
- """
- RenderPass.__init__(self, output, None)
- self.bakemodel = bakemodel
- self.bakestvar = bakestvar
-
- # doPass
- def doPass(self, framenr):
- scene = getScene()
-
- RiArchiveRecord(RI_COMMENT, "")
- RiArchiveRecord(RI_COMMENT, "Bake pass")
- RiArchiveRecord(RI_COMMENT, "")
- RiFrameBegin(framenr)
-
- i,j = scene.getGlobal("pixelsamples", (2,2))
- RiPixelSamples(i,j)
- res = scene.getGlobal("resolution", (256,256))
- try:
- if len(res)==2:
- w,h = res
- aspect = 1
- elif len(res)==3:
- w,h,aspect = res
- else:
- raise Exception
- except:
- print >>sys.stderr, "Error: Invalid resolution setting:",res
- w,h,aspect = 256,256,1
- RiFormat(w,h,aspect)
- RiShadingRate(scene.getGlobal("shadingrate", 1.0))
-
- # Do RiDisplay() calls...
- self.initDisplays()
-
- # Camera...
- RiProjection(RI_ORTHOGRAPHIC)
- bb = scene.boundingBox()
- bmin, bmax = bb.getBounds()
- RiScale(2,2,2)
- RiTranslate(-0.5, -0.5, -bmax.z-1)
-
- RiWorldBegin()
-
- # Set light sources...
- for lgt in self.exporter.lights:
- RiAttributeBegin()
- RiAttribute("identifier", "name", lgt.name)
- RiConcatTransform(lgt.worldtransform.toList())
- lid = self.exporter.applyLightSource(lgt)
- RiAttributeEnd()
- if lid!=None:
- RiIlluminate(lid, lgt.enabled)
-
- # Flattened geometry
- obj = self.bakemodel
- RiAttributeBegin()
- self.exporter.applyMaterial(obj.getMaterial(0))
- # RiCoordSysTransform("camera")
- # RiScale(2,2,2)
- # RiTranslate(-0.5,-0.5,1)
- RiTranslate(0,0, bmax.z+1.5)
- self.bakeModel(obj, self.bakestvar)
- RiAttributeEnd()
-
- # 3Delight attribute...
- RiAttribute("visibility", "string transmission", "opaque")
- # Pixie attribute...
- RiAttribute("visibility", "int trace", 1)
-
- self.renderChilds(scene.worldRoot())
-
- RiWorldEnd()
- RiFrameEnd()
-
- def bakeModel(self, obj, stvarname="st"):
- """
- obj is the model that should be baked. stvarname is the name
- of the variable that holds the texture coordinates for baking.
- """
-
- # Check texture coordinates...
- info = obj.geom.findVariable(stvarname)
- if info==None:
- raise RuntimeError, "No variable '%s' found"%stvarname
-
- name, storage, type, mult = info
-
- if type!=FLOAT or mult!=2:
- raise TypeError, "variable '%s' is of wrong type"%stvarname
-
- if storage==FACEVARYING:
- geom = cmds.convFaceVarToVar(obj.geom)
- elif storage==VARYING:
- geom = obj.geom
- else:
- raise TypeError, "'%s' storage class %s not supported for baking"%(stvarname,storage)
-
- # Convert the model into a trimesh...
- if not isinstance(geom, TriMeshGeom):
- tm = TriMeshGeom()
- geom.convert(tm)
- geom = tm
-
- # Convert the tex coords into vec3s...
- st = geom.slot(stvarname)
- # print "sizes:",geom.verts.size(), st.size()
- stcoords = map(lambda x: vec3(x), st)
-
- # Transform the verts...
- # verts = []
- # W = obj.worldtransform
- # for i,j,k in geom.faces:
- # verts.append(W*geom.verts[i])
- # verts.append(W*geom.verts[j])
- # verts.append(W*geom.verts[k])
-
- # verts = 156*[(0,0,0)]
-
- # Create parameter list...
- W = obj.worldtransform
- params = {"P":stcoords,
- "Pref":map(lambda x: W*x, geom.verts)}
- RiDeclare("Pref", "vertex point")
- clss = ["constant", "uniform", "varying", "vertex", "facevarying", "facevertex", "user"]
- typs = ["integer", "float", "string", "color", "point", "vector",
- "normal", "matrix", "hpoint"]
- for name, storage, type, multiplicity in geom.iterVariables():
- cls = clss[abs(storage)]
- typ = typs[abs(type)]
- if cls!="user":
- s = geom.slot(name)
- params[name] = list(s)
- if multiplicity==1:
- decl = "%s %s"%(cls, typ)
- else:
- decl = "%s %s[%d]"%(cls, typ, multiplicity)
- RiDeclare(name, decl)
-
- # RiCoordSysTransform("camera")
- RiPointsPolygons(len(geom.faces)*[3], list(geom.faces), params)
-
- def renderChilds(self, obj):
- exporter = self.exporter
- for child in obj.iterChilds():
- if not child.visible:
- continue
- # No geometry and no children? Then ignore this node
- if child.geom==None and child.lenChilds()==0:
- continue
- # if not exporter.isExportable(child):
- # continue
-
- RiAttributeBegin()
-
- # Store the name of the object
- RiAttribute("identifier", "name", child.name)
- # Transform the object
- exporter.applyTransformation(child.localTransform(), child.linearvel, child.angularvel)
-
- for i in range(child.getNumMaterials()):
- # Set shaders...
- exporter.applyMaterial(child.getMaterial(i))
-
- # Custom RIB
- rib = getattr(child, "rib", None)
- if rib!=None:
- RiArchiveRecord(RI_VERBATIM, rib+"\n")
-
- # Output geometry
- exporter.applyGeometry(child.geom, i)
-
- # Recursively render all childs
- self.renderChilds(child)
-
- RiAttributeEnd()
-
-
- # TexPass
- class TexPass(RenderPass):
- def __init__(self, maps, output=[]):
- """Constructor.
-
- The map definition list contains one tuple for every map.
- The tuple is a 7-tuple with the following entries:
-
- - Map name (incl. path)
- - swrap ("periodic", "clamp", "black")
- - twrap ("periodic", "clamp", "black")
- - filterfunc ("gaussian", "box", "triangle", "sinc", "catmullrom", ...)
- - swidth
- - twidth
- - params - A dictionary with additional parameters
-
- These are the parameters for the \c RiMakeTexture() call.
- The output file name is generated from the input map name by
- replacing the suffix with "*.tex".
-
- \param maps A list with map defintions
- """
- RenderPass.__init__(self, output)
- self.maps = maps
-
- def doPass(self, framenr):
-
- for map,swrap,twrap,filterfunc,swidth,twidth,params in self.maps:
-
- # Copy the original image into the map directory and convert
- # to tif if necessary
- self.copyImageMap(map)
-
- # Call RiMakeTexture() to convert the .tif into .tex
- mapbase = os.path.basename(map)
- name, ext = os.path.splitext(mapbase)
- tifname = os.path.join(self.exporter.map_path, name)+".tif"
- texname = os.path.join(self.exporter.map_path, name)+".tex"
- if sys.platform=="win32":
- tifname = tifname.replace("\\", "\\\\")
- texname = texname.replace("\\", "\\\\")
- RiMakeTexture(tifname, texname,
- swrap, twrap,
- filterfunc, swidth, twidth, **params)
-
- ## protected:
-
- def copyImageMap(self, texmap):
- """Copy the texture map image into the map folder.
-
- \param texmap (\c str) Texture map name (incl. path)
- """
-
- self.exporter.checkMapPath()
- texname = os.path.basename(texmap)
- name, ext = os.path.splitext(texname)
- if ext.lower()!=".tif":
- print 'Converting "%s"'%texmap
- tifname = os.path.join(self.exporter.map_path, name+".tif")
- # Read original map
- try:
- img = Image.open(texmap)
- except IOError, e:
- print e
- return
- # Save map as TIF file
- img.save(tifname)
- else:
- print 'Copying "%s"'%texmap
- dest = os.path.join(self.exporter.map_path, os.path.basename(texmap))
- shutil.copyfile(texmap, dest)
-
-
- ######################################################################
- ####################### Geometry adapters ############################
- ######################################################################
-
- class BoxAdapter:
- protocols.advise(instancesProvide=[IGeometry], asAdapterForTypes=[BoxGeom])
-
- def __init__(self, boxgeom, proto):
- self.geom = boxgeom
-
- def render(self, matid):
- if matid!=0:
- return
-
- lx2 = self.geom.lx/2
- ly2 = self.geom.ly/2
- lz2 = self.geom.lz/2
- A = vec3(-lx2,-ly2,-lz2)
- B = vec3( lx2,-ly2,-lz2)
- C = vec3( lx2, ly2,-lz2)
- D = vec3(-lx2, ly2,-lz2)
- E = vec3(-lx2,-ly2, lz2)
- F = vec3( lx2,-ly2, lz2)
- G = vec3( lx2, ly2, lz2)
- H = vec3(-lx2, ly2, lz2)
- RiPatch(RI_BILINEAR, P=[D,C,A,B])
- RiPatch(RI_BILINEAR, P=[A,B,E,F])
- RiPatch(RI_BILINEAR, P=[D,A,H,E])
- RiPatch(RI_BILINEAR, P=[C,D,G,H])
- RiPatch(RI_BILINEAR, P=[B,C,F,G])
- RiPatch(RI_BILINEAR, P=[E,F,H,G])
-
-
- class SphereAdapter:
- protocols.advise(instancesProvide=[IGeometry], asAdapterForTypes=[SphereGeom])
-
- def __init__(self, spheregeom, proto):
- self.geom = spheregeom
-
- def render(self, matid):
- if matid==0:
- r = self.geom.radius
- RiSphere(r, -r, r, 360)
-
-
- class CCylinderAdapter:
- protocols.advise(instancesProvide=[IGeometry], asAdapterForTypes=[CCylinderGeom])
-
- def __init__(self, ccylgeom, proto):
- self.geom = ccylgeom
-
- def render(self, matid):
- if matid!=0:
- return
-
- r = self.geom.radius
- l = self.geom.length
- l2 = l/2
- silhouette_len = pi*r+l
- cap_len = pi/2*r;
- v1 = cap_len/silhouette_len
- v2 = v1+l/silhouette_len
-
- RiCylinder(r, -l2, l2, 360, st=[0,v1, 1,v1, 0,v2, 1,v2])
- RiTransformBegin()
- RiTranslate(0,0,l2)
- RiSphere(r, 0, r, 360, st=[0,v2, 1,v2, 0,1, 1,1])
- RiTransformEnd()
- RiTransformBegin()
- RiTranslate(0,0,-l2)
- RiSphere(r, -r, 0, 360, st=[0,0, 1,0, 0,v1, 1,v1])
- RiTransformEnd()
-
- class PlaneAdapter:
- protocols.advise(instancesProvide=[IGeometry], asAdapterForTypes=[PlaneGeom])
-
- def __init__(self, planegeom, proto):
- self.geom = planegeom
-
- def render(self, matid):
- if matid!=0:
- return
-
- lx2 = self.geom.lx/2
- ly2 = self.geom.ly/2
- A = vec3(-lx2,-ly2,0)
- B = vec3( lx2,-ly2,0)
- C = vec3( lx2, ly2,0)
- D = vec3(-lx2, ly2,0)
- RiPatch(RI_BILINEAR, P=[A,B,D,C])
-
- class TriMeshAdapter:
- protocols.advise(instancesProvide=[IGeometry], asAdapterForTypes=[TriMeshGeom])
-
- def __init__(self, meshgeom, proto):
- self.geom = meshgeom
-
- def render(self, matid):
- if self.geom.findVariable("matid")!=None:
- tm = cmds.extractUniform(self.geom, "matid", matid)
- tm = cmds.removeIsolatedVertices(tm)
- else:
- if matid!=0:
- return
- tm = self.geom
-
- if len(tm.faces)==0:
- return
-
- if tm.findVariable("N")!=None and tm.findVariable("Nfaces")!=None:
- tm = cmds.convMeshAttr(tm, "N", "Nfaces")
-
- # Create parameter list...
- params = {"P":list(tm.verts)}
- clss = ["constant", "uniform", "varying", "vertex", "facevarying", "facevertex", "user"]
- typs = ["integer", "float", "string", "color", "point", "vector",
- "normal", "matrix", "hpoint"]
- for name, storage, type, multiplicity in tm.iterVariables():
- cls = clss[abs(storage)]
- typ = typs[abs(type)]
- if cls!="user":
- s = tm.slot(name)
- params[name] = list(s)
- if multiplicity==1:
- decl = "%s %s"%(cls, typ)
- else:
- decl = "%s %s[%d]"%(cls, typ, multiplicity)
- RiDeclare(name, decl)
-
- if hasattr(self.geom, "subdiv"):
- RiSubdivisionMesh("catmull-clark", len(tm.faces)*[3],
- list(tm.faces), [],0,[],[], params)
- else:
- RiPointsPolygons(len(tm.faces)*[3], list(tm.faces), params)
-
- class PolyhedronAdapter:
- protocols.advise(instancesProvide=[IGeometry], asAdapterForTypes=[PolyhedronGeom])
-
- def __init__(self, polyhedrongeom, proto):
- self.geom = polyhedrongeom
-
- def render(self, matid):
- if matid!=0:
- return
-
- pg = self.geom
-
- # Create parameter list...
- params = {"P":list(pg.verts)}
- clss = ["constant", "uniform", "varying", "vertex", "facevarying", "facevertex", "user"]
- typs = ["integer", "float", "string", "color", "point", "vector",
- "normal", "matrix", "hpoint"]
- for name, storage, type, multiplicity in pg.iterVariables():
- cls = clss[abs(storage)]
- typ = typs[abs(type)]
- if cls!="user":
- s = pg.slot(name)
- params[name] = list(s)
- if multiplicity==1:
- decl = "%s %s"%(cls, typ)
- else:
- decl = "%s %s[%d]"%(cls, typ, multiplicity)
- RiDeclare(name, decl)
-
- nloops = []
- nverts = []
- vertids = []
- for i in range(pg.getNumPolys()):
- poly = pg.getPoly(i)
- nloops.append(len(poly))
- for loop in poly:
- nverts.append(len(loop))
- vertids.append(loop)
-
- if hasattr(self.geom, "subdiv"):
- if nloops==len(nloops)*[1]:
- RiSubdivisionMesh("catmull-clark", nverts, vertids,
- [], 0, [], [], params)
- else:
- print >>sys.stderr, "Warning: Polyhedron with holes in its polys can't be used as subdiv"
- else:
- RiPointsGeneralPolygons(nloops, nverts, vertids, params)
-
-
- ######################################################################
- ######################### Light adapters #############################
- ######################################################################
-
- # SpotLight3DSAdapter
- class SpotLight3DSAdapter:
- protocols.advise(instancesProvide=[ILightSource], asAdapterForTypes=[SpotLight3DS])
-
- def __init__(self, lgt, proto):
- self.obj = lgt
-
- def createPasses(self):
- """Returns a list of RenderPass objects."""
- if self.obj.shadowed:
- shadpass = ShadowPass(output=[("shadow.z", "zfile", RI_Z, {})],
- light=self.obj, fov=self.obj.falloff,
- resolution = self.obj.shadow_size)
- return [shadpass]
-
- return []
-
- def shaderName(self):
- """Returns the name of the corresponding light shader or None.
- """
- return "spotlight3ds"
-
- def shaderSource(self):
- """Returns surface shader source code as a string or None.
- """
- return """// SpotLight3DS shader
-
- light $SHADERNAME(float intensity = 1.0;
- uniform color lightcolor = color "rgb" (1, 1, 1);
- float falloff = 45.0;
- float hotspot = 43.0;
- float attenuation = 0;
- float inner_range = 0;
- float outer_range = 999;
- float overshoot = 0;
- float shadow_filter = 4.0;
- float shadow_bias = 0.01;
- float shadow_samples = 16;
- string shadowname = "")
- {
- uniform float cosfalloff = cos(radians(0.5*falloff));
- uniform float coshotspot = cos(radians(0.5*hotspot));
- uniform vector axis = normalize(vector "shader" (0,0,1));
- float illuminate_angle;
-
- if (overshoot==0)
- {
- illuminate_angle = falloff*PI/360.0;
- }
- else
- {
- illuminate_angle = PI;
- }
-
- illuminate(point "shader" (0,0,0), axis, illuminate_angle)
- {
- vector L0 = normalize(L);
- float dist = length(L);
- float att = 1.0;
-
- // Attenuation due to hotspot/falloff
- if (overshoot==0)
- {
- float ca = L0.axis;
- att = smoothstep(cosfalloff, coshotspot, ca);
- }
-
- // Attenuation due to distance
- if (attenuation!=0)
- att *= 1.0-smoothstep(inner_range, outer_range, dist);
-
- Cl = att * intensity * lightcolor;
-
- if (shadowname!="")
- Cl *= 1 - shadow(shadowname, Ps, "width", shadow_filter, "bias", shadow_bias, "samples", shadow_samples);
-
- }
- }
- """
-
- def shaderParams(self, passes):
- """Return a dictionary with shader parameters and their values."""
- params = {"intensity":self.obj.intensity,
- "uniform color lightcolor":self.obj.color,
- "uniform float falloff":self.obj.falloff,
- "uniform float attenuation":self.obj.attenuation,
- "uniform float inner_range":self.obj.inner_range,
- "uniform float outer_range":self.obj.outer_range,
- "uniform float hotspot":self.obj.hotspot,
- "uniform float overshoot":int(self.obj.overshoot)
- }
- if self.obj.shadowed and passes[0].done():
- zfile = passes[0].realFilename(passes[0].output[0][0])
- mapname = os.path.splitext(zfile)[0]+".map"
- params["uniform string shadowname"] = mapname
- params["uniform float shadow_filter"] = self.obj.shadow_filter
- params["uniform float shadow_bias"] = self.obj.shadow_bias
- return params
-
-
-
- # GLPointLightAdapter
- class GLPointLightAdapter:
- protocols.advise(instancesProvide=[ILightSource], asAdapterForTypes=[GLPointLight])
-
- def __init__(self, lgt, proto):
- self.obj = lgt
-
- def createPasses(self):
- """Returns a list of RenderPass objects."""
- return []
-
- def shaderName(self):
- """Returns the name of the corresponding light shader or None.
- """
- return "glpointlight"
-
- def shaderSource(self):
- """Returns surface shader source code as a string or None.
- """
- return """// GLPointLight shader
- light $SHADERNAME(float intensity = 1.0;
- color diffuse = color "rgb" (1, 1, 1);
- color specular = color "rgb" (1, 1, 1);
- float constant_attenuation = 1;
- float linear_attenuation = 0;
- float quadratic_attenuation = 0)
- {
- illuminate(point "shader" (0,0,0))
- {
- float d = length(L);
- float att = 1.0/(constant_attenuation + linear_attenuation*d + quadratic_attenuation*d*d);
-
- Cl = att*intensity*color "rgb" (1,1,1);
- }
- }
- """
-
- def shaderParams(self, passes):
- """Return a dictionary with shader parameters and their values."""
- return {"intensity":self.obj.intensity,
- "uniform color diffuse":self.obj.diffuse,
- "uniform color specular":self.obj.specular,
- "uniform float constant_attenuation":self.obj.constant_attenuation,
- "uniform float linear_attenuation":self.obj.linear_attenuation,
- "uniform float quadratic_attenuation":self.obj.quadratic_attenuation}
-
-
- # GLSpotLightAdapter
- class GLSpotLightAdapter:
- protocols.advise(instancesProvide=[ILightSource], asAdapterForTypes=[GLTargetSpotLight, GLFreeSpotLight])
-
- def __init__(self, lgt, proto):
- self.obj = lgt
-
- def createPasses(self):
- """Returns a list of RenderPass objects."""
- if hasattr(self.obj, "shadowmap"):
- res,width,blur,bias,samples = self.obj.shadowmap
- shadpass = ShadowPass(output=[("shadow.z", "zfile", RI_Z, {})],
- light=self.obj, fov=self.obj.cutoff,
- resolution = res)
- return [shadpass]
-
- return []
-
- def shaderName(self):
- """Returns the name of the corresponding light shader or None.
- """
- return "glspotlight"
-
- def shaderSource(self):
- """Returns surface shader source code as a string or None.
- """
- return """// GLSpotLight shader
- light $SHADERNAME(float intensity = 1.0;
- uniform color diffuse = color "rgb" (1, 1, 1);
- uniform color specular = color "rgb" (1, 1, 1);
- float constant_attenuation = 1;
- float linear_attenuation = 0;
- float quadratic_attenuation = 0;
- float exponent = 0.0;
- float cutoff = 45.0;
- string shadowname = "";
- float width = 1.0;
- float blur = 0.0;
- float bias = 0.1;
- float samples = 16;)
- {
- float cutoff_rad = cutoff*PI/180.0;
-
- illuminate(point "shader" (0,0,0), vector "shader" (0,0,1), cutoff_rad)
- {
- float d = length(L);
- float att = 1.0/(constant_attenuation + linear_attenuation*d + quadratic_attenuation*d*d);
-
- vector Lshad = normalize(vtransform("shader", L));
- float sp = max(zcomp(Lshad), 0);
- float spot = 0;
- if (sp>=cos(cutoff_rad))
- {
- spot = pow(sp, exponent);
- }
-
- Cl = att * spot * intensity * color "rgb" (1,1,1);
-
- if (shadowname!="")
- Cl *= 1 - shadow(shadowname, Ps, "blur", blur, "width", width, "bias", bias, "samples", samples);
-
- }
- }
- """
-
- def shaderParams(self, passes):
- """Return a dictionary with shader parameters and their values."""
- params = {"intensity":self.obj.intensity,
- "uniform color diffuse":self.obj.diffuse,
- "uniform color specular":self.obj.specular,
- "uniform float constant_attenuation":self.obj.constant_attenuation,
- "uniform float linear_attenuation":self.obj.linear_attenuation,
- "uniform float quadratic_attenuation":self.obj.quadratic_attenuation,
- "uniform float exponent":self.obj.exponent,
- "uniform float cutoff":self.obj.cutoff}
- if hasattr(self.obj, "shadowmap") and passes[0].done():
- res,width,blur,bias,samples = self.obj.shadowmap
- zfile = passes[0].realFilename(passes[0].output[0][0])
- mapname = os.path.splitext(zfile)[0]+".map"
- params["uniform string shadowname"] = mapname
- params["uniform float width"] = width
- params["uniform float blur"] = blur
- params["uniform float bias"] = bias
- params["uniform float samples"] = samples
- return params
-
- # GLDistantLightAdapter
- class GLDistantLightAdapter:
- protocols.advise(instancesProvide=[ILightSource], asAdapterForTypes=[GLTargetDistantLight, GLFreeDistantLight])
-
- def __init__(self, lgt, proto):
- self.obj = lgt
-
- def createPasses(self):
- """Returns a list of RenderPass objects."""
- return []
-
- def shaderName(self):
- """Returns the name of the corresponding light shader or None.
- """
- return "gldistantlight"
-
- def shaderSource(self):
- """Returns surface shader source code as a string or None.
- """
- return """// GLDistantLight shader
- light $SHADERNAME(float intensity = 1.0;
- uniform color diffuse = color "rgb" (1, 1, 1);
- uniform color specular = color "rgb" (1, 1, 1))
- {
- solar(vector "shader" (0,0,1), PI/2)
- {
- Cl = intensity * color "rgb" (1,1,1);
- }
- }
- """
-
- def shaderParams(self, passes):
- """Return a dictionary with shader parameters and their values."""
- return {"intensity":self.obj.intensity,
- "uniform color diffuse":self.obj.diffuse,
- "uniform color specular":self.obj.specular}
-
-
- ######################################################################
- ####################### Material adapters ############################
- ######################################################################
-
-
- # GLMaterialAdapter
- class GLMaterialAdapter:
- """
- """
-
- protocols.advise(instancesProvide=[IMaterial], asAdapterForTypes=[GLMaterial])
-
- def __init__(self, material, proto):
- self.mat = material
-
- def createPasses(self):
- """Returns a list of RenderPass objects."""
- if self.mat.getTexture(0)==None:
- return []
-
- tex = self.mat.getTexture(0)
- return [TexPass(maps=[(tex.imagename, "periodic", "periodic", "gaussian", 1, 1, {})])]
-
- def preProcess(self, exporter):
- """Preprocessing method.
-
- This method is called before the image is rendered and can be used
- to create or copy image maps.
- """
- pass
-
- def color(self):
- """Return the color for the RiColor() call or None.
- """
- return self.mat.diffuse
-
- def opacity(self):
- """Return the opacity for the RiOpacity() call or None.
- """
- return None
- # a = self.mat.diffuse.w
- # return (a,a,a)
-
- def surfaceShaderName(self):
- """Returns the name of the corresponding surface shader or None.
- """
- return "glmaterial"
-
- def surfaceShaderSource(self):
- """Returns surface shader source code as a string or None.
-
- If the return value is None, then shaderName() must return
- the name of the shader to use.
- """
- ambient = self.mat.ambient
- emission = self.mat.emission
- return """// GLMaterial shader
- surface $SHADERNAME(color ambient = color "rgb" (0.2, 0.2, 0.2);
- color specular = color "rgb" (0, 0, 0);
- float shininess = 0.0;
- color emission = color "rgb" (0, 0, 0);
- float diffuse_alpha = 1.0;
- string texname = "";
- float T[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
- float mode = 0;
- color texenvcolor = color "rgb" (1,1,1);
- float texenvcolor_alpha = 1;
- float blend_sfactor = -1;
- float blend_dfactor = -1;
- varying point Pref = point(0,0,0);
- )
- {
- BAKE_BEGIN
- normal Nf = BAKE_NORMAL(N);
- vector V = normalize(-I);
- color diffuse = Cs;
-
- Ci = emission + 0*ambient;
- illuminance(P, Nf, PI/2)
- {
- vector L0 = normalize(L);
- vector S = normalize(L0+V);
- float NL = max(Nf.L0, 0);
- float fi = (NL!=0)? 1 : 0;
-
- color diffuse_lgt = color "rgb" (1,1,1);
- color specular_lgt = color "rgb" (1,1,1);
- lightsource("diffuse", diffuse_lgt);
- lightsource("specular", specular_lgt);
-
- Ci += Cl*(diffuse*diffuse_lgt*NL +
- fi*specular*specular_lgt*pow(max(Nf.S, 0), shininess) );
- }
-
- if (texname!="")
- {
- float ss = T[0]*s + T[1]*t + T[3];
- float tt = T[4]*s + T[5]*t + T[7];
- float dn = T[12]*s + T[13]*t + T[15];
- color texcolor = texture(texname, ss/dn, tt/dn);
- if (mode==0) // GL_REPLACE
- {
- Ci = texcolor;
- }
- else if (mode==1) // GL_MODULATE
- {
- Ci = texcolor*Ci;
- }
- else if (mode==2) // GL_DECAL
- {
- Ci = texcolor;
- }
- else // GL_BLEND
- {
- Ci = Ci*(color "rgb" (1,1,1)-texcolor) + texenvcolor*texcolor;
- }
- }
-
- Oi = 1;
-
- if (blend_sfactor!=-1 && blend_dfactor!=-1)
- {
- color S = 0;
- color D = 0;
-
- if (blend_sfactor==1)
- S = 1;
- else if (blend_sfactor==3)
- S = Ci;
- else if (blend_sfactor==5)
- S = 1-Ci;
- else if (blend_sfactor==6)
- S = diffuse_alpha;
- else if (blend_sfactor==7)
- S = 1-diffuse_alpha;
-
- if (blend_dfactor==1)
- D = 1;
- else if (blend_dfactor==3)
- D = Ci;
- else if (blend_dfactor==5)
- D = 1-Ci;
- else if (blend_dfactor==6)
- D = diffuse_alpha;
- else if (blend_dfactor==7)
- D = 1-diffuse_alpha;
-
- Ci = S*Ci;
- Oi = 1-D;
- }
- BAKE_END
- }
- """
-
- def surfaceShaderParams(self, passes):
- """Return a dictionary with shader parameters and their values."""
- blend_dict = { GL_ZERO : 0,
- GL_ONE : 1,
- GL_DST_COLOR : 2,
- GL_SRC_COLOR : 3,
- GL_ONE_MINUS_DST_COLOR : 4,
- GL_ONE_MINUS_SRC_COLOR : 5,
- GL_SRC_ALPHA : 6,
- GL_ONE_MINUS_SRC_ALPHA : 7,
- GL_DST_ALPHA : 8,
- GL_ONE_MINUS_DST_ALPHA : 9,
- GL_SRC_ALPHA_SATURATE : 10
- }
- sfactor = blend_dict.get(self.mat.blend_sfactor, -1)
- dfactor = blend_dict.get(self.mat.blend_dfactor, -1)
- res = {"uniform float shininess" : self.mat.shininess,
- "uniform color specular" : tuple(self.mat.specular)[:3],
- "uniform color ambient" : tuple(self.mat.ambient)[:3],
- "uniform color emission" : tuple(self.mat.emission)[:3],
- "uniform float blend_sfactor" : sfactor,
- "uniform float blend_dfactor" : dfactor,
- "uniform float diffuse_alpha" : self.mat.diffuse.w
- }
-
- if self.mat.getTexture(0)!=None:
- tex = self.mat.getTexture(0)
- # Image name
- n = os.path.basename(tex.imagename)
- name,ext = os.path.splitext(n)
- res["uniform string texname"] = name+".tex"
- # Mode
- try:
- res["uniform float mode"] = [GL_REPLACE, GL_MODULATE, GL_DECAL, GL_BLEND].index(tex.mode)
- except:
- pass
- res["uniform color texenvcolor"] = tuple(tex.texenvcolor)[:3]
- res["uniform float texenvcolor_alpha"] = tex.texenvcolor.w
- res["uniform float [16] T"] = tex.transform.transpose()
-
- return res
-
- def surfaceShaderTransform(self):
- return mat4(1)
-
- def displacementShaderName(self):
- return None
-
- def displacementShaderSource(self):
- return None
-
- def displacementShaderParams(self, passes):
- return {}
-
- def displacementShaderTransform(self):
- return mat4(1)
-
- def displacementBound(self):
- return "current", 0
-
- def interiorShaderName(self):
- return None
-
- def interiorShaderSource(self):
- return None
-
- def interiorShaderParams(self, passes):
- return {}
-
- def interiorShaderTransform(self):
- return mat4(1)
-
-
- ######################################################################
-
- # Register the OffImporter class as a plugin class
- pluginmanager.register(RIBExporter)
-