/// <summary> /// Computes the grass mesh for [Billboard-set Grass System]. /// </summary> /// <returns> /// Offset in 'grass_list' from where you can compute the next mesh. /// </returns> /// <param name='grass_list'> /// The grass instance list. /// </param> /// <param name='offset'> /// Offset in 'grass_list' from where you compute the mesh. /// </param> /// <param name='mf_inout'> /// [inout] The MeshFilter component receives the mesh. /// </param> public static int ComputeMesh(List <GrassInstance> grass_list, int offset, MeshFilter mf_inout) { if (grass_list == null) { return(0); } offset = Mathf.Clamp(offset, 0, grass_list.Count); int grasspermesh = Mathf.Clamp(s_GrassCountPerMesh, 128, 16240); int grasscount = Mathf.Min(grasspermesh, grass_list.Count - offset); if (grasscount < 1) { return(grass_list.Count); } if (mf_inout == null) { return(grass_list.Count); } Vector3[] verts = new Vector3 [grasscount << 2]; Vector3[] norms = new Vector3 [grasscount << 2]; Vector2[] uvs = new Vector2 [grasscount << 2]; Vector2[] uv2s = new Vector2 [grasscount << 2]; Color32[] colors32 = new Color32 [grasscount << 2]; int[] indices = new int [grasscount * 6]; Vector3 A = new Vector3(-1, -1, 0); Vector3 B = new Vector3(-1, 1, 0); Vector3 C = new Vector3(1, 1, 0); Vector3 D = new Vector3(1, -1, 0); Vector3 up = Vector3.up; for (int i = 0; i < grasscount; ++i) { int a = i * 4; int b = a + 1; int c = a + 2; int d = a + 3; indices[i * 6 + 0] = a; indices[i * 6 + 1] = b; indices[i * 6 + 2] = c; indices[i * 6 + 3] = c; indices[i * 6 + 4] = d; indices[i * 6 + 5] = a; verts[a] = A; verts[b] = B; verts[c] = C; verts[d] = D; GrassInstance gi = grass_list[offset + i]; norms[d] = norms[c] = norms[b] = norms[a] = gi.Position; Vector3 n = gi.Normal; Vector3 n1 = (n * 1.25f - up * 0.25f).normalized; Vector3 n2 = (n * 0.5f + up * 0.5f).normalized; uvs[a] = new Vector2(n1.x, n1.z); uvs[c] = uvs[b] = new Vector2(n2.x, n2.z); uvs[d] = uvs[a]; uv2s[d] = uv2s[c] = uv2s[b] = uv2s[a] = new Vector2((float)(gi.Prototype) / (float)(GrassPrototypeMgr.s_PrototypeCount), 0); colors32[d] = colors32[c] = colors32[b] = colors32[a] = gi.ColorDw; } Mesh mesh = mf_inout.mesh; mesh.Clear(); mesh.vertices = verts; mesh.triangles = indices; mesh.normals = norms; mesh.uv = uvs; mesh.uv2 = uv2s; mesh.colors32 = colors32; return(offset + grasscount); }
/// <summary> /// Computes the grass mesh for [Billboard-set Tri-grass System]. /// </summary> /// <returns> /// Offset in 'grass_list' from where you can compute the next mesh. /// </returns> /// <param name='grass_list'> /// The grass instance list. /// </param> /// <param name='offset'> /// Offset in 'grass_list' from where you compute the mesh. /// </param> /// <param name='mf_inout'> /// [inout] The MeshFilter component receives the mesh. /// </param> public static int ComputeMesh(List <GrassInstance> grass_list, int offset, MeshFilter mf_inout) { //Win32.HiPerfTimer hitimer = new Win32.HiPerfTimer (); //hitimer.Start(); if (grass_list == null) { return(0); } offset = Mathf.Clamp(offset, 0, grass_list.Count); int grasspermesh = Mathf.Clamp(s_GrassCountPerMesh, 128, 5400); int grasscount = Mathf.Min(grasspermesh, grass_list.Count - offset); if (grasscount < 1) { return(grass_list.Count); } if (mf_inout == null) { return(grass_list.Count); } Vector3[] verts = new Vector3 [grasscount * 12]; Vector3[] norms = new Vector3 [grasscount * 12]; Vector2[] uvs = new Vector2 [grasscount * 12]; Vector2[] uv2s = new Vector2 [grasscount * 12]; Color32[] colors32 = new Color32 [grasscount * 12]; int[] indices = new int [grasscount * 18]; Vector3 A = new Vector3(-1, -1, 0); Vector3 B = new Vector3(-1, 1, 0); Vector3 C = new Vector3(1, 1, 0); Vector3 D = new Vector3(1, -1, 0); Vector3 up = Vector3.up; float _2pi = Mathf.PI * 2; float _page_interval = _2pi / 3; float angle_randomness = 0.3f; // float size_randomness = 0.3f; // float min_size = 0.85f; // float bias_randomness = 0.3f; // float min_bias = 0.1f; // float side_randomness = 2f; for (int i = 0; i < grasscount; ++i) { float phase = Random.value * _2pi; for (int p = 0; p < 3; ++p) { // float angle = angle_randomness * (Random.value - 0.5f) + p*_page_interval + phase; // float height = min_size + Random.value * size_randomness; // float width = min_size + Random.value * size_randomness; // float bias = Random.value * bias_randomness + min_bias; // float side = (Random.value - 0.5f) * side_randomness; // // float cos = width*Mathf.Cos(angle); // float sin = width*Mathf.Sin(angle); // float bias_x_up = (-sin*bias) * (1+side); // float bias_z_up = (cos*bias) * (1+side); // float bias_x_dn = (-sin*bias) * (1-side); // float bias_z_dn = (cos*bias) * (1-side); // // Vector3 A = new Vector3 (-cos + bias_x_dn, -height, -sin + bias_z_dn); // Vector3 B = new Vector3 (-cos + bias_x_up, height, -sin + bias_z_up); // Vector3 C = new Vector3 ( cos + bias_x_up, height, sin + bias_z_up); // Vector3 D = new Vector3 ( cos + bias_x_dn, -height, sin + bias_z_dn); int a = i * 12 + p * 4; int b = a + 1; int c = a + 2; int d = a + 3; int idx = i * 18 + p * 6; indices[idx + 0] = a; indices[idx + 1] = b; indices[idx + 2] = c; indices[idx + 3] = c; indices[idx + 4] = d; indices[idx + 5] = a; verts[a] = A; verts[b] = B; verts[c] = C; verts[d] = D; GrassInstance gi = grass_list[offset + i]; norms[d] = norms[c] = norms[b] = norms[a] = gi.Position; Vector3 n = gi.Normal; Vector3 n1 = (n * 1.1f - up * 0.1f).normalized; Vector3 n2 = (n * 0.5f + up * 0.5f).normalized; uvs[a] = new Vector2(n1.x, n1.z); uvs[c] = uvs[b] = new Vector2(n2.x, n2.z); uvs[d] = uvs[a]; uv2s[d] = uv2s[c] = uv2s[b] = uv2s[a] = new Vector2((float)(gi.Prototype) / (float)(GrassPrototypeMgr.s_PrototypeCount), p * _page_interval + phase + (Random.value - 0.5f) * angle_randomness); colors32[d] = colors32[c] = colors32[b] = colors32[a] = gi.ColorDw; } } Mesh mesh = mf_inout.mesh; mesh.Clear(); mesh.vertices = verts; mesh.triangles = indices; mesh.normals = norms; mesh.uv = uvs; mesh.uv2 = uv2s; mesh.colors32 = colors32; //hitimer.Stop(); //hitimer.PrintDuration("Compute Mesh"); return(offset + grasscount); }
void ReGen() { m_Grasses.Clear(); SimplexNoise noise = new SimplexNoise(); //Random.seed = Time.frameCount + Mathf.RoundToInt(Random.value*1000000); RaycastHit rch; for (int i = 0; i < m_GrassCount; i++) { Vector3 origin = new Vector3(Random.value, 1, Random.value) * m_GenAreaSize + m_StartCoord; // IntVector3 origin_i = new IntVector3(origin); // int hash = origin_i.GetHashCode(); // // if ( !m_map.ContainsKey(hash) ) // m_map.Add(hash, new List<GrassInstance>()); // if ( m_map[hash].Count > 1 ) // { // float p = Mathf.Pow(0.7f, (float)(m_map[hash].Count)); // if ( Random.value > p ) // continue; // } origin.y = 512f; if (Physics.Raycast(origin, Vector3.down, out rch, 1024, 1 << Pathea.Layer.VFVoxelTerrain)) { float nx = (float)(noise.Noise(rch.point.x / 32, rch.point.y / 32, rch.point.z / 32)) + 1; float ny = (float)(noise.Noise((rch.point.x + m_GenAreaSize) / 32, (rch.point.y + m_GenAreaSize) / 32, (rch.point.z + m_GenAreaSize) / 32)) + 1; float nz = (float)(noise.Noise(rch.point.y / 16, rch.point.z / 16, rch.point.x / 16)) + 1; nx = Mathf.Pow(nx, 15); ny = Mathf.Pow(ny, 15); nz = Mathf.Pow(nz, 15); float sum = nx + ny + nz; nx /= sum; ny /= sum; ny += nx; nz /= sum; nz += ny; GrassInstance gi = new GrassInstance(); gi.Position = rch.point; gi.Normal = rch.normal; gi.ColorF = m_GrassColor; float r = Random.value; if (r < nx) { gi.Prototype = m_ProtoType0; } else if (r < ny) { gi.Prototype = m_ProtoType1; } else if (r < nz) { gi.Prototype = m_ProtoType2; } m_Grasses.Add(gi); // m_map[hash].Add(gi); } } TrigrassMeshComputer.ComputeMesh(m_Grasses, 0, m_Mesh); m_Grasses.Clear(); }
static void SplatOcclusion(GrassPrototype grassPrototype, TreeInstance[] instances, TreePrototype[] prototypes, Material material, float terrainScale, bool nonTerrainInstances, Matrix4x4 worldToLocal) { if (!grassPrototype.m_Use) { return; } int instanceCount = 0; foreach (TreeInstance ti in instances) { if (prototypes[ti.prototypeIndex].prefab == grassPrototype.m_Prefab) { instanceCount++; } } List <GameObject> manualInstances = null; if (nonTerrainInstances) { manualInstances = FindAllPrefabInstances(grassPrototype.m_Prefab); instanceCount += manualInstances.Count; } if (instanceCount == 0) { return; } GrassInstance[] grassInstances = new GrassInstance[instanceCount]; Bounds bounds = grassPrototype.m_Prefab.GetComponent <LODGroup>().GetLODs()[0].renderers[0].GetComponent <MeshFilter>().sharedMesh.bounds; float sizex = bounds.extents.x + Mathf.Abs(bounds.center.x); float sizez = bounds.extents.z + Mathf.Abs(bounds.center.z); float size = Mathf.Max(sizex * grassPrototype.m_Prefab.transform.localScale.x, sizez * grassPrototype.m_Prefab.transform.localScale.z); size *= terrainScale; int i = 0; foreach (TreeInstance inst in instances) { //TreePrototype prototype = prototypes[ti.prototypeIndex]; if (prototypes[inst.prototypeIndex].prefab != grassPrototype.m_Prefab) { continue; } GrassInstance grassInstance = new GrassInstance(); Vector3 pos = inst.position; grassInstance.position = new Vector2(pos.x, pos.z); grassInstance.scale = inst.widthScale * size; grassInstance.rotation = inst.rotation; grassInstances[i] = grassInstance; i++; } if (nonTerrainInstances && manualInstances != null && manualInstances.Count > 0) { foreach (GameObject inst in manualInstances) { GrassInstance grassInstance = new GrassInstance(); Vector3 pos = inst.transform.position; pos = worldToLocal.MultiplyPoint3x4(pos); grassInstance.position = new Vector2(pos.x, pos.z); grassInstance.scale = inst.transform.localScale.x * size; grassInstance.rotation = inst.transform.rotation.eulerAngles.y * Mathf.Deg2Rad; grassInstances[i] = grassInstance; i++; } } ComputeBuffer grassInstancesCB = new ComputeBuffer(instanceCount, 16); grassInstancesCB.SetData(grassInstances); material.SetBuffer(UniformsBake._Instances, grassInstancesCB); Vector2[] verts = new Vector2[] { new Vector2(-1, -1), new Vector2(1, -1), new Vector2(1, 1), new Vector2(-1, -1), new Vector2(1, 1), new Vector2(-1, 1) }; int vertCount = verts.Length; ComputeBuffer vertsCB = new ComputeBuffer(vertCount, 8); vertsCB.SetData(verts); material.SetBuffer(UniformsBake._Verts, vertsCB); material.SetTexture(UniformsBake._Occlusion, grassPrototype.m_Occlusion); material.SetFloat(UniformsBake._Bias, grassPrototype.m_Bias); material.SetPass(0); Graphics.DrawProcedural(MeshTopology.Triangles, vertCount, instanceCount); vertsCB.Release(); }
public void Init() { var timeNow = DateTime.Now; Debug.Log("##### Start preparing simulation #####"); if (Settings == null) { Settings = new SimulationSettings(); } if (EditorSettings == null) { EditorSettings = new EditorSettings(); } if (CollisionCamera == null) { CollisionCamera = GameObject.FindWithTag("GrassSimulationCollisionCamera").GetComponent <Camera>(); } if (BillboardTextureCamera == null) { BillboardTextureCamera = GameObject.FindWithTag("BillboardTextureCamera").GetComponent <Camera>(); } BillboardTexturePatchContainer = null; BillboardTexturePatchContainer = CreateInstance <BillboardTexturePatchContainer>(); if (BladeContainer == null) { BladeContainer = CreateInstance <BladeContainer>(); } BladeContainer.Init(this); BlossomCount = BladeContainer.GetBlossomCount(); var timeTextureArrays = DateTime.Now; BladeTexture2DArray0 = BladeContainer.GetGeoemetryTexture2DArray(0); BladeTexture2DArray1 = BladeContainer.GetGeoemetryTexture2DArray(2); BlossomTexture2DArray0 = BladeContainer.GetGeoemetryTexture2DArray(1); BlossomTexture2DArray1 = BladeContainer.GetGeoemetryTexture2DArray(3); Debug.Log("\t Created Texture Arrays for LookUp- and Surface-Textures for " + BladeContainer.Blades.Length + " Blades and " + BlossomCount + " Blossoms in " + (int)(DateTime.Now - timeTextureArrays).TotalMilliseconds + "ms"); if (!Transform || !Camera || !CollisionCamera || !BillboardTextureCamera || !GrassSimulationComputeShader || !CollisionDepthShader || !GrassSimulationShader || !DimensionsInput || !GrassMapInput || !HeightInput || !NormalInput || !PositionInput || !PatchContainer || BladeTexture2DArray0 == null || BladeTexture2DArray1 == null) { Debug.LogWarning("GrassSimulation: Not all dependencies are set."); if (!Transform) { Debug.Log("GrassSimulation: Transform not set."); } if (!Camera) { Debug.Log("GrassSimulation: Camera not set."); } if (!CollisionCamera) { Debug.Log("GrassSimulation: Could not find Camera on GameObject with Tag GrassSimulationCollisionCamera"); } if (!BillboardTextureCamera) { Debug.Log("GrassSimulation: Could not find Camera on GameObject with Tag BillboardTextureCamera"); } if (!GrassSimulationComputeShader) { Debug.Log("GrassSimulation: GrassSimulationComputeShader not set."); } if (!CollisionDepthShader) { Debug.Log("GrassSimulation: CollisionDepthShader not set."); } if (!GrassSimulationShader) { Debug.Log("GrassSimulation: GrassSimulationShader not set."); } if (!DimensionsInput) { Debug.Log("GrassSimulation: DimensionsInput not set."); } if (!GrassMapInput) { Debug.Log("GrassSimulation: GrassMapInput not set."); } if (!HeightInput) { Debug.Log("GrassSimulation: HeightInput not set."); } if (!NormalInput) { Debug.Log("GrassSimulation: NormalInput not set."); } if (!PositionInput) { Debug.Log("GrassSimulation: PositionInput not set."); } if (!PatchContainer) { Debug.Log("GrassSimulation: PatchContainer not set."); } if (BladeTexture2DArray0 == null || BladeTexture2DArray1 == null) { Debug.Log("GrassSimulation: No Grass Blades set. Cannot create Textures."); } IsReady = false; return; } //Create a single random object Random = new Random(Settings.RandomSeed); //Find kernels for ComputeShaders KernelPhysics = GrassSimulationComputeShader.FindKernel("PhysicsMain"); KernelSimulationSetup = GrassSimulationComputeShader.FindKernel("SimulationSetup"); //Create Material Variants GrassGeometry = new Material(GrassSimulationShader); GrassBillboardGeneration = new Material(GrassGeometry); GrassBillboardCrossed = new Material(GrassGeometry); GrassBillboardScreen = new Material(GrassGeometry); //if (BlossomCount > 0) //{ GrassBlossom = new Material(GrassGeometry); GrassBlossomBillboardGeneration = new Material(GrassGeometry); GrassBlossom.EnableKeyword("GRASS_BLOSSOM"); GrassBlossom.DisableKeyword("GRASS_GEOMETRY"); GrassBlossom.DisableKeyword("GRASS_BILLBOARD_CROSSED"); GrassBlossom.DisableKeyword("GRASS_BILLBOARD_SCREEN"); GrassBlossom.SetTexture("GrassBlossom0", BlossomTexture2DArray0); GrassBlossom.SetTexture("GrassBlossom1", BlossomTexture2DArray1); GrassBlossom.SetInt("EnableHeightTransition", Settings.EnableHeightTransition ? 1 : 0); GrassBlossom.SetInt("VertexCount", (int)Settings.GetMinAmountBladesPerPatch()); GrassBlossom.SetInt("BlossomCount", BlossomCount); GrassBlossom.SetFloat("BladeTextureMaxMipmapLevel", Settings.BladeTextureMaxMipmapLevel); GrassBlossom.SetFloat("BladeHeightCullingThreshold", Settings.BladeHeightCullingThreshold); GrassBlossom.SetFloat("LodTessellationMax", Settings.LodTessellationMax); GrassBlossom.SetFloat("LodInstancesGeometry", Settings.LodInstancesGeometry / (float)Settings.LodGeometryTransitionSegments); GrassBlossom.SetFloat("LodGeometryTransitionSegments", Settings.LodGeometryTransitionSegments); GrassBlossom.SetFloat("LodDistanceGeometryStart", Settings.LodDistanceGeometryStart); GrassBlossom.SetFloat("LodDistanceGeometryEnd", Settings.LodDistanceGeometryEnd); GrassBlossom.SetFloat("LodTessellationMin", Settings.LodTessellationMin); GrassBlossom.SetFloat("LodTessellationMax", Settings.LodTessellationMax); GrassBlossom.SetFloat("LodDistanceTessellationMin", Settings.LodDistanceTessellationMin); GrassBlossom.SetFloat("LodDistanceTessellationMax", Settings.LodDistanceTessellationMax); GrassBlossomBillboardGeneration.EnableKeyword("BILLBOARD_GENERATION"); GrassBlossomBillboardGeneration.EnableKeyword("GRASS_BLOSSOM"); GrassBlossomBillboardGeneration.DisableKeyword("GRASS_GEOMETRY"); GrassBlossomBillboardGeneration.DisableKeyword("GRASS_BILLBOARD_CROSSED"); GrassBlossomBillboardGeneration.DisableKeyword("GRASS_BILLBOARD_SCREEN"); GrassBlossomBillboardGeneration.SetTexture("GrassBlossom0", BlossomTexture2DArray0); GrassBlossomBillboardGeneration.SetTexture("GrassBlossom1", BlossomTexture2DArray1); GrassBlossomBillboardGeneration.SetInt("EnableHeightTransition", Settings.EnableHeightTransition ? 1 : 0); GrassBlossomBillboardGeneration.SetInt("VertexCount", (int)Settings.BillboardGrassCount); GrassBlossomBillboardGeneration.SetInt("BlossomCount", BlossomCount); GrassBlossomBillboardGeneration.SetFloat("BladeTextureMaxMipmapLevel", Settings.BladeTextureMaxMipmapLevel); GrassBlossomBillboardGeneration.SetFloat("BladeHeightCullingThreshold", Settings.BladeHeightCullingThreshold); GrassBlossomBillboardGeneration.SetFloat("LodTessellationMax", Settings.LodTessellationMax); GrassBlossomBillboardGeneration.SetFloat("LodInstancesGeometry", Settings.LodInstancesGeometry / (float)Settings.LodGeometryTransitionSegments); GrassBlossomBillboardGeneration.SetFloat("LodGeometryTransitionSegments", Settings.LodGeometryTransitionSegments); //GrassBlossomBillboardGeneration.SetFloat("LodDistanceGeometryStart", 0); GrassBlossomBillboardGeneration.SetFloat("LodDistanceGeometryStart", 1); GrassBlossomBillboardGeneration.SetFloat("LodDistanceGeometryEnd", 100); GrassBlossomBillboardGeneration.SetFloat("LodTessellationMin", Settings.LodTessellationMin); GrassBlossomBillboardGeneration.SetFloat("LodTessellationMax", Settings.LodTessellationMax); GrassBlossomBillboardGeneration.SetFloat("LodDistanceTessellationMin", Settings.LodDistanceTessellationMin); GrassBlossomBillboardGeneration.SetFloat("LodDistanceTessellationMax", Settings.LodDistanceTessellationMax); /*} else * { * GrassBlossom = null; * GrassBlossomBillboardGeneration = null; * }*/ GrassGeometry.EnableKeyword("GRASS_GEOMETRY"); GrassGeometry.DisableKeyword("GRASS_BLOSSOM"); GrassGeometry.DisableKeyword("GRASS_BILLBOARD_CROSSED"); GrassGeometry.DisableKeyword("GRASS_BILLBOARD_SCREEN"); GrassGeometry.SetTexture("GrassBlades0", BladeTexture2DArray0); GrassGeometry.SetTexture("GrassBlades1", BladeTexture2DArray1); GrassGeometry.SetInt("EnableHeightTransition", Settings.EnableHeightTransition ? 1 : 0); GrassGeometry.SetInt("VertexCount", (int)Settings.GetMinAmountBladesPerPatch()); GrassGeometry.SetFloat("BladeTextureMaxMipmapLevel", Settings.BladeTextureMaxMipmapLevel); GrassGeometry.SetFloat("BladeHeightCullingThreshold", Settings.BladeHeightCullingThreshold); GrassGeometry.SetFloat("LodTessellationMax", Settings.LodTessellationMax); GrassGeometry.SetFloat("LodInstancesGeometry", Settings.LodInstancesGeometry / (float)Settings.LodGeometryTransitionSegments); GrassGeometry.SetFloat("LodGeometryTransitionSegments", Settings.LodGeometryTransitionSegments); GrassGeometry.SetFloat("LodDistanceGeometryStart", Settings.LodDistanceGeometryStart); GrassGeometry.SetFloat("LodDistanceGeometryEnd", Settings.LodDistanceGeometryEnd); GrassGeometry.SetFloat("LodTessellationMin", Settings.LodTessellationMin); GrassGeometry.SetFloat("LodTessellationMax", Settings.LodTessellationMax); GrassGeometry.SetFloat("LodDistanceTessellationMin", Settings.LodDistanceTessellationMin); GrassGeometry.SetFloat("LodDistanceTessellationMax", Settings.LodDistanceTessellationMax); GrassBillboardGeneration.EnableKeyword("BILLBOARD_GENERATION"); GrassBillboardGeneration.EnableKeyword("GRASS_GEOMETRY"); GrassBillboardGeneration.DisableKeyword("GRASS_BLOSSOM"); GrassBillboardGeneration.DisableKeyword("GRASS_BILLBOARD_CROSSED"); GrassBillboardGeneration.DisableKeyword("GRASS_BILLBOARD_SCREEN"); GrassBillboardGeneration.SetTexture("GrassBlades0", BladeTexture2DArray0); GrassBillboardGeneration.SetTexture("GrassBlades1", BladeTexture2DArray1); GrassBillboardGeneration.SetInt("EnableHeightTransition", Settings.EnableHeightTransition ? 1 : 0); GrassBillboardGeneration.SetInt("VertexCount", (int)Settings.BillboardGrassCount); GrassBillboardGeneration.SetFloat("BladeTextureMaxMipmapLevel", Settings.BladeTextureMaxMipmapLevel); GrassBillboardGeneration.SetFloat("BladeHeightCullingThreshold", Settings.BladeHeightCullingThreshold); GrassBillboardGeneration.SetFloat("LodTessellationMax", Settings.LodTessellationMax); GrassBillboardGeneration.SetFloat("LodInstancesGeometry", Settings.LodInstancesGeometry / (float)Settings.LodGeometryTransitionSegments); GrassBillboardGeneration.SetFloat("LodGeometryTransitionSegments", Settings.LodGeometryTransitionSegments); //GrassBillboardGeneration.SetFloat("LodDistanceGeometryStart", 0); GrassBillboardGeneration.SetFloat("LodDistanceGeometryStart", 1); GrassBillboardGeneration.SetFloat("LodDistanceGeometryEnd", 100); GrassBillboardGeneration.SetFloat("LodTessellationMin", Settings.LodTessellationMin); GrassBillboardGeneration.SetFloat("LodTessellationMax", Settings.LodTessellationMax); GrassBillboardGeneration.SetFloat("LodDistanceTessellationMin", Settings.LodDistanceTessellationMin); GrassBillboardGeneration.SetFloat("LodDistanceTessellationMax", Settings.LodDistanceTessellationMax); GrassBillboardCrossed.SetOverrideTag("Queue", "AlphaTest"); GrassBillboardCrossed.SetOverrideTag("RenderType", "TransparentCutout"); GrassBillboardCrossed.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); GrassBillboardCrossed.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); //GrassBillboardCrossed.SetInt("_ZWrite", 0); GrassBillboardCrossed.SetInt("_AlphaToMask", 1); GrassBillboardCrossed.renderQueue = 3000; GrassBillboardCrossed.DisableKeyword("GRASS_GEOMETRY"); GrassBillboardCrossed.DisableKeyword("GRASS_BLOSSOM"); GrassBillboardCrossed.EnableKeyword("GRASS_BILLBOARD_CROSSED"); GrassBillboardCrossed.DisableKeyword("GRASS_BILLBOARD_SCREEN"); GrassBillboardCrossed.SetTexture("GrassBlades0", BladeTexture2DArray0); GrassBillboardCrossed.SetInt("EnableHeightTransition", Settings.EnableHeightTransition ? 1 : 0); GrassBillboardCrossed.SetInt("VertexCount", (int)Settings.GetMinAmountBillboardsPerPatch()); GrassBillboardCrossed.SetFloat("BillboardAlphaCutoff", Settings.BillboardAlphaCutoff); GrassBillboardCrossed.SetFloat("BillboardHeightAdjustment", Settings.BillboardHeightAdjustment); GrassBillboardCrossed.SetFloat("BladeHeightCullingThreshold", Settings.BladeHeightCullingThreshold); GrassBillboardCrossed.SetFloat("LodInstancesBillboardCrossed", Settings.LodInstancesBillboardCrossed / (float)Settings.LodBillboardCrossedTransitionSegments); GrassBillboardCrossed.SetFloat("LodBillboardCrossedTransitionSegments", Settings.LodBillboardCrossedTransitionSegments); GrassBillboardCrossed.SetFloat("LodDistanceBillboardCrossedStart", Settings.LodDistanceBillboardCrossedStart); GrassBillboardCrossed.SetFloat("LodDistanceBillboardCrossedPeak", Settings.LodDistanceBillboardCrossedPeak); GrassBillboardCrossed.SetFloat("LodDistanceBillboardCrossedEnd", Settings.LodDistanceBillboardCrossedEnd); GrassBillboardScreen.SetOverrideTag("Queue", "AlphaTest"); GrassBillboardScreen.SetOverrideTag("RenderType", "TransparentCutout"); GrassBillboardScreen.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); GrassBillboardScreen.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); //GrassBillboardScreen.SetInt("_ZWrite", 0); GrassBillboardScreen.SetInt("_AlphaToMask", 1); GrassBillboardScreen.renderQueue = 2900; GrassBillboardScreen.DisableKeyword("GRASS_GEOMETRY"); GrassBillboardScreen.DisableKeyword("GRASS_BLOSSOM"); GrassBillboardScreen.DisableKeyword("GRASS_BILLBOARD_CROSSED"); GrassBillboardScreen.EnableKeyword("GRASS_BILLBOARD_SCREEN"); GrassBillboardScreen.SetTexture("GrassBlades0", BladeTexture2DArray0); GrassBillboardScreen.SetInt("EnableHeightTransition", Settings.EnableHeightTransition ? 1 : 0); GrassBillboardScreen.SetInt("VertexCount", (int)Settings.GetMinAmountBillboardsPerPatch()); GrassBillboardScreen.SetFloat("BillboardAlphaCutoff", Settings.BillboardAlphaCutoff); GrassBillboardScreen.SetFloat("BillboardHeightAdjustment", Settings.BillboardHeightAdjustment); GrassBillboardScreen.SetFloat("BladeHeightCullingThreshold", Settings.BladeHeightCullingThreshold); GrassBillboardScreen.SetFloat("LodInstancesBillboardScreen", Settings.LodInstancesBillboardScreen / (float)Settings.LodBillboardScreenTransitionSegments); GrassBillboardScreen.SetFloat("LodBillboardScreenTransitionSegments", Settings.LodBillboardScreenTransitionSegments); GrassBillboardScreen.SetFloat("LodDistanceBillboardScreenStart", Settings.LodDistanceBillboardScreenStart); GrassBillboardScreen.SetFloat("LodDistanceBillboardScreenPeak", Settings.LodDistanceBillboardScreenPeak); GrassBillboardScreen.SetFloat("LodDistanceBillboardScreenEnd", Settings.LodDistanceBillboardScreenEnd); GrassSimulationComputeShader.SetInt("WindLayerCount", Settings.WindLayerCount); GrassSimulationComputeShader.SetFloat("GrassDataResolution", Settings.GrassDataResolution); GrassSimulationComputeShader.SetFloat("BladeHeightCullingThreshold", Settings.BladeHeightCullingThreshold); GrassSimulationComputeShader.SetFloat("RecoveryFactor", Settings.RecoveryFactor); GrassSimulationComputeShader.SetFloat("LodTessellationMin", Settings.LodTessellationMin); GrassSimulationComputeShader.SetFloat("LodTessellationMax", Settings.LodTessellationMax); GrassSimulationComputeShader.SetFloat("LodDistanceTessellationMin", Settings.LodDistanceTessellationMin); GrassSimulationComputeShader.SetFloat("LodDistanceTessellationMax", Settings.LodDistanceTessellationMax); //If possible initialize the Data Providers // ReSharper disable SuspiciousTypeConversion.Global if (DimensionsInput is IInitializableWithCtx) { ((IInitializableWithCtx)DimensionsInput).Init(this); } else if (DimensionsInput is IInitializable) { ((IInitializable)DimensionsInput).Init(); } if (GrassMapInput is IInitializableWithCtx) { ((IInitializableWithCtx)GrassMapInput).Init(this); } else if (GrassMapInput is IInitializable) { ((IInitializable)GrassMapInput).Init(); } if (HeightInput is IInitializableWithCtx) { ((IInitializableWithCtx)HeightInput).Init(this); } else if (HeightInput is IInitializable) { ((IInitializable)HeightInput).Init(); } if (NormalInput is IInitializableWithCtx) { ((IInitializableWithCtx)NormalInput).Init(this); } else if (NormalInput is IInitializable) { ((IInitializable)NormalInput).Init(); } if (PositionInput is IInitializableWithCtx) { ((IInitializableWithCtx)PositionInput).Init(this); } else if (PositionInput is IInitializable) { ((IInitializable)PositionInput).Init(); } GrassInstance = new GrassInstance(this); var timePatchConstruction = DateTime.Now; PatchContainer.Init(this); PatchContainer.SetupContainer(); Debug.Log("\t Created and initialized " + (Settings.PatchSize * Settings.PatchSize) + " patches and hierarchy in " + (int)(DateTime.Now - timePatchConstruction).TotalMilliseconds + "ms"); CollisionTextureRenderer = new CollisionTextureRenderer(this, PatchContainer.GetBounds()); if (WindManager == null) { WindManager = new WindManager(this); } else { WindManager.InitBuffer(); } WindManager.Update(); //ProceduralWind = new ProceduralWind(this); //ProceduralWind.Update(); var timeBillboardTextures = DateTime.Now; //Create Billboard Textures BillboardTexturePatchContainer.Init(this); BillboardTexturePatchContainer.SetupContainer(); BillboardTexturePatchContainer.Draw(); Debug.Log("\t Rendered Billboard Textures in " + (int)(DateTime.Now - timeBillboardTextures).TotalMilliseconds + "ms"); //Needs to be reset here, since BillboardTexturePatchContainer sets its own NormalHeightTexture GrassSimulationComputeShader.SetTexture(KernelPhysics, "NormalHeightTexture", GrassInstance.NormalHeightTexture); GrassSimulationComputeShader.SetTexture(KernelSimulationSetup, "NormalHeightTexture", GrassInstance.NormalHeightTexture); GrassBillboardCrossed.SetTexture("GrassBillboards", BillboardTexturePatchContainer.BillboardTextures); GrassBillboardCrossed.SetTexture("GrassBillboardNormals", BillboardTexturePatchContainer.BillboardNormals); GrassBillboardCrossed.SetFloat("BillboardAspect", BillboardTexturePatchContainer.BillboardAspect); GrassBillboardCrossed.SetInt("RepetitionCount", (int)PositionInput.GetRepetitionCount()); GrassBillboardScreen.SetTexture("GrassBillboards", BillboardTexturePatchContainer.BillboardTextures); GrassBillboardScreen.SetTexture("GrassBillboardNormals", BillboardTexturePatchContainer.BillboardNormals); GrassBillboardScreen.SetFloat("BillboardAspect", BillboardTexturePatchContainer.BillboardAspect); GrassBillboardScreen.SetInt("RepetitionCount", (int)PositionInput.GetRepetitionCount()); Debug.Log("\t Finished Simulation Preperation in " + (int)(DateTime.Now - timeNow).TotalMilliseconds + "ms"); Settings.LogSettings(); //Everything is ready. IsReady = true; }
public static void BatchesFromParticles() { List <float[]> particlesInfo = new List <float[]>(); Console.WriteLine("Insert the name of the file to load"); string filepath = Console.ReadLine(); float posXmax = float.MinValue; float posXmin = float.MaxValue; float posYmax = float.MinValue; float posYmin = float.MaxValue; float posZmax = float.MinValue; float posZmin = float.MaxValue; BinaryReader reader = new BinaryReader(File.OpenRead(filepath)); while (reader.BaseStream.Position != reader.BaseStream.Length) { float posx = reader.ReadSingle(); float posy = reader.ReadSingle(); float posz = reader.ReadSingle(); float dirx = reader.ReadSingle(); float diry = reader.ReadSingle(); float[] pInfo = new float[5] { posx, posy, posz, dirx, diry }; //Console.WriteLine("POS: {0},{1},{2} DIR:{3},{4}", posx, posy, posz, dirx, diry); particlesInfo.Add(pInfo); posXmax = Math.Max(posXmax, posx); posXmin = Math.Min(posXmin, posx); posYmax = Math.Max(posYmax, posy); posYmin = Math.Min(posYmin, posy); posZmax = Math.Max(posZmax, posz); posZmin = Math.Min(posZmin, posz); } reader.Close(); if (particlesInfo == null || !particlesInfo.Any()) { return; } Random rnd = new Random(); List <string> archetypes = new List <string>() { "proc_brittlebush_01", "proc_desert_sage_01", "proc_drygrasses01", "proc_drygrasses01b", "proc_drygrassfronds01", "proc_dryplantsgrass_01", "proc_dryplantsgrass_02", "proc_dry_plants_01", "proc_forest_grass01", "proc_forest_ivy_01", "proc_grassdandelion01", "proc_grasses01", "proc_grasses01b", "proc_grassfronds01", "proc_grassplantmix_01", "proc_grassplantmix_02", "proc_indian_pbrush_01", "proc_leafybush_01", "proc_leafyplant_01", "proc_lizardtail_01", "proc_lupins_01", "proc_meadowmix_01", "proc_meadowpoppy_01", "proc_sage_01", "proc_scrub_bush01", "proc_sml_reeds_01", "proc_sml_reeds_01b", "proc_sml_reeds_01c", "proc_stones_01", "proc_stones_02", "proc_stones_03", "proc_stones_04", "proc_stones_05", "proc_stones_06", "proc_wildquinine", "prop_dandy_b", "prop_dryweed_001_a", "prop_dryweed_002_a", "prop_fernba", "prop_fernbb", "prop_flowerweed_005_a", "prop_grass_001_a", "prop_grass_ca", "prop_grass_da", "prop_log_aa", "prop_log_ab", "prop_log_ac", "prop_log_ad", "prop_log_ae", "prop_log_af", "prop_saplin_001_b", "prop_saplin_001_c", "prop_saplin_002_b", "prop_saplin_002_c", "prop_small_bushyba", "prop_tall_drygrass_aa", "prop_tall_grass_ba", "prop_thindesertfiller_aa", "prop_weed_001_aa", "prop_weed_002_ba", "urbandryfrnds_01", "urbandrygrass_01", "urbangrnfrnds_01", "urbangrngrass_01", "urbanweeds01", "urbanweeds01_l1", "urbanweeds02", "urbanweeds02_l1" }; string archetype = archetypes[rnd.Next(0, archetypes.Count() - 1)]; Vector3 batchSize = new Vector3(100, 100, 75); Vector3 bbmax = new Vector3(posXmax, posYmax, posZmax); Vector3 bbmin = new Vector3(posXmin, posYmin, posZmin); Vector3 numblocks = (bbmax - bbmin) / batchSize; //Console.WriteLine("{0},{1},{2}",numblocks.X,numblocks.Y,numblocks.Z); int blockX = (int)(numblocks.X + 1); int blockY = (int)(numblocks.Y + 1); int blockZ = (int)(numblocks.Z + 1); Ymap map = new Ymap("instancedData"); map.CMapData.contentFlags = 1088; map.CMapData.physicsDictionaries.Add("v_proc1"); for (int x = -blockX; x <= blockX; x++) { for (int y = -blockY; y <= blockY; y++) { for (int z = -blockZ; z <= blockZ; z++) { IEnumerable <float[]> currentBatch = Enumerable.Empty <float[]>(); float maxX = (x + 1) * batchSize.X; float minX = x * batchSize.X; float maxY = (y + 1) * batchSize.Y; float minY = y * batchSize.Y; float maxZ = (z + 1) * batchSize.Z; float minZ = z * batchSize.Z; ///Console.WriteLine("maxX:{0},minX{1},maxY{2},minY{3},maxZ{4},minZ{5}",maxX,minX,maxY,minY,maxZ,minZ); currentBatch = particlesInfo.Where(a => a[0] < maxX && a[0] >= minX && a[1] < maxY && a[1] >= minY && a[2] < maxZ && a[2] >= minZ).ToList(); // Console.WriteLine(currentBatch.Count()); if (currentBatch?.Any() ?? false) { BatchAABB aabb = new BatchAABB(new Vector4(minX, minY, minZ, 0), new Vector4(maxX, maxY, maxZ, 0)); GrassInstance grassBatch = new GrassInstance(archetype); grassBatch.BatchAABB = aabb; foreach (float[] inst in currentBatch) { Vector4 worldPos = new Vector4(inst[0], inst[1], inst[2], 0); Vector4 batchPos = (worldPos - aabb.min) / (aabb.max - aabb.min) * 65535; byte NormalX = (byte)((inst[3] + 1) * 0.5 * 255); byte NormalY = (byte)((inst[4] + 1) * 0.5 * 255); byte[] color = new byte[3] { 150, 150, 150 }; byte scale = (byte)rnd.Next(0, 255);; Instance i = new Instance(new ushort[] { (ushort)batchPos.X, (ushort)batchPos.Y, (ushort)batchPos.Z }, NormalX, NormalY, color, scale); grassBatch.InstanceList.Add(i); } map.CMapData.instancedData.GrassInstanceList.Add(grassBatch); } } } } map.UpdateExtents(new List <CBaseArchetypeDef>()); Console.WriteLine("Total batches: {0}", map.CMapData.instancedData.GrassInstanceList.Count); Console.WriteLine("Total instances: {0}", particlesInfo.Count); map.WriteXML().Save("grass.ymap.xml"); Console.WriteLine("Exported grass.ymap.xml"); }