Fix per vertex normals and colors import #6
@ -9,6 +9,7 @@ import os
|
|||||||
import shlex
|
import shlex
|
||||||
import math
|
import math
|
||||||
import re
|
import re
|
||||||
|
import mathutils
|
||||||
from math import sin, cos, pi
|
from math import sin, cos, pi
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
@ -1964,14 +1965,21 @@ def importMesh_IndexedFaceSet(geom, ancestry):
|
|||||||
vectors = normals.getFieldAsArray('vector', 3, ancestry)
|
vectors = normals.getFieldAsArray('vector', 3, ancestry)
|
||||||
normal_index = geom.getFieldAsArray('normalIndex', 0, ancestry)
|
normal_index = geom.getFieldAsArray('normalIndex', 0, ancestry)
|
||||||
if per_vertex:
|
if per_vertex:
|
||||||
|
if len(normal_index) == 0:
|
||||||
|
normal_index = index
|
||||||
co = [co for f in processPerVertexIndex(normal_index)
|
co = [co for f in processPerVertexIndex(normal_index)
|
||||||
for v in f
|
for v in f
|
||||||
for co in vectors[v]]
|
for co in mathutils.Vector(vectors[v]).normalized().to_tuple()]
|
||||||
bpymesh.vertices.foreach_set("normal", co)
|
bpymesh.vertices.foreach_set("normal", co)
|
||||||
|
|
||||||
|
# Mesh must be validated before assigning normals, but validation might
|
||||||
|
# reorder corners. We must store normals in a temporary attribute
|
||||||
|
bpymesh.attributes.new("temp_custom_normals", 'FLOAT_VECTOR', 'CORNER')
|
||||||
|
bpymesh.attributes["temp_custom_normals"].data.foreach_set("vector", co)
|
||||||
else:
|
else:
|
||||||
co = [co for (i, f) in enumerate(faces)
|
co = [co for (i, f) in enumerate(faces)
|
||||||
for j in f
|
for j in f
|
||||||
for co in vectors[normal_index[i] if normal_index else i]]
|
for co in mathutils.Vector(vectors[normal_index[i] if normal_index else i]).normalized().to_tuple()]
|
||||||
bpymesh.polygons.foreach_set("normal", co)
|
bpymesh.polygons.foreach_set("normal", co)
|
||||||
|
|
||||||
# Apply vertex/face colors
|
# Apply vertex/face colors
|
||||||
@ -1988,8 +1996,6 @@ def importMesh_IndexedFaceSet(geom, ancestry):
|
|||||||
has_color_index = len(color_index) != 0
|
has_color_index = len(color_index) != 0
|
||||||
has_valid_color_index = index.count(-1) == color_index.count(-1)
|
has_valid_color_index = index.count(-1) == color_index.count(-1)
|
||||||
|
|
||||||
d = bpymesh.vertex_colors.new().data
|
|
||||||
|
|
||||||
# rebuild a corrupted colorIndex field (assuming the end of face markers -1 are missing)
|
# rebuild a corrupted colorIndex field (assuming the end of face markers -1 are missing)
|
||||||
if has_color_index and not has_valid_color_index:
|
if has_color_index and not has_valid_color_index:
|
||||||
# remove all -1 beforehand to ensure clean working copy
|
# remove all -1 beforehand to ensure clean working copy
|
||||||
@ -2020,7 +2026,15 @@ def importMesh_IndexedFaceSet(geom, ancestry):
|
|||||||
cco = [cco for (i, f) in enumerate(faces)
|
cco = [cco for (i, f) in enumerate(faces)
|
||||||
for j in f
|
for j in f
|
||||||
for cco in rgb[i]]
|
for cco in rgb[i]]
|
||||||
d.foreach_set('color', cco)
|
|
||||||
|
if color_per_vertex:
|
||||||
|
# Mesh must be validated before assigning colors, but validation might
|
||||||
|
# reorder corners. We must store colors in a temporary attribute
|
||||||
|
bpymesh.attributes.new("temp_custom_colors", 'FLOAT_COLOR', 'CORNER')
|
||||||
|
bpymesh.attributes["temp_custom_colors"].data.foreach_set("color", cco)
|
||||||
|
else:
|
||||||
|
d = bpymesh.vertex_colors.new().data
|
||||||
|
d.foreach_set('color', cco)
|
||||||
|
|
||||||
# Texture coordinates (UVs)
|
# Texture coordinates (UVs)
|
||||||
tex_coord = geom.getChildBySpec('TextureCoordinate')
|
tex_coord = geom.getChildBySpec('TextureCoordinate')
|
||||||
@ -2070,7 +2084,37 @@ def importMesh_IndexedFaceSet(geom, ancestry):
|
|||||||
|
|
||||||
importMesh_ApplyTextureToLoops(bpymesh, loops)
|
importMesh_ApplyTextureToLoops(bpymesh, loops)
|
||||||
|
|
||||||
bpymesh.validate()
|
bpymesh.validate(clean_customdata=False)
|
||||||
|
|
||||||
|
# Apply normals per vertex
|
||||||
|
if normals and per_vertex:
|
||||||
|
co2 = [0.0 for x in range(int(len(bpymesh.attributes["temp_custom_normals"].data)*3))]
|
||||||
|
bpymesh.attributes["temp_custom_normals"].data.foreach_get("vector", co2)
|
||||||
|
bpymesh.normals_split_custom_set(tuple(zip(*(iter(co2),) * 3)))
|
||||||
|
bpymesh.attributes.remove(bpymesh.attributes["temp_custom_normals"])
|
||||||
|
|
||||||
|
def linear_to_srgb(linear):
|
||||||
|
if linear <= 0.0031308:
|
||||||
|
return linear * 12.92
|
||||||
|
else:
|
||||||
|
return 1.055 * (linear ** (1.0 / 2.4)) - 0.055
|
||||||
|
|
||||||
|
def srgb_to_linear(srgb_value):
|
||||||
|
if srgb_value <= 0.04045:
|
||||||
|
return srgb_value / 12.92
|
||||||
|
else:
|
||||||
|
return ((srgb_value + 0.055) / 1.055) ** 2.4
|
||||||
|
|
||||||
|
# Apply colors per vertex
|
||||||
|
if colors and color_per_vertex:
|
||||||
|
cco2 = [0.0 for x in range(int(len(bpymesh.attributes["temp_custom_colors"].data)*4))]
|
||||||
|
bpymesh.attributes["temp_custom_colors"].data.foreach_get("color", cco2)
|
||||||
|
# convert color spaces to account for api changes
|
||||||
|
cco2 = [srgb_to_linear(col_val) for col_val in cco2]
|
||||||
|
bpymesh.color_attributes.new('ColorPerCorner', 'FLOAT_COLOR', 'CORNER')
|
||||||
|
bpymesh.color_attributes["ColorPerCorner"].data.foreach_set("color", cco2)
|
||||||
|
bpymesh.attributes.remove(bpymesh.attributes["temp_custom_colors"])
|
||||||
|
|
||||||
bpymesh.update()
|
bpymesh.update()
|
||||||
return bpymesh
|
return bpymesh
|
||||||
|
|
||||||
@ -2741,10 +2785,10 @@ def appearance_CreateMaterial(vrmlname, mat, ancestry, is_vcol):
|
|||||||
bpymat.blend_method = "BLEND"
|
bpymat.blend_method = "BLEND"
|
||||||
bpymat.shadow_method = "HASHED"
|
bpymat.shadow_method = "HASHED"
|
||||||
|
|
||||||
# NOTE - leaving this disabled for now
|
if is_vcol:
|
||||||
if False and is_vcol:
|
|
||||||
node_vertex_color = bpymat.node_tree.nodes.new("ShaderNodeVertexColor")
|
node_vertex_color = bpymat.node_tree.nodes.new("ShaderNodeVertexColor")
|
||||||
node_vertex_color.location = (-200, 300)
|
node_vertex_color.location = (-200, 300)
|
||||||
|
node_vertex_color.layer_name = "ColorPerCorner"
|
||||||
|
|
||||||
bpymat.node_tree.links.new(
|
bpymat.node_tree.links.new(
|
||||||
bpymat_wrap.node_principled_bsdf.inputs["Base Color"],
|
bpymat_wrap.node_principled_bsdf.inputs["Base Color"],
|
||||||
@ -3060,7 +3104,7 @@ def importShape_ProcessObject(
|
|||||||
# solid, as understood by the spec, is always true in Blender
|
# solid, as understood by the spec, is always true in Blender
|
||||||
# solid=false, we don't support it yet.
|
# solid=false, we don't support it yet.
|
||||||
creaseAngle = geom.getFieldAsFloat('creaseAngle', None, ancestry)
|
creaseAngle = geom.getFieldAsFloat('creaseAngle', None, ancestry)
|
||||||
if creaseAngle is not None:
|
if creaseAngle is not None and not bpydata.has_custom_normals:
|
||||||
bpydata.set_sharp_from_angle(angle=creaseAngle)
|
bpydata.set_sharp_from_angle(angle=creaseAngle)
|
||||||
else:
|
else:
|
||||||
bpydata.polygons.foreach_set("use_smooth", [False] * len(bpydata.polygons))
|
bpydata.polygons.foreach_set("use_smooth", [False] * len(bpydata.polygons))
|
||||||
|
Loading…
Reference in New Issue
Block a user