Exemplo n.º 1
0
        /// <summary>
        /// Add a billboard to batch.
        /// Use this overload for custom atlas material.
        /// </summary>
        public void AddItem(Rect rect, Vector2 size, Vector2 scale, Vector3 localPosition)
        {
            // Cannot use with auto material
            if (customMaterial == null)
                throw new Exception("Cannot use with auto material. Use AddItem(int record, Vector3 localPosition) overload instead.");

            // Add new billboard to batch
            BillboardItem bi = new BillboardItem()
            {
                position = BlockOrigin + localPosition,
                customRect = rect,
                customSize = size,
                customScale = scale,
            };
            billboardItems.Add(bi);
        }
        /// <summary>
        /// Add a billboard to batch.
        /// </summary>
        public void AddItem(int record, Vector3 localPosition)
        {
            // Limit maximum billboards in batch
            if (billboardItems.Count + 1 > maxBillboardCount)
            {
                DaggerfallUnity.LogMessage("DaggerfallBillboardBatch: Maximum batch size reached.", true);
                return;
            }

            // Add new billboard to batch
            BillboardItem bi = new BillboardItem()
            {
                record   = record,
                position = origin + localPosition,
            };

            billboardItems.Add(bi);
        }
        /// <summary>
        /// Add a billboard to batch.
        /// </summary>
        public void AddItem(int record, Vector3 localPosition)
        {
            // Cannot use with a custom material
            if (customMaterial != null)
            {
                throw new Exception("Cannot use with custom material. Use AddItem(Rect rect, Vector2 size, Vector2 scale, Vector3 localPosition) overload instead.");
            }

            // Must have set a material
            if (cachedMaterial.key == 0)
            {
                DaggerfallUnity.LogMessage("DaggerfallBillboardBatch: Must call SetMaterial() before adding items.", true);
                return;
            }

            // Limit maximum billboards in batch
            if (billboardItems.Count + 1 > maxBillboardCount)
            {
                DaggerfallUnity.LogMessage("DaggerfallBillboardBatch: Maximum batch size reached.", true);
                return;
            }

            // Get frame count and start frame
            int frameCount = cachedMaterial.atlasFrameCounts[record];
            int startFrame = 0;

            if (RandomStartFrame)
            {
                startFrame = UnityEngine.Random.Range(0, frameCount);
            }

            // Add new billboard to batch
            BillboardItem bi = new BillboardItem()
            {
                record       = record,
                position     = BlockOrigin + localPosition,
                totalFrames  = frameCount,
                currentFrame = startFrame,
            };

            billboardItems.Add(bi);
        }
        IEnumerator AnimateBillboards()
        {
            while (true)
            {
                // Tick animation when valid
                if (FramesPerSecond > 0 && cachedMaterial.key != 0 && customMaterial == null && uvs != null)
                {
                    // Look for animated billboards
                    for (int billboard = 0; billboard < billboardItems.Count; billboard++)
                    {
                        // Get billboard and do nothing if single frame
                        BillboardItem bi = billboardItems[billboard];
                        if (bi.totalFrames > 1)
                        {
                            // Increment current billboard frame
                            if (++bi.currentFrame >= bi.totalFrames)
                            {
                                bi.currentFrame = 0;
                            }
                            billboardItems[billboard] = bi;

                            // Set new UV properties based on current frame
                            Rect rect   = cachedMaterial.atlasRects[cachedMaterial.atlasIndices[bi.record].startIndex + bi.currentFrame];
                            int  offset = billboard * vertsPerQuad;
                            uvs[offset]     = new Vector2(rect.x, rect.yMax);
                            uvs[offset + 1] = new Vector2(rect.xMax, rect.yMax);
                            uvs[offset + 2] = new Vector2(rect.x, rect.y);
                            uvs[offset + 3] = new Vector2(rect.xMax, rect.y);
                        }
                    }

                    // Store new mesh UV set
                    if (uvs != null && uvs.Length > 0)
                    {
                        billboardMesh.uv = uvs;
                    }
                }

                yield return(new WaitForSeconds(1f / FramesPerSecond));
            }
        }
Exemplo n.º 5
0
                public unsafe bool CanUseInstancingForTransparentWith(ref BillboardItem billboardItem)
                {
                    if (BoundingBoxCenter != billboardItem.BoundingBoxCenter)
                    {
                        return(false);
                    }
                    if (BoundingSphere != billboardItem.BoundingSphere)
                    {
                        return(false);
                    }
                    if (CastShadows != billboardItem.CastShadows)
                    {
                        return(false);
                    }
                    if (ReceiveDecals != billboardItem.ReceiveDecals)
                    {
                        return(false);
                    }
                    if (Material != billboardItem.Material)
                    {
                        return(false);
                    }

                    if (LODValue != billboardItem.LODValue)
                    {
                        return(false);
                    }
                    //if( LODValue != 0 || billboardItem.LODValue != 0 )
                    //	return false;

                    //public object Creator;
                    //public object AnyData;

                    ////public BillboardData[] BillboardArray;

                    return(true);
                }
        // Packs all billboards into single mesh
        private void CreateMesh()
        {
            // Using half way between forward and up for billboard normal
            // Workable for most lighting but will need a better system eventually
            Vector3 normalTemplate = Vector3.Normalize(Vector3.up + Vector3.forward);

            // Create billboard data
            // Serializing UV array creates less garbage than recreating every time animation ticks
            Bounds newBounds   = new Bounds();
            int    vertexCount = billboardItems.Count * vertsPerQuad;
            int    indexCount  = billboardItems.Count * indicesPerQuad;

            Vector3[] vertices = new Vector3[vertexCount];
            Vector3[] normals  = new Vector3[vertexCount];
            Vector4[] tangents = new Vector4[vertexCount];
            uvs = new Vector2[vertexCount];
            int[] indices      = new int[indexCount];
            int   currentIndex = 0;

            for (int billboard = 0; billboard < billboardItems.Count; billboard++)
            {
                int           offset = billboard * vertsPerQuad;
                BillboardItem bi     = billboardItems[billboard];

                // Billboard size and origin
                Vector2 finalSize = GetScaledBillboardSize(bi.record);
                //float hx = (finalSize.x / 2);
                float   hy       = (finalSize.y / 2);
                Vector3 position = bi.position + new Vector3(0, hy, 0);

                // Billboard UVs
                Rect rect = cachedMaterial.atlasRects[cachedMaterial.atlasIndices[bi.record].startIndex + bi.currentFrame];
                uvs[offset]     = new Vector2(rect.x, rect.yMax);
                uvs[offset + 1] = new Vector2(rect.xMax, rect.yMax);
                uvs[offset + 2] = new Vector2(rect.x, rect.y);
                uvs[offset + 3] = new Vector2(rect.xMax, rect.y);

                // Tangent data for shader is used to size billboard
                tangents[offset]     = new Vector4(finalSize.x, finalSize.y, 0, 1);
                tangents[offset + 1] = new Vector4(finalSize.x, finalSize.y, 1, 1);
                tangents[offset + 2] = new Vector4(finalSize.x, finalSize.y, 0, 0);
                tangents[offset + 3] = new Vector4(finalSize.x, finalSize.y, 1, 0);

                // Other data for shader
                for (int vertex = 0; vertex < vertsPerQuad; vertex++)
                {
                    vertices[offset + vertex] = position;
                    normals[offset + vertex]  = normalTemplate;
                }

                // Assign index data
                indices[currentIndex]     = offset;
                indices[currentIndex + 1] = offset + 1;
                indices[currentIndex + 2] = offset + 2;
                indices[currentIndex + 3] = offset + 3;
                indices[currentIndex + 4] = offset + 2;
                indices[currentIndex + 5] = offset + 1;
                currentIndex += indicesPerQuad;

                // Update bounds tracking using actual position and size
                // This can be a little wonky with single billboards side-on as AABB does not rotate
                // But it generally works well for large batches as intended
                // Multiply finalSize * 2f if culling problems with standalone billboards
                Bounds currentBounds = new Bounds(position, finalSize);
                newBounds.Encapsulate(currentBounds);
            }

            // Create mesh
            if (billboardMesh == null)
            {
                // New mesh
                billboardMesh      = new Mesh();
                billboardMesh.name = "BillboardBatchMesh";
            }
            else
            {
                // Existing mesh
                if (billboardMesh.vertexCount == vertices.Length)
                {
                    billboardMesh.Clear(true);      // Same vertex layout
                }
                else
                {
                    billboardMesh.Clear(false);     // New vertex layout
                }
            }

            // Assign mesh data
            billboardMesh.vertices  = vertices;             // Each vertex is positioned at billboard origin
            billboardMesh.tangents  = tangents;             // Tangent stores corners and size
            billboardMesh.triangles = indices;              // Standard indices
            billboardMesh.normals   = normals;              // Standard normals
            billboardMesh.uv        = uvs;                  // Standard uv coordinates into atlas

            // Manually update bounds to account for max billboard height
            billboardMesh.bounds = newBounds;

            // Assign mesh
            MeshFilter filter = GetComponent <MeshFilter>();

            filter.sharedMesh = billboardMesh;
        }
        /// <summary>
        /// Add a billboard to batch.
        /// Use this overload for custom atlas material.
        /// </summary>
        public void AddItem(Rect rect, Vector2 size, Vector2 scale, Vector3 localPosition)
        {
            // Cannot use with auto material
            if (customMaterial == null)
                throw new Exception("Cannot use with auto material. Use AddItem(int record, Vector3 localPosition) overload instead.");

            // Add new billboard to batch
            BillboardItem bi = new BillboardItem()
            {
                position = BlockOrigin + localPosition,
                customRect = rect,
                customSize = size,
                customScale = scale,
            };
            billboardItems.Add(bi);
        }
        /// <summary>
        /// Add a billboard to batch.
        /// </summary>
        public void AddItem(int record, Vector3 localPosition)
        {
            // Cannot use with a custom material
            if (customMaterial != null)
                throw new Exception("Cannot use with custom material. Use AddItem(Rect rect, Vector2 size, Vector2 scale, Vector3 localPosition) overload instead.");

            // Must have set a material
            if (cachedMaterial.key == 0)
            {
                DaggerfallUnity.LogMessage("DaggerfallBillboardBatch: Must call SetMaterial() before adding items.", true);
                return;
            }

            // Limit maximum billboards in batch
            if (billboardItems.Count + 1 > maxBillboardCount)
            {
                DaggerfallUnity.LogMessage("DaggerfallBillboardBatch: Maximum batch size reached.", true);
                return;
            }

            // Get frame count and start frame
            int frameCount = cachedMaterial.atlasFrameCounts[record];
            int startFrame = 0;
            if (RandomStartFrame)
                startFrame = UnityEngine.Random.Range(0, frameCount);

            // Add new billboard to batch
            BillboardItem bi = new BillboardItem()
            {
                record = record,
                position = BlockOrigin + localPosition,
                totalFrames = frameCount,
                currentFrame = startFrame,
            };
            billboardItems.Add(bi);
        }