繁体   English   中英

Unity - 使用 C#(无着色器)在网格上投影纹理

[英]Unity - Project a texture on a mesh using C# (No Shaders)

我正在尝试仅使用 C# 在简单的立方体 meshFilter 上投影纹理,但我很难理解该怎么做。 我几乎让它适用于 X 轴旋转,并且 Y/Z 有很多不好的翘曲。 基本上,当相机的位置/旋转发生变化时,我会更新 UV,这是我的代码:

[ExecuteInEditMode]
public class ObjectEditor : MonoBehaviour {

    public GameObject Model;

    public void UpdateTexture(Camera camera) {
        MeshFilter[] mesheFilters = Model.GetComponentsInChildren<MeshFilter>();
        foreach (MeshFilter meshFilter in mesheFilters) {
            int size = meshFilter.sharedMesh.vertices.Length;
            Vector2[] uvs = new Vector2[size];
            for (int i = 0; i < size; i++) {
                uvs[i] = vertexToUVPosition(camera, meshFilter, i);
            }
            meshFilter.sharedMesh.SetUVs(0, uvs);
        }
    }

    private Vector2 vertexToUVPosition(Camera camera, MeshFilter meshFilter, int index) {
        Vector3 vertex = meshFilter.sharedMesh.vertices[index];
        Matrix4x4 VP = camera.projectionMatrix * camera.worldToCameraMatrix;
        Vector4 worldPos = new Vector4(vertex.x, vertex.y, vertex.z, 1f);
        Vector4 clipPos = VP * worldPos;
        clipPos *= 1f / clipPos.w;
        return camera.WorldToScreenPoint(clipPos);
    }
}

关于投影的一切都发生在 vertexToUVPosition 中。 这就是我现在所拥有的(投影纹理是一个简单的黑白棋盘): 投影测试

有预测经验的人可以向我解释我做错了什么,并可能提供一个可以正常工作的示例 C# 代码吗? 谢谢你。

我找到了一个完全解决问题的解决方案,但我想它在数学上并不正确,因为我对矩阵和投影知之甚少。 然而,对于想要在没有任何经验的情况下做类似事情的人来说,这是一个很好的起点。

在显示代码之前,您应该设置一些东西以便更容易调试潜在问题:

  1. 确保您的纹理处于钳制模式,这样可以更轻松地查看投影是否正常工作。
  2. Position 你的 object 在 (0,0,0)。
  3. Position 你的相机在 (0,0,0) 并确保它处于透视模式。
  4. 使用正交模式下的另一个相机查看投影纹理并验证它是否正确显示。

算法:

// Calculate the VP matrix based on the Perspective Camera
VP = camera.projectionMatrix * camera.worldToCameraMatrix
foreach vertex in mesh
    // Replace the "w" component by 1.
    worldPosition = new Vector4(vertex.x, vertex.y, vertex.z, 1f);
    clipPosition = VP * worldPosition;
    // Small correction on Y axis (maybe someone can explain why I need this?).
    clipPosition.Scale(new Vector3(1, 0.5f, 1));
    // Use the clipPosition as UV coordinates for that vertex.
    ...

我的实现:

[ExecuteInEditMode]
public class ObjectEditor : MonoBehaviour {

    public GameObject Model;

    public void UpdateTexture(Camera camera) {
        Matrix4x4 vp = camera.projectionMatrix * camera.worldToCameraMatrix;
        MeshFilter[] mesheFilters = Model.GetComponentsInChildren<MeshFilter>();
        foreach (MeshFilter meshFilter in mesheFilters) {
            int size = meshFilter.sharedMesh.vertices.Length;
            Vector2[] uvs = new Vector2[size];
            for (int i = 0; i < size; i++) {
                uvs[i] = vertexToUVPosition(vp, meshFilter, i);
            }
            meshFilter.sharedMesh.SetUVs(0, uvs);
        }
    }

    private Vector2 vertexToUVPosition(Matrix4x4 vp, MeshFilter meshFilter, int index) {
        Vector3 vertex = meshFilter.sharedMesh.vertices[index];
        Vector4 worldPos = new Vector4(vertex.x, vertex.y, vertex.z, 1f);
        Vector4 clipPos = vp * worldPos;
        clipPos.Scale(new Vector3(1, 0.5f, 1));
        return clipPos;
    }
}

结果 - 在两个轴 (40,-45,0) 上旋转测试: 透视相机投影

正交相机视图: 正交视图中的验证

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM