glTF importer: manage texture wrap modes.

Thanks scurest!
This commit is contained in:
Julien Duroure 2020-03-17 08:25:00 +01:00
parent f3683cf7bf
commit d0dee32d2b
2 changed files with 78 additions and 43 deletions

View File

@ -15,7 +15,7 @@
bl_info = {
'name': 'glTF 2.0 format',
'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
"version": (1, 2, 45),
"version": (1, 2, 46),
'blender': (2, 82, 7),
'location': 'File > Import-Export',
'description': 'Import-Export as glTF 2.0',

View File

@ -30,13 +30,19 @@ def texture(
):
"""Creates nodes for a TextureInfo and hooks up the color/alpha outputs."""
x, y = location
pytexture = mh.gltf.data.textures[tex_info.index]
if pytexture.sampler is not None:
pysampler = mh.gltf.data.samplers[pytexture.sampler]
else:
pysampler = Sampler.from_dict({})
needs_uv_map = False # whether to create UVMap node
# Image Texture
tex_img = mh.node_tree.nodes.new('ShaderNodeTexImage')
tex_img.location = x - 240, y
tex_img.label = label
# Get image
pytexture = mh.gltf.data.textures[tex_info.index]
if pytexture.source is not None:
BlenderImage.create(mh.gltf, pytexture.source)
pyimg = mh.gltf.data.images[pytexture.source]
@ -47,13 +53,8 @@ def texture(
if is_data:
if tex_img.image:
tex_img.image.colorspace_settings.is_data = True
# Set wrapping/filtering
if pytexture.sampler is not None:
pysampler = mh.gltf.data.samplers[pytexture.sampler]
else:
pysampler = Sampler.from_dict({})
# Set filtering
set_filtering(tex_img, pysampler)
set_wrap_mode(tex_img, pysampler)
# Outputs
mh.node_tree.links.new(color_socket, tex_img.outputs['Color'])
if alpha_socket is not None:
@ -63,6 +64,73 @@ def texture(
x -= 340
# Do wrapping
wrap_s = pysampler.wrap_s
wrap_t = pysampler.wrap_t
if wrap_s is None:
wrap_s = TextureWrap.Repeat
if wrap_t is None:
wrap_t = TextureWrap.Repeat
# If wrapping is REPEATxREPEAT or CLAMPxCLAMP, just set tex_img.extension
if (wrap_s, wrap_t) == (TextureWrap.Repeat, TextureWrap.Repeat):
tex_img.extension = 'REPEAT'
elif (wrap_s, wrap_t) == (TextureWrap.ClampToEdge, TextureWrap.ClampToEdge):
tex_img.extension = 'EXTEND'
else:
# Otherwise separate the UV components and use math nodes to compute
# the wrapped UV coordinates
# => [Separate XYZ] => [Wrap for S] => [Combine XYZ] =>
# => [Wrap for T] =>
tex_img.extension = 'EXTEND' # slightly better errors near the edge than REPEAT
# Combine XYZ
com_uv = mh.node_tree.nodes.new('ShaderNodeCombineXYZ')
com_uv.location = x - 140, y - 100
mh.node_tree.links.new(uv_socket, com_uv.outputs[0])
u_socket = com_uv.inputs[0]
v_socket = com_uv.inputs[1]
x -= 200
for i in [0, 1]:
wrap = [wrap_s, wrap_t][i]
socket = [u_socket, v_socket][i]
if wrap == TextureWrap.Repeat:
# WRAP node for REPEAT
math = mh.node_tree.nodes.new('ShaderNodeMath')
math.location = x - 140, y + 30 - i*200
math.operation = 'WRAP'
math.inputs[1].default_value = 0
math.inputs[2].default_value = 1
mh.node_tree.links.new(socket, math.outputs[0])
socket = math.inputs[0]
elif wrap == TextureWrap.MirroredRepeat:
# PINGPONG node for MIRRORED_REPEAT
math = mh.node_tree.nodes.new('ShaderNodeMath')
math.location = x - 140, y + 30 - i*200
math.operation = 'PINGPONG'
math.inputs[1].default_value = 1
mh.node_tree.links.new(socket, math.outputs[0])
socket = math.inputs[0]
else:
# Pass-through CLAMP since the tex_img node is set to EXTEND
pass
if i == 0:
u_socket = socket
else:
v_socket = socket
x -= 200
# Separate XYZ
sep_uv = mh.node_tree.nodes.new('ShaderNodeSeparateXYZ')
sep_uv.location = x - 140, y - 100
mh.node_tree.links.new(u_socket, sep_uv.outputs[0])
mh.node_tree.links.new(v_socket, sep_uv.outputs[1])
uv_socket = sep_uv.inputs[0]
x -= 200
needs_uv_map = True
# UV Transform (for KHR_texture_transform)
needs_tex_transform = 'KHR_texture_transform' in (tex_info.extensions or {})
if needs_tex_transform:
@ -83,6 +151,7 @@ def texture(
mapping.inputs['Scale'].default_value[1] = transform['scale'][1]
x -= 260
needs_uv_map = True
# UV Map
uv_idx = tex_info.tex_coord or 0
@ -90,7 +159,7 @@ def texture(
uv_idx = tex_info.extensions['KHR_texture_transform']['texCoord']
except Exception:
pass
if uv_idx != 0 or needs_tex_transform:
if uv_idx != 0 or needs_uv_map:
uv_map = mh.node_tree.nodes.new('ShaderNodeUVMap')
uv_map.location = x - 160, y - 70
uv_map.uv_map = 'UVMap' if uv_idx == 0 else 'UVMap.%03d' % uv_idx
@ -117,37 +186,3 @@ def set_filtering(tex_img, pysampler):
tex_img.interpolation = 'Closest'
else:
tex_img.interpolation = 'Linear'
def set_wrap_mode(tex_img, pysampler):
"""Set the extension on an Image Texture node from the pysampler."""
wrap_s = pysampler.wrap_s
wrap_t = pysampler.wrap_t
if wrap_s is None:
wrap_s = TextureWrap.Repeat
if wrap_t is None:
wrap_t = TextureWrap.Repeat
# The extension property on the Image Texture node can only handle the case
# where both directions are the same and are either REPEAT or CLAMP_TO_EDGE.
if (wrap_s, wrap_t) == (TextureWrap.Repeat, TextureWrap.Repeat):
extension = TextureWrap.Repeat
elif (wrap_s, wrap_t) == (TextureWrap.ClampToEdge, TextureWrap.ClampToEdge):
extension = TextureWrap.ClampToEdge
else:
print_console('WARNING',
'texture wrap mode unsupported: (%s, %s)' % (wrap_name(wrap_s), wrap_name(wrap_t)),
)
# Default to repeat
extension = TextureWrap.Repeat
if extension == TextureWrap.Repeat:
tex_img.extension = 'REPEAT'
elif extension == TextureWrap.ClampToEdge:
tex_img.extension = 'EXTEND'
def wrap_name(wrap):
if wrap == TextureWrap.ClampToEdge: return 'CLAMP_TO_EDGE'
if wrap == TextureWrap.MirroredRepeat: return 'MIRRORED_REPEAT'
if wrap == TextureWrap.Repeat: return 'REPEAT'
return 'UNKNOWN (%s)' % wrap