/// <summary> /// Can be used to change the material of a prototype at runtime /// </summary> /// <param name="manager">GPUI Manager</param> /// <param name="prototype">GPUI Prototype</param> /// <param name="material">New material to set on the renderer</param> /// <param name="lodLevel">LOD level</param> /// <param name="rendererIndex">Renderer index on the LOD level</param> /// <param name="subMeshIndex">Submesh index of the renderer</param> public static void ChangeMaterial(GPUInstancerManager manager, GPUInstancerPrototype prototype, Material material, int lodLevel = 0, int rendererIndex = 0, int subMeshIndex = 0) { GPUInstancerRuntimeData runtimeData = manager.GetRuntimeData(prototype, true); if (runtimeData == null) { return; } GPUInstancerRenderer gpuiRenderer = runtimeData.instanceLODs[lodLevel].renderers[rendererIndex]; // Generate proxy GO with a Mesh Renderer to get material property blocks GameObject proxyGameObject = new GameObject("ProxyGO"); MeshFilter meshFilter = proxyGameObject.AddComponent <MeshFilter>(); MeshRenderer proxyRenderer = proxyGameObject.AddComponent <MeshRenderer>(); // Set mesh to proxy GO meshFilter.mesh = gpuiRenderer.mesh; // Set new material to runtime data gpuiRenderer.materials[subMeshIndex] = GPUInstancerConstants.gpuiSettings.shaderBindings.GetInstancedMaterial(material); // Set new material to proxy GO proxyRenderer.materials[subMeshIndex] = material; // Get material property blocks proxyRenderer.GetPropertyBlock(gpuiRenderer.mpb); if (gpuiRenderer.shadowMPB != null) { proxyRenderer.GetPropertyBlock(gpuiRenderer.shadowMPB); } // Destroy proxy GO GameObject.Destroy(proxyGameObject); // Setup new materials for instancing GPUInstancerUtility.SetAppendBuffers(runtimeData); }
/// <summary> /// Can be used to change the mesh of a prototype at runtime /// </summary> /// <param name="manager">GPUI Manager</param> /// <param name="prototype">GPUI Prototype</param> /// <param name="mesh">New mesh to set on the renderer</param> /// <param name="lodLevel">LOD level</param> /// <param name="rendererIndex">Renderer index on the LOD level</param> /// <param name="subMeshIndex">Submesh index of the renderer</param> public static void ChangeMesh(GPUInstancerManager manager, GPUInstancerPrototype prototype, Mesh mesh, int lodLevel = 0, int rendererIndex = 0, int subMeshIndex = 0) { GPUInstancerRuntimeData runtimeData = manager.GetRuntimeData(prototype, true); if (runtimeData == null) { return; } GPUInstancerRenderer gpuiRenderer = runtimeData.instanceLODs[lodLevel].renderers[rendererIndex]; if (gpuiRenderer.mesh.subMeshCount != mesh.subMeshCount) { Debug.LogError("ChangeMesh method can not be used with a mesh that has different amount of submeshes than the original mesh."); return; } if (gpuiRenderer.mesh.vertexCount != mesh.vertexCount) { int argsLastIndex = gpuiRenderer.argsBufferOffset; // Setup the indirect renderer buffer: for (int j = 0; j < gpuiRenderer.mesh.subMeshCount; j++) { runtimeData.args[argsLastIndex++] = gpuiRenderer.mesh.GetIndexCount(j); // index count per instance runtimeData.args[argsLastIndex++] = 0; // (uint)runtimeData.bufferSize; runtimeData.args[argsLastIndex++] = gpuiRenderer.mesh.GetIndexStart(j); // start index location runtimeData.args[argsLastIndex++] = 0; // base vertex location runtimeData.args[argsLastIndex++] = 0; // start instance location } runtimeData.argsBuffer.SetData(runtimeData.args); } gpuiRenderer.mesh = mesh; }
public virtual void DrawRegisteredPrefabsBoxList() { if (Application.isPlaying && _manager.runtimeDataList != null && _manager.runtimeDataList.Count > 0) { int totalInsanceCount = 0; int totalDrawCallCount = 0; int totalShadowDrawCall = 0; foreach (GPUInstancerRuntimeData runtimeData in _manager.runtimeDataList) { if (runtimeData == null) { continue; } int drawCallCount = 0; int shadowDrawCallCount = 0; if (runtimeData.transformationMatrixVisibilityBuffer != null && runtimeData.instanceLODs != null && runtimeData.bufferSize > 0 && runtimeData.instanceCount > 0) { for (int i = 0; i < runtimeData.instanceLODs.Count; i++) { for (int j = 0; j < runtimeData.instanceLODs[i].renderers.Count; j++) { GPUInstancerRenderer gpuiRenderer = runtimeData.instanceLODs[i].renderers[j]; if (!GPUInstancerUtility.IsInLayer(prop_layerMask.intValue, gpuiRenderer.layer)) { continue; } drawCallCount += gpuiRenderer.materials.Count; if (runtimeData.prototype.isShadowCasting && gpuiRenderer.castShadows) { shadowDrawCallCount += gpuiRenderer.materials.Count * QualitySettings.shadowCascades; } } } } GUILayout.Label(runtimeData.prototype.ToString() + " Instance Count: " + runtimeData.instanceCount + "\n" + runtimeData.prototype.ToString() + " Geometry Draw Call Count: " + drawCallCount + (shadowDrawCallCount > 0 ? "\n" + runtimeData.prototype.ToString() + " Shadow Draw Call Count: " + shadowDrawCallCount : ""), GPUInstancerEditorConstants.Styles.label); totalInsanceCount += runtimeData.instanceCount; totalDrawCallCount += drawCallCount; totalShadowDrawCall += shadowDrawCallCount; } GUILayout.Label("\nTotal Instance Count: " + totalInsanceCount + "\n\n" + "Total Geometry Draw Call Count: " + totalDrawCallCount + "\n" + "Total Shadow Draw Call Count: " + totalShadowDrawCall + " (" + QualitySettings.shadowCascades + " Cascades)" + "\n\n" + "Total Draw Call Count: " + (totalDrawCallCount + totalShadowDrawCall) , GPUInstancerEditorConstants.Styles.boldLabel); } else { GPUInstancerEditorConstants.DrawCustomLabel("No registered prefabs.", GPUInstancerEditorConstants.Styles.label, false); } }
/// <summary> /// Adds a renderer to an LOD. Renderers define the meshes and materials to render for a given instance prototype LOD. /// </summary> /// <param name="lod">The LOD to add this renderer to. LOD indices start from 0.</param> /// <param name="mesh">The mesh that this renderer will use.</param> /// <param name="materials">The list of materials that this renderer will use (must be GPU Instancer compatible materials)</param> /// <param name="transformOffset">The transformation matrix that represents a change in position, rotation and scale /// for this renderer as an offset from the instance prototype. This matrix will be applied to the prototype instance /// matrix for final rendering calculations in the shader. Use Matrix4x4.Identity if no offset is desired.</param> public virtual void AddRenderer(int lod, Mesh mesh, List <Material> materials, Matrix4x4 transformOffset, MaterialPropertyBlock mpb, bool castShadows, int layer = 0, MaterialPropertyBlock shadowMPB = null, Renderer rendererRef = null) { if (instanceLODs == null || instanceLODs.Count <= lod || instanceLODs[lod] == null) { Debug.LogError("Can't add renderer: Invalid LOD"); return; } if (mesh == null) { Debug.LogError("Can't add renderer: mesh is null. Make sure that all the MeshFilters on the objects has a mesh assigned."); return; } if (materials == null || materials.Count == 0) { Debug.LogError("Can't add renderer: no materials. Make sure that all the MeshRenderers have their materials assigned."); return; } if (instanceLODs[lod].renderers == null) { instanceLODs[lod].renderers = new List <GPUInstancerRenderer>(); } GPUInstancerRenderer renderer = new GPUInstancerRenderer { mesh = mesh, materials = materials, transformOffset = transformOffset, mpb = mpb, shadowMPB = shadowMPB, layer = layer, castShadows = castShadows, rendererRef = rendererRef }; instanceLODs[lod].renderers.Add(renderer); CalculateBounds(); }