This commit is contained in:
CortexCore
2024-05-17 16:24:41 +08:00
parent 81913ff82f
commit e2650195a5
186 changed files with 72475 additions and 1 deletions

View File

@@ -0,0 +1,119 @@
//////////////////////////////////////////////////////
// MicroSplat
// Copyright (c) Jason Booth
//////////////////////////////////////////////////////
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace JBooth.MicroSplat
{
#if __MICROSPLAT__ && (__MICROSPLAT_STREAMS__ || __MICROSPLAT_GLOBALTEXTURE__ || __MICROSPLAT_SNOW__ || __MICROSPLAT_SCATTER__ || __MICROSPLAT_PROCTEX__ || __MICROSPLAT_MEGA__)
public class TerrainPaintJob : ScriptableObject
{
public Terrain terrain;
public Texture2D streamTex;
public Texture2D tintTex;
public Texture2D snowTex;
public Texture2D scatterTex;
public Texture2D biomeMask;
public Texture2D biomeMask2;
public Texture2D megaSplat;
public Collider collider;
public byte [] streamBuffer;
public byte [] tintBuffer;
public byte [] snowBuffer;
public byte [] scatterBuffer;
public byte [] biomeMaskBuffer;
public byte [] biomeMaskBuffer2;
public byte [] megaBuffer;
public void RegisterUndo()
{
bool undo = false;
if (streamTex != null)
{
streamBuffer = streamTex.GetRawTextureData();
undo = true;
}
if (tintTex != null)
{
tintBuffer = tintTex.GetRawTextureData ();
undo = true;
}
if (snowTex != null)
{
snowBuffer = snowTex.GetRawTextureData ();
undo = true;
}
if (scatterTex != null)
{
scatterBuffer = scatterTex.GetRawTextureData ();
undo = true;
}
if (biomeMask != null)
{
biomeMaskBuffer = biomeMask.GetRawTextureData ();
undo = true;
}
if (biomeMask2 != null)
{
biomeMaskBuffer2 = biomeMask2.GetRawTextureData ();
undo = true;
}
if (megaSplat != null)
{
megaBuffer = megaSplat.GetRawTextureData();
undo = true;
}
if (undo)
{
UnityEditor.Undo.RegisterCompleteObjectUndo(this, "Terrain Edit");
}
}
public void RestoreUndo()
{
if (streamBuffer != null && streamBuffer.Length > 0)
{
streamTex.LoadRawTextureData(streamBuffer);
streamTex.Apply();
}
if (tintTex != null && tintBuffer.Length > 0)
{
tintTex.LoadRawTextureData (tintBuffer);
tintTex.Apply ();
}
if (snowBuffer != null && snowBuffer.Length > 0)
{
snowTex.LoadRawTextureData (streamBuffer);
snowTex.Apply ();
}
if (scatterBuffer != null && scatterBuffer.Length > 0)
{
scatterTex.LoadRawTextureData (scatterBuffer);
scatterTex.Apply ();
}
if (biomeMask != null && biomeMaskBuffer.Length > 0)
{
biomeMask.LoadRawTextureData (biomeMaskBuffer);
biomeMask.Apply ();
}
if (biomeMask2 != null && biomeMaskBuffer2.Length > 0)
{
biomeMask.LoadRawTextureData (biomeMaskBuffer2);
biomeMask.Apply ();
}
if (megaSplat != null && megaBuffer.Length > 0)
{
megaSplat.LoadRawTextureData(megaBuffer);
megaSplat.Apply();
}
}
}
#endif
}

View File

@@ -0,0 +1,278 @@
//////////////////////////////////////////////////////
// MicroSplat
// Copyright (c) Jason Booth
//////////////////////////////////////////////////////
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
namespace JBooth.MicroSplat
{
#if __MICROSPLAT__ && (__MICROSPLAT_STREAMS__ || __MICROSPLAT_GLOBALTEXTURE__ || __MICROSPLAT_SNOW__ || __MICROSPLAT_SCATTER__ || __MICROSPLAT_PROCTEX__ || __MICROSPLAT_MEGA__)
public partial class TerrainPainterWindow : EditorWindow
{
[MenuItem("Window/MicroSplat/Terrain FX Painter")]
public static void ShowWindow()
{
var window = GetWindow<JBooth.MicroSplat.TerrainPainterWindow>();
window.InitTerrains();
window.Show();
}
bool enabled = true;
TerrainPaintJob[] terrains;
bool[] jobEdits;
TerrainPaintJob FindJob (Terrain t)
{
if (terrains == null || t == null)
return null;
for (int i = 0; i < terrains.Length; ++i)
{
if (terrains[i] != null && terrains[i].terrain == t)
return terrains[i];
}
return null;
}
List<Terrain> rawTerrains = new List<Terrain>();
void InitTerrains()
{
Object[] objs = Selection.GetFiltered(typeof(Terrain), SelectionMode.Editable | 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");
bool hasMega = t.materialTemplate.HasProperty("_MegaSplatTexture");
if (!hasSnow && !hasStream && !hasTint && !hasScatter && !hasBiome && !hasBiome2 && !hasMega)
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
#if __MICROSPLAT_MEGA__
if (hasMega && mst.megaSplatMap == null)
{
mst.megaSplatMap = CreateTexture(t, mst.megaSplatMap, "_megasplat", new Color(0, 0, 0, 0), true, false);
}
#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_MEGA__
tj.megaSplat = mst.megaSplatMap;
#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_MEGA__
tj.megaSplat = mst.megaSplatMap;
#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 OnSelectionChange()
{
InitTerrains();
this.Repaint();
}
void OnFocus()
{
#if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui -= this.OnSceneGUI;
SceneView.duringSceneGui += this.OnSceneGUI;
#else
SceneView.onSceneGUIDelegate -= this.OnSceneGUI;
SceneView.onSceneGUIDelegate += this.OnSceneGUI;
#endif
Undo.undoRedoPerformed -= this.OnUndo;
Undo.undoRedoPerformed += this.OnUndo;
UnityEditor.SceneManagement.EditorSceneManager.sceneSaving -= OnSceneSaving;
UnityEditor.SceneManagement.EditorSceneManager.sceneSaving += OnSceneSaving;
this.titleContent = new GUIContent("MicroSplat Terrain FX Painter");
InitTerrains();
Repaint();
}
public static void SaveTexture (Texture2D tex)
{
if (tex != null)
{
string path = AssetDatabase.GetAssetPath (tex);
if (path.EndsWith(".tga"))
{
AssetImporter ai = AssetImporter.GetAtPath(path);
TextureImporter ti = ai as TextureImporter;
if (ti.textureCompression == TextureImporterCompression.Uncompressed &&
ti.isReadable)
{
var bytes = tex.EncodeToTGA();
System.IO.File.WriteAllBytes(path, bytes);
}
}
else
{
Debug.LogError(path + " is not a TGA file");
}
}
}
void SaveAll ()
{
if (terrains == null)
return;
for (int i = 0; i < terrains.Length; ++i)
{
SaveTexture (terrains [i].streamTex);
SaveTexture (terrains [i].tintTex);
SaveTexture (terrains [i].snowTex);
SaveTexture (terrains [i].scatterTex);
SaveTexture (terrains [i].biomeMask);
SaveTexture (terrains [i].biomeMask2);
SaveTexture (terrains [i].megaSplat);
}
AssetDatabase.Refresh ();
}
void OnSceneSaving (UnityEngine.SceneManagement.Scene scene, string path)
{
SaveAll ();
}
void OnUndo()
{
if (terrains == null)
return;
for (int i = 0; i < terrains.Length; ++i)
{
if (terrains[i] != null)
{
terrains[i].RestoreUndo();
}
}
Repaint();
}
void OnInspectorUpdate()
{
// unfortunate...
Repaint ();
}
void OnDestroy()
{
#if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui -= this.OnSceneGUI;
#else
SceneView.onSceneGUIDelegate -= this.OnSceneGUI;
#endif
terrains = null;
}
}
#endif
}

View File

@@ -0,0 +1,484 @@
//////////////////////////////////////////////////////
// MicroSplat
// Copyright (c) Jason Booth
//////////////////////////////////////////////////////
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
namespace JBooth.MicroSplat
{
#if __MICROSPLAT__ && (__MICROSPLAT_STREAMS__ || __MICROSPLAT_GLOBALTEXTURE__ || __MICROSPLAT_SNOW__ || __MICROSPLAT_SCATTER__ || __MICROSPLAT_PROCTEX__ || __MICROSPLAT_MEGA__)
public partial class TerrainPainterWindow : EditorWindow
{
double deltaTime = 0;
double lastTime = 0;
bool painting = false;
public Vector3 oldpos = Vector3.zero;
public float brushSize = 1;
public float brushFlow = 8;
public float brushFalloff = 1; // linear
public Color paintColor = Color.grey;
public float paintValue = 1;
public int biomeChannel = 0;
[System.Serializable]
public enum MegaLayerMode
{
Bottom,
Top,
Auto
}
[System.Serializable]
public enum MegaBrushMode
{
Single,
Cluster,
Blend
}
[System.Serializable]
public class ClusterBrush
{
public List<int> textures = new List<int>();
public float frequency = 1;
public float offset;
}
public int megaIndex = 0;
public MegaLayerMode megaLayerMode = MegaLayerMode.Auto;
public MegaBrushMode megaBrushMode = MegaBrushMode.Single;
public ClusterBrush clusterBrush = new ClusterBrush();
public System.Action<TerrainPaintJob []> OnBeginStroke;
public System.Action<TerrainPaintJob, bool> OnStokeModified; // bool is true when doing a fill or other non-bounded opperation
public System.Action OnEndStroke;
public enum BrushVisualization
{
Sphere,
Disk
}
public BrushVisualization brushVisualization = BrushVisualization.Sphere;
public Vector2 lastMousePosition;
void OnSceneGUI(SceneView sceneView)
{
deltaTime = EditorApplication.timeSinceStartup - lastTime;
lastTime = EditorApplication.timeSinceStartup;
if (terrains == null || terrains.Length == 0 && Selection.activeGameObject != null)
{
InitTerrains();
}
if (!enabled || terrains.Length == 0 || Selection.activeGameObject == null)
{
return;
}
RaycastHit hit;
float distance = float.MaxValue;
Vector3 mousePosition = Event.current.mousePosition;
// So, in 5.4, Unity added this value, which is basically a scale to mouse coordinates for retna monitors.
// Not all monitors, just some of them.
// What I don't get is why the fuck they don't just pass me the correct fucking value instead. I spent hours
// finding this, and even the paid Unity support my company pays many thousands of dollars for had no idea
// after several weeks of back and forth. If your going to fake the coordinates for some reason, please do
// it everywhere to not just randomly break things everywhere you don't multiply some new value in.
float mult = EditorGUIUtility.pixelsPerPoint;
mousePosition.y = sceneView.camera.pixelHeight - mousePosition.y * mult;
mousePosition.x *= mult;
Vector3 fakeMP = mousePosition;
fakeMP.z = 20;
Vector3 point = sceneView.camera.ScreenToWorldPoint(fakeMP);
Vector3 normal = Vector3.forward;
Ray ray = sceneView.camera.ScreenPointToRay(mousePosition);
bool registerUndo = (Event.current.type == EventType.MouseDown && Event.current.button == 0 && Event.current.alt == false);
for (int i = 0; i < terrains.Length; ++i)
{
if (terrains[i] == null)
continue;
// Early out if we're not in the area..
var cld = terrains[i].collider;
Bounds b = cld.bounds;
b.Expand(brushSize*2);
if (!b.IntersectRay(ray))
{
continue;
}
if (registerUndo)
{
painting = true;
for (int x = 0; x < jobEdits.Length; ++x)
{
jobEdits[x] = false;
}
if (i == 0 && OnBeginStroke != null)
{
OnBeginStroke(terrains);
}
}
if (cld.Raycast(ray, out hit, float.MaxValue))
{
if (Event.current.shift == false)
{
if (hit.distance < distance)
{
distance = hit.distance;
point = hit.point;
normal = hit.normal;
}
}
else
{
point = oldpos;
}
}
else
{
if (Event.current.shift == true)
{
point = oldpos;
}
}
}
if (Event.current.type == EventType.MouseMove && Event.current.shift)
{
brushSize += Event.current.delta.x * (float)deltaTime * 6.0f;
brushFalloff -= Event.current.delta.y * (float)deltaTime * 48.0f;
}
if (Event.current.rawType == EventType.MouseUp)
{
EndStroke();
}
if (Event.current.type == EventType.MouseMove && Event.current.alt)
{
brushSize += Event.current.delta.y * (float)deltaTime;
}
if (brushVisualization == BrushVisualization.Sphere)
{
Handles.SphereHandleCap(0, point, Quaternion.identity, brushSize * 2, EventType.Repaint);
}
else
{
Handles.color = new Color(0.8f, 0, 0, 1.0f);
float r = Mathf.Pow(0.5f, brushFalloff);
Handles.DrawWireDisc(point, normal, brushSize * r);
Handles.color = new Color(0.9f, 0, 0, 0.8f);
Handles.DrawWireDisc(point, normal, brushSize);
}
// eat current event if mouse event and we're painting
if (Event.current.isMouse && painting)
{
Event.current.Use();
}
if (Event.current.type == EventType.Layout)
{
HandleUtility.AddDefaultControl(GUIUtility.GetControlID(GetHashCode(), FocusType.Passive));
}
// only paint once per frame
if (Event.current.type != EventType.Repaint)
{
return;
}
if (terrains.Length > 0 && painting)
{
for (int i = 0; i < terrains.Length; ++i)
{
Bounds b = terrains[i].collider.bounds;
b.Expand(brushSize * 2);
if (!b.IntersectRay(ray))
{
continue;
}
if (jobEdits[i] == false)
{
jobEdits[i] = true;
terrains[i].RegisterUndo();
}
PaintTerrain(terrains[i], point);
if (OnStokeModified != null)
{
OnStokeModified(terrains[i], false);
}
}
}
lastMousePosition = Event.current.mousePosition;
// update views
sceneView.Repaint();
HandleUtility.Repaint();
}
void EndStroke()
{
painting = false;
if (OnEndStroke != null)
{
OnEndStroke();
}
}
public static Vector3 WorldToTerrain(Terrain ter, Vector3 point, Texture2D splatControl)
{
float x = (point.x / ter.terrainData.size.x) * splatControl.width;
float z = (point.z / ter.terrainData.size.z) * splatControl.height;
float y = ter.terrainData.GetHeight((int)x, (int)z);
return new Vector3(x, y, z);
}
public static Vector3 TerrainToWorld(Terrain ter, int x, int y, Texture2D splatControl)
{
Vector3 wp = new Vector3(x, 0, y);
wp.x *= ter.terrainData.size.x / (float)splatControl.width;
wp.y = ter.terrainData.GetHeight(x, y);
wp.z *= ter.terrainData.size.z / (float)splatControl.height;
wp += ter.transform.position;
return wp;
}
void MegaBrush(Texture2D tex, int x, int y, float finalStr)
{
Color data = tex.GetPixel(x, y);
int index0 = Mathf.RoundToInt(data.r * 256);
int index1 = Mathf.RoundToInt(data.g * 256);
float weight = data.b;
if (megaBrushMode != MegaBrushMode.Blend)
{
if (megaBrushMode == MegaBrushMode.Cluster)
{
float px = (float)x / (tex.width) * 128;
float py = (float)y / (tex.height) * 128;
float v = Mathf.PerlinNoise(px * clusterBrush.frequency + clusterBrush.offset, py * clusterBrush.frequency - clusterBrush.offset);
v = Mathf.Clamp01(v);
int idx = (int)(v * clusterBrush.textures.Count);
if (idx >= clusterBrush.textures.Count)
{
idx = clusterBrush.textures.Count - 1;
}
megaIndex = clusterBrush.textures[idx];
}
if (megaLayerMode == MegaLayerMode.Auto)
{
// replace lowest weight if we're new.
if (megaIndex != index0 && megaIndex != index1)
{
if (weight >= 0.5f)
{
index0 = megaIndex;
}
else
{
index1 = megaIndex;
}
}
if (megaIndex == index0)
{
weight -= finalStr;
}
else
{
weight += finalStr;
}
}
else if (megaLayerMode == MegaLayerMode.Bottom)
{
index0 = megaIndex;
weight -= finalStr;
}
else
{
index1 = megaIndex;
weight += finalStr;
}
}
else if (megaBrushMode == MegaBrushMode.Blend)
{
weight = Mathf.Lerp(weight, paintValue, finalStr);
}
weight = Mathf.Clamp01(weight);
data.r = (float)index0 / 255.0f;
data.g = (float)index1 / 255.0f;
data.b = weight;
tex.SetPixel(x, y, data);
}
void PaintTerrain(TerrainPaintJob tj, Vector3 worldPoint)
{
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 (tab == Tab.Scatter)
{
filtered = false;
}
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);
}
else if (tab == Tab.Scatter)
{
Color c = tex.GetPixel (x, y);
#if __MICROSPLAT_SCATTER__
if (scatterLayer == ScatterLayer.First)
{
c.r = (float)(scatterIndex + 1) / 64.0f;
c.g = Mathf.Lerp (c.g, paintValue, finalStr);
if (c.g <= 0)
{
c.r = 0;
}
}
else
{
c.a = (float)(scatterIndex + 1) / 64.0f;
c.b = Mathf.Lerp (c.b, paintValue, finalStr);
if (c.b <= 0)
{
c.a = 0;
}
}
#endif
tex.SetPixel (x, y, c);
}
else if (tab == Tab.Biome)
{
Color c = tex.GetPixel (x, y);
int ch = biomeChannel;
if (ch > 3)
ch -= 4;
c[ch] = Mathf.Lerp(c[ch], paintValue, finalStr);
tex.SetPixel (x, y, c);
}
else if (tab == Tab.Mega)
{
MegaBrush(tex, x, y, finalStr);
}
}
}
}
}
tex.Apply();
}
}
}
#endif
}