2using System.Collections.Generic;
20 [RequireComponent(typeof(Renderer))]
21 [DisallowMultipleComponent]
30 [HideInInspector] [NonSerialized]
public Material
material;
32 [SerializeField] [Tooltip(
"The property name of the main texture.")]
35 [SerializeField] [Tooltip(
"Normal map texture property name.")]
38 [SerializeField] [Tooltip(
"The property name of the heightmap texture.")]
41 [SerializeField] [Tooltip(
"Whether or not use main texture paint.")]
44 [SerializeField] [Tooltip(
"Whether or not use normal map paint (you need material on normal maps).")]
47 [SerializeField] [Tooltip(
"Whether or not use heightmap painting (you need material on the heightmap).")]
80 #region ShaderPropertyID
88 #endregion ShaderPropertyID
139 #endregion Constractor
142 private static Material paintMainMaterial;
143 private static Material paintNormalMaterial;
144 private static Material paintHeightMaterial;
145 private bool eraseFlag;
146 private RenderTexture debugEraserMainView;
147 private RenderTexture debugEraserNormalView;
148 private RenderTexture debugEraserHeightView;
149 private Bounds myBounds;
150#pragma warning disable 0649
151 private bool eraserDebug;
152#pragma warning restore 0649
160 set => paintSet = value;
188 #region SerializedField
190 [SerializeField]
private List<PaintSet> paintSet;
192 #endregion SerializedField
194 #region ShaderPropertyID
196 private int paintUVPropertyID;
198 private int brushTexturePropertyID;
199 private int brushScalePropertyID;
200 private int brushRotatePropertyID;
201 private int brushColorPropertyID;
202 private int brushNormalTexturePropertyID;
203 private int brushNormalBlendPropertyID;
204 private int brushHeightTexturePropertyID;
205 private int brushHeightBlendPropertyID;
206 private int brushHeightColorPropertyID;
208 #endregion ShaderPropertyID
210 #region ShaderKeywords
212 private const string COLOR_BLEND_USE_CONTROL =
"INK_PAINTER_COLOR_BLEND_USE_CONTROL";
213 private const string COLOR_BLEND_USE_BRUSH =
"INK_PAINTER_COLOR_BLEND_USE_BRUSH";
214 private const string COLOR_BLEND_NEUTRAL =
"INK_PAINTER_COLOR_BLEND_NEUTRAL";
215 private const string COLOR_BLEND_ALPHA_ONLY =
"INK_PAINTER_COLOR_BLEND_ALPHA_ONLY";
217 private const string NORMAL_BLEND_USE_BRUSH =
"INK_PAINTER_NORMAL_BLEND_USE_BRUSH";
218 private const string NORMAL_BLEND_ADD =
"INK_PAINTER_NORMAL_BLEND_ADD";
219 private const string NORMAL_BLEND_SUB =
"INK_PAINTER_NORMAL_BLEND_SUB";
220 private const string NORMAL_BLEND_MIN =
"INK_PAINTER_NORMAL_BLEND_MIN";
221 private const string NORMAL_BLEND_MAX =
"INK_PAINTER_NORMAL_BLEND_MAX";
222 private const string DXT5NM_COMPRESS_USE =
"DXT5NM_COMPRESS_USE";
223 private const string DXT5NM_COMPRESS_UNUSE =
"DXT5NM_COMPRESS_UNUSE";
225 private const string HEIGHT_BLEND_USE_BRUSH =
"INK_PAINTER_HEIGHT_BLEND_USE_BRUSH";
226 private const string HEIGHT_BLEND_ADD =
"INK_PAINTER_HEIGHT_BLEND_ADD";
227 private const string HEIGHT_BLEND_SUB =
"INK_PAINTER_HEIGHT_BLEND_SUB";
228 private const string HEIGHT_BLEND_MIN =
"INK_PAINTER_HEIGHT_BLEND_MIN";
229 private const string HEIGHT_BLEND_MAX =
"INK_PAINTER_HEIGHT_BLEND_MAX";
230 private const string HEIGHT_BLEND_COLOR_RGB_HEIGHT_A =
"INK_PAINTER_HEIGHT_BLEND_COLOR_RGB_HEIGHT_A";
232 #endregion ShaderKeywords
242 if (meshOperator ==
null)
244 "To take advantage of the features must Mesh filter or Skinned mesh renderer component associated Mesh.");
252 #region UnityEventMethod
273 private void OnDestroy()
276 ReleaseRenderTexture();
283 if (debugEraserMainView !=
null)
284 GUI.DrawTexture(
new Rect(0, 0, 100, 100), debugEraserMainView);
285 if (debugEraserNormalView !=
null)
286 GUI.DrawTexture(
new Rect(0, 100, 100, 100), debugEraserNormalView);
287 if (debugEraserHeightView !=
null)
288 GUI.DrawTexture(
new Rect(0, 200, 100, 100), debugEraserHeightView);
292 #endregion UnityEventMethod
294 #region PrivateMethod
299 private void MeshDataCache()
301 var meshFilter = GetComponent<MeshFilter>();
302 var skinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();
303 if (meshFilter !=
null)
306 myBounds = meshFilter.sharedMesh.bounds;
308 else if (skinnedMeshRenderer !=
null)
310 meshOperator =
new MeshOperator(skinnedMeshRenderer.sharedMesh);
315 "Sometimes if the MeshFilter or SkinnedMeshRenderer does not exist in the component part does not work correctly.");
322 private void InitPropertyID()
324 if (paintSet ==
null || paintSet.Count == 0)
326 var m = GetComponent<Renderer>().materials;
327 paintSet =
new List<PaintSet>
331 for (var i = 1; i < m.Length; i++) paintSet.Add(
new PaintSet());
334 foreach (var p
in paintSet)
336 p.mainTexturePropertyID = Shader.PropertyToID(p.mainTextureName);
337 p.normalTexturePropertyID = Shader.PropertyToID(p.normalTextureName);
338 p.heightTexturePropertyID = Shader.PropertyToID(p.heightTextureName);
341 paintUVPropertyID = Shader.PropertyToID(
"_PaintUV");
342 brushTexturePropertyID = Shader.PropertyToID(
"_Brush");
343 brushScalePropertyID = Shader.PropertyToID(
"_BrushScale");
344 brushRotatePropertyID = Shader.PropertyToID(
"_BrushRotate");
345 brushColorPropertyID = Shader.PropertyToID(
"_ControlColor");
346 brushNormalTexturePropertyID = Shader.PropertyToID(
"_BrushNormal");
347 brushNormalBlendPropertyID = Shader.PropertyToID(
"_NormalBlend");
348 brushHeightTexturePropertyID = Shader.PropertyToID(
"_BrushHeight");
349 brushHeightBlendPropertyID = Shader.PropertyToID(
"_HeightBlend");
350 brushHeightColorPropertyID = Shader.PropertyToID(
"_Color");
356 private void SetMaterial()
358 if (paintMainMaterial ==
null)
359 paintMainMaterial =
new Material(Resources.Load<Material>(
"Es.InkPainter.PaintMain"));
360 if (paintNormalMaterial ==
null)
361 paintNormalMaterial =
new Material(Resources.Load<Material>(
"Es.InkPainter.PaintNormal"));
362 if (paintHeightMaterial ==
null)
363 paintHeightMaterial =
new Material(Resources.Load<Material>(
"Es.InkPainter.PaintHeight"));
364 var m = GetComponent<Renderer>().materials;
365 for (var i = 0; i < m.Length; ++i)
366 if (paintSet[i].material ==
null)
367 paintSet[i].material = m[i];
373 private void SetTexture()
375 foreach (var p
in paintSet)
377 if (p.material.HasProperty(p.mainTexturePropertyID))
378 p.mainTexture = p.material.GetTexture(p.mainTexturePropertyID);
379 if (p.material.HasProperty(p.normalTexturePropertyID))
380 p.normalTexture = p.material.GetTexture(p.normalTexturePropertyID);
381 if (p.material.HasProperty(p.heightTexturePropertyID))
382 p.heightTexture = p.material.GetTexture(p.heightTexturePropertyID);
392 private RenderTexture SetupRenderTexture(Texture baseTex,
int propertyID, Material material)
394 var rt =
new RenderTexture(baseTex.width, baseTex.height, 0, RenderTextureFormat.ARGB32,
395 RenderTextureReadWrite.Linear);
396 rt.filterMode = baseTex.filterMode;
398 material.SetTexture(propertyID, rt);
405 private void SetRenderTexture()
407 foreach (var p
in paintSet)
410 if (p.mainTexture !=
null)
411 p.paintMainTexture = SetupRenderTexture(p.mainTexture, p.mainTexturePropertyID, p.material);
414 "To take advantage of the main texture paint must set main texture to materials.");
415 if (p.useNormalPaint)
416 if (p.normalTexture !=
null)
417 p.paintNormalTexture =
418 SetupRenderTexture(p.normalTexture, p.normalTexturePropertyID, p.material);
420 Debug.LogWarning(
"To take advantage of the normal map paint must set normal map to materials.");
421 if (p.useHeightPaint)
422 if (p.heightTexture !=
null)
423 p.paintHeightTexture =
424 SetupRenderTexture(p.heightTexture, p.heightTexturePropertyID, p.material);
426 Debug.LogWarning(
"To take advantage of the height map paint must set height map to materials.");
433 private void ReleaseRenderTexture()
435 foreach (var p
in paintSet)
437 if (RenderTexture.active != p.paintMainTexture && p.paintMainTexture !=
null &&
438 p.paintMainTexture.IsCreated())
439 p.paintMainTexture.Release();
440 if (RenderTexture.active != p.paintNormalTexture && p.paintNormalTexture !=
null &&
441 p.paintNormalTexture.IsCreated())
442 p.paintNormalTexture.Release();
443 if (RenderTexture.active != p.paintHeightTexture && p.paintHeightTexture !=
null &&
444 p.paintHeightTexture.IsCreated())
445 p.paintHeightTexture.Release();
454 private void SetPaintMainData(Brush brush, Vector2 uv)
456 paintMainMaterial.SetVector(paintUVPropertyID, uv);
457 paintMainMaterial.SetTexture(brushTexturePropertyID, brush.BrushTexture);
458 paintMainMaterial.SetFloat(brushScalePropertyID, brush.Scale);
459 paintMainMaterial.SetFloat(brushRotatePropertyID, brush.RotateAngle);
460 paintMainMaterial.SetVector(brushColorPropertyID, brush.Color);
462 foreach (var key
in paintMainMaterial.shaderKeywords)
463 paintMainMaterial.DisableKeyword(key);
464 switch (brush.ColorBlending)
466 case Brush.ColorBlendType.UseColor:
467 paintMainMaterial.EnableKeyword(COLOR_BLEND_USE_CONTROL);
470 case Brush.ColorBlendType.UseBrush:
471 paintMainMaterial.EnableKeyword(COLOR_BLEND_USE_BRUSH);
474 case Brush.ColorBlendType.Neutral:
475 paintMainMaterial.EnableKeyword(COLOR_BLEND_NEUTRAL);
478 case Brush.ColorBlendType.AlphaOnly:
479 paintMainMaterial.EnableKeyword(COLOR_BLEND_ALPHA_ONLY);
483 paintMainMaterial.EnableKeyword(COLOR_BLEND_USE_CONTROL);
493 private void SetPaintNormalData(Brush brush, Vector2 uv,
bool erase)
495 paintNormalMaterial.SetVector(paintUVPropertyID, uv);
496 paintNormalMaterial.SetTexture(brushTexturePropertyID, brush.BrushTexture);
497 paintNormalMaterial.SetTexture(brushNormalTexturePropertyID, brush.BrushNormalTexture);
498 paintNormalMaterial.SetFloat(brushScalePropertyID, brush.Scale);
499 paintNormalMaterial.SetFloat(brushRotatePropertyID, brush.RotateAngle);
500 paintNormalMaterial.SetFloat(brushNormalBlendPropertyID, brush.NormalBlend);
502 foreach (var key
in paintNormalMaterial.shaderKeywords)
503 paintNormalMaterial.DisableKeyword(key);
504 switch (brush.NormalBlending)
506 case Brush.NormalBlendType.UseBrush:
507 paintNormalMaterial.EnableKeyword(NORMAL_BLEND_USE_BRUSH);
510 case Brush.NormalBlendType.Add:
511 paintNormalMaterial.EnableKeyword(NORMAL_BLEND_ADD);
514 case Brush.NormalBlendType.Sub:
515 paintNormalMaterial.EnableKeyword(NORMAL_BLEND_SUB);
518 case Brush.NormalBlendType.Min:
519 paintNormalMaterial.EnableKeyword(NORMAL_BLEND_MIN);
522 case Brush.NormalBlendType.Max:
523 paintNormalMaterial.EnableKeyword(NORMAL_BLEND_MAX);
527 paintNormalMaterial.EnableKeyword(NORMAL_BLEND_USE_BRUSH);
534 paintNormalMaterial.EnableKeyword(DXT5NM_COMPRESS_UNUSE);
537 paintNormalMaterial.EnableKeyword(DXT5NM_COMPRESS_USE);
547 private void SetPaintHeightData(Brush brush, Vector2 uv)
549 paintHeightMaterial.SetVector(paintUVPropertyID, uv);
550 paintHeightMaterial.SetTexture(brushTexturePropertyID, brush.BrushTexture);
551 paintHeightMaterial.SetTexture(brushHeightTexturePropertyID, brush.BrushHeightTexture);
552 paintHeightMaterial.SetFloat(brushScalePropertyID, brush.Scale);
553 paintHeightMaterial.SetFloat(brushRotatePropertyID, brush.RotateAngle);
554 paintHeightMaterial.SetFloat(brushHeightBlendPropertyID, brush.HeightBlend);
555 paintHeightMaterial.SetVector(brushHeightColorPropertyID, brush.Color);
557 foreach (var key
in paintHeightMaterial.shaderKeywords)
558 paintHeightMaterial.DisableKeyword(key);
559 switch (brush.HeightBlending)
561 case Brush.HeightBlendType.UseBrush:
562 paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_USE_BRUSH);
565 case Brush.HeightBlendType.Add:
566 paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_ADD);
569 case Brush.HeightBlendType.Sub:
570 paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_SUB);
573 case Brush.HeightBlendType.Min:
574 paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_MIN);
577 case Brush.HeightBlendType.Max:
578 paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_MAX);
581 case Brush.HeightBlendType.ColorRGB_HeightA:
582 paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_COLOR_RGB_HEIGHT_A);
586 paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_ADD);
601 private Brush GetEraser(Brush brush, PaintSet paintSet, Vector2 uv,
bool useMainPaint,
bool useNormalPaint,
604 var b = brush.Clone() as Brush;
605 b.Color =
Color.white;
606 b.ColorBlending = Brush.ColorBlendType.UseBrush;
607 b.NormalBlending = Brush.NormalBlendType.UseBrush;
608 b.HeightBlending = Brush.HeightBlendType.UseBrush;
614 var rt = RenderTexture.GetTemporary(brush.BrushTexture.width, brush.BrushTexture.height);
615 GrabArea.Clip(brush.BrushTexture, brush.Scale, paintSet.mainTexture, uv, brush.RotateAngle,
616 GrabArea.GrabTextureWrapMode.Clamp, rt);
622 var rt = RenderTexture.GetTemporary(brush.BrushNormalTexture.width, brush.BrushNormalTexture.height);
623 GrabArea.Clip(brush.BrushNormalTexture, brush.Scale, paintSet.normalTexture, uv, brush.RotateAngle,
624 GrabArea.GrabTextureWrapMode.Clamp, rt,
false);
625 b.BrushNormalTexture = rt;
630 var rt = RenderTexture.GetTemporary(brush.BrushHeightTexture.width, brush.BrushHeightTexture.height);
631 GrabArea.Clip(brush.BrushHeightTexture, brush.Scale, paintSet.heightTexture, uv, brush.RotateAngle,
632 GrabArea.GrabTextureWrapMode.Clamp, rt,
false);
633 b.BrushHeightTexture = rt;
638 if (debugEraserMainView ==
null && useMainPaint)
639 debugEraserMainView =
new RenderTexture(b.BrushTexture.width, b.BrushTexture.height, 0);
640 if (debugEraserNormalView ==
null && useNormalPaint)
641 debugEraserNormalView =
642 new RenderTexture(b.BrushNormalTexture.width, b.BrushNormalTexture.height, 0);
643 if (debugEraserHeightView ==
null && useHeightpaint)
644 debugEraserHeightView =
645 new RenderTexture(b.BrushHeightTexture.width, b.BrushHeightTexture.height, 0);
648 Graphics.Blit(b.BrushTexture, debugEraserMainView);
650 Graphics.Blit(b.BrushNormalTexture, debugEraserNormalView);
652 Graphics.Blit(b.BrushHeightTexture, debugEraserHeightView);
665 private void ReleaseEraser(Brush brush,
bool useMainPaint,
bool useNormalPaint,
bool useHeightpaint)
667 if (useMainPaint && brush.BrushTexture is RenderTexture)
668 RenderTexture.ReleaseTemporary(brush.BrushTexture as RenderTexture);
670 if (useNormalPaint && brush.BrushNormalTexture is RenderTexture)
671 RenderTexture.ReleaseTemporary(brush.BrushNormalTexture as RenderTexture);
673 if (useHeightpaint && brush.BrushHeightTexture is RenderTexture)
674 RenderTexture.ReleaseTemporary(brush.BrushHeightTexture as RenderTexture);
677 #endregion PrivateMethod
693 Debug.LogError(
"Do not set the brush.");
698 #endregion ErrorCheck
700 #region BrushSizeFixer
702 if (myBounds.size.x < 0.05f && myBounds.size.z < 0.05f && myBounds.size.y < 0.05f)
716 var
set = materialSelector ==
null ? paintSet : paintSet.Where(materialSelector);
717 foreach (var p
in set)
719 var mainPaintConditions = p.useMainPaint && brush.BrushTexture !=
null && p.paintMainTexture !=
null &&
720 p.paintMainTexture.IsCreated();
721 var normalPaintConditions = p.useNormalPaint && brush.BrushNormalTexture !=
null &&
722 p.paintNormalTexture !=
null && p.paintNormalTexture.IsCreated();
723 var heightPaintConditions = p.useHeightPaint && brush.BrushHeightTexture !=
null &&
724 p.paintHeightTexture !=
null && p.paintHeightTexture.IsCreated();
727 brush = GetEraser(brush, p, uv, mainPaintConditions, normalPaintConditions, heightPaintConditions);
729 if (mainPaintConditions)
731 var mainPaintTextureBuffer = RenderTexture.GetTemporary(p.paintMainTexture.width,
732 p.paintMainTexture.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
733 SetPaintMainData(brush, uv);
734 Graphics.Blit(p.paintMainTexture, mainPaintTextureBuffer, paintMainMaterial);
735 Graphics.Blit(mainPaintTextureBuffer, p.paintMainTexture);
736 RenderTexture.ReleaseTemporary(mainPaintTextureBuffer);
739 if (normalPaintConditions)
741 var normalPaintTextureBuffer = RenderTexture.GetTemporary(p.paintNormalTexture.width,
742 p.paintNormalTexture.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
743 SetPaintNormalData(brush, uv, eraseFlag);
744 Graphics.Blit(p.paintNormalTexture, normalPaintTextureBuffer, paintNormalMaterial);
745 Graphics.Blit(normalPaintTextureBuffer, p.paintNormalTexture);
746 RenderTexture.ReleaseTemporary(normalPaintTextureBuffer);
749 if (heightPaintConditions)
751 var heightPaintTextureBuffer = RenderTexture.GetTemporary(p.paintHeightTexture.width,
752 p.paintHeightTexture.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
753 SetPaintHeightData(brush, uv);
754 Graphics.Blit(p.paintHeightTexture, heightPaintTextureBuffer, paintHeightMaterial);
755 Graphics.Blit(heightPaintTextureBuffer, p.paintHeightTexture);
756 RenderTexture.ReleaseTemporary(heightPaintTextureBuffer);
760 ReleaseEraser(brush, mainPaintConditions, normalPaintConditions, heightPaintConditions);
778 Func<PaintSet, bool> materialSelector =
null, Camera renderCamera =
null)
780 var p = transform.worldToLocalMatrix.MultiplyPoint(worldPos);
783 return Paint(brush, transform.localToWorldMatrix.MultiplyPoint(pd), materialSelector, renderCamera);
793 public bool Paint(
Brush brush, Vector3 worldPos, Func<PaintSet, bool> materialSelector =
null,
794 Camera renderCamera =
null)
798 if (renderCamera ==
null)
799 renderCamera = Camera.main;
801 var p = transform.InverseTransformPoint(worldPos);
802 var mvp = renderCamera.projectionMatrix * renderCamera.worldToCameraMatrix * transform.localToWorldMatrix;
808 Debug.LogWarning(
"Could not get the point on the surface.");
814 var renderCamera = Camera.main;
816 var mvp = renderCamera.projectionMatrix * renderCamera.worldToCameraMatrix * transform.localToWorldMatrix;
830 public bool Paint(
Brush brush, RaycastHit hitInfo, Func<PaintSet, bool> materialSelector =
null)
832 if (hitInfo.collider !=
null)
834 if (hitInfo.collider is MeshCollider)
835 return PaintUVDirect(brush, hitInfo.textureCoord, materialSelector);
836 Debug.LogWarning(
"If you want to paint using a RaycastHit, need set MeshCollider for object.");
863 Func<PaintSet, bool> materialSelector =
null, Camera renderCamera =
null)
876 public bool Erase(
Brush brush, Vector3 worldPos, Func<PaintSet, bool> materialSelector =
null,
877 Camera renderCamera =
null)
880 return Paint(brush, worldPos, materialSelector, renderCamera);
890 public bool Erase(
Brush brush, RaycastHit hitInfo, Func<PaintSet, bool> materialSelector =
null)
893 return Paint(brush, hitInfo, materialSelector);
901 ReleaseRenderTexture();
914 materialName = materialName.Replace(
" (Instance)",
"");
915 var data = paintSet.FirstOrDefault(p => p.material.name.Replace(
" (Instance)",
"") == materialName);
918 return data.mainTexture;
928 materialName = materialName.Replace(
" (Instance)",
"");
929 var data = paintSet.FirstOrDefault(p => p.material.name.Replace(
" (Instance)",
"") == materialName);
932 return data.paintMainTexture;
942 materialName = materialName.Replace(
" (Instance)",
"");
943 var data = paintSet.FirstOrDefault(p => p.material.name.Replace(
" (Instance)",
"") == materialName);
946 Debug.LogError(
"Failed to set texture.");
950 data.paintMainTexture = newTexture;
951 data.material.SetTexture(data.mainTextureName, data.paintMainTexture);
952 data.useMainPaint =
true;
962 materialName = materialName.Replace(
" (Instance)",
"");
963 var data = paintSet.FirstOrDefault(p => p.material.name.Replace(
" (Instance)",
"") == materialName);
966 return data.normalTexture;
976 materialName = materialName.Replace(
" (Instance)",
"");
977 var data = paintSet.FirstOrDefault(p => p.material.name.Replace(
" (Instance)",
"") == materialName);
980 return data.paintNormalTexture;
990 materialName = materialName.Replace(
" (Instance)",
"");
991 var data = paintSet.FirstOrDefault(p => p.material.name.Replace(
" (Instance)",
"") == materialName);
994 Debug.LogError(
"Failed to set texture.");
998 data.paintNormalTexture = newTexture;
999 data.material.SetTexture(data.normalTextureName, data.paintNormalTexture);
1000 data.useNormalPaint =
true;
1010 materialName = materialName.Replace(
" (Instance)",
"");
1011 var data = paintSet.FirstOrDefault(p => p.material.name.Replace(
" (Instance)",
"") == materialName);
1014 return data.heightTexture;
1024 materialName = materialName.Replace(
" (Instance)",
"");
1025 var data = paintSet.FirstOrDefault(p => p.material.name.Replace(
" (Instance)",
"") == materialName);
1028 return data.paintHeightTexture;
1038 materialName = materialName.Replace(
" (Instance)",
"");
1039 var data = paintSet.FirstOrDefault(p => p.material.name.Replace(
" (Instance)",
"") == materialName);
1042 Debug.LogError(
"Failed to set texture.");
1046 data.paintHeightTexture = newTexture;
1047 data.material.SetTexture(data.heightTextureName, data.paintHeightTexture);
1048 data.useHeightPaint =
true;
1051 #endregion PublicMethod
1053 #region CustomEditor
1058 [CanEditMultipleObjects]
1059 private class InkCanvasInspectorExtension : Editor
1061 private Renderer renderer;
1062 private Material[] materials;
1063 private List<bool> foldOut;
1065 public override void OnInspectorGUI()
1068 if (instance.paintSet ==
null)
1069 instance.paintSet =
new List<PaintSet>();
1071 if (renderer ==
null)
1072 renderer = instance.GetComponent<Renderer>();
1073 if (materials ==
null)
1074 materials = renderer.sharedMaterials;
1075 if (foldOut ==
null)
1076 foldOut =
new List<bool>();
1078 if (instance.paintSet.Count < materials.Length)
1080 for (var i = instance.paintSet.Count; i < materials.Length; ++i)
1081 instance.paintSet.Add(
new PaintSet
1083 mainTextureName =
"_MainTex",
1084 normalTextureName =
"_BumpMap",
1085 heightTextureName =
"_ParallaxMap",
1086 useMainPaint =
true,
1087 useNormalPaint =
false,
1088 useHeightPaint =
false
1093 if (instance.paintSet.Count > materials.Length)
1095 instance.paintSet.RemoveRange(materials.Length, instance.paintSet.Count - materials.Length);
1099 if (foldOut.Count < instance.paintSet.Count)
1100 for (var i = foldOut.Count; i < instance.paintSet.Count; ++i)
1103 EditorGUILayout.Space();
1105 if (EditorApplication.isPlaying)
1107 #region PlayModeOperation
1109 EditorGUILayout.HelpBox(
"Can not change while playing.\n but you can saved painted texture.",
1111 for (var i = 0; i < instance.paintSet.Count; ++i)
1112 if (foldOut[i] = Foldout(foldOut[i],
string.Format(
"Material \"{0}\"", materials[i].name)))
1114 EditorGUILayout.BeginVertical(
"ProgressBarBack");
1115 var backColorBuf = GUI.backgroundColor;
1116 GUI.backgroundColor =
Color.green;
1118 var paintSet = instance.paintSet[i];
1120 if (paintSet.paintMainTexture !=
null && GUILayout.Button(
"Save main texture"))
1121 SaveRenderTextureToPNG(
1122 paintSet.mainTexture !=
null ? paintSet.mainTexture.name :
"main_texture",
1123 paintSet.paintMainTexture);
1125 if (instance.paintSet[i].paintNormalTexture !=
null &&
1126 GUILayout.Button(
"Save normal texture"))
1128 SaveRenderTextureToPNG(
1129 paintSet.normalTexture !=
null ? paintSet.normalTexture.name :
"normal_texture",
1130 paintSet.paintNormalTexture);
1132 if (instance.paintSet[i].paintHeightTexture !=
null &&
1133 GUILayout.Button(
"Save height texture"))
1134 SaveRenderTextureToPNG(
1135 paintSet.heightTexture !=
null ? paintSet.heightTexture.name :
"height_texture",
1136 paintSet.paintHeightTexture);
1138 GUI.backgroundColor = backColorBuf;
1139 EditorGUILayout.EndVertical();
1142 EditorGUILayout.Space();
1143 instance.eraserDebug = EditorGUILayout.Toggle(
"Eracer debug option", instance.eraserDebug);
1144 if (instance.eraserDebug)
1146 if (GUILayout.Button(
"Save eracer main texture"))
1147 SaveRenderTextureToPNG(
"eracer_main", instance.debugEraserMainView);
1148 if (GUILayout.Button(
"Save eracer normal texture"))
1149 SaveRenderTextureToPNG(
"eracer_normal", instance.debugEraserNormalView);
1150 if (GUILayout.Button(
"Save eracer height texture"))
1151 SaveRenderTextureToPNG(
"eracer_height", instance.debugEraserHeightView);
1154 #endregion PlayModeOperation
1158 #region Property Setting
1160 for (var i = 0; i < instance.paintSet.Count; ++i)
1161 if (foldOut[i] = Foldout(foldOut[i],
string.Format(
"Material \"{0}\"", materials[i].name)))
1163 EditorGUI.indentLevel = 0;
1164 EditorGUILayout.BeginVertical(
"ProgressBarBack");
1167 EditorGUI.BeginChangeCheck();
1168 instance.paintSet[i].useMainPaint =
1169 EditorGUILayout.Toggle(
"Use Main Paint", instance.paintSet[i].useMainPaint);
1170 if (EditorGUI.EndChangeCheck())
1171 ChangeValue(i,
"Use Main Paint",
1172 p => p.useMainPaint = instance.paintSet[i].useMainPaint);
1173 if (instance.paintSet[i].useMainPaint)
1175 EditorGUI.indentLevel++;
1176 EditorGUI.BeginChangeCheck();
1177 instance.paintSet[i].mainTextureName =
1178 EditorGUILayout.TextField(
"MainTexture Property Name",
1179 instance.paintSet[i].mainTextureName);
1180 if (EditorGUI.EndChangeCheck())
1181 ChangeValue(i,
"Main Texture Name",
1182 p => p.mainTextureName = instance.paintSet[i].mainTextureName);
1183 EditorGUI.indentLevel--;
1187 EditorGUI.BeginChangeCheck();
1188 instance.paintSet[i].useNormalPaint = EditorGUILayout.Toggle(
"Use NormalMap Paint",
1189 instance.paintSet[i].useNormalPaint);
1190 if (EditorGUI.EndChangeCheck())
1191 ChangeValue(i,
"Use Normal Paint",
1192 p => p.useNormalPaint = instance.paintSet[i].useNormalPaint);
1193 if (instance.paintSet[i].useNormalPaint)
1195 EditorGUI.indentLevel++;
1196 EditorGUI.BeginChangeCheck();
1197 instance.paintSet[i].normalTextureName =
1198 EditorGUILayout.TextField(
"NormalMap Property Name",
1199 instance.paintSet[i].normalTextureName);
1200 if (EditorGUI.EndChangeCheck())
1201 ChangeValue(i,
"Normal Texture Name",
1202 p => p.normalTextureName = instance.paintSet[i].normalTextureName);
1203 EditorGUI.indentLevel--;
1207 EditorGUI.BeginChangeCheck();
1208 instance.paintSet[i].useHeightPaint = EditorGUILayout.Toggle(
"Use HeightMap Paint",
1209 instance.paintSet[i].useHeightPaint);
1210 if (EditorGUI.EndChangeCheck())
1211 ChangeValue(i,
"Use Height Paint",
1212 p => p.useHeightPaint = instance.paintSet[i].useHeightPaint);
1213 if (instance.paintSet[i].useHeightPaint)
1215 EditorGUI.indentLevel++;
1216 EditorGUI.BeginChangeCheck();
1217 instance.paintSet[i].heightTextureName =
1218 EditorGUILayout.TextField(
"HeightMap Property Name",
1219 instance.paintSet[i].heightTextureName);
1220 if (EditorGUI.EndChangeCheck())
1221 ChangeValue(i,
"Height Texture Name",
1222 p => p.heightTextureName = instance.paintSet[i].heightTextureName);
1223 EditorGUI.indentLevel--;
1226 EditorGUILayout.EndVertical();
1227 EditorGUI.indentLevel = 0;
1230 #endregion Property Setting
1234 private void SaveRenderTextureToPNG(
string textureName, RenderTexture renderTexture,
1235 Action<TextureImporter> importAction =
null)
1237 var path = EditorUtility.SaveFilePanel(
"Save to png", Application.dataPath,
1238 textureName +
"_painted.png",
"png");
1239 if (path.Length != 0)
1241 var newTex =
new Texture2D(renderTexture.width, renderTexture.height);
1242 RenderTexture.active = renderTexture;
1243 newTex.ReadPixels(
new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
1246 var pngData = newTex.EncodeToPNG();
1247 if (pngData !=
null)
1249 File.WriteAllBytes(path, pngData);
1250 AssetDatabase.Refresh();
1251 var importer = AssetImporter.GetAtPath(path) as TextureImporter;
1252 if (importAction !=
null)
1253 importAction(importer);
1260 private void ChangeValue(
int paintSetIndex,
string recordName, Action<PaintSet> assign)
1262 Undo.RecordObjects(targets,
"Change " + recordName);
1263 foreach (var t
in targets.Where(_t => _t is InkCanvas).Select(_t => _t as InkCanvas))
1264 if (t.paintSet.Count > paintSetIndex)
1266 assign(t.paintSet[paintSetIndex]);
1267 EditorUtility.SetDirty(t);
1270 EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
1273 public bool Foldout(
bool foldout,
string content)
1275 var style =
new GUIStyle(
"ShurikenModuleTitle");
1276 style.font =
new GUIStyle(EditorStyles.label).font;
1277 style.border =
new RectOffset(1, 7, 4, 4);
1278 style.fixedHeight = 28;
1279 style.contentOffset =
new Vector2(20f, -2f);
1281 var rect = GUILayoutUtility.GetRect(16f, 22f, style);
1282 GUI.Box(rect, content, style);
1284 var e = Event.current;
1286 var toggleRect =
new Rect(rect.x + 4f, rect.y + 5f, 13f, 13f);
1287 if (e.type == EventType.Repaint) EditorStyles.foldout.Draw(toggleRect,
false,
false, foldout,
false);
1289 if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition))
1301 #endregion CustomEditor
Class managing brush information.
float Scale
The size of the brush. It takes a range from 0 to 1.
Texture mainTexture
In the first time set to the material's main texture.
int mainTexturePropertyID
RenderTexture paintNormalTexture
Copied the normal map to rendertexture that use to paint.
RenderTexture paintHeightTexture
Copied the height map to rendertexture that use to paint.
int heightTexturePropertyID
Material material
Applying paint materials.
PaintSet(string mainTextureName, string normalTextureName, string heightTextureName, bool useMainPaint, bool useNormalPaint, bool useHeightPaint)
Setup paint data.
PaintSet()
Default constractor.
Texture heightTexture
In the first time set to the material's height map.
PaintSet(string mainTextureName, string normalTextureName, string heightTextureName, bool useMainPaint, bool useNormalPaint, bool useHeightPaint, Material material)
Setup paint data.
RenderTexture paintMainTexture
Copied the main texture to rendertexture that use to paint.
int normalTexturePropertyID
Texture normalTexture
In the first time set to the material's normal map.
Texture paint to canvas. To set the per-material.
bool Paint(Brush brush, Vector3 localPos)
Action< InkCanvas, Brush > OnPaintStart
Called at paint start.
Action< InkCanvas > OnCanvasAttached
Called by InkCanvas attached game object.
bool Erase(Brush brush, Vector3 worldPos, Func< PaintSet, bool > materialSelector=null, Camera renderCamera=null)
Erase processing that use world-space surface position.
bool PaintNearestTriangleSurface(Brush brush, Vector3 worldPos, Func< PaintSet, bool > materialSelector=null, Camera renderCamera=null)
Paint of points close to the given world-space position on the Mesh surface.
bool PaintUVDirect(Brush brush, Vector2 uv, Func< PaintSet, bool > materialSelector=null)
Paint processing that UV coordinates to the specified.
Action< InkCanvas > OnInitializedAfter
Called by InkCanvas initialization completion times.
bool EraseNearestTriangleSurface(Brush brush, Vector3 worldPos, Func< PaintSet, bool > materialSelector=null, Camera renderCamera=null)
Erase of points close to the given world-space position on the Mesh surface.
List< PaintSet > PaintDatas
Access data used for painting.
void ResetPaint()
To reset the paint.
Action< InkCanvas > OnInitializedStart
Called by InkCanvas initialization start times.
MeshOperator MeshOperator
Texture GetMainTexture(string materialName)
To get the original main texture.
bool EraseUVDirect(Brush brush, Vector2 uv, Func< PaintSet, bool > materialSelector=null)
Erase processing that UV coordinates to the specified.
bool Paint(Brush brush, Vector3 worldPos, Func< PaintSet, bool > materialSelector=null, Camera renderCamera=null)
Paint processing that use world-space surface position.
bool Erase(Brush brush, RaycastHit hitInfo, Func< PaintSet, bool > materialSelector=null)
Erase processing that use raycast hit data. Must MeshCollider is set to the canvas.
RenderTexture GetPaintNormalTexture(string materialName)
To get the paint in normal map.
void SetPaintHeightTexture(string materialName, RenderTexture newTexture)
Set paint texture.
void SetPaintMainTexture(string materialName, RenderTexture newTexture)
Set paint texture.
bool Paint(Brush brush, RaycastHit hitInfo, Func< PaintSet, bool > materialSelector=null)
Paint processing that use raycast hit data. Must MeshCollider is set to the canvas.
Action< InkCanvas > OnPaintEnd
Called at paint end.
RenderTexture GetPaintMainTexture(string materialName)
To get the main texture in paint.
Texture GetHeightTexture(string materialName)
To get the original height map.
Texture GetNormalTexture(string materialName)
To get the original normal map.
RenderTexture GetPaintHeightTexture(string materialName)
To get the paint in height map.
void SetPaintNormalTexture(string materialName, RenderTexture newTexture)
Set paint texture.
A class that manipulates Mesh.
bool LocalPointToUV(Vector3 localPoint, Matrix4x4 matrixMVP, out Vector2 uv)
Convert local-space point to texture coordinates.
Vector3 NearestLocalSurfacePoint(Vector3 localPoint)
Returns the point on the surface of Mesh closest to the point on the specified local-space.