OBJ importer: add support for (custom) normals.
Not much to say, pretty similar to how FBX custom normals import works...
This commit is contained in:
parent
4b1ccc3a7b
commit
cfdf95dc8a
|
@ -31,6 +31,7 @@ Note, This loads mesh objects and materials only, nurbs and curves are not suppo
|
|||
http://wiki.blender.org/index.php/Scripts/Manual/Import/wavefront_obj
|
||||
"""
|
||||
|
||||
import array
|
||||
import os
|
||||
import time
|
||||
import bpy
|
||||
|
@ -379,7 +380,7 @@ def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP):
|
|||
oldkey = -1 # initialize to a value that will never match the key
|
||||
|
||||
for face in faces:
|
||||
key = face[4]
|
||||
key = face[5]
|
||||
|
||||
if oldkey != key:
|
||||
# Check the key has changed.
|
||||
|
@ -407,7 +408,7 @@ def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP):
|
|||
|
||||
face_vert_loc_indices[enum] = map_index # remap to the local index
|
||||
|
||||
matname = face[2]
|
||||
matname = face[3]
|
||||
if matname and matname not in unique_materials_split:
|
||||
unique_materials_split[matname] = unique_materials[matname]
|
||||
|
||||
|
@ -420,6 +421,7 @@ def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP):
|
|||
def create_mesh(new_objects,
|
||||
use_edges,
|
||||
verts_loc,
|
||||
verts_nor,
|
||||
verts_tex,
|
||||
faces,
|
||||
unique_materials,
|
||||
|
@ -446,6 +448,7 @@ def create_mesh(new_objects,
|
|||
# reverse loop through face indices
|
||||
for f_idx in range(len(faces) - 1, -1, -1):
|
||||
(face_vert_loc_indices,
|
||||
face_vert_nor_indices,
|
||||
face_vert_tex_indices,
|
||||
context_material,
|
||||
context_smooth_group,
|
||||
|
@ -522,6 +525,11 @@ def create_mesh(new_objects,
|
|||
me.polygons.foreach_set("loop_start", faces_loop_start)
|
||||
me.polygons.foreach_set("loop_total", faces_loop_total)
|
||||
|
||||
if verts_nor:
|
||||
# Note: we store 'temp' normals in loops, since validate() may alter final mesh,
|
||||
# we can only set custom lnors *after* calling it.
|
||||
me.create_normals_split()
|
||||
|
||||
if verts_tex and me.polygons:
|
||||
me.uv_textures.new()
|
||||
|
||||
|
@ -533,6 +541,7 @@ def create_mesh(new_objects,
|
|||
raise Exception("bad face") # Shall not happen, we got rid of those earlier!
|
||||
|
||||
(face_vert_loc_indices,
|
||||
face_vert_nor_indices,
|
||||
face_vert_tex_indices,
|
||||
context_material,
|
||||
context_smooth_group,
|
||||
|
@ -548,6 +557,10 @@ def create_mesh(new_objects,
|
|||
context_material_old = context_material
|
||||
blen_poly.material_index = mat
|
||||
|
||||
if verts_nor:
|
||||
for face_noidx, lidx in zip(face_vert_nor_indices, blen_poly.loop_indices):
|
||||
me.loops[lidx].normal[:] = verts_nor[face_noidx]
|
||||
|
||||
if verts_tex:
|
||||
if context_material:
|
||||
image = unique_material_images[context_material]
|
||||
|
@ -555,8 +568,8 @@ def create_mesh(new_objects,
|
|||
me.uv_textures[0].data[i].image = image
|
||||
|
||||
blen_uvs = me.uv_layers[0]
|
||||
for j, lidx in enumerate(blen_poly.loop_indices):
|
||||
blen_uvs.data[lidx].uv = verts_tex[face_vert_tex_indices[j]]
|
||||
for face_uvidx, lidx in zip(face_vert_tex_indices, blen_poly.loop_indices):
|
||||
blen_uvs.data[lidx].uv = verts_tex[face_uvidx]
|
||||
|
||||
use_edges = use_edges and bool(edges)
|
||||
if use_edges:
|
||||
|
@ -564,13 +577,26 @@ def create_mesh(new_objects,
|
|||
# edges should be a list of (a, b) tuples
|
||||
me.edges.foreach_set("vertices", unpack_list(edges))
|
||||
|
||||
me.validate()
|
||||
me.validate(cleanup_cddata=False) # *Very* important to not remove lnors here!
|
||||
me.update(calc_edges=use_edges)
|
||||
|
||||
# XXX If validate changes the geometry, this is likely to be broken...
|
||||
if unique_smooth_groups and sharp_edges:
|
||||
for e in me.edges:
|
||||
if e.key in sharp_edges:
|
||||
e.use_edge_sharp = True
|
||||
me.show_edge_sharp = True
|
||||
|
||||
if verts_nor:
|
||||
clnors = array.array('f', [0.0] * (len(me.loops) * 3))
|
||||
me.loops.foreach_get("normal", clnors)
|
||||
|
||||
if not unique_smooth_groups:
|
||||
me.polygons.foreach_set("use_smooth", [True] * len(me.polygons))
|
||||
|
||||
me.normals_split_custom_set(tuple(zip(*(iter(clnors),) * 3)))
|
||||
me.use_auto_smooth = True
|
||||
me.show_edge_sharp = True
|
||||
|
||||
ob = bpy.data.objects.new(me.name, me)
|
||||
new_objects.append(ob)
|
||||
|
@ -717,6 +743,7 @@ def load(operator, context, filepath,
|
|||
time_main = time.time()
|
||||
|
||||
verts_loc = []
|
||||
verts_nor = []
|
||||
verts_tex = []
|
||||
faces = [] # tuples of the faces
|
||||
material_libs = [] # filanems to material libs this uses
|
||||
|
@ -736,9 +763,6 @@ def load(operator, context, filepath,
|
|||
nurbs = []
|
||||
context_parm = b'' # used by nurbs too but could be used elsewhere
|
||||
|
||||
has_ngons = False
|
||||
# has_smoothgroups= False - is explicit with len(unique_smooth_groups) being > 0
|
||||
|
||||
# Until we can use sets
|
||||
unique_materials = {}
|
||||
unique_material_images = {}
|
||||
|
@ -768,7 +792,7 @@ def load(operator, context, filepath,
|
|||
verts_loc.append((float_func(line_split[1]), float_func(line_split[2]), float_func(line_split[3])))
|
||||
|
||||
elif line_start == b'vn':
|
||||
pass
|
||||
verts_nor.append((float_func(line_split[1]), float_func(line_split[2]), float_func(line_split[3])))
|
||||
|
||||
elif line_start == b'vt':
|
||||
verts_tex.append((float_func(line_split[1]), float_func(line_split[2])))
|
||||
|
@ -784,10 +808,12 @@ def load(operator, context, filepath,
|
|||
else:
|
||||
line_split = line_split[1:]
|
||||
face_vert_loc_indices = []
|
||||
face_vert_nor_indices = []
|
||||
face_vert_tex_indices = []
|
||||
|
||||
# Instance a face
|
||||
faces.append((face_vert_loc_indices,
|
||||
face_vert_nor_indices,
|
||||
face_vert_tex_indices,
|
||||
context_material,
|
||||
context_smooth_group,
|
||||
|
@ -813,22 +839,27 @@ def load(operator, context, filepath,
|
|||
|
||||
face_vert_loc_indices.append(vert_loc_index)
|
||||
|
||||
# formatting for faces with normals and textures is
|
||||
# loc_index/tex_index/nor_index
|
||||
if len(obj_vert) > 1 and obj_vert[1]:
|
||||
# formatting for faces with normals and textures us
|
||||
# loc_index/tex_index/nor_index
|
||||
|
||||
vert_tex_index = int(obj_vert[1]) - 1
|
||||
# Make relative negative vert indices absolute
|
||||
if vert_tex_index < 0:
|
||||
vert_tex_index = len(verts_tex) + vert_tex_index + 1
|
||||
|
||||
face_vert_tex_indices.append(vert_tex_index)
|
||||
else:
|
||||
# dummy
|
||||
face_vert_tex_indices.append(0)
|
||||
|
||||
if len(face_vert_loc_indices) > 4:
|
||||
has_ngons = True
|
||||
if len(obj_vert) > 2 and obj_vert[2]:
|
||||
vert_nor_index = int(obj_vert[2]) - 1
|
||||
# Make relative negative vert indices absolute
|
||||
if vert_nor_index < 0:
|
||||
vert_nor_index = len(verts_nor) + vert_nor_index + 1
|
||||
face_vert_nor_indices.append(vert_nor_index)
|
||||
else:
|
||||
# dummy
|
||||
face_vert_nor_indices.append(0)
|
||||
|
||||
elif use_edges and (line_start == b'l' or context_multi_line == b'l'):
|
||||
# very similar to the face load function above with some parts removed
|
||||
|
@ -840,10 +871,12 @@ def load(operator, context, filepath,
|
|||
else:
|
||||
line_split = line_split[1:]
|
||||
face_vert_loc_indices = []
|
||||
face_vert_nor_indices = []
|
||||
face_vert_tex_indices = []
|
||||
|
||||
# Instance a face
|
||||
faces.append((face_vert_loc_indices,
|
||||
face_vert_nor_indices,
|
||||
face_vert_tex_indices,
|
||||
context_material,
|
||||
context_smooth_group,
|
||||
|
@ -855,8 +888,6 @@ def load(operator, context, filepath,
|
|||
else:
|
||||
context_multi_line = b''
|
||||
|
||||
# isline = line_start == b'l' # UNUSED
|
||||
|
||||
for v in line_split:
|
||||
obj_vert = v.split(b'/')
|
||||
vert_loc_index = int(obj_vert[0]) - 1
|
||||
|
@ -986,6 +1017,7 @@ def load(operator, context, filepath,
|
|||
create_mesh(new_objects,
|
||||
use_edges,
|
||||
verts_loc_split,
|
||||
verts_nor,
|
||||
verts_tex,
|
||||
faces_split,
|
||||
unique_materials_split,
|
||||
|
|
Loading…
Reference in New Issue