简体   繁体   English

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

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

I'm trying to project a texture on a simple cube meshFilter using only C# but I'm having a bit of a hard time understanding what to do.我正在尝试仅使用 C# 在简单的立方体 meshFilter 上投影纹理,但我很难理解该怎么做。 I almost got it working for the X axis rotation and there is a lot of bad warping for Y/Z.我几乎让它适用于 X 轴旋转,并且 Y/Z 有很多不好的翘曲。 Basically, I update the UVs when the position/rotation of the camera changes, here is my code:基本上,当相机的位置/旋转发生变化时,我会更新 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);
    }
}

Everything regarding the projection happens in vertexToUVPosition.关于投影的一切都发生在 vertexToUVPosition 中。 And here is what I have right now (the projected texture is a simple black/white checkerboard):这就是我现在所拥有的(投影纹理是一个简单的黑白棋盘): 投影测试

Can someone experienced in projections explain to me what I'm doing wrong and maybe provide a sample C# code that works correctly?有预测经验的人可以向我解释我做错了什么,并可能提供一个可以正常工作的示例 C# 代码吗? Thank you.谢谢你。

I found a solution which solves the problem completely but I guess it is not mathematically correct since I don't really know much about matrixes and projections.我找到了一个完全解决问题的解决方案,但我想它在数学上并不正确,因为我对矩阵和投影知之甚少。 It is however a good starting point for whoever wants to do something similar without any experience.然而,对于想要在没有任何经验的情况下做类似事情的人来说,这是一个很好的起点。

Before showing the code, some things you should setup in order to make it easier to debug potential problems:在显示代码之前,您应该设置一些东西以便更容易调试潜在问题:

  1. Make sure your texture is in clamp mode, it will be easier to see if the projection works correctly.确保您的纹理处于钳制模式,这样可以更轻松地查看投影是否正常工作。
  2. Position your object at (0,0,0). Position 你的 object 在 (0,0,0)。
  3. Position your camera at (0,0,0) and make sure it is in perspective mode. Position 你的相机在 (0,0,0) 并确保它处于透视模式。
  4. Use another camera in orthographic mode to look at the projected texture and validate it is shown correctly.使用正交模式下的另一个相机查看投影纹理并验证它是否正确显示。

The algorithm:算法:

// 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.
    ...

My implementation:我的实现:

[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;
    }
}

The result - Test with rotation on two axis (40,-45,0):结果 - 在两个轴 (40,-45,0) 上旋转测试: 透视相机投影

The orthographic camera view:正交相机视图: 正交视图中的验证

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

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