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