Newer
Older
Campbell Barton
committed
def writeMaterialH3D(ident, material, world,
Campbell Barton
committed
material_id = quoteattr(unique_name(material, 'MA_' + material.name, uuid_cache_material, clean_func=clean_def, sep="_"))
Campbell Barton
committed
if material.tag:
fw('%s<ComposedShader USE=%s />\n' % (ident, material_id))
Campbell Barton
committed
material.tag = True
# GPU_material_bind_uniforms
# GPU_begin_object_materials
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
#~ CD_MCOL 6
#~ CD_MTFACE 5
#~ CD_ORCO 14
#~ CD_TANGENT 18
#~ GPU_DATA_16F 7
#~ GPU_DATA_1F 2
#~ GPU_DATA_1I 1
#~ GPU_DATA_2F 3
#~ GPU_DATA_3F 4
#~ GPU_DATA_4F 5
#~ GPU_DATA_4UB 8
#~ GPU_DATA_9F 6
#~ GPU_DYNAMIC_LAMP_DYNCO 7
#~ GPU_DYNAMIC_LAMP_DYNCOL 11
#~ GPU_DYNAMIC_LAMP_DYNENERGY 10
#~ GPU_DYNAMIC_LAMP_DYNIMAT 8
#~ GPU_DYNAMIC_LAMP_DYNPERSMAT 9
#~ GPU_DYNAMIC_LAMP_DYNVEC 6
#~ GPU_DYNAMIC_OBJECT_COLOR 5
#~ GPU_DYNAMIC_OBJECT_IMAT 4
#~ GPU_DYNAMIC_OBJECT_MAT 2
#~ GPU_DYNAMIC_OBJECT_VIEWIMAT 3
#~ GPU_DYNAMIC_OBJECT_VIEWMAT 1
#~ GPU_DYNAMIC_SAMPLER_2DBUFFER 12
#~ GPU_DYNAMIC_SAMPLER_2DIMAGE 13
#~ GPU_DYNAMIC_SAMPLER_2DSHADOW 14
'''
inline const char* typeToString( X3DType t ) {
switch( t ) {
case SFFLOAT: return "SFFloat";
case MFFLOAT: return "MFFloat";
case SFDOUBLE: return "SFDouble";
case MFDOUBLE: return "MFDouble";
case SFTIME: return "SFTime";
case MFTIME: return "MFTime";
case SFINT32: return "SFInt32";
case MFINT32: return "MFInt32";
case SFVEC2F: return "SFVec2f";
case MFVEC2F: return "MFVec2f";
case SFVEC2D: return "SFVec2d";
case MFVEC2D: return "MFVec2d";
case SFVEC3F: return "SFVec3f";
case MFVEC3F: return "MFVec3f";
case SFVEC3D: return "SFVec3d";
case MFVEC3D: return "MFVec3d";
case SFVEC4F: return "SFVec4f";
case MFVEC4F: return "MFVec4f";
case SFVEC4D: return "SFVec4d";
case MFVEC4D: return "MFVec4d";
case SFBOOL: return "SFBool";
case MFBOOL: return "MFBool";
case SFSTRING: return "SFString";
case MFSTRING: return "MFString";
case SFNODE: return "SFNode";
case MFNODE: return "MFNode";
case SFCOLOR: return "SFColor";
case MFCOLOR: return "MFColor";
case SFCOLORRGBA: return "SFColorRGBA";
case MFCOLORRGBA: return "MFColorRGBA";
case SFROTATION: return "SFRotation";
case MFROTATION: return "MFRotation";
case SFQUATERNION: return "SFQuaternion";
case MFQUATERNION: return "MFQuaternion";
case SFMATRIX3F: return "SFMatrix3f";
case MFMATRIX3F: return "MFMatrix3f";
case SFMATRIX4F: return "SFMatrix4f";
case MFMATRIX4F: return "MFMatrix4f";
case SFMATRIX3D: return "SFMatrix3d";
case MFMATRIX3D: return "MFMatrix3d";
case SFMATRIX4D: return "SFMatrix4d";
case MFMATRIX4D: return "MFMatrix4d";
default:return "UNKNOWN_X3D_TYPE";
'''
import gpu
Campbell Barton
committed
fw('%s<ComposedShader DEF=%s language="GLSL" >\n' % (ident, material_id))
shader_url_frag = 'shaders/%s_%s.frag' % (filename_strip, material_id[1:-1])
shader_url_vert = 'shaders/%s_%s.vert' % (filename_strip, material_id[1:-1])
shader_dir = os.path.join(base_dst, 'shaders')
if not os.path.isdir(shader_dir):
os.mkdir(shader_dir)
# ------------------------------------------------------
# shader-patch
field_descr = " <!--- H3D View Matrix Patch -->"
fw('%s<field name="%s" type="SFMatrix4f" accessType="inputOutput" />%s\n' % (ident, H3D_VIEW_MATRIX, field_descr))
frag_vars = ["uniform mat4 %s;" % H3D_VIEW_MATRIX]
# annoying!, we need to track if some of the directional lamp
# vars are children of the camera or not, since this adjusts how
# they are patched.
frag_uniform_var_map = {}
h3d_material_route.append(
'<ROUTE fromNode="%s" fromField="glModelViewMatrix" toNode=%s toField="%s" />%s' %
(H3D_TOP_LEVEL, material_id, H3D_VIEW_MATRIX, field_descr))
# ------------------------------------------------------
for uniform in gpu_shader['uniforms']:
if uniform['type'] == gpu.GPU_DYNAMIC_SAMPLER_2DIMAGE:
field_descr = " <!--- Dynamic Sampler 2d Image -->"
fw('%s<field name="%s" type="SFNode" accessType="inputOutput">%s\n' % (ident, uniform['varname'], field_descr))
writeImageTexture(ident + '\t', uniform['image'])
elif uniform['type'] == gpu.GPU_DYNAMIC_LAMP_DYNCO:
lamp_obj = uniform['lamp']
frag_uniform_var_map[uniform['varname']] = lamp_obj
if uniform['datatype'] == gpu.GPU_DATA_3F: # should always be true!
lamp_obj_id = quoteattr(unique_name(lamp_obj, LA_ + lamp_obj.name, uuid_cache_lamp, clean_func=clean_def, sep="_"))
lamp_obj_transform_id = quoteattr(unique_name(lamp_obj, lamp_obj.name, uuid_cache_object, clean_func=clean_def, sep="_"))
value = '%.6f %.6f %.6f' % (global_matrix * lamp_obj.matrix_world).to_translation()[:]
field_descr = " <!--- Lamp DynCo '%s' -->" % lamp_obj.name
fw('%s<field name="%s" type="SFVec3f" accessType="inputOutput" value="%s" />%s\n' % (ident, uniform['varname'], value, field_descr))
# ------------------------------------------------------
# shader-patch
field_descr = " <!--- Lamp DynCo '%s' (shader patch) -->" % lamp_obj.name
fw('%s<field name="%s_transform" type="SFMatrix4f" accessType="inputOutput" />%s\n' % (ident, uniform['varname'], field_descr))
# transform
frag_vars.append("uniform mat4 %s_transform;" % uniform['varname'])
h3d_material_route.append(
'<ROUTE fromNode=%s fromField="accumulatedForward" toNode=%s toField="%s_transform" />%s' %
(suffix_quoted_str(lamp_obj_transform_id, _TRANSFORM), material_id, uniform['varname'], field_descr))
h3d_material_route.append(
'<ROUTE fromNode=%s fromField="location" toNode=%s toField="%s" /> %s' %
(lamp_obj_id, material_id, uniform['varname'], field_descr))
# ------------------------------------------------------
else:
assert(0)
elif uniform['type'] == gpu.GPU_DYNAMIC_LAMP_DYNCOL:
# odd we have both 3, 4 types.
lamp_obj = uniform['lamp']
frag_uniform_var_map[uniform['varname']] = lamp_obj
value = '%.6f %.6f %.6f' % (lamp.color * lamp.energy)[:]
field_descr = " <!--- Lamp DynColor '%s' -->" % lamp_obj.name
fw('%s<field name="%s" type="SFVec3f" accessType="inputOutput" value="%s" />%s\n' % (ident, uniform['varname'], value, field_descr))
fw('%s<field name="%s" type="SFVec4f" accessType="inputOutput" value="%s 1.0" />%s\n' % (ident, uniform['varname'], value, field_descr))
elif uniform['type'] == gpu.GPU_DYNAMIC_LAMP_DYNENERGY:
# not used ?
assert(0)
elif uniform['type'] == gpu.GPU_DYNAMIC_LAMP_DYNVEC:
lamp_obj = uniform['lamp']
frag_uniform_var_map[uniform['varname']] = lamp_obj
lamp_obj = uniform['lamp']
value = '%.6f %.6f %.6f' % ((global_matrix * lamp_obj.matrix_world).to_quaternion() * mathutils.Vector((0.0, 0.0, 1.0))).normalized()[:]
field_descr = " <!--- Lamp DynDirection '%s' -->" % lamp_obj.name
fw('%s<field name="%s" type="SFVec3f" accessType="inputOutput" value="%s" />%s\n' % (ident, uniform['varname'], value, field_descr))
# route so we can have the lamp update the view
if h3d_is_object_view(scene, lamp_obj):
lamp_id = quoteattr(unique_name(lamp_obj, LA_ + lamp_obj.name, uuid_cache_lamp, clean_func=clean_def, sep="_"))
h3d_material_route.append(
'<ROUTE fromNode=%s fromField="direction" toNode=%s toField="%s" />%s' %
(lamp_id, material_id, uniform['varname'], field_descr))
else:
assert(0)
elif uniform['type'] == gpu.GPU_DYNAMIC_OBJECT_VIEWIMAT:
frag_uniform_var_map[uniform['varname']] = None
Campbell Barton
committed
field_descr = " <!--- Object View Matrix Inverse '%s' -->" % obj.name
fw('%s<field name="%s" type="SFMatrix4f" accessType="inputOutput" />%s\n' % (ident, uniform['varname'], field_descr))
Campbell Barton
committed
h3d_material_route.append(
'<ROUTE fromNode="%s" fromField="glModelViewMatrixInverse" toNode=%s toField="%s" />%s' %
(H3D_TOP_LEVEL, material_id, uniform['varname'], field_descr))
else:
assert(0)
elif uniform['type'] == gpu.GPU_DYNAMIC_OBJECT_IMAT:
frag_uniform_var_map[uniform['varname']] = None
value = ' '.join(['%.6f' % f for v in (global_matrix * obj.matrix_world).inverted().transposed() for f in v])
field_descr = " <!--- Object Invertex Matrix '%s' -->" % obj.name
fw('%s<field name="%s" type="SFMatrix4f" accessType="inputOutput" value="%s" />%s\n' % (ident, uniform['varname'], value, field_descr))
else:
assert(0)
elif uniform['type'] == gpu.GPU_DYNAMIC_SAMPLER_2DSHADOW:
pass # XXX, shadow buffers not supported.
elif uniform['type'] == gpu.GPU_DYNAMIC_SAMPLER_2DBUFFER:
frag_uniform_var_map[uniform['varname']] = None
if uniform['datatype'] == gpu.GPU_DATA_1I:
if 1:
tex = uniform['texpixels']
value = []
for i in range(0, len(tex) - 1, 4):
col = tex[i:i + 4]
value.append('0x%.2x%.2x%.2x%.2x' % (col[0], col[1], col[2], col[3]))
field_descr = " <!--- Material Buffer -->"
fw('%s<field name="%s" type="SFNode" accessType="inputOutput">%s\n' % (ident, uniform['varname'], field_descr))
ident_step = ident + (' ' * (-len(ident) + \
fw('%s<PixelTexture \n' % ident)))
fw(ident_step + 'repeatS="false"\n')
fw(ident_step + 'repeatT="false"\n')
fw(ident_step + 'image="%s 1 4 %s"\n' % (len(value), " ".join(value)))
fw(ident_step + '/>\n')
ident = ident[:-1]
fw('%s</field>\n' % ident)
#for i in range(0, 10, 4)
#value = ' '.join(['%d' % f for f in uniform['texpixels']])
# value = ' '.join(['%.6f' % (f / 256) for f in uniform['texpixels']])
#fw('%s<field name="%s" type="SFInt32" accessType="inputOutput" value="%s" />%s\n' % (ident, uniform['varname'], value, field_descr))
#print('test', len(uniform['texpixels']))
else:
print("SKIPPING", uniform['type'])
file_frag = open(os.path.join(base_dst, shader_url_frag), 'w', encoding='utf-8')
file_frag.write(gpu_shader['fragment'])
file_frag.close()
h3d_shader_glsl_frag_patch(os.path.join(base_dst, shader_url_frag),
scene,
frag_vars,
frag_uniform_var_map,
)
file_vert = open(os.path.join(base_dst, shader_url_vert), 'w', encoding='utf-8')
file_vert.write(gpu_shader['vertex'])
file_vert.close()
fw('%s<ShaderPart type="FRAGMENT" url=%s />\n' % (ident, quoteattr(shader_url_frag)))
fw('%s<ShaderPart type="VERTEX" url=%s />\n' % (ident, quoteattr(shader_url_vert)))
fw('%s</ComposedShader>\n' % ident)
def writeImageTexture(ident, image):
image_id = quoteattr(unique_name(image, IM_ + image.name, uuid_cache_image, clean_func=clean_def, sep="_"))
if image.tag:
Campbell Barton
committed
fw('%s<ImageTexture USE=%s />\n' % (ident, image_id))
else:
image.tag = True
ident_step = ident + (' ' * (-len(ident) + \
fw('%s<ImageTexture ' % ident)))
Campbell Barton
committed
fw('DEF=%s\n' % image_id)
# collect image paths, can load multiple
Campbell Barton
committed
# [relative, name-only, absolute]
filepath_full = bpy.path.abspath(filepath, library=image.library)
filepath_ref = bpy_extras.io_utils.path_reference(filepath_full, base_src, base_dst, path_mode, "textures", copy_set, image.library)
filepath_base = os.path.basename(filepath_full)
filepath_base,
images = [f.replace('\\', '/') for f in images]
images = [f for i, f in enumerate(images) if f not in images[:i]]
fw(ident_step + "url='%s' " % ' '.join(['"%s"' % escape(f) for f in images]))
Campbell Barton
committed
def writeBackground(ident, world):
Campbell Barton
committed
if world is None:
return
Campbell Barton
committed
# note, not re-used
world_id = quoteattr(unique_name(world, WO_ + world.name, uuid_cache_world, clean_func=clean_def, sep="_"))
Campbell Barton
committed
blending = world.use_sky_blend, world.use_sky_paper, world.use_sky_real
grd_triple = clamp_color(world.horizon_color)
sky_triple = clamp_color(world.zenith_color)
mix_triple = clamp_color((grd_triple[i] + sky_triple[i]) / 2.0 for i in range(3))
ident_step = ident + (' ' * (-len(ident) + \
fw('%s<Background ' % ident)))
Campbell Barton
committed
fw('DEF=%s\n' % world_id)
# No Skytype - just Hor color
if blending == (False, False, False):
fw(ident_step + 'groundColor="%.3f %.3f %.3f"\n' % grd_triple)
fw(ident_step + 'skyColor="%.3f %.3f %.3f"\n' % grd_triple)
# Blend Gradient
elif blending == (True, False, False):
fw(ident_step + 'groundColor="%.3f %.3f %.3f, %.3f %.3f %.3f"\n' % (grd_triple + mix_triple))
fw(ident_step + 'skyColor="%.3f %.3f %.3f, %.3f %.3f %.3f"\n' % (sky_triple + mix_triple))
# Blend+Real Gradient Inverse
elif blending == (True, False, True):
fw(ident_step + 'groundColor="%.3f %.3f %.3f, %.3f %.3f %.3f"\n' % (sky_triple + grd_triple))
fw(ident_step + 'skyColor="%.3f %.3f %.3f, %.3f %.3f %.3f, %.3f %.3f %.3f"\n' % (sky_triple + grd_triple + sky_triple))
# Paper - just Zen Color
elif blending == (False, False, True):
fw(ident_step + 'groundColor="%.3f %.3f %.3f"\n' % sky_triple)
fw(ident_step + 'skyColor="%.3f %.3f %.3f"\n' % sky_triple)
# Blend+Real+Paper - komplex gradient
elif blending == (True, True, True):
fw(ident_step + 'groundColor="%.3f %.3f %.3f, %.3f %.3f %.3f"\n' % (sky_triple + grd_triple))
fw(ident_step + 'skyColor="%.3f %.3f %.3f, %.3f %.3f %.3f"\n' % (sky_triple + grd_triple))
# Any Other two colors
else:
fw(ident_step + 'groundColor="%.3f %.3f %.3f"\n' % grd_triple)
fw(ident_step + 'skyColor="%.3f %.3f %.3f"\n' % sky_triple)
if tex.type == 'IMAGE' and tex.image:
namemat = tex.name
pic = tex.image
basename = quoteattr(bpy.path.basename(pic.filepath))
fw(ident_step + 'backUrl=%s\n' % basename)
fw(ident_step + 'bottomUrl=%s\n' % basename)
fw(ident_step + 'frontUrl=%s\n' % basename)
fw(ident_step + 'leftUrl=%s\n' % basename)
fw(ident_step + 'rightUrl=%s\n' % basename)
fw(ident_step + 'topUrl=%s\n' % basename)
# -------------------------------------------------------------------------
# Export Object Hierarchy (recursively called)
# -------------------------------------------------------------------------
def export_object(ident, obj_main_parent, obj_main, obj_children):
world = scene.world
free, derived = create_derived_objects(scene, obj_main)
if use_hierarchy:
obj_main_matrix_world = obj_main.matrix_world
if obj_main_parent:
obj_main_matrix = obj_main_parent.matrix_world.inverted() * obj_main_matrix_world
else:
obj_main_matrix = obj_main_matrix_world
obj_main_matrix_world_invert = obj_main_matrix_world.inverted()
Campbell Barton
committed
obj_main_id = quoteattr(unique_name(obj_main, obj_main.name, uuid_cache_object, clean_func=clean_def, sep="_"))
ident = writeTransform_begin(ident, obj_main_matrix if obj_main_parent else global_matrix * obj_main_matrix, suffix_quoted_str(obj_main_id, _TRANSFORM))
for obj, obj_matrix in (() if derived is None else derived):
obj_type = obj.type
if use_hierarchy:
# make transform node relative
obj_matrix = obj_main_matrix_world_invert * obj_matrix
# H3D - use for writing a dummy transform parent
is_dummy_tx = False
if obj_type == 'CAMERA':
writeViewpoint(ident, obj, obj_matrix, scene)
if use_h3d and scene.camera == obj:
view_id = uuid_cache_view[obj]
fw('%s<Transform DEF="%s">\n' % (ident, H3D_CAMERA_FOLLOW))
h3d_material_route.extend([
'<ROUTE fromNode="%s" fromField="totalPosition" toNode="%s" toField="translation" />' % (view_id, H3D_CAMERA_FOLLOW),
'<ROUTE fromNode="%s" fromField="totalOrientation" toNode="%s" toField="rotation" />' % (view_id, H3D_CAMERA_FOLLOW),
])
is_dummy_tx = True
ident += '\t'
Campbell Barton
committed
elif obj_type in {'MESH', 'CURVE', 'SURFACE', 'FONT'}:
if (obj_type != 'MESH') or (use_apply_modifiers and obj.is_modified(scene, 'PREVIEW')):
try:
me = obj.to_mesh(scene, use_apply_modifiers, 'PREVIEW')
except:
me = None
do_remove = True
else:
me = obj.data
do_remove = False
if me is not None:
# ensure unique name, we could also do this by
# postponing mesh removal, but clearing data - TODO
if do_remove:
me.name = obj.name.rstrip("1234567890").rstrip(".")
me_name_new = me_name_org = me.name
count = 0
while me_name_new in mesh_name_set:
me.name = "%.17s.%03d" % (me_name_org, count)
me_name_new = me.name
count += 1
mesh_name_set.add(me_name_new)
del me_name_new, me_name_org, count
# done
writeIndexedFaceSet(ident, obj, me, obj_matrix, world)
# free mesh created with create_mesh()
if do_remove:
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
bpy.data.meshes.remove(me)
elif obj_type == 'LAMP':
data = obj.data
datatype = data.type
if datatype == 'POINT':
writePointLight(ident, obj, obj_matrix, data, world)
elif datatype == 'SPOT':
writeSpotLight(ident, obj, obj_matrix, data, world)
elif datatype == 'SUN':
writeDirectionalLight(ident, obj, obj_matrix, data, world)
else:
writeDirectionalLight(ident, obj, obj_matrix, data, world)
else:
#print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType)
pass
if free:
free_derived_objects(obj_main)
# ---------------------------------------------------------------------
# write out children recursively
# ---------------------------------------------------------------------
for obj_child, obj_child_children in obj_children:
export_object(ident, obj_main, obj_child, obj_child_children)
if is_dummy_tx:
ident = ident[:-1]
fw('%s</Transform>\n' % ident)
is_dummy_tx = False
if use_hierarchy:
ident = writeTransform_end(ident)
# -------------------------------------------------------------------------
# Main Export Function
# -------------------------------------------------------------------------
# tag un-exported IDs
bpy.data.meshes.tag(False)
bpy.data.materials.tag(False)
bpy.data.images.tag(False)
print('Info: starting X3D export to %r...' % file.name)
ident = ''
ident = writeHeader(ident)
Campbell Barton
committed
writeNavigationInfo(ident, scene)
writeBackground(ident, world)
writeFog(ident, world)
Campbell Barton
committed
Campbell Barton
committed
if use_selection:
objects = [obj for obj in scene.objects if obj.is_visible(scene) and obj.select]
Campbell Barton
committed
else:
objects = [obj for obj in scene.objects if obj.is_visible(scene)]
Campbell Barton
committed
if use_hierarchy:
objects_hierarchy = build_hierarchy(objects)
else:
objects_hierarchy = ((obj, []) for obj in objects)
for obj_main, obj_main_children in objects_hierarchy:
export_object(ident, None, obj_main, obj_main_children)
ident = writeFooter(ident)
# -------------------------------------------------------------------------
# global cleanup
# -------------------------------------------------------------------------
if use_h3d:
bpy.data.materials.remove(gpu_shader_dummy_mat)
# print(copy_set)
bpy_extras.io_utils.path_reference_copy(copy_set)
print('Info: finished X3D export to %r' % file.name)
##########################################################
# Callbacks, needed before Main
##########################################################
def gzip_open_utf8(filepath, mode):
"""Workaround for py3k only allowing binary gzip writing"""
import gzip
# need to investigate encoding
file = gzip.open(filepath, mode)
write_real = file.write
def write_wrap(data):
return write_real(data.encode("utf-8"))
file.write = write_wrap
return file
def save(operator, context, filepath="",
use_selection=True,
use_apply_modifiers=False,
use_triangulate=False,
use_hierarchy=True,
name_decorations=True,
Campbell Barton
committed
bpy.path.ensure_ext(filepath, '.x3dz' if use_compress else '.x3d')
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set(mode='OBJECT')
file = gzip_open_utf8(filepath, 'w')
Campbell Barton
committed
else:
file = open(filepath, 'w', encoding='utf-8')
if global_matrix is None:
global_matrix = mathutils.Matrix()
export(file,
global_matrix,
context.scene,
use_apply_modifiers=use_apply_modifiers,
use_selection=use_selection,
use_triangulate=use_triangulate,
use_normals=use_normals,
use_hierarchy=use_hierarchy,
name_decorations=name_decorations,
return {'FINISHED'}