以编程方式为模型生成简单的 UV 映射 [英] Programmatically generate simple UV Mapping for models

查看:36
本文介绍了以编程方式为模型生成简单的 UV 映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自

黑色背景在 PNG 图像中只是透明的.我需要将它应用到我的模型中,它只是一个闪光效果,所以我不关心模型中的确切位置,有没有办法为这种情况以编程方式创建一个简单的 UV 贴图?

我正在使用链接问题中的这段代码,它对平面模型很有用,但对非平面模型不起作用:

assignUVs = 函数(几何){geometry.computeBoundingBox();var max = geometry.boundingBox.max;var min = geometry.boundingBox.min;var offset = new THREE.Vector2(0 - min.x, 0 - min.y);var range = new THREE.Vector2(max.x - min.x, max.y - min.y);geometry.faceVertexUvs[0] = [];var face = geometry.faces;for (i = 0; i < geometry.faces.length ; i++) {var v1 = geometry.vertices[faces[i].a];var v2 = geometry.vertices[faces[i].b];var v3 = geometry.vertices[faces[i].c];geometry.faceVertexUvs[0].push([new THREE.Vector2( ( v1.x + offset.x )/range.x , ( v1.y + offset.y )/range.y ),new THREE.Vector2( ( v2.x + offset.x )/range.x , ( v2.y + offset.y )/range.y ),new THREE.Vector2( ( v3.x + offset.x )/range.x , ( v3.y + offset.y )/range.y )]);}geometry.uvsNeedUpdate = true;}

解决方案

你需要更具体.在这里,我将以编程方式应用 UV 映射

for (i = 0; i < geometry.faces.length ; i++) {geometry.faceVertexUvs[0].push([new THREE.Vector2( 0, 0 ),new THREE.Vector2( 0, 0 ),new THREE.Vector2( 0, 0 ),]);}

开心吗?

应用 UV 坐标的方法有无数种.这个怎么样

for (i = 0; i < geometry.faces.length ; i++) {geometry.faceVertexUvs[0].push([new THREE.Vector2( Math.random(), Math.random() ),new THREE.Vector2( Math.random(), Math.random() ),new THREE.Vector2( Math.random(), Math.random() ),]);}

没有正确的答案.您想做什么取决于您.这有点像问我如何将铅笔涂在纸上.

抱歉这么尖酸刻薄,仅仅指出这个问题在某种意义上是荒谬的.

无论如何,有几种常用的纹理应用方法.

  • 球面映射

    假设您的模型是半透明的,里面有一个由胶片制成的球体,球体内部是一个点光源,因此它从球体向各个方向投射(就像电影放映机一样).因此,您可以通过数学计算为该情况计算正确的 UV

    要获得球体上的一个点,请将您的点乘以球体的世界矩阵的倒数,然后对结果进行归一化.在那之后,仍然存在如何将纹理本身映射到假想球体的问题,而这又是无数种方法.

    我猜最简单的方法是墨卡托投影,这就是世界上大多数二维地图的方式工作.他们的问题是在北极和南极浪费了大量空间.假设 x,y,z 是上一段提到的归一化坐标,那么

    U = Math.atan2(z, x)/Math.PI * 0.5 - 0.5;V = 0.5 - Math.asin(y)/Math.PI;

  • 投影映射

    这就像一部电影.你有一个从一个点投影的二维图像.想象一下,您将电影放映机(或投影电视)指向椅子.计算这些点

    计算这些点与从 3D 数据计算 2D 图像完全一样,几乎所有 WebGL 应用程序都会这样做.通常他们的顶点着色器中有一条这样的线

    gl_Position = 矩阵 * 位置;

    其中 matrix = worldViewProjection.然后你可以做

    clipSpace = gl_Position.xy/gl_Position.w

    您现在拥有从 -1 到 +1 的 x,y 值.然后你转换它们UV 坐标为 0 到 1

    uv = clipSpace * 0.5 + 0.5;

    当然,通常您会在 JavaScript 初始化时计算 UV 坐标,但概念是相同的.

  • 平面映射

    这与投影映射几乎相同,只是想象投影仪不是一个点,而是与您想要投影的尺寸相同.换句话说,使用投影映射,当您将模型移近投影仪时,被投影的图片会变小,但平面不会.

    按照投影映射示例,这里唯一的区别是使用正交投影而不是透视投影.

  • 立方体映射?

    这实际上是从 6 个方向进行平面映射.由你决定决定哪个 UV 坐标获得 6 个平面中的哪个.我猜大多数时候你会取三角形的法线来看看哪个平面它最面向,然后从该平面进行平面映射.

    实际上我可能会混淆我的条款.你也可以这样做真正的立方体映射,你有一个立方体纹理,但这需要U,V,W 而不仅仅是 U,V.为此它与球体相同示例,除了您直接使用归一化坐标作为U、V、W.

  • 圆柱映射

    这就像球体贴图,只是假设有一个小圆柱体投射到您的模型上.与球体不同,圆柱体具有方向,但基本上您可以将模型的点移动到圆柱体的方向,然后假设 x,y,z 现在是相对于圆柱体的(换句话说,您将它们乘以矩阵的逆矩阵表示圆柱体的方向),然后 .

    U = Math.atan2(x, z)/Math.PI * 0.5 + 0.5V = y

另外 2 个解决方案

  1. 也许您想要环境映射?

    这是 1 个示例这是另一个.

  2. 也许您应该考虑使用具有 UV 的 Maya 或 Blender 等建模包编辑器和内置 UV 投影仪.

Coming from this question I'm trying to generate UV Mappings programmatically with Three.js for some models, I need this because my models are being generated programmatically too and I need to apply a simple texture to them. I have read here and successfully generated UV mapping for some simple 3D text but when applying the same mapping to more complex models it just doesn't work.

The texture I'm trying to apply is something like this:

The black background it's just transparent in the PNG image. I need to apply this to my models, it's just a glitter effect so I don't care about the exact position in the model, is any way to create a simple UV Map programatically for this cases?

I'm using this code from the linked question which works great for planar models but doesn't work for non-planar models:

assignUVs = function( geometry ){

    geometry.computeBoundingBox();

    var max     = geometry.boundingBox.max;
    var min     = geometry.boundingBox.min;

    var offset  = new THREE.Vector2(0 - min.x, 0 - min.y);
    var range   = new THREE.Vector2(max.x - min.x, max.y - min.y);

    geometry.faceVertexUvs[0] = [];
    var faces = geometry.faces;

    for (i = 0; i < geometry.faces.length ; i++) {

      var v1 = geometry.vertices[faces[i].a];
      var v2 = geometry.vertices[faces[i].b];
      var v3 = geometry.vertices[faces[i].c];

      geometry.faceVertexUvs[0].push([
        new THREE.Vector2( ( v1.x + offset.x ) / range.x , ( v1.y + offset.y ) / range.y ),
        new THREE.Vector2( ( v2.x + offset.x ) / range.x , ( v2.y + offset.y ) / range.y ),
        new THREE.Vector2( ( v3.x + offset.x ) / range.x , ( v3.y + offset.y ) / range.y )
      ]);

    }

    geometry.uvsNeedUpdate = true;
}

解决方案

You need to be more specific. Here, I'll apply UV mapping programmatically

for (i = 0; i < geometry.faces.length ; i++) {
   geometry.faceVertexUvs[0].push([
     new THREE.Vector2( 0, 0 ),
     new THREE.Vector2( 0, 0 ),
     new THREE.Vector2( 0, 0 ),
   ]);
}

Happy?

There are an infinite ways of applying UV coordinates. How about this

for (i = 0; i < geometry.faces.length ; i++) {
   geometry.faceVertexUvs[0].push([
     new THREE.Vector2( Math.random(), Math.random() ),
     new THREE.Vector2( Math.random(), Math.random() ),
     new THREE.Vector2( Math.random(), Math.random() ),
   ]);
}

There's no RIGHT answer. There's just whatever you want to do is up to you. It's kind of like asking how do I apply pencil to paper.

Sorry to be so snarky, just pointing out the question is in one sense nonsensical.

Anyway, there are a few common methods for applying a texture.

  • Spherical mapping

    Imagine your model is translucent, there's a sphere inside made of film and inside the sphere is a point light so that it projects (like a movie projector) from the sphere in all directions. So you do the math to computer the correct UVs for that situation

    To get a point on there sphere multiply your points by the inverse of the world matrix for the sphere then normalize the result. After that though there's still the problem of how the texture itself is mapped to the imaginary sphere for which again there are an infinite number of ways.

    The simplest way is I guess called mercator projection which is how most 2d maps of the world work. they have the problem that lots of space is wasted at the north and south poles. Assuming x,y,z are the normalized coordinates mentioned in the previous paragraph then

    U = Math.atan2(z, x) / Math.PI * 0.5 - 0.5;
    V = 0.5 - Math.asin(y) / Math.PI;
    

  • Projection Mapping

    This is just like a movie. You have a 2d image being projected from a point. Imagine you pointed a movie projector (or a projection TV) at a chair. Compute those points

    Computing these points is exactly like computing the 2D image from 3D data that nearly all WebGL apps do. Usually they have a line in their vertex shader like this

    gl_Position = matrix * position;
    

    Where matrix = worldViewProjection. You can then do

    clipSpace = gl_Position.xy / gl_Position.w
    

    You now have x,y values that go from -1 to +1. You then convert them to 0 to 1 for UV coords

    uv = clipSpace * 0.5 + 0.5;
    

    Of course normally you'd compute UV coordinates at init time in JavaScript but the concept is the same.

  • Planar Mapping

    This is the almost the same as projection mapping except imagine the projector, instead of being a point, is the same size as you want to project it. In other words, with projection mapping as you move your model closer to the projector the picture being projected will get smaller but with planar it won't.

    Following the projection mapping example the only difference here is using an orthographic projection instead of a perspective projection.

  • Cube Mapping?

    This is effectively planar mapping from 6 directions. It's up to you to decide which UV coordinates get which of the 6 planes. I'd guess most of the time you'd take the normal of the triangle to see which plane it most faces, then do planar mapping from that plane.

    Actually I might be getting my terms mixed up. You can also do real cube mapping where you have a cube texture but that requires U,V,W instead of just U,V. For that it's the same as the sphere example except you just use the normalized coordinates directly as U,V,W.

  • Cylindrical mapping

    This is like sphere mapping except assume there's tiny cylinder projecting on to your model. Unlike a sphere a cylinder has orientation but basically you can move the points of the model into the orientation of the cylinder then assuming x,y,z are now relative to the cylinder (in other words you multiplied them by the inverse matrix of the matrix that represents the orientation of the cylinder), then .

    U = Math.atan2(x, z) / Math.PI * 0.5 + 0.5
    V = y
    

2 more solutions

  1. Maybe you want Environment Mapping?

    Here's 1 example and Here's another.

  2. Maybe you should consider using a modeling package like Maya or Blender that have UV editors and UV projectors built in.

这篇关于以编程方式为模型生成简单的 UV 映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆