Apply texture coordinates to Path
Closed this issue ยท 10 comments
Hi @nicklockwood,
Just wondering if there is a supported means to apply texture coordinates to a Path
and its PathPoint
s?
Looking at the implementation details, it appears as though the uvs are calculated from a flattening plane when creating the vertices for a Path
. I can not see a way to supply these manually for each vertex.
I have a textured surface Mesh
that I want to loft into a solid so I was attempting to convert it to a Path
instead but this looks like I will not be able to maintain the uvs for each vertex? Is this the case, or is there an alternative means to provide texture coordinates?
@CaptainRedmuff this isn't possible currently, but it wouldn't be hard to add. Could you perhaps write out the pseudocode for what you want to do and I'll extend the API to support it?
Thanks for your response, @nicklockwood.
Some background context:
I am creating surface meshes that I want to stretch out into a closed shape. I have tried to do this by pushing a polygon away from itself along the face normal, reversing the winding order of the vertices and then stitching together each "edge". This does work but it is a little cumbersome as not all shapes I have made thus far follow the same rules for edge stitching.
What I have so far:
//Plot points for shape, eg: quad
v = [{0, 0}, {0, 1}, {1, 1}, {1, 0}]
//determine uvs for each vertex
uvs = v
//calculate face normal
n = faceNormal(v)
//create polygon
p = Polygon(v, n, uvs)
//translate polygon along inverse normal
ip = p.translated(-n)
//create additional polygons for each "edge"
//by looping through vertex pairs
e = //overly complex and poorly implemented edge stitching
//merge everything together into a single mesh
m = Mesh(p + ip + e)
This does create a cube from a single quad by creating the front face, inverting it to create the back face and then adding additional polygons for each edge between the two faces. The UV's of the back face are simply flipped from the front face but I have no idea what to do with the UVs for edges. This works but it is messy and unscalable for my needs.
Ideally I would like to be able to define an array of vertices with positions, normals and uvs to create a closed path, then translate the path by a given vector (or path) to create a 3D mesh. I believe this is what the extrude
method does?
Pseudocode for Path implementation
//Plot points for shape, eg: quad
v = [{0, 0}, {0, 1}, {1, 1}, {1, 0}]
//determine uvs for each vertex
uvs = v
//loop through each point (anti?)clockwise and create vertices
for each v {
//calculate face normal somehow?
nX = ?
//create path point
pX.append( V(vX, nX, uvX) )
}
//create path from points
p = Path(pX)
//stretch the path into a 3D mesh by translating each point by given vector
m = p.mesh(V(0, 1, 0))
Thanks for the explanation.
It's easy enough for me to preserve the UV coordinates for the face polygons, but I also don't see any obvious way to extrapolate the UVs for the edge polygons when performing the extrude operation.
Simply preserving the UV values wouldn't work, as the result would just be a smear of the face texture. I could do something like offsetting the V value by the extrusion distance, but it seems unlikely that would do the right thing either.
If you just want to preserve the face UVs, and then either smear the sides, or apply a basic cylinder wrap like it does at the moment, I have the code for that pretty much ready to go. Normals shouldn't be a problem as they are already generated from the path contours.
Preserving the face uvs and either smearing the edges or the default cylindrical wrap would be sufficient for my needs at this time ๐
@CaptainRedmuff I've pushed an implementation to the develop branch which I think will do what you want. It includes a new texcoord
property for PathPoint
, and also a new Path(polygon:)
initializer that preserves the texture coordinates of the polygon.
Try it and let me know if it solves your issue.
I have amended my implementation to generate a single closed path but this does not appear to be working as the initialiser for the Polygon
is failing.
Adding a breakpoint at this guard I can see that the guard inside faceVertices
fail because the plane
is nil.
Are paths designed to be constrained to a single plane or can I throw a bunch of non-coplanar points at this?
@CaptainRedmuff polygons have to be planar, but paths don't. I guess you'll just need to construct the path directly rather than via the Polygon initializer.
Another problem is that while extruding a non-planar path should work OK, filling it won't. You'll probably need to construct the shape by extruding the path and then merging the polygons for the end caps separately (in which case there was probably no need for preserving the UV coords in the path, but oh well).
Ahhh, of course! Apologies, I had a senior moment there and did not put two and two together for the polygons being planar.
I did create the path directly with the Path(_ points:)
initialiser rather than the Polygon
initialiser but both of these yield the same result, obviously :D
//shape is a tuple with arrays of PathPoints for each "side" and the centre curve of the shape
let lhp = Path(shape.lhs + shape.curve.reversed())
let rhp = Path(shape.curve + shape.rhs.reversed())
//guard fails here as both shapes have a nil plane
guard let lhs = Polygon(shape: lhp),
let rhs = Polygon(shape: rhp) else { return [] }
In principle there's no reason why it shouldn't be possible to convert a non-planar shape to an array of polygons. I'll see how feasible that is.
@CaptainRedmuff this is now implemented in version 0.5.0. Let me know if you need anything else.