Comment utiliser le BillboardRenderer dans Unity?

11

Depuis la version 5 (?), Unity a un nouveau type de composant BillboardRenderer. Malheureusement, la documentation est assez pauvre.

Il peut être ajouté dans l'inspecteur en cliquant sur "Ajouter un composant -> Misceallaneous -> Billboard Renderer" mais apparemment, il nécessite un Billboard Assetpour faire quoi que ce soit. Il ne semble pas y avoir de moyen d'en créer un à partir de l'interface Unity.

L'une des rares phrases de la documentation tout aussi pauvre de BillboardAsset se lit comme suit:

imageCount Nombre d'images précuites pouvant être commutées lorsque le panneau d'affichage est vu sous différents angles.

Mon nouveau projet aura des graphiques de mélange sprite / polygone, donc un composant qui rend un panneau d'affichage avec un sprite différent en fonction de l'angle de vue est quelque chose que je pourrais vraiment utiliser. Mais il ne semble pas y avoir de méthode pour ajouter de telles images.

Je me suis donc demandé si vous pouviez poster un exemple sur la façon dont ce composant est utilisé.

Philipp
la source
Le panneau d'affichage fait-il ce à quoi je m'attendais? Ou autre chose? (Je m'attendrais à ce que l'image reste face à la caméra.)
Evorlor
@Evorlor C'est ce à quoi je m'attendrais aussi, mais jusqu'à présent, je n'ai pas réussi à faire quoi que ce soit .
Philipp

Réponses:

6

MISE À JOUR (2018): Il y a plus de propriétés exposées depuis que j'ai écrit cette réponse. Peut-être que nous pouvons le créer maintenant, peut-être pas. Je dois faire des recherches.

Vous ne pouvez pas l'utiliser.

Voici le BillboardAssetcode décompilé :

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

Il n'y a littéralement aucun moyen de définir des images, même par réflexion. On peut penser: «d'accord, vous ne pouvez pas le faire directement, mais peut-être y a-t-il une sorte d'usine fournie?». J'appuie sur Find Usages dans le décompilateur et j'obtiens: BillboardAssetInspectoret BillboardRenderer.

Voici 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()
        {
        }
    }
}

Wow, cette classe est encore plus bête. C'est juste un détenteur de données sans logique. De toute évidence, tout le travail est effectué par Renderer. Plus précisément, par une ou deux [WraplessIcall]méthodes en elle. Je ne mettrai pas son code ici car c'est une liste longue et inutile de [WraplessIcall]-membres.

Contrairement au contenu UnityEngine.dll , BillboardAssetInspector(qui réside dans UnityEditor.dll ) contient du vrai code. Encore une fois, je ne mettrai pas son code ici, car il ressort clairement de son nom que ce n'est rien de plus qu'Inspector , de toute façon.

Même situation avec BillboardAssetInspector.


Je l'ai, c'est pour un usage interne; mais où est-il utilisé exactement?

Dans le système SpeedTree (regardez la dernière image en particulier).

Pourquoi la documentation explique-t-elle des choses inutiles au lieu d'avertir de ne pas l'utiliser immédiatement?

Probablement, il suffit de copier-coller tout de la documentation de développement interne, des pièces améliorées qui sont importantes pour les nouveaux arrivants et en général; était alors trop occupé à participer au battage médiatique VR pour prendre la peine de polir ces coins sombres de la documentation.

Que pouvons-nous y faire?

Dites-leur qu'ils ont ignoré ce «coin sombre» dans la documentation, par exemple: dans l'éditeur Unity, ouvrez Help → Report a bug..., What is problem related tochoisissez documentation, etc.

Que peut-on utiliser à la place?

Les options possibles incluent:

Maxim Kamalov
la source
2
Comme autre alternative: souvent lorsque j'ai besoin de placer un tas de panneaux d'affichage, j'utilise un système de particules, avec son émission et son animation désactivées afin que je puisse positionner manuellement chaque quad panneau d'affichage où je le veux.
DMGregory
@DMGregory Je ne peux pas être en désaccord, le système de particules d'Unity est idéal pour de nombreuses choses qui ne sont même pas à distance proches des "particules". Encore mieux, depuis Unity 5, la prise en charge de la personnalisation du système de particules a été explicitement améliorée / optimisée. Dois-je ajouter cette option à la réponse, ou ces commentaires suffisent, qu'en pensez-vous?
Maxim Kamalov
Je pense que c'est bien de laisser dans les commentaires. Si quelqu'un veut plus de détails, je pense que c'est assez charnu pour poser une nouvelle question.
DMGregory
Je ne le crois pas pour un usage interne, le doc a déclaré: "Vous pouvez également créer le vôtre une fois que vous savez comment le panneau d'affichage est décrit." - docs.unity3d.com/ScriptReference/BillboardAsset.html
123iamking
@ 123iamking Et maintenant, il y a plus de propriétés exposées. Donc, oui, il est probablement possible de les utiliser directement maintenant.
Maxim Kamalov
1

Pour utiliser BillboardRenderer, vous avez besoin de Billboard Asset, vous pouvez construire Billboard Asset avec le script C #. Vérifiez ce post .

Le Billboard Asset a un contenu comme celui-ci: 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}

Voici le code C # utilisé pour générer le fichier ci-dessus

 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
     }

pour plus de détails, veuillez consulter le post que j'ai donné au début de la réponse.

123iamking
la source