Как взять каждую вершину меша, создать куб икру и перейти к каждой? (Unity C #) - PullRequest
1 голос
/ 03 июня 2019

Вот скрипт, который у меня сейчас есть для объекта 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 Ответ

1 голос
/ 03 июня 2019

Есть две части этого.

Сначала вам нужно перейти на рендеринг треугольников вместо точек, и дать шейдеру вершины всех треугольников, из которых состоят ваши кубы.

Измените MeshInfo, чтобы создатьбуфер вершин 36 * количество вершин в сетке.Это потому, что вам нужно сделать 12 треугольников для каждой вершины (2 треугольника для каждой из 6 сторон куба).Для каждой из 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, поэтому могут быть некоторые недостающие фрагменты.но это следует считать хотя бы частичным ответом.

...