使用C#在unity3d中的四边形上渲染透明图片的问题

时间:2019-02-10 00:57:54

标签: c# unity3d

问题

我在用Unity3D块的网格中的块侧的3D四边形上渲染透明图片时遇到问题。
我正在尝试创建体素地形生成器,并且想将2个纹理层放到立方体一侧(例如用于块破裂动画)。
图片大小不同。第一层是坚固的16x16纹理(来自64x64地图集,通过uvs获取),第二层是透明的256x256立方体侧面轮廓。它们的规模相同。

我试图使用“透明/漫反射”着色器渲染透明图像,但是它渲染得很杂色。
只需看下面的图像(2个相同块的视图):
Rendered chunk
Rendered chunk
我完全不知道为什么会这样渲染。我试图通过使用google搜索来找到答案,但没有任何积极结果。

我的代码

这就是我定义材质,着色器和纹理的方式:

    // It will load just once on class load. This is second layer.
    static BlockData() {
        Shader shader = Shader.Find("Transparent/Diffuse");
        outlineMaterial = new Material(shader);
        Texture2D texture = Resources.Load("Textures/BLOCK_FRAME") as Texture2D;
        texture.filterMode = FilterMode.Point;
        outlineMaterial.mainTexture = texture;
        outlineMaterial.SetFloat("_Metallic", 0.7f);
    }

    // Method used to load all materials of block types. This is first layer.
    private void LoadData() {
        if (blockType == BlockType.AIR) {
            this.isSolid = false;
            return;
        }
        this.material = new Material(Shader.Find("Standard"));
        Texture2D texture = Resources.Load("Textures/" + blockType) as Texture2D;
        if (texture != null) {
            texture.filterMode = FilterMode.Point;
        }
        this.material.mainTexture = texture;
        if (texture != null) {
            Debug.Log(this.material.mainTexture.width);
        }
        this.material.SetFloat("_Metallic", 0.7f);
    }

这是我为每个四边形(立方体侧)设置uvs的方式:

    public void BuildQuad(CubeSide cubeSide) {
        // Stworzenie siatki
        Mesh mesh = new Mesh();
        mesh.name = "QuadMesh";
        // Zdefiniowanie zmiennych
        Vector3[] vertices = new Vector3[4];
        Vector3[] normals = new Vector3[4];
        Vector2[] uvs = new Vector2[4];
        int[] triangles = new int[6];
        // Ustawienie zmiennych zależnie od CubeSide
        if (cubeSide == CubeSide.FRONT) {
            vertices = new Vector3[] {p4, p5, p1, p0};
            normals = new Vector3[] {
                Vector3.forward, 
                Vector3.forward, 
                Vector3.forward, 
                Vector3.forward
            };
            uvs = new Vector2[] {
                new Vector2(0.25f, 0.25f),
                new Vector2(0.0f, 0.25f),
                new Vector2(0.0f, 0.0f),
                new Vector2(0.25f, 0),
            };
        } else if (cubeSide == CubeSide.BACK) {
            vertices = new Vector3[] {p6, p7, p3, p2};
            normals = new Vector3[] {
                Vector3.back, 
                Vector3.back, 
                Vector3.back, 
                Vector3.back
            };
            uvs = new Vector2[] {
                new Vector2(0.5f, 0.25f), // 1
                new Vector2(0.251f, 0.25f), // 2
                new Vector2(0.251f, 0.0f), // 3
                new Vector2(0.5f, 0.0f),  // 4
            };
        } else if (cubeSide == CubeSide.LEFT) {
            vertices = new Vector3[] {p7, p4, p0, p3};
            normals = new Vector3[] {
                Vector3.left, 
                Vector3.left, 
                Vector3.left, 
                Vector3.left
            };
            uvs = new Vector2[] {
                new Vector2(0.75f, 0.25f),
                new Vector2(0.501f, 0.25f),
                new Vector2(0.501f, 0.0f), 
                new Vector2(0.75f, 0.0f),
            };
        } else if (cubeSide == CubeSide.RIGHT) {
            vertices = new Vector3[] {p5, p6, p2, p1};
            normals = new Vector3[] {
                Vector3.right, 
                Vector3.right, 
                Vector3.right, 
                Vector3.right
            };
            uvs = new Vector2[] {
                new Vector2(1.0f, 0.25f),
                new Vector2(0.751f, 0.25f),
                new Vector2(0.751f, 0.0f), 
                new Vector2(1.00f, 0.0f),
            };
        } else if (cubeSide == CubeSide.BOTTOM) {
            vertices = new Vector3[] {p0, p1, p2, p3};
            normals = new Vector3[] {
                Vector3.down, 
                Vector3.down, 
                Vector3.down, 
                Vector3.down
            };
            uvs = new Vector2[] {
                new Vector2(0.25f, 0.50f),
                new Vector2(0.0f, 0.50f),
                new Vector2(0.0f, 0.251f), 
                new Vector2(0.25f, 0.251f),
            };
        } else if (cubeSide == CubeSide.TOP) {
            vertices = new Vector3[] {p7, p6, p5, p4};
            normals = new Vector3[] {
                Vector3.up, 
                Vector3.up, 
                Vector3.up, 
                Vector3.up
            };
            uvs = new Vector2[] {
                new Vector2(0.50f, 0.50f),
                new Vector2(0.251f, 0.5f),
                new Vector2(0.251f, 0.251f), 
                new Vector2(0.5f, 0.251f),
            };
        }
        triangles = new int[] {3, 1, 0, 3, 2, 1};
        // Ustawienie danych w siatce 
        mesh.vertices = vertices;
        mesh.normals = normals;
        mesh.uv = uvs;
        mesh.triangles = triangles;
        // Rekalkulacja siatki
        mesh.RecalculateBounds();
        // Stworzenie nowego obiektu w unity, ustawienie parent i dodanie do niego filtra siatki i renderera.
        GameObject quad = new GameObject("quad");
        quad.transform.position = location.position;
        quad.transform.parent = parent.transform;
        MeshFilter meshFilter = (MeshFilter) quad.AddComponent(typeof(MeshFilter));
        meshFilter.mesh = mesh;
    }

这是我将材质设置为渲染器的方式(4。):

    void CombineQuads() {

        //1. Combine all children meshes
        MeshFilter[] meshFilters = chunkGameObject.GetComponentsInChildren<MeshFilter>();
        CombineInstance[] combine = new CombineInstance[meshFilters.Length];
        int i = 0;
        while (i < meshFilters.Length) {
            combine[i].mesh = meshFilters[i].sharedMesh;
            combine[i].transform = meshFilters[i].transform.localToWorldMatrix;
            i++;
        }

        //2. Create a new mesh on the parent object 
        MeshFilter meshFilter = (MeshFilter) chunkGameObject.AddComponent(typeof(MeshFilter));
        meshFilter.mesh = new Mesh();

        //3. Add combined meshes on children as the parent's mesh 
        meshFilter.mesh.CombineMeshes(combine);

        //4. Create a renderer for the parent
        MeshRenderer renderer = chunkGameObject.AddComponent(typeof(MeshRenderer)) as MeshRenderer;
        renderer.materials = new Material[] {BlockData.GetBlockData(BlockType.DIRT).material, BlockData.outlineMaterial};

        //5. Delete all uncombined children
        foreach (Transform quad in chunkGameObject.transform) {
            GameObject.Destroy(quad.gameObject);
        }
    }

最后,这就是我渲染它的方式:

    public void Draw() {
        if (blockType == BlockType.AIR) {
            return;
        }
        int x = location.x();
        int y = location.y();
        int z = location.z();
        //Debug.Log(x+","+y+","+z);
        if(!HasSolidNeighbour(x, y, z + 1)){
            BuildQuad(CubeSide.FRONT);
        }
        if(!HasSolidNeighbour(x, y, z - 1)){
            BuildQuad(CubeSide.BACK);
        }
        if(!HasSolidNeighbour(x, y + 1, z)){
            BuildQuad(CubeSide.TOP);
        } 
        if(!HasSolidNeighbour(x, y - 1, z)){
            BuildQuad(CubeSide.BOTTOM);
        }
        if(!HasSolidNeighbour(x + 1, y, z)){
            BuildQuad(CubeSide.RIGHT);
        }
        if(!HasSolidNeighbour(x - 1, y, z)){
            BuildQuad(CubeSide.LEFT);
        }
    }

    public void prepareChunkBlocks() {
        chunkBlocks = new Block[World.chunkSize,World.chunkSize,World.chunkSize];
        for (int x = 0; x < World.chunkSize; x++) {
            for (int y = 0; y < World.chunkSize; y++) {
                for (int z = 0; z < World.chunkSize; z++) {
                    chunkBlocks[x,y,z] = new Block(
                        BlockType.DIRT, 
                        new Location(
                            x, 
                            y, 
                            z), 
                        chunkGameObject, 
                        this);
                }
            }
        }
    }

    public void drawChunkBlocks() {
        for (int x = 0; x < World.chunkSize; x++) {
            for (int y = 0; y < World.chunkSize; y++) {
                for (int z = 0; z < World.chunkSize; z++) {
                    chunkBlocks[x,y,z].Draw();
                }
            }
        }
        CombineQuads();
    }

    public void BuildChunkColumn() {
        for (int i = 0; i < columnHeight; i++) {
            ChunkLocation chunkLocation = new ChunkLocation((int)this.transform.position.x, i*chunkSize, (int)this.transform.position.z);
            Chunk chunk = new Chunk(chunkLocation, this);
            chunk.chunkGameObject.transform.parent = this.transform;
            chunks.Add(chunkLocation.ToString(), chunk);
        }
        foreach (KeyValuePair<string, Chunk> chunk in chunks) {
            chunk.Value.drawChunkBlocks();
        }
    }

这是我正在使用的纹理(第二个在中间是透明的):
Block texture
Block outline

预期结果

我想实现带边框的块,如下图所示: Rendered chunk
也许有更聪明或更轻松的方法来使块看起来像上图中的块?

0 个答案:

没有答案