using System; using System.Collections.Generic; using System.Linq; using Es.InkPainter.Effective; using UnityEngine; namespace Es.InkPainter { [RequireComponent(typeof(Renderer))] [DisallowMultipleComponent] public class InkCanvas : MonoBehaviour { [Serializable] public class PaintSet { [NonSerialized] [HideInInspector] public Material material; [SerializeField] [Tooltip("The property name of the main texture.")] public string mainTextureName = "_MainTex"; [SerializeField] [Tooltip("Normal map texture property name.")] public string normalTextureName = "_BumpMap"; [SerializeField] [Tooltip("The property name of the heightmap texture.")] public string heightTextureName = "_ParallaxMap"; [SerializeField] [Tooltip("Whether or not use main texture paint.")] public bool useMainPaint = true; [SerializeField] [Tooltip("Whether or not use normal map paint (you need material on normal maps).")] public bool useNormalPaint; [SerializeField] [Tooltip("Whether or not use heightmap painting (you need material on the heightmap).")] public bool useHeightPaint; [NonSerialized] [HideInInspector] public Texture mainTexture; [NonSerialized] [HideInInspector] public RenderTexture paintMainTexture; [NonSerialized] [HideInInspector] public Texture normalTexture; [NonSerialized] [HideInInspector] public RenderTexture paintNormalTexture; [NonSerialized] [HideInInspector] public Texture heightTexture; [NonSerialized] [HideInInspector] public RenderTexture paintHeightTexture; [NonSerialized] [HideInInspector] public int mainTexturePropertyID; [NonSerialized] [HideInInspector] public int normalTexturePropertyID; [NonSerialized] [HideInInspector] public int heightTexturePropertyID; public PaintSet() { } public PaintSet(string mainTextureName, string normalTextureName, string heightTextureName, bool useMainPaint, bool useNormalPaint, bool useHeightPaint) { this.mainTextureName = mainTextureName; this.normalTextureName = normalTextureName; this.heightTextureName = heightTextureName; this.useMainPaint = useMainPaint; this.useNormalPaint = useNormalPaint; this.useHeightPaint = useHeightPaint; } public PaintSet(string mainTextureName, string normalTextureName, string heightTextureName, bool useMainPaint, bool useNormalPaint, bool useHeightPaint, Material material) : this(mainTextureName, normalTextureName, heightTextureName, useMainPaint, useNormalPaint, useHeightPaint) { this.material = material; } } private static Material paintMainMaterial; private static Material paintNormalMaterial; private static Material paintHeightMaterial; private bool eraseFlag; private RenderTexture debugEraserMainView; private RenderTexture debugEraserNormalView; private RenderTexture debugEraserHeightView; private bool eraserDebug; [SerializeField] private List paintSet; private int paintUVPropertyID; private int brushTexturePropertyID; private int brushScalePropertyID; private int brushRotatePropertyID; private int brushColorPropertyID; private int brushNormalTexturePropertyID; private int brushNormalBlendPropertyID; private int brushHeightTexturePropertyID; private int brushHeightBlendPropertyID; private int brushHeightColorPropertyID; private const string COLOR_BLEND_USE_CONTROL = "INK_PAINTER_COLOR_BLEND_USE_CONTROL"; private const string COLOR_BLEND_USE_BRUSH = "INK_PAINTER_COLOR_BLEND_USE_BRUSH"; private const string COLOR_BLEND_NEUTRAL = "INK_PAINTER_COLOR_BLEND_NEUTRAL"; private const string COLOR_BLEND_ALPHA_ONLY = "INK_PAINTER_COLOR_BLEND_ALPHA_ONLY"; private const string NORMAL_BLEND_USE_BRUSH = "INK_PAINTER_NORMAL_BLEND_USE_BRUSH"; private const string NORMAL_BLEND_ADD = "INK_PAINTER_NORMAL_BLEND_ADD"; private const string NORMAL_BLEND_SUB = "INK_PAINTER_NORMAL_BLEND_SUB"; private const string NORMAL_BLEND_MIN = "INK_PAINTER_NORMAL_BLEND_MIN"; private const string NORMAL_BLEND_MAX = "INK_PAINTER_NORMAL_BLEND_MAX"; private const string DXT5NM_COMPRESS_USE = "DXT5NM_COMPRESS_USE"; private const string DXT5NM_COMPRESS_UNUSE = "DXT5NM_COMPRESS_UNUSE"; private const string HEIGHT_BLEND_USE_BRUSH = "INK_PAINTER_HEIGHT_BLEND_USE_BRUSH"; private const string HEIGHT_BLEND_ADD = "INK_PAINTER_HEIGHT_BLEND_ADD"; private const string HEIGHT_BLEND_SUB = "INK_PAINTER_HEIGHT_BLEND_SUB"; private const string HEIGHT_BLEND_MIN = "INK_PAINTER_HEIGHT_BLEND_MIN"; private const string HEIGHT_BLEND_MAX = "INK_PAINTER_HEIGHT_BLEND_MAX"; private const string HEIGHT_BLEND_COLOR_RGB_HEIGHT_A = "INK_PAINTER_HEIGHT_BLEND_COLOR_RGB_HEIGHT_A"; private MeshOperator meshOperator; public List PaintDatas { get { return paintSet; } set { paintSet = value; } } public MeshOperator MeshOperator { get { if (meshOperator == null) { Debug.LogError("To take advantage of the features must Mesh filter or Skinned mesh renderer component associated Mesh."); } return meshOperator; } } public event Action OnCanvasAttached; public event Action OnInitializedStart; public event Action OnInitializedAfter; public event Action OnPaintStart; public event Action OnPaintEnd; private void Awake() { if (this.OnCanvasAttached != null) { this.OnCanvasAttached(this); } InitPropertyID(); SetMaterial(); SetTexture(); MeshDataCache(); } private void Start() { if (this.OnInitializedStart != null) { this.OnInitializedStart(this); } SetRenderTexture(); if (this.OnInitializedAfter != null) { this.OnInitializedAfter(this); } } private void OnDestroy() { Debug.Log("InkCanvas has been destroyed."); ReleaseRenderTexture(); } private void OnGUI() { if (eraserDebug) { if (debugEraserMainView != null) { GUI.DrawTexture(new Rect(0f, 0f, 100f, 100f), debugEraserMainView); } if (debugEraserNormalView != null) { GUI.DrawTexture(new Rect(0f, 100f, 100f, 100f), debugEraserNormalView); } if (debugEraserHeightView != null) { GUI.DrawTexture(new Rect(0f, 200f, 100f, 100f), debugEraserHeightView); } } } private void MeshDataCache() { MeshFilter component = GetComponent(); SkinnedMeshRenderer component2 = GetComponent(); if (component != null) { meshOperator = new MeshOperator(component.sharedMesh); } else if (component2 != null) { meshOperator = new MeshOperator(component2.sharedMesh); } else { Debug.LogWarning("Sometimes if the MeshFilter or SkinnedMeshRenderer does not exist in the component part does not work correctly."); } } private void InitPropertyID() { foreach (PaintSet item in paintSet) { item.mainTexturePropertyID = Shader.PropertyToID(item.mainTextureName); item.normalTexturePropertyID = Shader.PropertyToID(item.normalTextureName); item.heightTexturePropertyID = Shader.PropertyToID(item.heightTextureName); } paintUVPropertyID = Shader.PropertyToID("_PaintUV"); brushTexturePropertyID = Shader.PropertyToID("_Brush"); brushScalePropertyID = Shader.PropertyToID("_BrushScale"); brushRotatePropertyID = Shader.PropertyToID("_BrushRotate"); brushColorPropertyID = Shader.PropertyToID("_ControlColor"); brushNormalTexturePropertyID = Shader.PropertyToID("_BrushNormal"); brushNormalBlendPropertyID = Shader.PropertyToID("_NormalBlend"); brushHeightTexturePropertyID = Shader.PropertyToID("_BrushHeight"); brushHeightBlendPropertyID = Shader.PropertyToID("_HeightBlend"); brushHeightColorPropertyID = Shader.PropertyToID("_Color"); } private void SetMaterial() { if (paintMainMaterial == null) { paintMainMaterial = new Material(Resources.Load("Es.InkPainter.PaintMain")); } if (paintNormalMaterial == null) { paintNormalMaterial = new Material(Resources.Load("Es.InkPainter.PaintNormal")); } if (paintHeightMaterial == null) { paintHeightMaterial = new Material(Resources.Load("Es.InkPainter.PaintHeight")); } Material[] materials = GetComponent().materials; for (int i = 0; i < materials.Length; i++) { if (paintSet[i].material == null) { paintSet[i].material = materials[i]; } } } private void SetTexture() { foreach (PaintSet item in paintSet) { if (item.material.HasProperty(item.mainTexturePropertyID)) { item.mainTexture = item.material.GetTexture(item.mainTexturePropertyID); } if (item.material.HasProperty(item.normalTexturePropertyID)) { item.normalTexture = item.material.GetTexture(item.normalTexturePropertyID); } if (item.material.HasProperty(item.heightTexturePropertyID)) { item.heightTexture = item.material.GetTexture(item.heightTexturePropertyID); } } } private RenderTexture SetupRenderTexture(Texture baseTex, int propertyID, Material material) { RenderTexture renderTexture = new RenderTexture(baseTex.width, baseTex.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); renderTexture.filterMode = baseTex.filterMode; Graphics.Blit(baseTex, renderTexture); material.SetTexture(propertyID, renderTexture); return renderTexture; } private void SetRenderTexture() { foreach (PaintSet item in paintSet) { if (item.useMainPaint) { if (item.mainTexture != null) { item.paintMainTexture = SetupRenderTexture(item.mainTexture, item.mainTexturePropertyID, item.material); } else { Debug.LogWarning("To take advantage of the main texture paint must set main texture to materials."); } } if (item.useNormalPaint) { if (item.normalTexture != null) { item.paintNormalTexture = SetupRenderTexture(item.normalTexture, item.normalTexturePropertyID, item.material); } else { Debug.LogWarning("To take advantage of the normal map paint must set normal map to materials."); } } if (item.useHeightPaint) { if (item.heightTexture != null) { item.paintHeightTexture = SetupRenderTexture(item.heightTexture, item.heightTexturePropertyID, item.material); } else { Debug.LogWarning("To take advantage of the height map paint must set height map to materials."); } } } } private void ReleaseRenderTexture() { foreach (PaintSet item in paintSet) { if (RenderTexture.active != item.paintMainTexture && item.paintMainTexture != null && item.paintMainTexture.IsCreated()) { item.paintMainTexture.Release(); } if (RenderTexture.active != item.paintNormalTexture && item.paintNormalTexture != null && item.paintNormalTexture.IsCreated()) { item.paintNormalTexture.Release(); } if (RenderTexture.active != item.paintHeightTexture && item.paintHeightTexture != null && item.paintHeightTexture.IsCreated()) { item.paintHeightTexture.Release(); } } } private void SetPaintMainData(Brush brush, Vector2 uv) { paintMainMaterial.SetVector(paintUVPropertyID, uv); paintMainMaterial.SetTexture(brushTexturePropertyID, brush.BrushTexture); paintMainMaterial.SetFloat(brushScalePropertyID, brush.Scale); paintMainMaterial.SetFloat(brushRotatePropertyID, brush.RotateAngle); paintMainMaterial.SetVector(brushColorPropertyID, brush.Color); string[] shaderKeywords = paintMainMaterial.shaderKeywords; foreach (string keyword in shaderKeywords) { paintMainMaterial.DisableKeyword(keyword); } switch (brush.ColorBlending) { case Brush.ColorBlendType.UseColor: paintMainMaterial.EnableKeyword("INK_PAINTER_COLOR_BLEND_USE_CONTROL"); break; case Brush.ColorBlendType.UseBrush: paintMainMaterial.EnableKeyword("INK_PAINTER_COLOR_BLEND_USE_BRUSH"); break; case Brush.ColorBlendType.Neutral: paintMainMaterial.EnableKeyword("INK_PAINTER_COLOR_BLEND_NEUTRAL"); break; case Brush.ColorBlendType.AlphaOnly: paintMainMaterial.EnableKeyword("INK_PAINTER_COLOR_BLEND_ALPHA_ONLY"); break; default: paintMainMaterial.EnableKeyword("INK_PAINTER_COLOR_BLEND_USE_CONTROL"); break; } } private void SetPaintNormalData(Brush brush, Vector2 uv, bool erase) { paintNormalMaterial.SetVector(paintUVPropertyID, uv); paintNormalMaterial.SetTexture(brushTexturePropertyID, brush.BrushTexture); paintNormalMaterial.SetTexture(brushNormalTexturePropertyID, brush.BrushNormalTexture); paintNormalMaterial.SetFloat(brushScalePropertyID, brush.Scale); paintNormalMaterial.SetFloat(brushRotatePropertyID, brush.RotateAngle); paintNormalMaterial.SetFloat(brushNormalBlendPropertyID, brush.NormalBlend); string[] shaderKeywords = paintNormalMaterial.shaderKeywords; foreach (string keyword in shaderKeywords) { paintNormalMaterial.DisableKeyword(keyword); } switch (brush.NormalBlending) { case Brush.NormalBlendType.UseBrush: paintNormalMaterial.EnableKeyword("INK_PAINTER_NORMAL_BLEND_USE_BRUSH"); break; case Brush.NormalBlendType.Add: paintNormalMaterial.EnableKeyword("INK_PAINTER_NORMAL_BLEND_ADD"); break; case Brush.NormalBlendType.Sub: paintNormalMaterial.EnableKeyword("INK_PAINTER_NORMAL_BLEND_SUB"); break; case Brush.NormalBlendType.Min: paintNormalMaterial.EnableKeyword("INK_PAINTER_NORMAL_BLEND_MIN"); break; case Brush.NormalBlendType.Max: paintNormalMaterial.EnableKeyword("INK_PAINTER_NORMAL_BLEND_MAX"); break; default: paintNormalMaterial.EnableKeyword("INK_PAINTER_NORMAL_BLEND_USE_BRUSH"); break; } if (erase) { paintNormalMaterial.EnableKeyword("DXT5NM_COMPRESS_UNUSE"); } else { paintNormalMaterial.EnableKeyword("DXT5NM_COMPRESS_USE"); } } private void SetPaintHeightData(Brush brush, Vector2 uv) { paintHeightMaterial.SetVector(paintUVPropertyID, uv); paintHeightMaterial.SetTexture(brushTexturePropertyID, brush.BrushTexture); paintHeightMaterial.SetTexture(brushHeightTexturePropertyID, brush.BrushHeightTexture); paintHeightMaterial.SetFloat(brushScalePropertyID, brush.Scale); paintHeightMaterial.SetFloat(brushRotatePropertyID, brush.RotateAngle); paintHeightMaterial.SetFloat(brushHeightBlendPropertyID, brush.HeightBlend); paintHeightMaterial.SetVector(brushHeightColorPropertyID, brush.Color); string[] shaderKeywords = paintHeightMaterial.shaderKeywords; foreach (string keyword in shaderKeywords) { paintHeightMaterial.DisableKeyword(keyword); } switch (brush.HeightBlending) { case Brush.HeightBlendType.UseBrush: paintHeightMaterial.EnableKeyword("INK_PAINTER_HEIGHT_BLEND_USE_BRUSH"); break; case Brush.HeightBlendType.Add: paintHeightMaterial.EnableKeyword("INK_PAINTER_HEIGHT_BLEND_ADD"); break; case Brush.HeightBlendType.Sub: paintHeightMaterial.EnableKeyword("INK_PAINTER_HEIGHT_BLEND_SUB"); break; case Brush.HeightBlendType.Min: paintHeightMaterial.EnableKeyword("INK_PAINTER_HEIGHT_BLEND_MIN"); break; case Brush.HeightBlendType.Max: paintHeightMaterial.EnableKeyword("INK_PAINTER_HEIGHT_BLEND_MAX"); break; case Brush.HeightBlendType.ColorRGB_HeightA: paintHeightMaterial.EnableKeyword("INK_PAINTER_HEIGHT_BLEND_COLOR_RGB_HEIGHT_A"); break; default: paintHeightMaterial.EnableKeyword("INK_PAINTER_HEIGHT_BLEND_ADD"); break; } } private Brush GetEraser(Brush brush, PaintSet paintSet, Vector2 uv, bool useMainPaint, bool useNormalPaint, bool useHeightpaint) { Brush brush2 = brush.Clone() as Brush; brush2.Color = Color.white; brush2.ColorBlending = Brush.ColorBlendType.UseBrush; brush2.NormalBlending = Brush.NormalBlendType.UseBrush; brush2.HeightBlending = Brush.HeightBlendType.UseBrush; brush2.NormalBlend = 1f; brush2.HeightBlend = 1f; if (useMainPaint) { RenderTexture temporary = RenderTexture.GetTemporary(brush.BrushTexture.width, brush.BrushTexture.height); GrabArea.Clip(brush.BrushTexture, brush.Scale, paintSet.mainTexture, uv, brush.RotateAngle, GrabArea.GrabTextureWrapMode.Clamp, temporary); brush2.BrushTexture = temporary; } if (useNormalPaint) { RenderTexture temporary2 = RenderTexture.GetTemporary(brush.BrushNormalTexture.width, brush.BrushNormalTexture.height); GrabArea.Clip(brush.BrushNormalTexture, brush.Scale, paintSet.normalTexture, uv, brush.RotateAngle, GrabArea.GrabTextureWrapMode.Clamp, temporary2, replaceAlpha: false); brush2.BrushNormalTexture = temporary2; } if (useHeightpaint) { RenderTexture temporary3 = RenderTexture.GetTemporary(brush.BrushHeightTexture.width, brush.BrushHeightTexture.height); GrabArea.Clip(brush.BrushHeightTexture, brush.Scale, paintSet.heightTexture, uv, brush.RotateAngle, GrabArea.GrabTextureWrapMode.Clamp, temporary3, replaceAlpha: false); brush2.BrushHeightTexture = temporary3; } if (eraserDebug) { if (debugEraserMainView == null && useMainPaint) { debugEraserMainView = new RenderTexture(brush2.BrushTexture.width, brush2.BrushTexture.height, 0); } if (debugEraserNormalView == null && useNormalPaint) { debugEraserNormalView = new RenderTexture(brush2.BrushNormalTexture.width, brush2.BrushNormalTexture.height, 0); } if (debugEraserHeightView == null && useHeightpaint) { debugEraserHeightView = new RenderTexture(brush2.BrushHeightTexture.width, brush2.BrushHeightTexture.height, 0); } if (useMainPaint) { Graphics.Blit(brush2.BrushTexture, debugEraserMainView); } if (useNormalPaint) { Graphics.Blit(brush2.BrushNormalTexture, debugEraserNormalView); } if (useHeightpaint) { Graphics.Blit(brush2.BrushHeightTexture, debugEraserHeightView); } } return brush2; } private void ReleaseEraser(Brush brush, bool useMainPaint, bool useNormalPaint, bool useHeightpaint) { if (useMainPaint && brush.BrushTexture is RenderTexture) { RenderTexture.ReleaseTemporary(brush.BrushTexture as RenderTexture); } if (useNormalPaint && brush.BrushNormalTexture is RenderTexture) { RenderTexture.ReleaseTemporary(brush.BrushNormalTexture as RenderTexture); } if (useHeightpaint && brush.BrushHeightTexture is RenderTexture) { RenderTexture.ReleaseTemporary(brush.BrushHeightTexture as RenderTexture); } } public bool PaintUVDirect(Brush brush, Vector2 uv, Func materialSelector = null) { if (brush == null) { Debug.LogError("Do not set the brush."); eraseFlag = false; return false; } if (this.OnPaintStart != null) { brush = brush.Clone() as Brush; this.OnPaintStart(this, brush); } IEnumerable enumerable; if (materialSelector != null) { enumerable = paintSet.Where(materialSelector); } else { IEnumerable enumerable2 = paintSet; enumerable = enumerable2; } foreach (PaintSet item in enumerable) { bool flag = item.useMainPaint && brush.BrushTexture != null && item.paintMainTexture != null && item.paintMainTexture.IsCreated(); bool flag2 = item.useNormalPaint && brush.BrushNormalTexture != null && item.paintNormalTexture != null && item.paintNormalTexture.IsCreated(); bool flag3 = item.useHeightPaint && brush.BrushHeightTexture != null && item.paintHeightTexture != null && item.paintHeightTexture.IsCreated(); if (eraseFlag) { brush = GetEraser(brush, item, uv, flag, flag2, flag3); } if (flag) { RenderTexture temporary = RenderTexture.GetTemporary(item.paintMainTexture.width, item.paintMainTexture.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); SetPaintMainData(brush, uv); Graphics.Blit(item.paintMainTexture, temporary, paintMainMaterial); Graphics.Blit(temporary, item.paintMainTexture); RenderTexture.ReleaseTemporary(temporary); } if (flag2) { RenderTexture temporary2 = RenderTexture.GetTemporary(item.paintNormalTexture.width, item.paintNormalTexture.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); SetPaintNormalData(brush, uv, eraseFlag); Graphics.Blit(item.paintNormalTexture, temporary2, paintNormalMaterial); Graphics.Blit(temporary2, item.paintNormalTexture); RenderTexture.ReleaseTemporary(temporary2); } if (flag3) { RenderTexture temporary3 = RenderTexture.GetTemporary(item.paintHeightTexture.width, item.paintHeightTexture.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); SetPaintHeightData(brush, uv); Graphics.Blit(item.paintHeightTexture, temporary3, paintHeightMaterial); Graphics.Blit(temporary3, item.paintHeightTexture); RenderTexture.ReleaseTemporary(temporary3); } if (eraseFlag) { ReleaseEraser(brush, flag, flag2, flag3); } } if (this.OnPaintEnd != null) { this.OnPaintEnd(this); } eraseFlag = false; return true; } public bool PaintNearestTriangleSurface(Brush brush, Vector3 worldPos, Func materialSelector = null, Camera renderCamera = null) { Vector3 localPoint = base.transform.worldToLocalMatrix.MultiplyPoint(worldPos); Vector3 point = MeshOperator.NearestLocalSurfacePoint(localPoint); return Paint(brush, base.transform.localToWorldMatrix.MultiplyPoint(point), materialSelector, renderCamera); } public bool Paint(Brush brush, Vector3 worldPos, Func materialSelector = null, Camera renderCamera = null) { if (renderCamera == null) { renderCamera = Camera.main; } Vector3 localPoint = base.transform.InverseTransformPoint(worldPos); Matrix4x4 matrixMVP = renderCamera.projectionMatrix * renderCamera.worldToCameraMatrix * base.transform.localToWorldMatrix; if (MeshOperator.LocalPointToUV(localPoint, matrixMVP, out var uv)) { return PaintUVDirect(brush, uv, materialSelector); } Debug.LogWarning("Could not get the point on the surface."); return PaintNearestTriangleSurface(brush, worldPos, materialSelector, renderCamera); } public bool Paint(Brush brush, RaycastHit hitInfo, Func materialSelector = null) { if (hitInfo.collider != null) { if (hitInfo.collider is MeshCollider) { return PaintUVDirect(brush, hitInfo.textureCoord, materialSelector); } Debug.LogWarning("If you want to paint using a RaycastHit, need set MeshCollider for object."); return PaintNearestTriangleSurface(brush, hitInfo.point, materialSelector); } return false; } public bool EraseUVDirect(Brush brush, Vector2 uv, Func materialSelector = null) { eraseFlag = true; return PaintUVDirect(brush, uv, materialSelector); } public bool EraseNearestTriangleSurface(Brush brush, Vector3 worldPos, Func materialSelector = null, Camera renderCamera = null) { eraseFlag = true; return PaintNearestTriangleSurface(brush, worldPos, materialSelector, renderCamera); } public bool Erase(Brush brush, Vector3 worldPos, Func materialSelector = null, Camera renderCamera = null) { eraseFlag = true; return Paint(brush, worldPos, materialSelector, renderCamera); } public bool Erase(Brush brush, RaycastHit hitInfo, Func materialSelector = null) { eraseFlag = true; return Paint(brush, hitInfo, materialSelector); } public void ResetPaint() { ReleaseRenderTexture(); SetRenderTexture(); if (this.OnInitializedAfter != null) { this.OnInitializedAfter(this); } } public Texture GetMainTexture(string materialName) { materialName = materialName.Replace(" (Instance)", ""); return paintSet.FirstOrDefault((PaintSet p) => p.material.name.Replace(" (Instance)", "") == materialName)?.mainTexture; } public RenderTexture GetPaintMainTexture(string materialName) { materialName = materialName.Replace(" (Instance)", ""); return paintSet.FirstOrDefault((PaintSet p) => p.material.name.Replace(" (Instance)", "") == materialName)?.paintMainTexture; } public void SetPaintMainTexture(string materialName, RenderTexture newTexture) { materialName = materialName.Replace(" (Instance)", ""); PaintSet paintSet = this.paintSet.FirstOrDefault((PaintSet p) => p.material.name.Replace(" (Instance)", "") == materialName); if (paintSet == null) { Debug.LogError("Failed to set texture."); return; } paintSet.paintMainTexture = newTexture; paintSet.material.SetTexture(paintSet.mainTextureName, paintSet.paintMainTexture); paintSet.useMainPaint = true; } public Texture GetNormalTexture(string materialName) { materialName = materialName.Replace(" (Instance)", ""); return paintSet.FirstOrDefault((PaintSet p) => p.material.name.Replace(" (Instance)", "") == materialName)?.normalTexture; } public RenderTexture GetPaintNormalTexture(string materialName) { materialName = materialName.Replace(" (Instance)", ""); return paintSet.FirstOrDefault((PaintSet p) => p.material.name.Replace(" (Instance)", "") == materialName)?.paintNormalTexture; } public void SetPaintNormalTexture(string materialName, RenderTexture newTexture) { materialName = materialName.Replace(" (Instance)", ""); PaintSet paintSet = this.paintSet.FirstOrDefault((PaintSet p) => p.material.name.Replace(" (Instance)", "") == materialName); if (paintSet == null) { Debug.LogError("Failed to set texture."); return; } paintSet.paintNormalTexture = newTexture; paintSet.material.SetTexture(paintSet.normalTextureName, paintSet.paintNormalTexture); paintSet.useNormalPaint = true; } public Texture GetHeightTexture(string materialName) { materialName = materialName.Replace(" (Instance)", ""); return paintSet.FirstOrDefault((PaintSet p) => p.material.name.Replace(" (Instance)", "") == materialName)?.heightTexture; } public RenderTexture GetPaintHeightTexture(string materialName) { materialName = materialName.Replace(" (Instance)", ""); return paintSet.FirstOrDefault((PaintSet p) => p.material.name.Replace(" (Instance)", "") == materialName)?.paintHeightTexture; } public void SetPaintHeightTexture(string materialName, RenderTexture newTexture) { materialName = materialName.Replace(" (Instance)", ""); PaintSet paintSet = this.paintSet.FirstOrDefault((PaintSet p) => p.material.name.Replace(" (Instance)", "") == materialName); if (paintSet == null) { Debug.LogError("Failed to set texture."); return; } paintSet.paintHeightTexture = newTexture; paintSet.material.SetTexture(paintSet.heightTextureName, paintSet.paintHeightTexture); paintSet.useHeightPaint = true; } } }