ho un problema che non riesco ad affrontare con C# per farmi un plug-in.
Avrei bisogno di sapere se è possibile gestire le coordinate uv di mappatura di una mesh, mi spiego meglio:
Uso un software esterno per mappare la mia mesh e dargli un uv a mia scelta, poi importo la mesh in rhino e voglio andare a “testare” le normali appartenenti a dei determinati punti della mesh utilizzando le coordinate uv. E’ possibile ?
Spero di essere stato chiaro, è un po’ complicato da spiegare.
Ho fatto un piccolo test con uno script e pare che questa lista contenga tante coppie di coordinate quanti sono i vertici della mesh.
Forse ti da’ le coordinate della texture corrispondenti ai vari vertici … adesso non riesco a scavare piu’ a fondo, sorry …
Se e’ cosi, credo che cercando i vertici vicini al valori uv che vuoi esaminare … magari interpolando … si possa risalire alla faccia della mesh in questione. … e quindi alla normale … forse
… O magari ho detto solo cavolate, come gia’ detto e’ un ambiente che purtroppo non frequento …
EDIT
Forse le facce non c’entrano, vedo che dovrebbero esserci direttamente le normali sui vertici …
innanzitutto grazie per la risposta.
Ho già provato tutti i comandi che ho trovato googlando, ma purtroppo nessuno di questi fa al caso mio, o forse non li uso correttamente. Mi servirebbe un modo per gestire i point3d e le normali sulla mesh come li gestisco sulle superfici attraverso PointAt(u,v) e NormalAt(u,v) ad un passo costante.
MeshTextureCoordinate di da le coordinate uv ai vertitci, il problema è che attraverso questi comandi non posso arrivare a gestire tutte le coordinate uv della mesh, almeno non direttamente.
Certo, nemmeno io ho trovato niente di gia’ fatto.
Ma, volendo, si prova a farselo.
Ho provato per il caso piu’ semplice:
Mesh senza triangoli, con texture singola, cioe’ non ripetuta sulla superficie.
Questo e’ lo script in Python di prova
import Rhino
import rhinoscriptsyntax as rs
import scriptcontext
def main():
gob = Rhino.Input.Custom.GetObject()
gob.SetCommandPrompt( 'Mesh ?' )
gob.AcceptNothing( True )
gob.Get()
res = gob.Result()
if res != Rhino.Input.GetResult.Object:
return
obref = gob.Object( 0 )
mesh = obref.Mesh()
# ricava coordinate texture
tcl = mesh.TextureCoordinates
# costruisce mesh ausiliaria con coordinate texture
muv = mesh.DuplicateMesh()
for ix in range( muv.Vertices.Count ):
muv.Vertices.SetVertex( ix, tcl[ ix ].X, tcl[ ix ].Y, 0.0 )
# ciclo input valori U,V per normali
while True:
gop = Rhino.Input.Custom.GetPoint()
gop.SetCommandPrompt( 'UV "point" ?' )
gop.AcceptNothing( True )
gop.Get()
res = gop.Result()
if res != Rhino.Input.GetResult.Point:
break
# punto U,V,0 appartenente alla mesh ausiliaria
pnt = gop.Point()
if ( ( pnt.X < 0.0 ) or ( pnt.X > 1.0) or
( pnt.Y < 0.0 ) or ( pnt.Y > 1.0 ) ):
break
pnt.Z = 0.0
# ricava il MeshPoint relativo dalla mesh ausiliaria
mp = muv.ClosestMeshPoint( pnt, 0.001 )
# ricava la faccia, sempre dalla mesh ausiliaria
facuv = muv.Faces[ mp.FaceIndex ]
veruv = muv.Vertices
# disegna una superficie ausialiria sulla faccia (della mesh ausiliaria)
suruv = rs.AddSrfPt(
[ veruv[ facuv.A ], veruv[ facuv.B ],
veruv[ facuv.C ], veruv[ facuv.D ] ] )
# ricava la posizione del punto cercato come U e V della superficie
# (normalizzata con Domain 0..1 , 0..1)
fau, fav = rs.SurfaceClosestPoint( suruv, pnt )
udom = rs.SurfaceDomain( suruv, 0 )
vdom = rs.SurfaceDomain( suruv, 1 )
fau /= ( udom[ 1 ] - udom[ 0 ] )
fav /= ( vdom[ 1 ] - vdom[ 0 ] )
# ora riporta il tutto sulla mesh originale ...
face = mesh.Faces[ mp.FaceIndex ]
vert = mesh.Vertices
# disegna la superficie ausialiria sulla faccia della mesh originale
sur = rs.AddSrfPt(
[ vert[ face.A ], vert[ face.B ], vert[ face.C ], vert[ face.D ] ] )
udom = rs.SurfaceDomain( sur, 0 )
vdom = rs.SurfaceDomain( sur, 1 )
# e riporta sulla mesh originale il punto con i valori U e V ricavati
# dalla mesh ausiliaria
pnt3d = rs.EvaluateSurface( sur,
fau * ( udom[ 1 ] - udom[ 0 ] ), fav * ( vdom[ 1 ] - vdom[ 0 ] ) )
# ( disegna il punto )
rs.AddTextDot( '%g,%g' % ( pnt.X, pnt.Y ), pnt3d )
# dal punto ricava il MeshPoint sulla mesh originale
mp3d = mesh.ClosestMeshPoint( pnt3d, 0.1 )
# dal MeshPoint ricava la normale
vec = mesh.NormalAt( mp3d )
# disegna la normale
gid = scriptcontext.doc.Objects.AddLine(
Rhino.Geometry.Line( pnt3d, vec * 50 ) )
rob = Rhino.DocObjects.ObjRef( gid ).Object()
att = rob.Attributes
att.ObjectDecoration = Rhino.DocObjects.ObjectDecoration.EndArrowhead
scriptcontext.doc.Objects.ModifyAttributes( rob, att, True )
main()
Selezioni la mesh e poi, nel ciclo di input dei valori U e V, scrivi U e V come se fossero X e Y di un punto, ad esempio digiti “0.5,0.6” … e cosi’ via
Lo script costruisce una mesh ausiliaria con le coordinate dei vertici corrispondenti alle coordinate della texture.
Su questa mesh ausialiria, ad esempio, il punto U=0.2, V=0.3 si trova in X=0.2,Y=0.3,Z=0
Cosi’, avendo un punto 3D e una mesh 3D (veramente 2D) su cui lavorare, ricava la faccia e, tramite una superficie ausiliaria corrispondente alla faccia, ricava la posizione del punto cercato relativa alla faccia.
Conoscendo la posizione sulla faccia, tramite un’altra superficie ausiliaria sulla mesh originale riporta il punto sulla mesh originale.
Dal punto ricava la normale.
Lo script e’ solo un test, non cancella nemmeno le varie cose che disegna.
E’ solo un modo, credo ce ne siano certamente altri per attaccare il problema.
E per casi meno semplici, la cosa si complica … si cercheranno altre vie …
OK … semplificato lo script usando le ‘coordinate baricentriche’ del MeshPoint.
Basta ricavarle dalla mesh ausiliaria e riportarle su quella originale.
import Rhino
import rhinoscriptsyntax as rs
import scriptcontext
def main():
gob = Rhino.Input.Custom.GetObject()
gob.SetCommandPrompt( 'Mesh ?' )
gob.AcceptNothing( True )
gob.Get()
res = gob.Result()
if res != Rhino.Input.GetResult.Object:
return
obref = gob.Object( 0 )
mesh = obref.Mesh()
# ricava coordinate texture
tcl = mesh.TextureCoordinates
# costruisce mesh ausiliaria con coordinate texture
muv = mesh.DuplicateMesh()
for ix in range( muv.Vertices.Count ):
muv.Vertices.SetVertex( ix, tcl[ ix ].X, tcl[ ix ].Y, 0.0 )
# ciclo input valori U,V per normali
while True:
gop = Rhino.Input.Custom.GetPoint()
gop.SetCommandPrompt( 'UV "point" ?' )
gop.AcceptNothing( True )
gop.Get()
res = gop.Result()
if res != Rhino.Input.GetResult.Point:
break
# punto U,V,0 appartenente alla mesh ausiliaria
pnt = gop.Point()
if ( ( pnt.X < 0.0 ) or ( pnt.X > 1.0) or
( pnt.Y < 0.0 ) or ( pnt.Y > 1.0 ) ):
break
pnt.Z = 0.0
# ricava il MeshPoint relativo dalla mesh ausiliaria
mp = muv.ClosestMeshPoint( pnt, 0.001 )
# ricava la faccia, sempre dalla mesh ausiliaria
facuv = muv.Faces[ mp.FaceIndex ]
veruv = muv.Vertices
# ricava coordinate baricentriche
tt = mp.T
# ricava il punto sulla mesh originale dalle coordinate baricentriche
pnt3d = mesh.PointAt( mp.FaceIndex, tt[ 0 ], tt[ 1 ], tt[ 2 ], tt[ 3 ] )
# ( disegna il punto )
rs.AddTextDot( '%g,%g' % ( pnt.X, pnt.Y ), pnt3d )
# dal punto ricava il MeshPoint sulla mesh originale
mp3d = mesh.ClosestMeshPoint( pnt3d, 0.1 )
# dal MeshPoint ricava la normale
vec = mesh.NormalAt( mp3d )
# disegna la normale
gid = scriptcontext.doc.Objects.AddLine(
Rhino.Geometry.Line( pnt3d, vec * 50 ) )
rob = Rhino.DocObjects.ObjRef( gid ).Object()
att = rob.Attributes
att.ObjectDecoration = Rhino.DocObjects.ObjectDecoration.EndArrowhead
scriptcontext.doc.Objects.ModifyAttributes( rob, att, True )
main()