Como usar o BillboardRenderer no Unity?

11

Desde a versão 5 (?), O Unity possui um novo tipo de componente BillboardRenderer. Infelizmente a documentação é bastante pobre.

Ele pode ser adicionado ao inspetor clicando em "Adicionar componente -> Miscelânea -> Billboard Renderer", mas aparentemente ele exige Billboard Assetque você faça qualquer coisa. Não parece haver nenhuma maneira de criar uma a partir da interface do Unity.

Uma das poucas frases da documentação igualmente pobre do BillboardAsset diz:

imageCount Número de imagens pré- processadas que podem ser alteradas quando o cartaz é visualizado de diferentes ângulos.

Meu projeto mais recente terá gráficos de mistura de sprites / polígonos, portanto, um componente que renderiza um outdoor com um sprite diferente, dependendo do ângulo de visão, é algo que eu realmente poderia usar. Mas não parece haver nenhum método para adicionar essas imagens.

Então, eu me perguntei se você poderia postar um exemplo de como esse componente é usado.

Philipp
fonte
O outdoor faz o que eu esperava? Ou outra coisa? (Eu esperaria que para manter a imagem de frente para a câmera.)
Evorlor
@Evorlor Isso é o que eu esperava também, mas até agora não consegui fazer nada .
28516 Philipp Philipp

Respostas:

6

ATUALIZAÇÃO (2018): Há mais propriedades expostas desde que escrevi esta resposta. Talvez possamos criá-lo agora, talvez não. Tenho que pesquisar.

Você não pode usá-lo.

Aqui está o BillboardAssetcódigo descompilado :

using System;

namespace UnityEngine
{
    /// <summary>
    ///   <para>BillboardAsset describes how a billboard is rendered.</para>
    /// </summary>
    public sealed class BillboardAsset : Object
    {
        /// <summary>
        ///   <para>Height of the billboard that is below ground.</para>
        /// </summary>
        public float bottom
        {
            [WrapperlessIcall]
            get;
            [WrapperlessIcall]
            set;
        }

        /// <summary>
        ///   <para>Height of the billboard.</para>
        /// </summary>
        public float height
        {
            [WrapperlessIcall]
            get;
            [WrapperlessIcall]
            set;
        }

        /// <summary>
        ///   <para>Number of pre-baked images that can be switched when the billboard is viewed from different angles.</para>
        /// </summary>
        public int imageCount
        {
            [WrapperlessIcall]
            get;
        }

        /// <summary>
        ///   <para>Number of indices in the billboard mesh. The mesh is not necessarily a quad. It can be a more complex shape which fits the actual image more precisely.</para>
        /// </summary>
        public int indexCount
        {
            [WrapperlessIcall]
            get;
        }

        /// <summary>
        ///   <para>The material used for rendering.</para>
        /// </summary>
        public Material material
        {
            [WrapperlessIcall]
            get;
            [WrapperlessIcall]
            set;
        }

        /// <summary>
        ///   <para>Number of vertices in the billboard mesh. The mesh is not necessarily a quad. It can be a more complex shape which fits the actual image more precisely.</para>
        /// </summary>
        public int vertexCount
        {
            [WrapperlessIcall]
            get;
        }

        /// <summary>
        ///   <para>Width of the billboard.</para>
        /// </summary>
        public float width
        {
            [WrapperlessIcall]
            get;
            [WrapperlessIcall]
            set;
        }

        /// <summary>
        ///   <para>Constructs a new BillboardAsset.</para>
        /// </summary>
        public BillboardAsset()
        {
        }

        [WrapperlessIcall]
        internal extern void MakeMaterialProperties(MaterialPropertyBlock properties, Camera camera);

        [WrapperlessIcall]
        internal extern void MakePreviewMesh(Mesh mesh);

        [WrapperlessIcall]
        internal extern void MakeRenderMesh(Mesh mesh, float widthScale, float heightScale, float rotation);
    }
}

Não há literalmente nenhuma maneira de definir imagens, nem por reflexão. Pode-se pensar: “ok, você não pode fazê-lo diretamente, mas talvez haja algum tipo de fábrica fornecida?”. Pressiono Encontrar usos no descompilador e recebo: BillboardAssetInspectore BillboardRenderer.

Aqui está BillboardRenderer:

using System;

namespace UnityEngine
{
    /// <summary>
    ///   <para>Renders a billboard.</para>
    /// </summary>
    public sealed class BillboardRenderer : Renderer
    {
        /// <summary>
        ///   <para>The BillboardAsset to render.</para>
        /// </summary>
        public BillboardAsset billboard
        {
            [WrapperlessIcall]
            get;
            [WrapperlessIcall]
            set;
        }

        /// <summary>
        ///   <para>Constructor.</para>
        /// </summary>
        public BillboardRenderer()
        {
        }
    }
}

Uau, essa classe é ainda mais burra. É apenas um suporte de dados sem lógica. Obviamente, todo o trabalho é feito por Renderer. Mais precisamente, por um ou dois [WraplessIcall]métodos nele. Não colocarei seu código aqui porque é uma lista longa e inútil de [WraplessIcall]membros.

Ao contrário do conteúdo do UnityEngine.dll , BillboardAssetInspector(que reside no UnityEditor.dll ) possui um código real. Mais uma vez, não colocarei seu código aqui, porque fica claro pelo nome que nada mais é do que o Inspetor .

A mesma situação com BillboardAssetInspector.


Entendi, é para uso interno; mas onde é usado exatamente?

No sistema SpeedTree (veja a última imagem em particular).

Por que a documentação explica coisas inúteis em vez de alertar contra o uso imediato?

Provavelmente, apenas copiei tudo, desde documentação interna de desenvolvimento, peças aprimoradas que são importantes para iniciantes e para uso geral; então, estava muito ocupado participando do hype de VR para se preocupar em polir esses cantos escuros da documentação.

O que podemos fazer sobre isso?

Diga a eles que eles ignoraram esse “canto escuro” da documentação, por exemplo: No Unity Editor, abra Help → Report a bug..., What is problem related toescolha documentation, etc.

O que se pode usar em vez disso?

As opções possíveis incluem:

Maxim Kamalov
fonte
2
Como outra alternativa: geralmente quando preciso colocar um monte de outdoors, uso um sistema de partículas, com a emissão e a animação desativadas, para que eu possa posicionar manualmente cada quadra de outdoor onde desejar.
DMGregory
@DMGregory Não posso discordar, o sistema de partículas do Unity é ótimo para muitas coisas que nem remotamente se aproximam de “partículas”. Ainda melhor, desde o Unity 5, o suporte para a personalização do sistema de partículas foi explicitamente aprimorado / otimizado. Devo adicionar esta opção à resposta, ou esses comentários são suficientes, o que você acha?
Maxim Kamalov
Eu acho que é bom deixar nos comentários. Se alguém quiser mais detalhes, acho que é suficiente fazer uma nova pergunta.
DMGregory
Não acredito nisso para uso interno, disse o documento: "Você também pode criar o seu próprio depois de saber como o quadro de avisos é descrito". - docs.unity3d.com/ScriptReference/BillboardAsset.html
123iamking
@ 123iamking E agora existem mais propriedades expostas. Então, sim, provavelmente é possível utilizá-los diretamente agora.
Maxim Kamalov 07/08/19
1

Para usar o BillboardRenderer, você precisa do Billboard Asset, pode construir o Billboard Asset com script C #. Verifique este post .

O ativo da Billboard tem um conteúdo como este: Billboard.asset

 %YAML 1.1
 %TAG !u! tag:unity3d.com,2011:
 --- !u!226 &22600000
 BillboardAsset:
   m_ObjectHideFlags: 0
   m_CorrespondingSourceObject: {fileID: 0}
   m_PrefabInternal: {fileID: 0}
   m_Name: Billboard_Original
   serializedVersion: 2
   width: 10.350581
   bottom: -0.2622106
   height: 7.172371
   imageTexCoords:
   - {x: 0.230981, y: 0.33333302, z: 0.230981, w: -0.33333302}
   - {x: 0.230981, y: 0.66666603, z: 0.230981, w: -0.33333302}
   - {x: 0.33333302, y: 0, z: 0.33333302, w: 0.23098099}
   - {x: 0.564314, y: 0.23098099, z: 0.23098099, w: -0.33333302}
   - {x: 0.564314, y: 0.564314, z: 0.23098099, w: -0.33333403}
   - {x: 0.66666603, y: 0, z: 0.33333302, w: 0.23098099}
   - {x: 0.89764804, y: 0.23098099, z: 0.230982, w: -0.33333302}
   - {x: 0.89764804, y: 0.564314, z: 0.230982, w: -0.33333403}
   vertices:
   - {x: 0.47093, y: 0.020348798}
   - {x: 0.037790697, y: 0.498547}
   - {x: 0.037790697, y: 0.976744}
   - {x: 0.52906996, y: 0.020348798}
   - {x: 0.95930207, y: 0.498547}
   - {x: 0.95930207, y: 0.976744}
   indices: 040003000000010004000000050004000100020005000100
   material: {fileID: 2100000, guid: 6e680dda9368db5418f19388474277a2, type: 2}

Aqui está o código C # usado para gerar o arquivo acima

 using System.Collections;
 using System.Collections.Generic;
 using UnityEditor;
 using UnityEngine;

     public class BillboardBaker : MonoBehaviour
     {
 #if UNITY_EDITOR
         public BillboardAsset m_outputFile;
         public Material m_material;

         [ContextMenu("Bake Billboard")]
         void BakeBillboard()
         {
             BillboardAsset billboard = new BillboardAsset();

             billboard.material = m_material;
             Vector4[] texCoords = new Vector4[8];
             ushort[] indices = new ushort[12];
             Vector2[] vertices = new Vector2[6];
             texCoords[0].Set(0.230981f, 0.33333302f, 0.230981f, -0.33333302f);
             texCoords[1].Set(0.230981f, 0.66666603f, 0.230981f,-0.33333302f);
             texCoords[2].Set(0.33333302f, 0.0f, 0.33333302f,0.23098099f);
             texCoords[3].Set(0.564314f, 0.23098099f, 0.23098099f,-0.33333302f);
             texCoords[4].Set(0.564314f, 0.564314f, 0.23098099f,-0.33333403f);
             texCoords[5].Set(0.66666603f, 0.0f, 0.33333302f,0.23098099f);
             texCoords[6].Set(0.89764804f, 0.23098099f, 0.230982f,-0.33333302f);
             texCoords[7].Set(0.89764804f, 0.564314f, 0.230982f,-0.33333403f);

             indices[0] = 4;
             indices[1] = 3;
             indices[2] = 0;
             indices[3] = 1;
             indices[4] = 4;
             indices[5] = 0;
             indices[6] = 5;
             indices[7] = 4;
             indices[8] = 1;
             indices[9] = 2;
             indices[10] = 5;
             indices[11] = 1;

             vertices[0].Set(0.47093f, 0.020348798f);
             vertices[1].Set(0.037790697f, 0.498547f);
             vertices[2].Set(0.037790697f, 0.976744f);
             vertices[3].Set(0.52906996f, 0.020348798f);
             vertices[4].Set(0.95930207f, 0.498547f);
             vertices[5].Set(0.95930207f, 0.976744f);

             billboard.SetImageTexCoords(texCoords);
             billboard.SetIndices(indices);
             billboard.SetVertices(vertices);

             billboard.width = 10.35058f;
             billboard.height = 7.172371f;
             billboard.bottom = -0.2622106f;

             if (m_outputFile != null)
             {
                 EditorUtility.CopySerialized(billboard, m_outputFile);
             }
             else
             {
                 string path;
                 path = AssetDatabase.GetAssetPath(m_material) + ".asset";
                 AssetDatabase.CreateAsset(billboard, path);
             }
         }
 #endif
     }

para mais detalhes, verifique o post que dei no início da resposta.

123iamking
fonte