/** * Update the LOD min/max distances for an object. * * @param isSpeedTree * If this is set to true, then we will check if we have a billboard renderer to an LOD * and we will skip it in case that we have one */ public static void UpdateDistancesLOD(FoliageTypeLODTree[] treeLods, LOD[] groupLods, float maxDistance, bool isSpeedTree) { if (groupLods != null && groupLods.Length > 0) { FoliageLog.Assert(groupLods.Length >= treeLods.Length, "Must have same or more lods than the tree lods!"); for (int i = 0; i < treeLods.Length; i++) { // If we are a speedtree check if we have a billboard renderer if (isSpeedTree && groupLods[i].renderers[0].GetComponent <BillboardRenderer>() != null) { continue; } FoliageTypeLODTree lodTree = treeLods[i]; LOD lodGroupCurrent = groupLods[i]; lodTree.m_EndDistance = ((1.0f - lodGroupCurrent.screenRelativeTransitionHeight) * maxDistance); } } else { treeLods[0].m_EndDistance = maxDistance; } }
private void IssueBatchLOD(Matrix4x4[] batch, int count, FoliageTypeLODTree lod, MaterialPropertyBlock mpb, ShadowCastingMode shadow) { // Set the MPB data mpb.SetFloat(m_ShaderIDCritiasFoliageLOD, lod.m_EndDistance); mpb.SetFloat(m_ShaderIDCritiasFoliageLODSqr, lod.m_EndDistance * lod.m_EndDistance); Mesh mesh = lod.m_Mesh; Material[] materials = lod.m_Materials; if (m_Settings.m_DrawInstanced) { for (int sub = 0, subCount = mesh.subMeshCount; sub < subCount; sub++) { Graphics.DrawMeshInstanced(mesh, sub, materials[sub], batch, count, mpb, shadow, true, m_CurrentFrameLayer, m_CurrentFrameCameraDraw); m_DrawStats.m_ProcessedDrawCalls++; } } else { for (int sub = 0, subCount = mesh.subMeshCount; sub < subCount; sub++) { for (int i = 0; i < count; i++) { Graphics.DrawMesh(mesh, batch[i], materials[sub], m_CurrentFrameLayer, m_CurrentFrameCameraDraw, sub, mpb, shadow, true, null, m_Settings.m_UseLightProbes); m_DrawStats.m_ProcessedDrawCalls++; } } } m_DrawStats.m_ProcessedInstances += count; }
/** To be used at edit-time */ public static void BuildDataPartialEditTime(FoliagePainter painter, FoliageType type) { GameObject prefab = type.m_Prefab; // Update the type type.Type = type.Type; FoliageLog.Assert(prefab != null, "Null foliage prefab!"); if (type.m_RuntimeData == null) { type.m_RuntimeData = new FoliageTypeRuntimeData(); } FoliageTypeRuntimeData runtime = type.m_RuntimeData; List <Material> checkMaterials = new List <Material>(); // Init the SpeedTree data if (type.IsSpeedTreeType) { if (runtime.m_SpeedTreeData == null) { runtime.m_SpeedTreeData = new FoliageTypeSpeedTreeData(); } } if (type.IsGrassType) { // Build the data universally for all grass types if (runtime.m_LODDataGrass == null) { runtime.m_LODDataGrass = new FoliageTypeLODGrass(); } runtime.m_LODDataGrass.m_Mesh = prefab.GetComponentInChildren <MeshFilter>().sharedMesh; runtime.m_LODDataGrass.m_Material = prefab.GetComponentInChildren <MeshRenderer>().sharedMaterial; checkMaterials.Add(runtime.m_LODDataGrass.m_Material); FoliageLog.Assert(runtime.m_LODDataGrass.m_Mesh != null, "Could not find mesh for type: " + prefab.name + ". Make sure that is has at least one mesh and one material"); FoliageLog.Assert(runtime.m_LODDataGrass.m_Material != null, "Could not find material for type: " + prefab.name + ". Make sure that is has at least one mesh and one material"); } else { LODGroup group = prefab.GetComponent <LODGroup>(); if (group == null) { FoliageLog.w("Detected tree: " + prefab.name + " without a lod group. Are you sure that you require a tree for this?"); if (runtime.m_LODDataTree == null || runtime.m_LODDataTree.Length == 0) { runtime.m_LODDataTree = new FoliageTypeLODTree[1]; } runtime.m_LODDataTree[0] = new FoliageTypeLODTree(); runtime.m_LODDataTree[0].m_Mesh = prefab.GetComponentInChildren <MeshFilter>().sharedMesh; runtime.m_LODDataTree[0].m_Materials = prefab.GetComponentInChildren <MeshRenderer>().sharedMaterials; runtime.m_LODDataTree[0].m_EndDistance = type.m_RenderInfo.m_MaxDistance; checkMaterials.AddRange(runtime.m_LODDataTree[0].m_Materials); } else { List <FoliageTypeLODTree> treeLods = new List <FoliageTypeLODTree>(group.lodCount); LOD[] lods = group.GetLODs(); for (int i = 0; i < group.lodCount; i++) { if (lods[i].renderers[0].gameObject.GetComponent <BillboardRenderer>() != null) { // Extract the billboard data var speedData = runtime.m_SpeedTreeData; FoliageWindTreeUtilities.ExtractBillboardData(lods[i].renderers[0].gameObject.GetComponent <BillboardRenderer>(), speedData); continue; } FoliageTypeLODTree treeLod = new FoliageTypeLODTree(); MeshRenderer rend = lods[i].renderers[0].gameObject.GetComponent <MeshRenderer>(); MeshFilter filter = lods[i].renderers[0].gameObject.GetComponent <MeshFilter>(); treeLod.m_Mesh = filter.sharedMesh; treeLod.m_Materials = rend.sharedMaterials; checkMaterials.AddRange(rend.sharedMaterials); treeLods.Add(treeLod); } runtime.m_LODDataTree = treeLods.ToArray(); // Update the LOD distances UpdateDistancesLOD(runtime.m_LODDataTree, lods, type.m_RenderInfo.m_MaxDistance, type.IsSpeedTreeType); } } if (checkMaterials.Count > 0) { if (type.IsSpeedTreeType) { if (type.m_RenderInfo.m_Hue == new Color(0, 0, 0, 0)) { type.m_RenderInfo.m_Hue = checkMaterials[0].GetColor("_HueVariation"); } if (type.m_RenderInfo.m_Color == new Color(0, 0, 0, 0)) { type.m_RenderInfo.m_Color = checkMaterials[0].GetColor("_Color"); } } for (int i = 0; i < checkMaterials.Count; i++) { if (checkMaterials[i].enableInstancing == false) { checkMaterials[i].enableInstancing = true; FoliageLog.w("Material: [" + checkMaterials[i].name + "] did not had instancing enabled! We enabled it!"); } } } // Moved the build at partial edit-time if (type.Type == EFoliageType.SPEEDTREE_GRASS) { Shader shader = painter.GetShaderGrass(); FoliageLog.Assert(shader, "Could not find shader: Critias/SpeedTree_Grass! Make sure that it is added to the project and that it compiled!"); FoliageTypeLODGrass lodGrass = type.m_RuntimeData.m_LODDataGrass; // Override the material at runtime lodGrass.m_Material = new Material(lodGrass.m_Material); lodGrass.m_Material.shader = shader; // Enable it for instancing lodGrass.m_Material.enableInstancing = true; } else if (type.Type == EFoliageType.SPEEDTREE_TREE || type.Type == EFoliageType.SPEEDTREE_TREE_BILLBOARD) { Shader shader = painter.GetShaderTreeMaster(); FoliageLog.Assert(shader, "Could not find shader: Critias/SpeedTree_Master! Make sure that it is added to the project and that it compiled!"); FoliageTypeLODTree[] lodTree = type.m_RuntimeData.m_LODDataTree; for (int i = 0; i < lodTree.Length; i++) { FoliageTypeLODTree tree = lodTree[i]; Material[] mats = tree.m_Materials; for (int m = 0; m < mats.Length; m++) { // Set the new material mats[m] = new Material(mats[m]); mats[m].shader = shader; // Enable instancing mats[m].enableInstancing = true; } tree.m_Materials = mats; } } // Set the materials the values for enabling the bend stuff if we have it if (type.IsGrassType) { if (type.m_EnableBend) { type.m_RuntimeData.m_LODDataGrass.m_Material.EnableKeyword("CRITIAS_DISTANCE_BEND"); } else { type.m_RuntimeData.m_LODDataGrass.m_Material.DisableKeyword("CRITIAS_DISTANCE_BEND"); } } }