From 9424045976be48c538a326a77c01e1b6c370c831 Mon Sep 17 00:00:00 2001 From: satabol Date: Wed, 8 Nov 2023 22:51:03 +0300 Subject: [PATCH] fix #5053. Node Find UV Coord on Surface has wrong object on UVMap out. 1. Now count of out sockets equals to count of input objects 2. Append Matrix socket of objects --- index.yaml | 2 +- menus/full_by_data_type.yaml | 2 +- menus/full_nortikin.yaml | 2 +- nodes/object_nodes/points_from_uv_to_mesh.py | 132 ++++++++------- old_nodes/points_from_uv_to_mesh_mk2.py | 164 +++++++++++++++++++ 5 files changed, 238 insertions(+), 64 deletions(-) create mode 100644 old_nodes/points_from_uv_to_mesh_mk2.py diff --git a/index.yaml b/index.yaml index e6edaf5752..5d4d66f4f6 100644 --- a/index.yaml +++ b/index.yaml @@ -767,7 +767,7 @@ - SvSetCustomUVMap - SvUVtextureNode - SvMeshUVColorNode - - SvUVPointonMeshNodeMK2 + - SvUVPointonMeshNodeMK3 - SvSampleUVColorNode - SvArmaturePropsNode - SvLatticePropsNode diff --git a/menus/full_by_data_type.yaml b/menus/full_by_data_type.yaml index e905e2ae10..b69cc76e58 100644 --- a/menus/full_by_data_type.yaml +++ b/menus/full_by_data_type.yaml @@ -796,7 +796,7 @@ - SvSetCustomUVMap - SvUVtextureNode - SvMeshUVColorNode - - SvUVPointonMeshNodeMK2 + - SvUVPointonMeshNodeMK3 - SvSampleUVColorNode - SvArmaturePropsNode - SvLatticePropsNode diff --git a/menus/full_nortikin.yaml b/menus/full_nortikin.yaml index f83e340cec..e8d772cf36 100644 --- a/menus/full_nortikin.yaml +++ b/menus/full_nortikin.yaml @@ -913,7 +913,7 @@ - SvSetCustomUVMap - SvUVtextureNode - SvMeshUVColorNode - - SvUVPointonMeshNodeMK2 + - SvUVPointonMeshNodeMK3 - SvSampleUVColorNode - SvArmaturePropsNode - SvLatticePropsNode diff --git a/nodes/object_nodes/points_from_uv_to_mesh.py b/nodes/object_nodes/points_from_uv_to_mesh.py index e884f94b23..7b27722561 100644 --- a/nodes/object_nodes/points_from_uv_to_mesh.py +++ b/nodes/object_nodes/points_from_uv_to_mesh.py @@ -18,13 +18,14 @@ import bpy import bmesh +from mathutils import Matrix, Vector from mathutils.bvhtree import BVHTree from mathutils.geometry import barycentric_transform import numpy as np from bpy.props import BoolProperty, StringProperty, FloatVectorProperty, EnumProperty from sverchok.node_tree import SverchCustomTreeNode -from sverchok.data_structure import (updateNode) +from sverchok.data_structure import updateNode, zip_long_repeat def UV(self, bm, uv_layer): @@ -47,9 +48,9 @@ def UV(self, bm, uv_layer): return [vertices_new, polygons_new] -class SvUVPointonMeshNodeMK2(SverchCustomTreeNode, bpy.types.Node): +class SvUVPointonMeshNodeMK3(SverchCustomTreeNode, bpy.types.Node): ''' Transform vectors from UV space to Object space ''' - bl_idname = 'SvUVPointonMeshNodeMK2' + bl_idname = 'SvUVPointonMeshNodeMK3' bl_label = 'Find UV Coord on Surface' bl_icon = 'GROUP_UVS' is_scene_dependent = True @@ -88,77 +89,86 @@ def sv_draw_buttons(self, context, layout): def sv_init(self, context): si, so = self.inputs.new, self.outputs.new - si('SvObjectSocket', 'Mesh Object') + si('SvMatrixSocket', 'Object Matrix') + si('SvObjectSocket', 'Object Mesh') si('SvVerticesSocket', 'Point on UV') so('SvVerticesSocket', 'Point on mesh') so('SvVerticesSocket', 'UVMapVert') so('SvStringsSocket', 'UVMapPoly') def process(self): - Object, PointsUV = self.inputs + ObjectMatrixes, Object, PointsUV = self.inputs Pom, uvV, uvP = self.outputs - obj = Object.sv_get()[0] # triangulate faces - if not obj.data.uv_layers: - raise Exception(f"Object '{obj.data.name}' has no UV Maps. Open Properties->Data->UV Maps and check list of UV Maps.") - - # get all UV Maps name in object UV Maps list - uv_layer_active_render_name = obj.data.uv_layers[0].name - for uv in obj.data.uv_layers: - if uv.active_render==True: - uv_layer_active_render_name = uv.name # get UV Map name active render (photo mark) - break - - bm = bmesh.new() - if self.apply_modifiers: - # apply modifiers and build mesh after it - sv_depsgraph = bpy.context.evaluated_depsgraph_get() - scene_object = sv_depsgraph.objects[ obj.name ] - object_to_mesh = scene_object.to_mesh(preserve_all_data_layers=True, depsgraph=sv_depsgraph) - bm.from_mesh(object_to_mesh) - scene_object.to_mesh_clear() - else: - # get mesh of original object from scene - bm.from_mesh(obj.data) - - uv_layer_active = bm.loops.layers.uv.active - uv_layer_active_render = obj.data.uv_layers[0] - for uv in bm.loops.layers.uv: - if uv.name==uv_layer_active_render_name: - uv_layer_active_render = uv - break - - if self.uv_select_mode=='active_item': - uv_layer = uv_layer_active - else: #if self.uv_select_mode=='active_render': - uv_layer = uv_layer_active_render - - bm.verts.ensure_lookup_table() - bm.faces.ensure_lookup_table() - UVMAPV, UVMAPP = UV(self, bm, uv_layer) - if Pom.is_linked: - # resore UV to 3D - pointuv = PointsUV.sv_get()[0] - bvh = BVHTree.FromPolygons(UVMAPV, UVMAPP, all_triangles=False, epsilon=0.0) - out = [] # result in 3D - for Puv in pointuv: - loc, norm, ind, dist = bvh.find_nearest(Puv) - _found_poly = bm.faces[ind] - _p1, _p2, _p3 = [v.co for v in bm.faces[ind].verts[0:3] ] - _uv1, _uv2, _uv3 = [l[uv_layer].uv.to_3d() for l in _found_poly.loops[0:3] ] - _V = barycentric_transform(Puv, _uv1, _uv2, _uv3, _p1, _p2, _p3) - out.append(_V[:]) + objs = Object.sv_get() + PointsUV = PointsUV.sv_get() + Matrixes = ObjectMatrixes.sv_get(default = [Matrix()]) + POMs, UVMAPPs, UVMAPVs = [], [], [] + for i, (obj, PointUV, obj_matrix) in enumerate(zip_long_repeat(objs,PointsUV, Matrixes) ): + if not obj.data.uv_layers: + raise Exception(f"Object '{obj.data.name}'[{i}] has no UV Maps. Open Properties->Data->UV Maps and check list of UV Maps.") - Pom.sv_set([out]) - bm.clear() + # get all UV Maps name in object UV Maps list + uv_layer_active_render_name = obj.data.uv_layers[0].name + for uv in obj.data.uv_layers: + if uv.active_render==True: + uv_layer_active_render_name = uv.name # get UV Map name active render (photo mark) + break + + bm = bmesh.new() + if self.apply_modifiers: + # apply modifiers and build mesh after it + sv_depsgraph = bpy.context.evaluated_depsgraph_get() + scene_object = sv_depsgraph.objects[ obj.name ] + object_to_mesh = scene_object.to_mesh(preserve_all_data_layers=True, depsgraph=sv_depsgraph) + bm.from_mesh(object_to_mesh) + scene_object.to_mesh_clear() + else: + # get mesh of original object from scene + bm.from_mesh(obj.data) + + uv_layer_active = bm.loops.layers.uv.active + uv_layer_active_render = obj.data.uv_layers[0] + for uv in bm.loops.layers.uv: + if uv.name==uv_layer_active_render_name: + uv_layer_active_render = uv + break + + if self.uv_select_mode=='active_item': + uv_layer = uv_layer_active + else: #if self.uv_select_mode=='active_render': + uv_layer = uv_layer_active_render + + bm.verts.ensure_lookup_table() + bm.faces.ensure_lookup_table() + UVMAPV, UVMAPP = UV(self, bm, uv_layer) + if Pom.is_linked: + # resore UV to 3D + bvh = BVHTree.FromPolygons(UVMAPV, UVMAPP, all_triangles=False, epsilon=0.0) + pom = [] # result in 3D + for Puv in PointUV: + loc, norm, ind, dist = bvh.find_nearest(Puv) + _found_poly = bm.faces[ind] + _p1, _p2, _p3 = [v.co for v in bm.faces[ind].verts[0:3] ] + _uv1, _uv2, _uv3 = [l[uv_layer].uv.to_3d() for l in _found_poly.loops[0:3] ] + _V = barycentric_transform(Puv, _uv1, _uv2, _uv3, _p1, _p2, _p3) + pom.append( obj_matrix @ Vector(_V[:])) + + POMs.append(pom) + bm.clear() + UVMAPVs.append(UVMAPV) + UVMAPPs.append(UVMAPP) + + if Pom.is_linked: + Pom.sv_set(POMs) if uvV.is_linked: - uvV.sv_set([UVMAPV]) - uvP.sv_set([UVMAPP]) + uvV.sv_set(UVMAPVs) + uvP.sv_set(UVMAPPs) def register(): - bpy.utils.register_class(SvUVPointonMeshNodeMK2) + bpy.utils.register_class(SvUVPointonMeshNodeMK3) def unregister(): - bpy.utils.unregister_class(SvUVPointonMeshNodeMK2) + bpy.utils.unregister_class(SvUVPointonMeshNodeMK3) diff --git a/old_nodes/points_from_uv_to_mesh_mk2.py b/old_nodes/points_from_uv_to_mesh_mk2.py new file mode 100644 index 0000000000..e884f94b23 --- /dev/null +++ b/old_nodes/points_from_uv_to_mesh_mk2.py @@ -0,0 +1,164 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +import bpy +import bmesh +from mathutils.bvhtree import BVHTree +from mathutils.geometry import barycentric_transform +import numpy as np +from bpy.props import BoolProperty, StringProperty, FloatVectorProperty, EnumProperty +from sverchok.node_tree import SverchCustomTreeNode + +from sverchok.data_structure import (updateNode) + + +def UV(self, bm, uv_layer): + # makes UV from layout texture area to sverchok vertices and polygons. + vertices_dict = {} + polygons_new = [] + polygons_new_append = polygons_new.append + for fi in bm.faces: + polygons_new_pol = [] + polygons_new_pol_append = polygons_new_pol.append + for loop in fi.loops: + li = loop.index + polygons_new_pol_append(li) + uv = loop[uv_layer].uv + vertices_dict[li] = [ uv.x, uv.y, 0.0] + + polygons_new_append(polygons_new_pol) + + vertices_new = list( vertices_dict.values() ) + return [vertices_new, polygons_new] + + +class SvUVPointonMeshNodeMK2(SverchCustomTreeNode, bpy.types.Node): + ''' Transform vectors from UV space to Object space ''' + bl_idname = 'SvUVPointonMeshNodeMK2' + bl_label = 'Find UV Coord on Surface' + bl_icon = 'GROUP_UVS' + is_scene_dependent = True + is_animation_dependent = True + + object_ref: StringProperty(default='', update=updateNode) + + apply_modifiers: BoolProperty( + name="Apply Modifiers", description="Off: use original object from scene\nOn: Apply modifiers before select UV Map", + default=False, update=updateNode) + + uv_select_modes = [ + ('active_item', "Active Selected", "UV Map selected by an active elem in the list of UV Maps of object data", 0), + ('active_render', "Active Render", "UV Map selected by property active_render in the list of UV Maps of object data (actived photo icon)", 1) + ] + + uv_select_mode : EnumProperty( + name = "Select UV Map by", + description = "UV Map select from object data property by", + items = uv_select_modes, + default = 'active_item', + update = updateNode) + + def sv_draw_buttons(self, context, layout): + row = layout.row() + col = row.column() + col.label(text='Apply midifiers:') + col = row.column() + col.alignment = 'LEFT' + col.prop(self, 'apply_modifiers', expand=True, text='') + row = layout.row() + row.column().label(text="Select UV Map by:") + row.column().prop(self, 'uv_select_mode', expand=True ) #, text='') + + + + def sv_init(self, context): + si, so = self.inputs.new, self.outputs.new + si('SvObjectSocket', 'Mesh Object') + si('SvVerticesSocket', 'Point on UV') + so('SvVerticesSocket', 'Point on mesh') + so('SvVerticesSocket', 'UVMapVert') + so('SvStringsSocket', 'UVMapPoly') + + def process(self): + Object, PointsUV = self.inputs + Pom, uvV, uvP = self.outputs + obj = Object.sv_get()[0] # triangulate faces + if not obj.data.uv_layers: + raise Exception(f"Object '{obj.data.name}' has no UV Maps. Open Properties->Data->UV Maps and check list of UV Maps.") + + # get all UV Maps name in object UV Maps list + uv_layer_active_render_name = obj.data.uv_layers[0].name + for uv in obj.data.uv_layers: + if uv.active_render==True: + uv_layer_active_render_name = uv.name # get UV Map name active render (photo mark) + break + + bm = bmesh.new() + if self.apply_modifiers: + # apply modifiers and build mesh after it + sv_depsgraph = bpy.context.evaluated_depsgraph_get() + scene_object = sv_depsgraph.objects[ obj.name ] + object_to_mesh = scene_object.to_mesh(preserve_all_data_layers=True, depsgraph=sv_depsgraph) + bm.from_mesh(object_to_mesh) + scene_object.to_mesh_clear() + else: + # get mesh of original object from scene + bm.from_mesh(obj.data) + + uv_layer_active = bm.loops.layers.uv.active + uv_layer_active_render = obj.data.uv_layers[0] + for uv in bm.loops.layers.uv: + if uv.name==uv_layer_active_render_name: + uv_layer_active_render = uv + break + + if self.uv_select_mode=='active_item': + uv_layer = uv_layer_active + else: #if self.uv_select_mode=='active_render': + uv_layer = uv_layer_active_render + + bm.verts.ensure_lookup_table() + bm.faces.ensure_lookup_table() + UVMAPV, UVMAPP = UV(self, bm, uv_layer) + if Pom.is_linked: + # resore UV to 3D + pointuv = PointsUV.sv_get()[0] + bvh = BVHTree.FromPolygons(UVMAPV, UVMAPP, all_triangles=False, epsilon=0.0) + out = [] # result in 3D + for Puv in pointuv: + loc, norm, ind, dist = bvh.find_nearest(Puv) + _found_poly = bm.faces[ind] + _p1, _p2, _p3 = [v.co for v in bm.faces[ind].verts[0:3] ] + _uv1, _uv2, _uv3 = [l[uv_layer].uv.to_3d() for l in _found_poly.loops[0:3] ] + _V = barycentric_transform(Puv, _uv1, _uv2, _uv3, _p1, _p2, _p3) + out.append(_V[:]) + + Pom.sv_set([out]) + bm.clear() + + if uvV.is_linked: + uvV.sv_set([UVMAPV]) + uvP.sv_set([UVMAPP]) + + +def register(): + bpy.utils.register_class(SvUVPointonMeshNodeMK2) + + +def unregister(): + bpy.utils.unregister_class(SvUVPointonMeshNodeMK2)