I'm having success, as long as I use the original mapping information, generated by 3dsmax, when creating the objects.

But as soon as I use the "UVW Map" modifier, things no longer work, because the mapping is different. For example, with a plane primitive, the UV map is a planar projection going from U=0..1 and V=0..1. W is always zero. (As I expect it, with planar projection).

When I put a new planar UVW map on top, then it's no longer as expected, but there are also W coordinates involved. I'm converting the UV coordinates to barycentric coordinates, so I have no clue what to do with those W coordinates, and why they are here in the first place.

When using the mapping for a bitmap, both versions look the same of course. What I'm trying to achieve is nothing different than projecting a bitmap. (Grid of pixels vs grid of world coordinates)

There are many old threads where people looked for that functionality and gave up. I'm happy that I got it working to some degree, but it would be cool if it also worked with the "UVW Map" modifier.

I'd be happy for any input.

Box with standard mapping:

Box with standard mapping, slightly rotated by UVW Xform modifier...result as expected:

UVW Map modifier on top with box projection. Should be the same as the first pic? But it's not what I'm expecting and I don't understand what's going on here...

Code:

( delete $Point* local meshObj = snapShotAsMesh $ local theChannel=1 local stepsU=5 as Double local stepsV=5 as Double local totalSteps=stepsU*stepsV --Point in triangle test function SameSide p1 p2 a b = dot (cross (b-a) (p1-a)) (cross (b-a) (p2-a))>=0 function PointInTriangle a b c p = (SameSide p a b c) and (SameSide p b a c) and (SameSide p c a b) --Alternative Point in triangle test...returns returns point2 value, or false if point outside. --http://www.blackpawn.com/texts/pointinpoly/default.html fn pointInTriangle2 a b c thisPoint = ( local v1 = c-a local v2 = b-a thisPoint.z=0 --only interested in the 2d plane local v3 = thisPoint-a local dot11 = dot v1 v1 local dot12 = dot v1 v2 local dot13 = dot v1 v3 local dot22 = dot v2 v2 local dot23 = dot v2 v3 local div = 1 / (dot11 * dot22 - dot12 * dot12) local u = (dot22 * dot13 - dot12 * dot23) * div local v = (dot11 * dot23 - dot12 * dot13) * div if (u > 0) and (v > 0) and (u + v <= 1) then [u,v] else false ) --fast version, only valid if point really in triangle? fn buildBarycentricCoordinates a b c p = ( local v1 = p-a local v2 = p-b local v3 = p-c local a1= (length(cross v2 v3))/2 local a2= (length(cross v3 v1))/2 local a3= (length(cross v1 v2))/2 local ta= a1+a2+a3 [a1/ta, a2/ta, a3/ta] ) --Bobo´s long version fn buildBarycentricCoordinates2 v1 v2 v3 p= ( local vector1 = p - v1 --this is the vector from vertex 1 to the dummy local vector2 = p - v2 --this is the vector from vertex 2 to the dummy local vector3 = p - v3 --this is the vector from vertex 3 to the dummy --Calculate the cross product of the 3 vectors local theCross1 = (cross vector2 vector3) local theCross2 = (cross vector3 vector1) local theCross3 = (cross vector1 vector2) --calculate the face normal using the cross product of two edges local theNormal = normalize (cross (v2-v1) (v3-v1)) --because the length of the cross product vector is equal to the area of the parallelogram --defined by the two operands, half of it is the area of the triangle! local area1 = (length theCross1 )/2 --this is the area of the first sub-triangle local area2 = (length theCross2 )/2 --this is the area of the second sub-triangle local area3 = (length theCross3 )/2 --this is the area of the third sub-triangle --calculate the angle of each cross product with the face normal local angle1 = acos ( dot ( normalize theCross1) theNormal ) local angle2 = acos ( dot ( normalize theCross2) theNormal ) local angle3 = acos ( dot ( normalize theCross3) theNormal ) --if the angle is different from the other two, take its area as negative if angle1 != angle2 and angle1 != angle3 then area1 = -area1 if angle2 != angle1 and angle2 != angle3 then area2 = -area2 if angle3 != angle1 and angle3 != angle2 then area3 = -area3 local fullArea = area1 + area2 + area3 --this is the full area of the triangle local b1 = area1 / fullArea --this is the proportion of the first triangle vs. the full triangle local b2 = area2 / fullArea --this is the proportion of the second triangle vs. the full triangle local b3 = area3 / fullArea --this is the proportion of the third triangle vs. the full triangle [b1, b2, b3] --Behold! Hand-made Barycentric coordinates!!!l ) --build array with steps grid fn buildStepsArray stepsU stepsV= ( local counteri1=0 local counteri2=0 local UVSearch=#() for i1=0 to 1 by (1/stepsU) do ( counteri1+=1 for i2=0 to 1 by (1/stepsV) do ( counteri2+=1 local result=[i1,i2,0] append UVSearch result ) ) UVSearch ) UVSearch=buildStepsArray stepsU stepsV --collect all faces local meshFaces=meshObj.faces as bitarray --collect all map verts for each face local theMapFaces=for f in meshFaces collect meshop.getMapFace meshObj theChannel f --collect UV coords of each face/vertex local theFaceVertsUVCoords=for v in theMapFaces collect #(meshop.getMapVert meshObj theChannel v.x, meshop.getMapVert meshObj theChannel v.y, meshop.getMapVert meshObj theChannel v.z) vertexPositions=#() for UVCoord in UVSearch do ( --collect all affected faces local hitFaces=for f in theFaceVertsUVCoords collect PointInTriangle f[1] f[2] f[3] UVCoord --Check if point is in triangle for f=1 to hitFaces.count where hitFaces[f]!=false do ( a=theFaceVertsUVCoords[f][1] b=theFaceVertsUVCoords[f][2] c=theFaceVertsUVCoords[f][3] baryCoords = buildBarycentricCoordinates a b c UVCoord theFace = getFace meshObj f --gives a Point3 with 3 vertex indices v1=getVert meshObj theFace.x v2=getVert meshObj theFace.y v3=getVert meshObj theFace.z appendIfUnique vertexPositions (v1*baryCoords.x + v2*baryCoords.y + v3*baryCoords.z) ) ) for i in vertexPositions do ( point pos:i ) )