如何获取网格的每个顶点并生成一个立方体并移动到每个顶点? (Unity C#)

时间:2019-06-03 18:14:12

标签: c# unity3d shader hlsl

这是我目前为对象emptsh使用的脚本,该脚本使用计算着色器使点显示在BoyMesh网格上每个顶点所在的屏幕上。

现在,我正在尝试,而不是在屏幕上为每个BoyMesh顶点位置显示简单的点,而是从不同的位置生成立方体,然后让它们飞到每个顶点位置(每个顶点位置一个立方体) )。有什么想法吗?

using UnityEngine;
using System.Collections;

public class emptsh : MonoBehaviour
{
    public BoyMesh BoyMesh;
    public Mesh meshdata;

    public ComputeShader cshader;
    public Material mat;

    private int kernel;
    private int num4pos;

    private ComputeBuffer posbuffer;
    private int num4vertex;
    private ComputeBuffer vertexbuffer;


    private void meshInfo()
    {
        Vector3[] vertics = meshdata.vertices;
        int[] triangles = meshdata.triangles;
        num4vertex = triangles.Length;

        Vector3[] newVertics = new Vector3[num4vertex];
        for (int i = 0; i < num4vertex; ++i)
        {
            newVertics[i] = vertics[triangles[i]];
        }

        vertexbuffer = new ComputeBuffer(num4vertex, 12);
        vertexbuffer.SetData(newVertics);
    }

    void Start()
    {   
        meshdata = BoyMesh.Mesh;

        kernel = cshader.FindKernel("CSMain");
        num4pos = 1; //this determines how many appear
        //num4vertex = ;
        meshInfo();
        //float3 
        posbuffer = new ComputeBuffer(num4pos, 12); 
    }

    private void BufferSet()
    {
        cshader.SetBuffer(kernel, "posbuffer", posbuffer); 
        mat.SetBuffer("posbuffer", posbuffer);     
        mat.SetBuffer("vertexbuffer", vertexbuffer);             
    }

    private void OnRenderObject()
    {
        BufferSet();
        //1
        cshader.Dispatch(kernel, 1, 1, 1);
        //2
        mat.SetPass(0);
        //3
        Graphics.DrawProceduralNow(MeshTopology.Points, num4vertex, num4pos);      
    }

    private void OnDestroy()
    {
        posbuffer.Release();
        vertexbuffer.Release();
    }
}

然后是实际的着色器代码:

Shader "Unlit/cshader4"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    CGINCLUDE
        #define time _Time.y 
        float3 Rotx(in float3 p,in float a){
            float c,s; float3 q = p;
            c = cos(a); s = sin(a);
            q.y = c * p.y - s * q.z;
            q.z = s * p.y + c * q.z;
            return q;
        }

        float random(float id){
            return frac(sin(id)*678.342231);
        }
    ENDCG
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass{
            CGPROGRAM
                #pragma target 5.0
                #pragma vertex vert
                #pragma fragment frag 
                #include "UnityCG.cginc"

                sampler2D _MainTex;

                StructuredBuffer<float3> vertexbuffer;
                StructuredBuffer<float3> posbuffer;
                struct vertIN{
                    uint vID : SV_VertexID;
                    uint ins : SV_InstanceID;
                };

                struct vertOUT{
                    float4 pos : SV_POSITION;
                };

                vertOUT vert(vertIN i){
                    vertOUT o = (vertOUT)0;
                        float4 position = float4(vertexbuffer[i.vID],1);
                        position.xyz = Rotx(position.xyz,time*(1+random(i.ins)));
                        position.xyz += posbuffer[i.ins];
                        o.pos = UnityObjectToClipPos(position);
                    return o;
                }

                fixed4 frag(vertOUT ou):SV_Target{

                    return 1;
                }
            ENDCG
        }
    }
}

1 个答案:

答案 0 :(得分:1)

有两个部分。

首先,您必须更改为渲染三角形而不是点,并为着色器提供构成立方体的所有三角形的顶点。

更改您的MeshInfo,以创建36 *网格中顶点数量的顶点缓冲区。这是因为您需要为每个顶点制作12个三角形(对于立方体的6个面中的每个侧面都使2个三角形)。对于这36个顶点中的每一个,您需要更改其位置,以将其从多维数据集的中心移至其角之一:

private void meshInfo()
{
    float cubeHalfWidth = 0.01f; // determines how big the cube is.
    num4vertex = 36 * meshdata.vertices;

    Vector3[] newVertics = new Vector3[num4vertex];
    for (int i = 0; i < meshdata.vertices; ++i)
    {
        Vector3 curVertex = meshdata.vertices[i];

        // find corner positions
        Vector3 bottomBackLeftCorner = new Vector3(curVertex.x - cubeHalfWidth, curVertex.y - cubeHalfWidth, curVertex.z - cubeHalfWidth);
        Vector3 bottomFrontLeftCorner = new Vector3(curVertex.x - cubeHalfWidth, curVertex.y - cubeHalfWidth, curVertex.z + cubeHalfWidth_;
        Vector3 bottomFrontRightCorner = new Vector3(curVertex.x + cubeHalfWidth, curVertex.y - cubeHalfWidth, curVertex.z + cubeHalfWidth);
        Vector3 bottomBackRightCorner = new Vector3(curVertex.x + cubeHalfWidth, curVertex.y - cubeHalfWidth, curVertex.z - cubeHalfWidth);
        Vector3 topBackLeftCorner = new Vector3(curVertex.x - cubeHalfWidth, curVertex.y + cubeHalfWidth, curVertex.z - cubeHalfWidth);
        Vector3 topFrontLeftCorner = new Vector3(curVertex.x - cubeHalfWidth, curVertex.y + cubeHalfWidth, curVertex.z + cubeHalfWidth);
        Vector3 topFrontRightCorner = new Vector3(curVertex.x + cubeHalfWidth, curVertex.y + cubeHalfWidth, curVertex.z + cubeHalfWidth);
        Vector3 topBackRightCorner = new Vector3(curVertex.x + cubeHalfWidth, curVertex.y + cubeHalfWidth, curVertex.z - cubeHalfWidth)};

        // create triangles, clockwise looking at visible side
        int o=i*36;
        // back Face
        newVertics[o++] = bottomBackLeftCorner;
        newVertics[o++] = topBackLeftCorner;
        newVertics[o++] = topBackRightCorner;

        newVertics[o++] = topBackRightCorner;
        newVertics[o++] = bottomBackRightCorner;
        newVertics[o++] = bottomBackLeftCorner;

        // bottom Face
        newVertics[o++] = bottomFrontRightCorner;
        newVertics[o++] = bottomFrontLeftCorner;
        newVertics[o++] = bottomBackLeftCorner;

        newVertics[o++] = bottomBackLeftCorner;
        newVertics[o++] = bottomBackRightCorner;
        newVertics[o++] = bottomFrontRightCorner;

        // front Face
        newVertics[o++] = bottomFrontRightCorner;
        newVertics[o++] = topFrontRightCorner;
        newVertics[o++] = topFrontLeftCorner;

        newVertics[o++] = topFrontLeftCorner;
        newVertics[o++] = bottomFrontLeftCorner;
        newVertics[o++] = bottomFrontRightCorner;

        // top Face
        newVertics[o++] = topBackRightCorner;
        newVertics[o++] = topBackLeftCorner;
        newVertics[o++] = topFrontLeftCorner;

        newVertics[o++] = topFrontLeftCorner;
        newVertics[o++] = topFrontRightCorner;
        newVertics[o++] = topBackRightCorner;

        // left Face
        newVertics[o++] = bottomFrontLeftCorner;
        newVertics[o++] = topFrontLeftCorner;
        newVertics[o++] = topBackLeftCorner;

        newVertics[o++] = topBackLeftCorner;
        newVertics[o++] = bottomBackLeftCorner;
        newVertics[o++] = bottomFrontLeftCorner;

        // right Face
        newVertics[o++] = bottomBackRightCorner;
        newVertics[o++] = topBackRightCorner;
        newVertics[o++] = topFrontRightCorner;

        newVertics[o++] = topFrontRightCorner;
        newVertics[o++] = bottomFrontRightCorner;
        newVertics[o] = bottomBackRightCorner;
    }

    vertexbuffer = new ComputeBuffer(num4vertex, Marshal.SizeOf(newVertics.GetType().GetElementType()));

    vertexbuffer.SetData(newVertics);
}

您还需要将MeshTopology更改为Triangles

Graphics.DrawProceduralNow(MeshTopology.Triangles, num4vertex, num4pos); 

第二部分是使多维数据集移动。这是更容易的步骤。

在着色器中,向着色器添加一个float _moveCubeT参数,并根据_moveCubeT参数从某个起始位置到您已经拥有的位置:

Shader "Unlit/cshader4"
{
    Properties
    {
        _moveCubeT ("MoveCubeT", Float) = 0
        _MainTex ("Texture", 2D) = "white" {}
    }
    CGINCLUDE
        #define time _Time.y 
        float3 Rotx(in float3 p,in float a){
            float c,s; float3 q = p;
            c = cos(a); s = sin(a);
            q.y = c * p.y - s * q.z;
            q.z = s * p.y + c * q.z;
            return q;
        }

        float random(float id){
            return frac(sin(id)*678.342231);
        }
    ENDCG
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass{
            CGPROGRAM
                #pragma target 5.0
                #pragma vertex vert
                #pragma fragment frag 
                #include "UnityCG.cginc"

                sampler2D _MainTex;

                StructuredBuffer<float3> vertexbuffer;
                StructuredBuffer<float3> posbuffer;
                float _moveCubeT;

                struct vertIN{
                    uint vID : SV_VertexID;
                    uint ins : SV_InstanceID;
                };

                struct vertOUT{
                    float4 pos : SV_POSITION;
                };

                vertOUT vert(vertIN i){
                    vertOUT o = (vertOUT)0;
                        float3 startingpos = float3(0,0,0); //set starting pos for each cube here
                        float4 position = float4(vertexbuffer[i.vID],1);
                        position.xyz = Rotx(position.xyz,time*(1+random(i.ins)));
                        position.xyz += posbuffer[i.ins];

                        position.xyz = lerp(startingpos, position.xyz, _moveCubeT); // lerp based on time

                        o.pos = UnityObjectToClipPos(position);
                    return o;
                }

                fixed4 frag(vertOUT ou):SV_Target{
                    return 1;
                }
            ENDCG
        }
    }
}

然后回到您的C#代码中,根据多维数据集的传输位置设置此_moveCubeT浮点数:

private void BufferSet()
{
    // Move cubes for 2 seconds and pause for 8 seconds, repeat.
    float t = Mathf.Clamp( (Time.time % 10f) / 2f, 0f, 1f); 
    cshader.SetBuffer(kernel, "posbuffer", posbuffer); 
    mat.SetBuffer("posbuffer", posbuffer);     
    mat.SetBuffer("vertexbuffer", vertexbuffer);
    mat.SetFloat("_moveCubeT", t);
} 

总而言之,这旨在为您提供完全无光照,无纹理的白色立方体,这些立方体将移动到顶点在网格上的位置。如果要对这些多维数据集进行照亮,纹理化或着色,则必须进行一些更改,但这更适合于另一个问题。

我从没使用过DrawProceduralNow,所以可能会有一些遗漏的地方,但这应该至少被认为是部分答案。