public static void Render( RenderTexture rt, GConditionalStampLayer layer, GStylizedTerrain terrain, Matrix4x4 stamperTransform, Texture mask, Texture falloffTexture, Vector2[] uvPoints, bool useTerrainMask) { GCommon.ClearRT(rt); if (layer.Ignore) { return; } Material brushMat = GInternalMaterials.TextureStamperBrushMaterial; int resolution = Mathf.Max(rt.width, rt.height); //no need to release these maps RenderTexture heightMap = terrain.GetHeightMap(resolution); RenderTexture normalMap = layer.NormalMapMode == GNormalMapMode.Sharp ? terrain.GetSharpNormalMap(resolution) : layer.NormalMapMode == GNormalMapMode.Interpolated ? terrain.GetInterpolatedNormalMap(resolution) : layer.NormalMapMode == GNormalMapMode.PerPixel ? terrain.GetPerPixelNormalMap(resolution) : null; brushMat.SetTexture("_HeightMap", heightMap); Vector3 position = stamperTransform.MultiplyPoint(Vector3.zero); Vector3 scale = stamperTransform.lossyScale; float stamperMinHeight = terrain.WorldPointToNormalized(position).y; float stamperMaxHeight = terrain.WorldPointToNormalized(position + Vector3.up * scale.y).y; brushMat.SetFloat("_StamperMinHeight", stamperMinHeight); brushMat.SetFloat("_StamperMaxHeight", stamperMaxHeight); Vector3 terrainSize = new Vector3( terrain.TerrainData.Geometry.Width, terrain.TerrainData.Geometry.Height, terrain.TerrainData.Geometry.Length); brushMat.SetTexture("_Mask", mask); brushMat.SetTexture("_Falloff", falloffTexture); brushMat.SetFloat("_MinHeight", GUtilities.InverseLerpUnclamped(0, terrainSize.y, layer.MinHeight)); brushMat.SetFloat("_MaxHeight", GUtilities.InverseLerpUnclamped(0, terrainSize.y, layer.MaxHeight)); brushMat.SetTexture("_HeightTransition", layer.heightTransitionTexture); brushMat.SetFloat("_MinSlope", layer.MinSlope * Mathf.Deg2Rad); brushMat.SetFloat("_MaxSlope", layer.MaxSlope * Mathf.Deg2Rad); brushMat.SetTexture("_SlopeTransition", layer.slopeTransitionTexture); brushMat.SetVector("_NoiseOrigin", layer.NoiseOrigin); brushMat.SetFloat("_NoiseFrequency", layer.NoiseFrequency); brushMat.SetInt("_NoiseOctaves", layer.NoiseOctaves); brushMat.SetFloat("_NoiseLacunarity", layer.NoiseLacunarity); brushMat.SetFloat("_NoisePersistence", layer.NoisePersistence); brushMat.SetTexture("_NoiseRemap", layer.noiseRemapTexture); brushMat.SetTexture("_NormalMap", normalMap); if (useTerrainMask) { brushMat.SetTexture("_TerrainMask", terrain.TerrainData.Mask.MaskMap); } else { brushMat.SetTexture("_TerrainMask", Texture2D.blackTexture); } GCommon.SetMaterialKeywordActive(brushMat, BLEND_HEIGHT_KW, layer.BlendHeight); GCommon.SetMaterialKeywordActive(brushMat, BLEND_SLOPE_KW, layer.BlendSlope); GCommon.SetMaterialKeywordActive(brushMat, BLEND_NOISE_KW, layer.BlendNoise); DrawOnBrushTexture(rt, uvPoints, brushMat, 0); }
private void SpawnObjectOnTerrain(GStylizedTerrain t, Color[] maskData, int layerIndex) { GObjectStampLayer layer = Layers[layerIndex]; Vector3 centerPos = Vector3.zero; Vector3 samplePos = Vector3.zero; Vector2 uv = Vector2.zero; float maskValue = 0; Vector3 terrainSize = new Vector3( t.TerrainData.Geometry.Width, t.TerrainData.Geometry.Height, t.TerrainData.Geometry.Length); Vector3 scale = new Vector3( GUtilities.InverseLerpUnclamped(0, terrainSize.x, Scale.x), 1, GUtilities.InverseLerpUnclamped(0, terrainSize.z, Scale.z)); Matrix4x4 matrix = Matrix4x4.TRS( t.WorldPointToNormalized(Position), Rotation, scale); int index = -1; int instanceCount = 0; int attempt = 0; int maxAttempt = layer.InstanceCount * 100; RaycastHit hit; #if UNITY_EDITOR string title = "Stamping on " + t.name; string info = string.Format("Layer: {0}", !string.IsNullOrEmpty(layer.Name) ? layer.Name : layerIndex.ToString()); int currentPercent = 0; int attemptPercent = 0; int instancePercent = 0; GCommonGUI.CancelableProgressBar(title, info, 0); #endif while (instanceCount < layer.InstanceCount && attempt <= maxAttempt) { attempt += 1; #if UNITY_EDITOR attemptPercent = (int)(attempt * 100.0f / maxAttempt); instancePercent = (int)(instanceCount * 100.0f / layer.InstanceCount); if (currentPercent != Mathf.Max(attemptPercent, instancePercent)) { currentPercent = Mathf.Max(attemptPercent, instancePercent); GCommonGUI.CancelableProgressBar(title, string.Format("{0} ... {1}%", info, currentPercent), currentPercent / 100.0f); } #endif index = layer.PrototypeIndices[Random.Range(0, layer.PrototypeIndices.Count)]; if (index < 0 || index >= layer.Prototypes.Count) { continue; } GameObject g = layer.Prototypes[index]; if (g == null) { continue; } centerPos.Set(Random.value - 0.5f, 0, Random.value - 0.5f); samplePos = matrix.MultiplyPoint(centerPos); if (samplePos.x < 0 || samplePos.x > 1 || samplePos.z < 0 || samplePos.z > 1) { continue; } uv.Set(samplePos.x, samplePos.z); maskValue = GUtilities.GetColorBilinear(maskData, MaskResolution, MaskResolution, uv).r; if (Random.value > maskValue) { continue; } if (t.Raycast(samplePos, out hit)) { GameObject instance = GSpawner.Spawn(t, g, hit.point); instance.transform.rotation = Quaternion.Euler(0, Random.Range(layer.MinRotation, layer.MaxRotation), 0); instance.transform.localScale = Vector3.Lerp(layer.MinScale, layer.MaxScale, Random.value); if (layer.AlignToSurface) { instance.transform.up = hit.normal; } instanceCount += 1; } } #if UNITY_EDITOR GCommonGUI.ClearProgressBar(); #endif }
private void DrawOnTexture(RenderTexture rt, Material mat, int pass, List <Vector4> worldPoints, GStylizedTerrain t) { Vector4 worldOffset = new Vector4(0, HeightOffset, 0, 0); List <Vector4> normalizedPoints = new List <Vector4>(); for (int i = 0; i < worldPoints.Count; ++i) { Vector3 v = t.WorldPointToNormalized(worldPoints[i] + worldOffset); normalizedPoints.Add(new Vector4(Mathf.Clamp01(v.x), Mathf.Clamp01(v.y), Mathf.Clamp01(v.z), worldPoints[i].w)); } RenderTexture.active = rt; GL.PushMatrix(); GL.LoadOrtho(); GL.Begin(GL.TRIANGLES); int trisCount = worldPoints.Count / 3; GCommon.SetMaterialKeywordActive(mat, "FALLOFF", true); mat.SetPass(pass); for (int i = 0; i < trisCount; ++i) { Vector4 v0 = worldPoints[i * 3 + 0]; Vector4 v1 = worldPoints[i * 3 + 1]; Vector4 v2 = worldPoints[i * 3 + 2]; if (v0.w == 0 || v1.w == 0 || v2.w == 0) { Vector4 vn0 = normalizedPoints[i * 3 + 0]; Vector4 vn1 = normalizedPoints[i * 3 + 1]; Vector4 vn2 = normalizedPoints[i * 3 + 2]; GL.MultiTexCoord3(0, vn0.x, vn0.z, vn0.y); GL.MultiTexCoord3(1, v0.x, v0.z, v0.y); GL.Color(new Color(vn0.w, vn0.w, vn0.w, vn0.w)); GL.Vertex3(vn0.x, vn0.z, vn0.y); GL.MultiTexCoord3(0, vn1.x, vn1.z, vn1.y); GL.MultiTexCoord3(1, v1.x, v1.z, v1.y); GL.Color(new Color(vn1.w, vn1.w, vn1.w, vn1.w)); GL.Vertex3(vn1.x, vn1.z, vn1.y); GL.MultiTexCoord3(0, vn2.x, vn2.z, vn2.y); GL.MultiTexCoord3(1, v2.x, v2.z, v2.y); GL.Color(new Color(vn2.w, vn2.w, vn2.w, vn2.w)); GL.Vertex3(vn2.x, vn2.z, vn2.y); } } GL.End(); GL.Begin(GL.TRIANGLES); GCommon.SetMaterialKeywordActive(mat, "FALLOFF", false); mat.SetPass(pass); for (int i = 0; i < trisCount; ++i) { Vector4 v0 = worldPoints[i * 3 + 0]; Vector4 v1 = worldPoints[i * 3 + 1]; Vector4 v2 = worldPoints[i * 3 + 2]; if (v0.w != 0 && v1.w != 0 && v2.w != 0) { Vector4 vn0 = normalizedPoints[i * 3 + 0]; Vector4 vn1 = normalizedPoints[i * 3 + 1]; Vector4 vn2 = normalizedPoints[i * 3 + 2]; GL.MultiTexCoord3(0, vn0.x, vn0.z, vn0.y); GL.MultiTexCoord3(1, v0.x, v0.z, v0.y); GL.Color(new Color(vn0.w, vn0.w, vn0.w, vn0.w)); GL.Vertex3(vn0.x, vn0.z, vn0.y); GL.MultiTexCoord3(0, vn1.x, vn1.z, vn1.y); GL.MultiTexCoord3(1, v1.x, v1.z, v1.y); GL.Color(new Color(vn1.w, vn1.w, vn1.w, vn1.w)); GL.Vertex3(vn1.x, vn1.z, vn1.y); GL.MultiTexCoord3(0, vn2.x, vn2.z, vn2.y); GL.MultiTexCoord3(1, v2.x, v2.z, v2.y); GL.Color(new Color(vn2.w, vn2.w, vn2.w, vn2.w)); GL.Vertex3(vn2.x, vn2.z, vn2.y); } } GL.End(); GL.PopMatrix(); RenderTexture.active = null; }
private void HandleSpawnGrass(GStylizedTerrain terrain, GFoliagePainterArgs args) { int grassIndex = -1; Vector3 randomPos = Vector3.zero; Vector3 rayOrigin = Vector3.zero; Vector3 rayDirection = Vector3.down; float sqrtTwo = Mathf.Sqrt(2); Ray ray = new Ray(); RaycastHit samplePoint; Vector3 bary0 = Vector3.zero; Vector3 bary1 = Vector3.zero; Vector2 maskUv = Vector2.zero; Color maskColor = Color.white; Texture2D clonedMask = null; if (args.Mask != null) { clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256); } int sampleCount = Mathf.Clamp(args.Density * args.Density / 10, 1, 1000); List <GGrassInstance> newInstances = new List <GGrassInstance>(); for (int i = 0; i < sampleCount; ++i) { grassIndex = args.GrassIndices[Random.Range(0, args.GrassIndices.Count)]; randomPos = args.HitPoint + Random.insideUnitSphere * args.Radius * sqrtTwo; rayOrigin.Set( randomPos.x, 10000, randomPos.z); ray.origin = rayOrigin; ray.direction = rayDirection; if (terrain.Raycast(ray, out samplePoint, float.MaxValue)) { GUtilities.CalculateBarycentricCoord( new Vector2(samplePoint.point.x, samplePoint.point.z), new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z), new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z), new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z), ref bary0); GUtilities.CalculateBarycentricCoord( new Vector2(samplePoint.point.x, samplePoint.point.z), new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z), new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z), new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z), ref bary1); if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0) { maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one; } else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0) { maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right; } else { continue; } //sample mask if (clonedMask != null) { maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y); if (Random.value > maskColor.grayscale) { continue; } } //apply filter GSpawnFilterArgs filterArgs = GSpawnFilterArgs.Create(); filterArgs.Terrain = terrain; filterArgs.Position = samplePoint.point; filterArgs.SurfaceNormal = samplePoint.normal; filterArgs.SurfaceTexcoord = samplePoint.textureCoord; List <Type> suitableFilter = SuitableFilterTypes; if (args.Filters != null) { for (int fIndex = 0; fIndex < args.Filters.Length; ++fIndex) { if (args.Filters[fIndex] != null && args.Filters[fIndex].Ignore != true) { if (suitableFilter.Contains(args.Filters[fIndex].GetType())) { args.Filters[fIndex].Apply(ref filterArgs); } } if (filterArgs.ShouldExclude) { break; } } } //spawn if (filterArgs.ShouldExclude) { continue; } GGrassInstance grass = GGrassInstance.Create(grassIndex); grass.Position = terrain.WorldPointToNormalized(filterArgs.Position); grass.Rotation = filterArgs.Rotation; grass.Scale = filterArgs.Scale; newInstances.Add(grass); } } terrain.TerrainData.Foliage.AddGrassInstances(newInstances); if (clonedMask != null) { Object.DestroyImmediate(clonedMask); } }