import Blender import string import os import sys from os import P_NOWAIT from Blender.Draw import * from Blender.BGL import * from Blender import Scene from Blender.Scene import Render from math import pi from math import e from math import atan from math import pow from Blender import Window import random """ MakeHair vers. alpha 10 -august- 2005 under terms of GPL www.dedalo-3d.com www.makehuman.org thanks to Fernando Luceri #----------------------------------- 03/12/2006 jms : version corrigee pour blender 2.42/43 #----------------------------------- """ hairDiameter = Create(0.010) samples = Create(2) subsurf = Create(1) nHairs= Create(50) randomFact= Create(0.0) percOfRebels = Create(5) clumptype = Create(0) alpha = Create(0) preview = Create(0) tuftSize= Create(0.10) colors1= [Create(0.109), Create(0.037), Create(0.007)] colors2= [Create(0.518), Create(0.325), Create(0.125)] filename = Blender.Get('filename') mainPath = Blender.sys.dirname(filename) def convertCoords(obj): #print "NAME: ",obj.getName() R2D = 57.2957 #Radiant to degree objLoc = obj.getLocation() objRot = obj.getEuler() objSize = obj.getSize() LocX = objLoc[0] LocY = objLoc[1] LocZ = objLoc[2] RotX = objRot[0]*R2D RotY = objRot[1]*R2D RotZ = objRot[2]*R2D SizeX = objSize[0] SizeY = objSize[1] SizeZ = objSize[2] #Convert Blender Coords in Renderman Coords #rightHandled in leftHandled locX = LocX locY = LocY locZ = -LocZ rotX = -RotX rotY = -RotY rotZ = RotZ sizeX = SizeX sizeY = SizeY sizeZ = SizeZ return (locX,locY,locZ,rotX,rotY,rotZ,sizeX,sizeY,sizeZ) def writeHeader(ribfile,imgFile): global samples #ribfile.write('Option "searchpath" "texture" ["%s"]\n'%(texturesdir + ":" + shadowdir)) display = Scene.GetCurrent() context = display.getRenderingContext() yResolution = context.imageSizeY() xResolution = context.imageSizeX() if xResolution >= yResolution: factor = yResolution / float(xResolution) else: factor = xResolution / float(yResolution) scene = Blender.Scene.GetCurrent() camobj = scene.getCurrentCamera() (locX,locY,locZ,rotX,rotY,rotZ,sizeX,sizeY,sizeZ) = convertCoords(camobj) camera = Blender.Camera.Get(camobj.getData().name) ribfile.write('Option "statistics" "endofframe" [1]\n') ribfile.write('Projection "perspective" "fov" [%s]\n'%(360.0 * atan(factor * 16.0 / camera.lens) /pi)) ribfile.write('Format %s %s 1\n' % (xResolution, yResolution)) ribfile.write("Clipping %s %s\n" % (camera.clipStart, camera.clipEnd)) ribfile.write('PixelSamples %s %s\n'%(samples.val, samples.val)) ribfile.write('Sides 2\n') ribfile.write('Display "00001.tif" "framebuffer" "rgb"\n') ribfile.write('Display "+%s" "file" "rgba"\n' % imgFile) ribfile.write("\t\tRotate %s 1 0 0\n" %(-rotX)) ribfile.write("\t\tRotate %s 0 1 0\n" %(-rotY)) ribfile.write("\t\tRotate %s 0 0 1\n" %(-rotZ)) ribfile.write("\t\tTranslate %s %s %s\n" %(-locX, -locY, -locZ)) ribfile.write('WorldBegin\n') def ambientLight(ribfile): if Blender.World.Get() != []: world = Blender.World.Get()[0] aR = world.amb[0] aG = world.amb[1] aB = world.amb[2] ribfile.write('\tLightSource "ambientlight" 998 "intensity" [1] "color lightcolor" [%s %s %s]\n\n'%(aR, aG, aB)) def pointspolygon(fileObj, mesh): objFile = file(fileObj,'w') index = 0 facenum = len(mesh.faces) if mesh.hasFaceUV() == 1: objFile.write('Declare "st" "facevarying float[2]"\n') objFile.write("PointsPolygons ["); for face in mesh.faces: objFile.write('%s '%(len(face.v))) index = index + 1 objFile.write("] ") objFile.write("[ ") for face in mesh.faces: num = len(face.v) if num == 3 or num == 4: for vert in face.v: objFile.write('%s ' % vert.index) objFile.write("]") objFile.write('\n"P" [') for vert in mesh.verts: objFile.write("%s %s %s " % (vert.co[0], vert.co[1], -vert.co[2])) objFile.write('] ') if mesh.faces[0].smooth: objFile.write(' "N" [') for vert in mesh.verts: objFile.write("%s %s %s " % (-vert.no[0], +vert.no[1], -vert.no[2])) objFile.write(']') if mesh.hasVertexColours() == 1: vertexcol = range(len(mesh.verts)) objFile.write('\n"Cs" [') for face in mesh.faces: num = len(face.v) if num == 3 or num == 4: for vi in range(len(face.v)): vertexcol[face.v[vi].index] = face.col[vi] for vc in vertexcol: objFile.write('%s %s %s ' % (vc.r/256.0, vc.g/256.0, vc.b/256.0)) objFile.write(']') if mesh.hasFaceUV() == 1: objFile.write('\n"st" [') for face in mesh.faces: num = len(face.v) if num == 3 or num == 4: for vi in range(len(face.v)): objFile.write('%s %s ' % (face.uv[vi][0], 1.0 - face.uv[vi][1])) objFile.write(']') objFile.write('\n') objFile.close() def writeHairs(fileObj, mesh): global mainPath,hairDiameter global nHairs,randomFact,colors2 global percOfRebels,tuftSize global clumptype,preview objFile = file(fileObj,'w') p =int(100/percOfRebels.val) nVerts = len(mesh.verts) nHair = nHairs.val if preview.val: nHair = 1 rebelHair = range(0,nVerts,p) objFile.write('\t\tDeclare "rootcolor" "color"\n') objFile.write('\t\tDeclare "tipcolor" "color"\n') objFile.write('\t\tSurface "hair" "rootcolor" [%s %s %s] "tipcolor" [%s %s %s]' % (colors1[0].val,colors1[1].val,colors1[2].val,colors2[0].val,colors2[1].val,colors2[2].val)) objFile.write('\t\tBasis "b-spline" 1 "b-spline" 1 ') objFile.write('Curves "cubic" [') for n in range (nHair): objFile.write('%i ' % nVerts) objFile.write('] "nonperiodic" "P" [') for n in range (nHair): size = tuftSize.val hDiameter = hairDiameter.val*random.uniform(0.5,1) if preview.val: hDiameter = size*2 vertsListToModify = [] for v in mesh.verts: vertsListToModify.append([v.co[0],v.co[1],v.co[2]]) delta1= size*random.uniform(-1.0,1.0) delta2= size*random.uniform(-1.0,1.0) delta3= size*random.uniform(-1.0,1.0) rebelVal = random.uniform(0,randomFact.val) for i in range(nVerts): vert = vertsListToModify[i] if i != nVerts-1: #Position is an in index that show the position along the hair #because al verts have a incremental number index = float(i)/nVerts position = 1.0-index if clumptype.val != 0: clump = 6-clumptype.val #6 because 6-5 = 1, min val accepted tipAttraction = (e**(clump*position) - e**(-clump*position))/(e**(clump*position) + e**(-clump*position)) else: tipAttraction = 1 #print tipAttraction,position if n in rebelHair: objFile.write("%s %s %s " % (vert[0]+delta1+rebelVal,\ vert[1]+delta2+rebelVal,\ -vert[2]+delta3+rebelVal)) else: objFile.write("%s %s %s " % (vert[0]+delta1*tipAttraction,\ vert[1]+delta2*tipAttraction,\ -vert[2]+delta3*tipAttraction)) else: objFile.write("%s %s %s " % (vert[0]+delta1+rebelVal,\ vert[1]+delta2+rebelVal,\ -vert[2])) objFile.write('] "constantwidth" [%s]' % (hDiameter)) objFile.close() def writeLamps(ribfile): numLamp = 0 for obj in Blender.Object.Get(): if obj.getType() == "Lamp": lamp = obj.getData() intensity = lamp.getEnergy() numLamp += 1 (locX,locY,locZ,rotX,rotY,rotZ,sizeX,sizeY,sizeZ) = convertCoords(obj) ribfile.write('\tLightSource "pointlight" %s "from" [%s %s %s] "intensity" %s "lightcolor" [%s %s %s] \n' %(numLamp,locX, locY, locZ, intensity, lamp.col[0], lamp.col[1], lamp.col[2])) def createObjects(ribfile, ribRepository): global nHairs,subsurf,alpha hairCounter = 0 for obj in Blender.Object.Get(): if obj.getType() == "Mesh": name = obj.getName() mesh = obj.getData() ribObj = os.path.join(ribRepository,name+".rib") (locX,locY,locZ,rotX,rotY,rotZ,sizeX,sizeY,sizeZ) = convertCoords(obj) ribfile.write('\tAttributeBegin\n') if (len(mesh.edges) == 0): ribfile.write('\tAttributeEnd\n') return if (mesh.materials): try: material = Blender.Material.Get(mesh.materials[0].name) ribfile.write("\t\tColor [%s %s %s]\n" %(material.R, material.G, material.B)) ribfile.write("\t\tOpacity [%s %s %s]\n" %(material.alpha, material.alpha, material.alpha)) except: pass ribfile.write("\t\tTranslate %s %s %s\n" %(locX, locY, locZ)) ribfile.write("\t\tRotate %s 0 0 1\n" %(rotZ)) ribfile.write("\t\tRotate %s 0 1 0\n" %(rotY)) ribfile.write("\t\tRotate %s 1 0 0\n" %(rotX)) ribfile.write("\t\tScale %s %s %s\n" %(sizeX,sizeY,sizeZ)) if obj.getName()[:4] == "Hair": if alpha.val: ribfile.write('\tMatte 0\n') writeHairs(ribObj, mesh) hairCounter += 1 else: if subsurf.val: subdivmesh(ribObj, mesh) else: pointspolygon(ribObj, mesh) if alpha.val: ribfile.write('\tMatte 1\n') else: ribfile.write('\t\tSurface "plastic" \n') ribfile.write('\t\tReadArchive "%s"\n' %(ribObj)) #ribfile.write('\t\tReadArchive "ribObjs\\%s"\n' %(name+".rib")) ribfile.write('\tAttributeEnd\n') print "Exported ",nHairs.val * hairCounter, " hairs" def subdivmesh(fileObj, mesh): objFile = file(fileObj,'w') if mesh.hasFaceUV() == 1: objFile.write('Declare "st" "facevarying float[2]"\n') objFile.write('SubdivisionMesh "catmull-clark" [') for face in mesh.faces: num = len(face.v) objFile.write('%s '%(num)) objFile.write(']\n[') for face in mesh.faces: for vert in face.v: objFile.write('%s ' % vert.index) objFile.write(']\n["interpolateboundary"] [0 0] [] []\n"P" [') for vert in mesh.verts: objFile.write("%s %s %s " % (vert.co[0], vert.co[1], -vert.co[2])) objFile.write(']') if mesh.hasFaceUV() == 1: objFile.write('\n"st" [') for face in mesh.faces: num = len(face.v) if num == 3 or num == 4: for vi in range(len(face.v)): objFile.write('%s %s ' % (face.uv[vi][0], 1.0 - face.uv[vi][1])) objFile.write(']') if mesh.hasVertexColours() == 1: vertexcol = range(len(mesh.verts)) objFile.write('\n"Cs" [') for face in mesh.faces: num = len(face.v) if num == 3 or num == 4: for vi in range(len(face.v)): vertexcol[face.v[vi].index] = face.col[vi] for vc in vertexcol: objFile.write('%s %s %s ' % (vc.r/256.0, vc.g/256.0, vc.b/256.0)) objFile.write(']') objFile.write('\n') def saveRib(fName): #d0 is [path,filename] #d1 is [name,extension] d0 = os.path.split(fName) d1 = os.path.splitext(d0[1]) imageName = os.path.join(d0[0],d1[0]+'.tif') if d1[1] == '' or d1[1] != '.rib': fName = os.path.join(d0[0],d1[0]+'.rib') print "Saved rib in ", fName print "Saved image in ", imageName objectsDirectory = os.path.join(d0[0],'ribObjs') if not os.path.isdir(objectsDirectory): os.mkdir(objectsDirectory) theFile = file(fName,'w') writeHeader(theFile,imageName) ambientLight(theFile) writeLamps(theFile) createObjects(theFile,objectsDirectory) theFile.write("WorldEnd\n") theFile.close() print fName if (os.name != "posix"): os.system('%s %s'%('aqsis', fName)) elif (os.name == "posix"): os.system('%s %s &'%('aqsis', fName)) ###############################INTERFACE##################################### ############################################################################# def draw(): global hairDiameter,alpha global nHairs,randomFact global percOfRebels,tuftSize,subsurf global samples,clumptype,preview glClearColor(0.5, 0.5, 0.5, 0.0) glClear(GL_COLOR_BUFFER_BIT) buttonY = 10 Button("Exit", 1, 210, buttonY, 50, 20) Button("Export", 2, 10, buttonY, 200, 20) subsurf = Toggle("Subsurf", 3, 135, buttonY+20, 125, 20, subsurf.val) alpha = Toggle("Alpha", 3, 10, buttonY+20, 125, 20, alpha.val) samples= Slider("Samples: ", 3, 10, buttonY+40, 250, 18, samples.val, 2, 10, 1) preview = Toggle("Preview", 3, 10, buttonY+60, 250, 20, preview.val) clumptype = Slider("Clumpiness: ", 3, 10, buttonY+120, 250, 18, clumptype.val, 0, 5, 1) hairDiameter = Slider("Hair diamter: ", 0, 10, buttonY+140, 250, 20, hairDiameter.val, 0, 0.05, 0) percOfRebels= Slider("% of unkempt: ", 3, 10, buttonY+160, 250, 18, percOfRebels.val, 1, 100, 0) randomFact= Slider("Unkempt val: ", 3, 10, buttonY+180, 250, 18, randomFact.val, 0, 1, 0) nHairs= Slider("n Hairs: ", 3, 10, buttonY+200, 250, 18, nHairs.val, 10, 1000, 0) tuftSize= Slider("Dupl. Size: ", 3, 10, buttonY+220, 250, 18, tuftSize.val, 0.0, 0.5, 0) glColor3f(colors1[0].val,colors1[1].val,colors1[2].val) glRectf(220,buttonY+300,260,buttonY+240) glColor3f(colors2[0].val,colors2[1].val,colors2[2].val) glRectf(220,buttonY+380,260,buttonY+320) colors1[0]= Slider("R: ", 3, 10, buttonY+240, 200, 18, colors1[0].val, 0, 1, 1) colors1[1]= Slider("G: ", 3, 10, buttonY+260, 200, 18, colors1[1].val, 0, 1, 1) colors1[2]= Slider("B: ", 3, 10, buttonY+280, 200, 18, colors1[2].val, 0, 1, 1) glColor3f(1, 1, 1) glRasterPos2i(10, buttonY+305) Text("Root Color",'small' ) colors2[0]= Slider("R: ", 3, 10, buttonY+320, 200, 18, colors2[0].val, 0, 1, 1) colors2[1]= Slider("G: ", 3, 10, buttonY+340, 200, 18, colors2[1].val, 0, 1, 1) colors2[2]= Slider("B: ", 3, 10, buttonY+360, 200, 18, colors2[2].val, 0, 1, 1) glColor3f(1, 1, 1) glRasterPos2i(10, buttonY+385) Text("Tip Color",'small' ) glColor3f(1, 1, 1) glRasterPos2i(10, 420) Text("MAKEHUMAN hair tool alpha 002" ) def event(evt, val): if (evt== QKEY and not val): Exit() def bevent(evt): global preview if (evt== 1): Exit() elif (evt== 2): Window.FileSelector (saveRib, "Export") elif (evt== 3): pass Window.RedrawAll() Register(draw, event, bevent)