[Bf-extensions-cvs] [5e72555] temp-x3d_import-T44758: Initial patch from sevaa (Seva Alekseyev (NIH)) T44758
Campbell Barton
noreply at git.blender.org
Sat May 23 06:00:04 CEST 2015
Commit: 5e72555f61bbc75d239872dfe26d2d57c7290702
Author: Campbell Barton
Date: Thu May 21 09:37:54 2015 +1000
Branches: temp-x3d_import-T44758
https://developer.blender.org/rBA5e72555f61bbc75d239872dfe26d2d57c7290702
Initial patch from sevaa (Seva Alekseyev (NIH)) T44758
===================================================================
M io_scene_x3d/import_x3d.py
===================================================================
diff --git a/io_scene_x3d/import_x3d.py b/io_scene_x3d/import_x3d.py
index 15ac760..2c59855 100644
--- a/io_scene_x3d/import_x3d.py
+++ b/io_scene_x3d/import_x3d.py
@@ -23,7 +23,10 @@ DEBUG = False
# This should work without a blender at all
import os
import shlex
+import math
+from math import sin, cos, pi
+EPSILON = 0.0000001 # Very crude.
def imageConvertCompat(path):
@@ -330,7 +333,8 @@ class vrmlNode(object):
'DEF_NAMESPACE',
'ROUTE_IPO_NAMESPACE',
'PROTO_NAMESPACE',
- 'x3dNode')
+ 'x3dNode',
+ 'parsed')
def __init__(self, parent, node_type, lineno):
self.id = None
@@ -338,6 +342,7 @@ class vrmlNode(object):
self.parent = parent
self.blendObject = None
self.x3dNode = None # for x3d import only
+ self.parsed = None # We try to reuse objects in a smart way
if parent:
parent.children.append(self)
@@ -471,6 +476,11 @@ class vrmlNode(object):
else:
# Check inside a list of optional types
return [child for child in self_real.children if child.getSpec() in node_spec]
+
+ def getChildrenBySpecCondition(self, cond): # spec could be Transform, Shape, Appearance
+ self_real = self.getRealNode()
+ # using getSpec functions allows us to use the spec of USE children that dont have their spec in their ID
+ return [child for child in self_real.children if cond(child.getSpec())]
def getChildBySpec(self, node_spec): # spec could be Transform, Shape, Appearance
# Use in cases where there is only ever 1 child of this type
@@ -479,6 +489,14 @@ class vrmlNode(object):
return ls[0]
else:
return None
+
+ def getChildBySpecCondition(self, cond): # spec could be Transform, Shape, Appearance
+ # Use in cases where there is only ever 1 child of this type
+ ls = self.getChildrenBySpecCondition(cond)
+ if ls:
+ return ls[0]
+ else:
+ return None
def getChildrenByName(self, node_name): # type could be geometry, children, appearance
self_real = self.getRealNode()
@@ -728,7 +746,7 @@ class vrmlNode(object):
def array_as_number(array_string):
array_data = []
try:
- array_data = [int(val) for val in array_string]
+ array_data = [int(val, 0) for val in array_string]
except:
try:
array_data = [float(val) for val in array_string]
@@ -1214,6 +1232,14 @@ class vrmlNode(object):
else:
self.fields.append(value)
i += 1
+
+ # This is a prerequisite for DEF/USE-based material caching
+ def canHaveReferences(self):
+ return self.node_type == NODE_NORMAL and self.getDefName()
+
+ # This is a prerequisite for raw XML-based material caching. For now, only for X3D
+ def desc(self):
+ return None
def gzipOpen(path):
@@ -1353,6 +1379,12 @@ class x3dNode(vrmlNode):
return value.split()
else:
return None
+
+ def canHaveReferences(self):
+ return self.x3dNode.getAttributeNode('DEF')
+
+ def desc(self):
+ return self.getRealNode().x3dNode.toxml()
def x3d_parse(path):
@@ -1414,7 +1446,7 @@ for i, f in enumerate(files):
# -----------------------------------------------------------------------------------
import bpy
from bpy_extras import image_utils
-from mathutils import Vector, Matrix
+from mathutils import Vector, Matrix, Quaternion
GLOBALS = {'CIRCLE_DETAIL': 16}
@@ -1515,12 +1547,6 @@ def translateTexTransform(node, ancestry):
return new_mat
-
-# 90d X rotation
-import math
-MATRIX_Z_TO_Y = Matrix.Rotation(math.pi / 2.0, 4, 'X')
-
-
def getFinalMatrix(node, mtx, ancestry, global_matrix):
transform_nodes = [node_tx for node_tx in ancestry if node_tx.getSpec() == 'Transform']
@@ -1540,306 +1566,624 @@ def getFinalMatrix(node, mtx, ancestry, global_matrix):
return mtx
+# -----------------------------------------------------------------------------------
+# Mesh import utilities
+
+# Assumes that the mesh has tessfaces - doesn't support polygons.
+# Also assumes that tessfaces are all triangles.
+# Assumes that the sequence of the mesh vertices array matches the source file.
+# For indexed meshes, that's almost a given; for nonindexed ones, this is a consideration.
+def importMesh_ApplyColors(bpymesh, geom, ancestry):
+ colors = geom.getChildBySpec(['ColorRGBA', 'Color'])
+ if colors:
+ if colors.getSpec() == 'ColorRGBA': # Array of arrays; no need to flatten
+ rgb = [c[:3] for c in colors.getFieldAsArray('color', 4, ancestry)]
+ else:
+ rgb = colors.getFieldAsArray('color', 3, ancestry)
+ tc = bpymesh.tessface_vertex_colors.new()
+ tc.data.foreach_set("color1", [i for face in bpymesh.tessfaces for i in rgb[face.vertices[0]]])
+ tc.data.foreach_set("color2", [i for face in bpymesh.tessfaces for i in rgb[face.vertices[1]]])
+ tc.data.foreach_set("color3", [i for face in bpymesh.tessfaces for i in rgb[face.vertices[2]]])
+
+# Assumes that the vertices have not been rearranged compared to the source file order
+# or in the order assumed by the spec (e. g. in Elevation, in rows by x).
+# Assumes tessfaces have been set, doesn't support polygons.
+def importMesh_ApplyNormals(bpymesh, geom, ancestry):
+ normals = geom.getChildBySpec('Normal')
+ if normals:
+ normalPerVertex = geom.getFieldAsBool('normalPerVertex', True, ancestry)
+ vectors = normals.getFieldAsArray('vector', 0, ancestry)
+ if normalPerVertex:
+ bpymesh.vertices.foreach_set("normal", vectors)
+ else:
+ bpymesh.tessfaces.foreach_set("normal", vectors)
+
+# Reads the standard Coordinate object - common for all mesh elements
+# Feeds the vertices in the mesh.
+# Rearranging the vertex order is a bad idea - other elements in X3D might rely on it,
+# if you need to rearrange, please play with vertex indices in the tessfaces/polygons instead.
+def importMesh_ReadVertices(bpymesh, geom, ancestry):
+ # We want points here as a flat array, but the caching logic in IndexedFaceSet presumes a 2D one.
+ # The case for caching is stronger over there.
+
+ points = geom.getChildBySpec('Coordinate').getFieldAsArray('point', 0, ancestry)
+ bpymesh.vertices.add(len(points)//3)
+ bpymesh.vertices.foreach_set("co", points)
+
+# Assumes the mesh only contains triangular tessfaces, and the order
+# of vertices matches the source.
+# Relies upon texture coordinates in the node; if a coordinate generation
+# algorithm for a geometry is in the spec (e. g. for ElevationGrid), it needs to be elsewhere.
+# Texture transform is applied elsewhere.
+def importMesh_ApplyTextureToTessfaces(bpymesh, geom, ancestry, bpyima):
+ if bpyima:
+ tex_coord = geom.getChildBySpec('TextureCoordinate')
+ if tex_coord:
+ coord_points = tex_coord.getFieldAsArray('point', 2, ancestry)
+ if coord_points:
+ d = bpymesh.tessface_uv_textures.new().data
+ for face in d: # No foreach_set for nonscalars
+ face.image = bpyima
+ d.foreach_set('uv', [i for face in bpymesh.tessfaces for vno in range(3) for i in coord_points[face.vertices[vno]]])
+
+# Common steps for all triangle meshes once the geometry has been set: normals, vertex colors, and texture.
+def importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry, bpyima):
+ bpymesh.validate()
+ importMesh_ApplyNormals(bpymesh, geom, ancestry)
+ importMesh_ApplyColors(bpymesh, geom, ancestry)
+ importMesh_ApplyTextureToTessfaces(bpymesh, geom, ancestry, bpyima)
+ bpymesh.update()
+ return bpymesh
-def importMesh_IndexedFaceSet(geom, bpyima, ancestry):
- # print(geom.lineno, geom.id, vrmlNode.DEF_NAMESPACE.keys())
-
- ccw = geom.getFieldAsBool('ccw', True, ancestry)
- ifs_colorPerVertex = geom.getFieldAsBool('colorPerVertex', True, ancestry) # per vertex or per face
- ifs_normalPerVertex = geom.getFieldAsBool('normalPerVertex', True, ancestry)
-
- # This is odd how point is inside Coordinate
-
- # VRML not x3d
- #coord = geom.getChildByName('coord') # 'Coordinate'
+# Assumes that the mesh is stored as polygons and loops, and the premade array of
+# texture coordinates follows the loop array.
+# The loops array must be flat.
+def importMesh_ApplyTextureToLoops(bpymesh, bpyima, loops):
+ for f in bpymesh.uv_textures.new().data:
+ f.image = bpyima
+ bpymesh.uv_layers[0].data.foreach_set('uv', loops)
+
+
+def flip(r, ccw):
+ return r if ccw else r[::-1]
+
+# -----------------------------------------------------------------------------------
+# Now specific geometry importers
- coord = geom.getChildBySpec('Coordinate') # works for x3d and vrml
- if coord:
- ifs_points = coord.getFieldAsArray('point', 3, ancestry)
+def importMesh_IndexedTriangleSet(geom, ancestry, bpyima):
+ # Ignoring solid
+ # colorPerVertex is always true
+ ccw = geom.getFieldAsBool('ccw', True, ancestry)
+
+ bpymesh = bpy.data.meshes.new(name="XXX")
+ importMesh_ReadVertices(bpymesh, geom, ancestry)
+
+ # Read the faces
+ index = geom.getFieldAsArray('index', 0, ancestry)
+ if not ccw:
+ index = [index[3*i+j] for i in range(n//3) for j in (1, 0, 2)]
+ bpymesh.tessfaces.add(len(index)//3)
+ bpymesh.tessfaces.foreach_set("vertices", index)
+
+ return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry, bpyima)
+
+def importMesh_IndexedTriangleStripSet(geom, ancestry, bpyima):
+ # Ignoring solid
+ # colorPerVertex is always true
+ cw = 0 if geom.getFieldAsBool('ccw', True, ancestry) else 1
+ bpymesh = bpy.data.meshes.new(name="IndexedTriangleStripSet")
+ importMesh_ReadVertices(bpymesh, geom, ancestry)
+
+ # Read the
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list