adp001 opened this issue on Dec 22, 2019 ยท 53 posts
adp001 posted Sun, 22 December 2019 at 2:34 PM
from __future__ import print_function
import numpy as NP
import os
import sys
import time
try:
import poser
except ImportError:
raise RuntimeError("Script must run in Poser.")
SCENE = poser.Scene()
SCALEFACTOR = 100 # Change this to the needs for your modeller.
USE_GROUPS = False # export groupnames (False for full-body-morphs)
EXPORT_UV = True # not needed for morphs, but nicer to model with textures ;)
USE_MATERIAL = True # export materialnames (should be True if UV is exported)
# Directory to store OBJ files.
# Default: Directory where this script lives + "MORPHS".
_scriptdir = os.path.dirname(sys.argv[0])
_dirname = "MORPHS"
BASE_DIR = os.path.abspath(os.path.join(_scriptdir, _dirname))
if not os.path.isdir(BASE_DIR):
try:
os.makedirs(BASE_DIR)
except IOError:
raise RuntimeError("Cant't create directory '{}'.n"
"Please change variable BASE_DIR in line 25.".format(BASE_DIR))
# Figure to work with.
FIGURE = SCENE.CurrentFigure()
# Default filename is "Fullbody-.obj" (Poser output)
# and "Fullbody-_mod.obj" (Poser input).
# //Fullbody-LaFemme_1R1.obj
# //Fullbody-LaFemme_1R1_mod.obj
OUT_FILE = os.path.join(BASE_DIR, "Fullbody-{}.obj".format(FIGURE.Name()))
IN_FILE = os.path.join(BASE_DIR, "Fullbody-{}_mod.obj".format(FIGURE.Name()))
# Forced floatingpoint precision. Mainly to help avoiding floatingpoint
# errors while reading files from external modelers.
PRECISION = 8
NP_PRECISION = NP.float32
# ---------------- end of editable constants
PATH = os.path.dirname(__file__) # default path for save (path from this scripts)
# helper to get one numpy vertex from Poser
np_vertex = lambda v: NP.array((v.X(), v.Y(), v.Z()), NP_PRECISION)
np_tvertex = lambda v: NP.array((v.U(), v.V()), NP_PRECISION)
def collect_geometry(figure=FIGURE, scalefactor=SCALEFACTOR):
geom, actors, actor_indices = figure.UnimeshInfo()
verts = NP.zeros((geom.NumVertices(), 3), NP_PRECISION)
tverts = NP.array([np_tvertex(v) for v in geom.TexVertices()], NP_PRECISION)
sets = NP.array(geom.Sets(), NP.int32)
tsets = NP.array(geom.TexSets(), NP.int32)
for actor_idx, actor in enumerate(actors):
world_verts = actor.Geometry().WorldVertices()
for i, vertex_idx in enumerate(actor_indices[actor_idx]):
verts[vertex_idx] = np_vertex(world_verts[i])
return dict(vertices=verts * scalefactor,
sets=sets,
polygons=geom.Polygons,
tex_vertices=tverts,
tsets=tsets,
tex_polygons=geom.TexPolygons,
actorlist=actors,
actor_indices=actor_indices,
materials=geom.Materials
)
def read_verts_from_file(filename):
"""
Read Wavefront obj-file saved to file. Typically a figure exported
from Poser and modified with an external modeller (Blender etc).
"""
try:
open(filename, "r")
except IOError:
raise RuntimeError("File '{}' does not exist or is not accessible.".
format(filename))
vertices = list()
idx = 0
with open(filename, "r") as fh:
for line in fh:
if not line:
break
c, _, v = line.strip().partition(" ")
if c == "v":
vert = map(float, v.split())
if len(vert) == 3:
vertices.append(vert)
else:
raise RuntimeError("Problem at vertex # {}: {}".
format(idx, line))
idx += 1
# Remove following line if vertices are not in one block,
# so the whole file is processed.
elif c in ("vt", "vn", "f"):
break
return NP.array(vertices, NP_PRECISION)
def write_matfile(filename, materials):
"""
Write out a simple material-file.
"""
try:
open(filename, "w")
except IOError:
raise RuntimeError("Can't create or write to file '{}'.n"
"Make sure directory '{}' exist and is writable.".
format(filename, os.path.dirname(filename)))
with open(filename, "w") as mfh:
for mat in materials:
print("newmtl", mat.Name(), file=mfh)
print("Ns", mat.Ns(), file=mfh)
print("Ka", "0 0 0", file=mfh)
print("Kd", " ".join(map(str, mat.DiffuseColor())), file=mfh)
print("Ks", "0 0 0", file=mfh)
if mat.TextureMapFileName():
print("map_Kd", mat.TextureMapFileName(), file=mfh)
if mat.BumpMapFileName():
print("map_Bump", mat.BumpMapFileName(), file=mfh)
def export(filename,
vertices=None, sets=None, polygons=None,
tex_vertices=None, tsets=None, tex_polygons=None,
materials=None, **kwargs):
"""
Export Wavefront obj-file to file.
"""
try:
open(filename, "w")
except IOError:
raise RuntimeError("Can't create or write to file '{}'.n"
"Make sure directory '{}' exist and is writable.".
format(filename, os.path.dirname(filename)))
with open(filename, "w") as fh:
print("### Date : %s" % time.asctime(), file=fh)
print("### Figure : %s" % FIGURE.Name(), file=fh)
print("### Vertices: %s" % len(vertices), file=fh)
if USE_MATERIAL and materials:
matfile = filename.rsplit(".", 1)[0] + ".mtl"
write_matfile(matfile, materials())
print("mtllib ./" + os.path.basename(matfile), file=fh)
for vertex in vertices:
print("v {} {} {}".format(*vertex), file=fh)
if EXPORT_UV or USE_MATERIAL:
for uv in tex_vertices:
print("vt {} {}".format(*uv), file=fh)
current_groups = list()
current_mat = list()
if not USE_GROUPS:
print("g", FIGURE.Name(), file=fh)
polys = polygons()
tpolys = tex_polygons()
for index, poly in enumerate(polys):
if USE_GROUPS:
if poly.Groups() != current_groups:
current_groups = poly.Groups()
print("g", ", ".join(current_groups), file=fh)
if USE_MATERIAL:
if poly.MaterialName() != current_mat:
current_mat = poly.MaterialName()
print("usemtl", current_mat, file=fh)
line = [str(sets[idx + poly.Start()] + 1) for idx in range(poly.NumVertices())]
if EXPORT_UV:
tpoly = tpolys[index]
for tidx, v in enumerate((tsets[idx + tpoly.Start()] + 1) for idx in range(tpoly.NumTexVertices())):
line[tidx] += "/%d" % v
print("f", " ".join(map(str, line)), file=fh)
del polys
del tpolys
return True
def fullbodymorph_import(figure, morphname, old_filename, new_filename,
actorlist, actor_indices,
**kwargs):
verts_new = read_verts_from_file(new_filename)
verts_old = read_verts_from_file(old_filename)
if len(verts_old) != len(verts_new):
raise RuntimeError("!!!Failed!!!n"
"Old number of vertices: {}n"
"New number of vertices: {}".
format(len(verts_old), len(verts_new)))
vertices = (verts_new - verts_old) / SCALEFACTOR
del verts_new
del verts_old
body = figure.ParentActor()
masterdial = body.Parameter(morphname)
if masterdial is None:
body.CreateValueParameter(morphname)
masterdial = body.Parameter(morphname)
if masterdial is None:
raise RuntimeError("Can't find or create morph in body actor.")
for actor_idx, actor in enumerate(actorlist):
morph = list()
for i, v_idx in enumerate(actor_indices[actor_idx]):
x, y, z = map(lambda a: round(a, PRECISION), vertices[v_idx])
if x != 0 or y != 0 or z != 0:
morph.append((i, x, y, z))
if len(morph) == 0:
continue
morphparm = actor.Parameter(morphname)
if morphparm is None:
actor.SpawnTarget(morphname)
morphparm = actor.Parameter(morphname)
assert morphparm is not None, "Could not create Morphtarget"
assert morphparm.IsMorphTarget(), "Parametername ('%s') " +
"already exist but is not a morph"
% morphname
for i, x, y, z in morph:
morphparm.SetMorphTargetDelta(i, x, y, z)
while morphparm.NumValueOperations():
morphparm.DeleteValueOperation(0)
morphparm.AddValueOperation(poser.kValueOpTypeCodeKEY, masterdial)
vop = morphparm.ValueOperations()[0]
vop.InsertKey(0, 0)
vop.InsertKey(1, 1)
masterdial.SetMinValue(-.5)
masterdial.SetMaxValue(1.0)