void FillTerrain(TerrainPaintJob t, float val) { InitTerrains(); t.RegisterUndo(); Texture2D tex = null; int channel = -1; // this means paint in RGB GetTexAndChannel(t, out tex, out channel); if (tex == null) { return; } int width = tex.width; int height = tex.height; for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { var c = tex.GetPixel(x, y); Vector3 normal = t.terrain.terrainData.GetInterpolatedNormal((float)x / tex.width, (float)y / tex.height); float dt = Vector3.Dot(normal, Vector3.up); dt = 1 - Mathf.Clamp01(dt); bool filtered = dt <slopeRange.x || dt> slopeRange.y; if (!filtered) { if (channel == -1) { if (val < float.Epsilon) { c.r = Color.grey.r; c.g = Color.grey.g; c.b = Color.grey.b; } else { c.r = paintColor.r; c.g = paintColor.g; c.b = paintColor.b; } tex.SetPixel(x, y, c); } else { c [channel] = val; tex.SetPixel(x, y, c); } } } } tex.Apply(); }
void GetTexAndChannel(TerrainPaintJob t, out Texture2D tex, out int channel) { channel = -1; tex = null; switch (tab) { case Tab.TintMap: { tex = t.tintTex; break; } case Tab.SnowMin: { tex = t.snowTex; channel = 1; break; } case Tab.SnowMax: { tex = t.snowTex; channel = 0; break; } case Tab.Wetness: { tex = t.streamTex; channel = 0; break; } case Tab.Puddles: { tex = t.streamTex; channel = 1; break; } case Tab.Streams: { tex = t.streamTex; channel = 2; break; } case Tab.Lava: { tex = t.streamTex; channel = 3; break; } } }
void InitTerrains() { Object[] objs = Selection.GetFiltered(typeof(Terrain), SelectionMode.Editable | SelectionMode.OnlyUserModifiable | SelectionMode.Deep); List <TerrainPaintJob> ts = new List <TerrainPaintJob> (); rawTerrains.Clear(); for (int i = 0; i < objs.Length; ++i) { Terrain t = objs[i] as Terrain; MicroSplatTerrain mst = t.GetComponent <MicroSplatTerrain>(); if (mst == null) { continue; } rawTerrains.Add(t); if (t.materialTemplate != null) { bool hasStream = t.materialTemplate.HasProperty("_StreamControl"); bool hasSnow = t.materialTemplate.HasProperty("_SnowMask"); bool hasTint = t.materialTemplate.HasProperty("_GlobalTintTex"); bool hasScatter = t.materialTemplate.HasProperty("_ScatterControl"); bool hasBiome = t.materialTemplate.HasProperty("_ProcTexBiomeMask"); bool hasBiome2 = t.materialTemplate.HasProperty("_ProcTexBiomeMask2"); if (!hasSnow && !hasStream && !hasTint && !hasScatter && !hasBiome && !hasBiome2) { continue; } #if __MICROSPLAT_STREAMS__ if (hasStream && mst.streamTexture == null) { mst.streamTexture = CreateTexture(t, mst.streamTexture, "_stream_data", new Color(0, 0, 0, 0), true); } #endif #if __MICROSPLAT_SNOW__ if (hasSnow && mst.snowMaskOverride == null) { mst.snowMaskOverride = CreateTexture(t, mst.snowMaskOverride, "_snowmask", new Color(1, 0, 0, 1), true); } #endif #if __MICROSPLAT_SCATTER__ if (hasScatter && mst.scatterMapOverride == null) { mst.scatterMapOverride = CreateTexture(t, mst.scatterMapOverride, "_scatter", new Color(0, 0, 0, 1), true); } #endif var tj = FindJob(t); if (tj != null) { tj.collider = t.GetComponent <Collider>(); #if __MICROSPLAT_STREAMS__ tj.streamTex = mst.streamTexture; #endif #if __MICROSPLAT_GLOBALTEXTURE__ tj.tintTex = mst.tintMapOverride; #endif #if __MICROSPLAT_SNOW__ tj.snowTex = mst.snowMaskOverride; #endif #if __MICROSPLAT_SCATTER__ tj.scatterTex = mst.scatterMapOverride; #endif #if __MICROSPLAT_PROCTEX__ tj.biomeMask = mst.procBiomeMask; tj.biomeMask2 = mst.procBiomeMask2; #endif ts.Add(tj); } else { tj = TerrainPaintJob.CreateInstance <TerrainPaintJob> (); tj.terrain = t; tj.collider = t.GetComponent <Collider>(); #if __MICROSPLAT_STREAMS__ tj.streamTex = mst.streamTexture; #endif #if __MICROSPLAT_GLOBALTEXTURE__ tj.tintTex = mst.tintMapOverride; #endif #if __MICROSPLAT_SNOW__ tj.snowTex = mst.snowMaskOverride; #endif #if __MICROSPLAT_SCATTER__ tj.scatterTex = mst.scatterMapOverride; #endif #if __MICROSPLAT_PROCTEX__ tj.biomeMask = mst.procBiomeMask; tj.biomeMask2 = mst.procBiomeMask2; #endif ts.Add(tj); } } } if (terrains != null) { // clear out old terrains for (int i = 0; i < terrains.Length; ++i) { if (!ts.Contains(terrains[i])) { DestroyImmediate(terrains[i]); } } } terrains = ts.ToArray(); jobEdits = new bool[ts.Count]; }
void PaintTerrain(TerrainPaintJob tj, Vector3 worldPoint, Vector2 uv) { if (tj == null) { return; } // convert point into local space, so we don't have to convert every point var mtx = Matrix4x4.TRS(tj.terrain.transform.position, tj.terrain.transform.rotation, Vector3.one).inverse; Vector3 localPoint = mtx.MultiplyPoint3x4(worldPoint); float bz = brushSize; float pressure = Event.current.pressure > 0 ? Event.current.pressure : 1.0f; Texture2D tex = null; int channel = -1; GetTexAndChannel(tj, out tex, out channel); if (tex == null) { return; } Vector3 terPoint = WorldToTerrain(tj.terrain, localPoint, tex); if (terPoint.x >= 0 && terPoint.z >= 0 && terPoint.x < tex.width || terPoint.z < tex.height) { // scale brush into texture space Vector3 offsetPnt = localPoint - new Vector3(bz, 0, bz); Vector3 beginTerPnt = WorldToTerrain(tj.terrain, offsetPnt, tex); beginTerPnt.x = Mathf.Clamp(beginTerPnt.x, 0, tex.width); beginTerPnt.z = Mathf.Clamp(beginTerPnt.z, 0, tex.height); Vector3 offset = terPoint - beginTerPnt; int pbx = (int)beginTerPnt.x; int pby = (int)beginTerPnt.z; int pex = (int)(terPoint.x + offset.x * 2.0f); int pey = (int)(terPoint.z + offset.z * 2.0f); pex = Mathf.Clamp(pex, 0, tex.width); pey = Mathf.Clamp(pey, 0, tex.height); for (int x = pbx; x < pex; ++x) { for (int y = pby; y < pey; ++y) { float h = tj.terrain.terrainData.GetHeight(x, y); float d = Vector3.Distance(terPoint, new Vector3(x, h, y)); float str = 1.0f - d / bz; str = Mathf.Pow(str, brushFalloff); float finalStr = str * (float)deltaTime * brushFlow * pressure; if (finalStr > 0) { Vector3 normal = tj.terrain.terrainData.GetInterpolatedNormal((float)x / tex.width, (float)y / tex.height); float dt = Vector3.Dot(normal, Vector3.up); dt = 1 - Mathf.Clamp01(dt); bool filtered = dt <slopeRange.x || dt> slopeRange.y; if (!filtered) { if (tab == Tab.TintMap) { Color c = tex.GetPixel(x, y); c.r = Mathf.Lerp(c.r, paintColor.r, finalStr); c.g = Mathf.Lerp(c.g, paintColor.g, finalStr); c.b = Mathf.Lerp(c.b, paintColor.b, finalStr); tex.SetPixel(x, y, c); } else if (tab == Tab.SnowMin) { Color c = tex.GetPixel(x, y); c.g = Mathf.Lerp(c.g, paintValue, finalStr); tex.SetPixel(x, y, c); } else if (tab == Tab.SnowMax) { Color c = tex.GetPixel(x, y); c.r = Mathf.Lerp(c.r, paintValue, finalStr); tex.SetPixel(x, y, c); } else if (tab == Tab.Wetness) { Color c = tex.GetPixel(x, y); c.r = Mathf.Lerp(c.r, paintValue, finalStr); tex.SetPixel(x, y, c); } else if (tab == Tab.Puddles) { Color c = tex.GetPixel(x, y); c.g = Mathf.Lerp(c.g, paintValue, finalStr); tex.SetPixel(x, y, c); } else if (tab == Tab.Streams) { Color c = tex.GetPixel(x, y); c.b = Mathf.Lerp(c.b, paintValue, finalStr); tex.SetPixel(x, y, c); } else if (tab == Tab.Lava) { Color c = tex.GetPixel(x, y); c.a = Mathf.Lerp(c.a, paintValue, finalStr); tex.SetPixel(x, y, c); } } } } } tex.Apply(); } }
void GetTexAndChannel(TerrainPaintJob t, out Texture2D tex, out int channel) { channel = -1; tex = null; switch (tab) { case Tab.TintMap: { tex = t.tintTex; break; } case Tab.SnowMin: { tex = t.snowTex; channel = 1; break; } case Tab.SnowMax: { tex = t.snowTex; channel = 0; break; } case Tab.Wetness: { tex = t.streamTex; channel = 0; break; } case Tab.Puddles: { tex = t.streamTex; channel = 1; break; } case Tab.Streams: { tex = t.streamTex; channel = 2; break; } case Tab.Lava: { tex = t.streamTex; channel = 3; break; } case Tab.Scatter: { tex = t.scatterTex; channel = -2; break; } case Tab.Biome: { tex = t.biomeMask; channel = biomeChannel; if (channel > 3) { channel -= 4; if (t.biomeMask2 != null) { tex = t.biomeMask2; } } break; } } }