/// <summary> /// ペイント処理を行う /// CanvasにはMeshColliderが設定されている必要があります /// </summary> /// <param name="brush">ブラシ</param> /// <param name="hitInfo">RaycastのHit情報</param> /// <returns>ペイントの成否</returns> public bool Paint(PaintBrush brush, RaycastHit hitInfo) { if (hitInfo.collider != null && hitInfo.collider.gameObject == gameObject) { #region ErrorCheck if (brush == null) { Debug.LogError("ブラシが設定されていません"); return(false); } #endregion ErrorCheck //MeshColliderが設定されていない場合はヒット位置でペイントを行う if (!(GetComponent <Collider>() is MeshCollider)) { Debug.LogWarning("MeshColliderが設定されていないキャンバスにRayCastを利用したPaintを行うと予期せぬ動作をする場合があります"); //頂点のTriangleから一番近いサーフェス上の点を算出してPaintに渡すように return(PaintNearestTriangleSurface(brush, hitInfo.point)); } return(PaintUVDirect(brush, hitInfo.textureCoord)); } return(false); }
/// <summary> /// 与えられたworldPosに近いMeshSurface上の点に対してペイント処理を行う /// </summary> /// <param name="brush">ブラシ</param> /// <param name="worldPos">近似点</param> /// <param name="renderCamera">レンダリングに利用するカメラ</param> /// <returns></returns> public bool PaintNearestTriangleSurface(PaintBrush brush, Vector3 worldPos, Camera renderCamera = null) { var p = transform.worldToLocalMatrix.MultiplyPoint(worldPos); //頂点の中で一番近いものを含む三角形を取得 var tris = Utility.Math.GetNearestVerticesTriangle(p, meshVertices, meshTriangles); //それぞれの三角形空間でそれっぽいp'を計算 var pds = new List <Vector3>(); for (int i = 0; i < tris.Length; i += 3) { var i0 = i; var i1 = i + 1; var i2 = i + 2; pds.Add(Utility.Math.TriangleSpaceProjection(p, tris[i0], tris[i1], tris[i2])); } //HACK:p'が三角形内部にない場合は一番近い頂点位置をp'に設定した方がいい? //pに一番近いp'が求めたかったオブジェクト表面 var pd = pds.OrderBy(t => Vector3.Distance(p, t)).First(); return(Paint(brush, transform.localToWorldMatrix.MultiplyPoint(pd), renderCamera)); }
/// <summary> /// Paint of points close to the given world-space position on the Mesh surface. /// </summary> /// <param name="brush">Brush data.</param> /// <param name="worldPos">Approximate point.</param> /// <param name="renderCamera">Camera to use to render the object.</param> /// <returns>The success or failure of the paint.</returns> public bool PaintNearestTriangleSurface(PaintBrush brush, Vector3 worldPos, Camera renderCamera = null) { var p = transform.worldToLocalMatrix.MultiplyPoint(worldPos); var pd = MeshOperator.NearestLocalSurfacePoint(p); return(Paint(brush, transform.localToWorldMatrix.MultiplyPoint(pd), renderCamera)); }
/// <summary> /// 直接UV座標を指定したペイント処理を行う /// </summary> /// <param name="brush">ブラシ</param> /// <param name="uv">ヒット位置のUV座標</param> /// <returns>ペイントの成否</returns> public bool PaintUVDirect(PaintBrush brush, Vector2 uv) { foreach (var p in paintSet) { //メインテクスチャへのペイント if (p.useMainPaint && brush.BrushTexture != null && p.paintMainTexture != null && p.paintMainTexture.IsCreated()) { var mainPaintTextureBuffer = RenderTexture.GetTemporary(p.mainTexture.width, p.mainTexture.height); SetPaintMainData(brush, uv); Graphics.Blit(p.paintMainTexture, mainPaintTextureBuffer, paintMaterial); Graphics.Blit(mainPaintTextureBuffer, p.paintMainTexture); RenderTexture.ReleaseTemporary(mainPaintTextureBuffer); } //法線マップへのペイント if (p.useNormalPaint && brush.BrushNormalTexture != null && p.paintNormalTexture != null && p.paintNormalTexture.IsCreated()) { var normalPaintTextureBuffer = RenderTexture.GetTemporary(p.normalTexture.width, p.normalTexture.height); SetPaintNormalData(brush, uv); Graphics.Blit(p.paintNormalTexture, normalPaintTextureBuffer, paintNormalMaterial); Graphics.Blit(normalPaintTextureBuffer, p.paintNormalTexture); RenderTexture.ReleaseTemporary(normalPaintTextureBuffer); } //ハイトマップへのペイント if (p.useHeightPaint && brush.BrushHeightTexture != null && p.paintHeightTexture != null && p.paintHeightTexture.IsCreated()) { var heightPaintTextureBuffer = RenderTexture.GetTemporary(p.heightTexture.width, p.heightTexture.height); SetPaintHeightData(brush, uv); Graphics.Blit(p.paintHeightTexture, heightPaintTextureBuffer, paintHeightMaterial); Graphics.Blit(heightPaintTextureBuffer, p.paintHeightTexture); RenderTexture.ReleaseTemporary(heightPaintTextureBuffer); } } return(true); }
/// <summary> /// ペイントに必要なデータをシェーダーにセットする /// </summary> /// <param name="brush">ブラシ</param> /// <param name="uv">ヒット位置のUV座標</param> private void SetPaintMainData(PaintBrush brush, Vector2 uv) { paintMaterial.SetVector(paintUVPropertyID, uv); paintMaterial.SetTexture(brushTexturePropertyID, brush.BrushTexture); paintMaterial.SetFloat(brushScalePropertyID, brush.Scale); paintMaterial.SetVector(brushColorPropertyID, brush.Color); foreach (var key in paintMaterial.shaderKeywords) { paintMaterial.DisableKeyword(key); } switch (brush.ColorBlending) { case PaintBrush.ColorBlendType.UseColor: paintMaterial.EnableKeyword(COLOR_BLEND_USE_CONTROL); break; case PaintBrush.ColorBlendType.UseBrush: paintMaterial.EnableKeyword(COLOR_BLEND_USE_BRUSH); break; case PaintBrush.ColorBlendType.Neutral: paintMaterial.EnableKeyword(COLOR_BLEND_NEUTRAL); break; default: paintMaterial.EnableKeyword(COLOR_BLEND_USE_CONTROL); break; } }
/// <summary> /// Paint processing that use raycast hit data. /// Must MeshCollider is set to the canvas. /// </summary> /// <param name="brush">Brush data.</param> /// <param name="hitInfo">Raycast hit info.</param> /// <returns>The success or failure of the paint.</returns> public bool Paint(PaintBrush brush, RaycastHit hitInfo) { if (hitInfo.collider != null && hitInfo.collider.gameObject == gameObject) { if (!(GetComponent <Collider>() is MeshCollider)) { Debug.LogWarning("If you want to paint using a Raycast, need set MeshCollider for canvas object."); return(PaintNearestTriangleSurface(brush, hitInfo.point)); } return(PaintUVDirect(brush, hitInfo.textureCoord)); } return(false); }
/// <summary> /// ペイント処理を行う /// </summary> /// <param name="brush">ブラシ</param> /// <param name="worldPos"> /// キャンバス上の塗る点(World-Space) /// メッシュが構成する形状のサーフェスの上の点 /// </param> /// <param name="renderCamera">レンダリングに利用するカメラ</param> /// <returns>ペイント成否</returns> public bool Paint(PaintBrush brush, Vector3 worldPos, Camera renderCamera = null) { if (renderCamera == null) { renderCamera = Camera.main; } int index0; int index1; int index2; Vector3 t1; Vector3 t2; Vector3 t3; Vector3 p = transform.InverseTransformPoint(worldPos); for (var i = 0; i < meshTriangles.Length; i += 3) { index0 = i + 0; index1 = i + 1; index2 = i + 2; t1 = meshVertices[meshTriangles[index0]]; t2 = meshVertices[meshTriangles[index1]]; t3 = meshVertices[meshTriangles[index2]]; //平面上に存在しない if (!Utility.Math.ExistPointInPlane(p, t1, t2, t3)) { continue; } //三角形の辺または内部に存在しない if (!Utility.Math.ExistPointOnTriangleEdge(p, t1, t2, t3) && !Utility.Math.ExistPointInTriangle(p, t1, t2, t3)) { continue; } //UV座標算出 var uv1 = meshUV[meshTriangles[index0]]; var uv2 = meshUV[meshTriangles[index1]]; var uv3 = meshUV[meshTriangles[index2]]; Matrix4x4 mvp = renderCamera.projectionMatrix * renderCamera.worldToCameraMatrix * transform.localToWorldMatrix; var uv = Utility.Math.TextureCoordinateCalculation(p, t1, uv1, t2, uv2, t3, uv3, mvp); return(PaintUVDirect(brush, uv)); } return(false); }
/// <summary> /// To set the data needed to height map paint shader. /// </summary> /// <param name="brush">Brush data.</param> /// <param name="uv">UV coordinates for the hit location.</param> private void SetPaintHeightData(PaintBrush brush, Vector2 uv) { paintHeightMaterial.SetVector(paintUVPropertyID, uv); paintHeightMaterial.SetTexture(brushTexturePropertyID, brush.BrushTexture); paintHeightMaterial.SetTexture(brushHeightTexturePropertyID, brush.BrushHeightTexture); paintHeightMaterial.SetFloat(brushScalePropertyID, brush.Scale); paintHeightMaterial.SetFloat(brushHeightBlendPropertyID, brush.HeightBlend); paintHeightMaterial.SetVector(brushHeightColorPropertyID, brush.Color); foreach (var key in paintHeightMaterial.shaderKeywords) { paintHeightMaterial.DisableKeyword(key); } switch (brush.HeightBlending) { case PaintBrush.HeightBlendType.UseBrush: paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_USE_BRUSH); break; case PaintBrush.HeightBlendType.Add: paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_ADD); break; case PaintBrush.HeightBlendType.Sub: paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_SUB); break; case PaintBrush.HeightBlendType.Min: paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_MIN); break; case PaintBrush.HeightBlendType.Max: paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_MAX); break; case PaintBrush.HeightBlendType.ColorRGB_HeightA: paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_COLOR_RGB_HEIGHT_A); break; default: paintHeightMaterial.EnableKeyword(HEIGHT_BLEND_ADD); break; } }
/// <summary> /// Paint processing that UV coordinates to the specified. /// </summary> /// <param name="brush">Brush data.</param> /// <param name="uv">UV coordinates for the hit location.</param> /// <returns>The success or failure of the paint.</returns> public bool PaintUVDirect(PaintBrush brush, Vector2 uv) { #region ErrorCheck if (brush == null) { Debug.LogError("Do not set the brush."); return(false); } #endregion ErrorCheck foreach (var p in paintSet) { if (p.useMainPaint && brush.BrushTexture != null && p.paintMainTexture != null && p.paintMainTexture.IsCreated()) { var mainPaintTextureBuffer = RenderTexture.GetTemporary(p.paintMainTexture.width, p.paintMainTexture.height); SetPaintMainData(brush, uv); Graphics.Blit(p.paintMainTexture, mainPaintTextureBuffer, paintMaterial); Graphics.Blit(mainPaintTextureBuffer, p.paintMainTexture); RenderTexture.ReleaseTemporary(mainPaintTextureBuffer); } if (p.useNormalPaint && brush.BrushNormalTexture != null && p.paintNormalTexture != null && p.paintNormalTexture.IsCreated()) { var normalPaintTextureBuffer = RenderTexture.GetTemporary(p.paintNormalTexture.width, p.paintNormalTexture.height); SetPaintNormalData(brush, uv); Graphics.Blit(p.paintNormalTexture, normalPaintTextureBuffer, paintNormalMaterial); Graphics.Blit(normalPaintTextureBuffer, p.paintNormalTexture); RenderTexture.ReleaseTemporary(normalPaintTextureBuffer); } if (p.useHeightPaint && brush.BrushHeightTexture != null && p.paintHeightTexture != null && p.paintHeightTexture.IsCreated()) { var heightPaintTextureBuffer = RenderTexture.GetTemporary(p.paintHeightTexture.width, p.paintHeightTexture.height); SetPaintHeightData(brush, uv); Graphics.Blit(p.paintHeightTexture, heightPaintTextureBuffer, paintHeightMaterial); Graphics.Blit(heightPaintTextureBuffer, p.paintHeightTexture); RenderTexture.ReleaseTemporary(heightPaintTextureBuffer); } } return(true); }
/// <summary> /// ペイント処理を行う /// </summary> /// <param name="brush">ブラシ</param> /// <param name="worldPos"> /// キャンバス上の塗る点(World-Space) /// メッシュが構成する形状のサーフェスの上の点 /// </param> /// <param name="renderCamera">レンダリングに利用するカメラ</param> /// <returns>ペイント成否</returns> public bool Paint(PaintBrush brush, Vector3 worldPos, Camera renderCamera = null) { Vector2 uv; if (renderCamera == null) { renderCamera = Camera.main; } Vector3 p = transform.InverseTransformPoint(worldPos); Matrix4x4 mvp = renderCamera.projectionMatrix * renderCamera.worldToCameraMatrix * transform.localToWorldMatrix; if (meshOperator.LocalPointToUV(p, mvp, out uv)) { return(PaintUVDirect(brush, uv)); } return(false); }
/// <summary> /// 法線マップペイントに必要なデータをシェーダーにセットする /// </summary> /// <param name="brush">ブラシ</param> /// <param name="uv">ヒット位置のUV座標</param> private void SetPaintNormalData(PaintBrush brush, Vector2 uv) { paintNormalMaterial.SetVector(paintUVPropertyID, uv); paintNormalMaterial.SetTexture(brushTexturePropertyID, brush.BrushTexture); paintNormalMaterial.SetTexture(brushNormalTexturePropertyID, brush.BrushNormalTexture); paintNormalMaterial.SetFloat(brushScalePropertyID, brush.Scale); paintNormalMaterial.SetFloat(brushNormalBlendPropertyID, brush.NormalBlend); foreach (var key in paintNormalMaterial.shaderKeywords) { paintNormalMaterial.DisableKeyword(key); } switch (brush.NormalBlending) { case PaintBrush.NormalBlendType.UseBrush: paintNormalMaterial.EnableKeyword(NORMAL_BLEND_USE_BRUSH); break; case PaintBrush.NormalBlendType.Add: paintNormalMaterial.EnableKeyword(NORMAL_BLEND_ADD); break; case PaintBrush.NormalBlendType.Sub: paintNormalMaterial.EnableKeyword(NORMAL_BLEND_SUB); break; case PaintBrush.NormalBlendType.Min: paintNormalMaterial.EnableKeyword(NORMAL_BLEND_MIN); break; case PaintBrush.NormalBlendType.Max: paintNormalMaterial.EnableKeyword(NORMAL_BLEND_MAX); break; default: paintNormalMaterial.EnableKeyword(NORMAL_BLEND_USE_BRUSH); break; } }
/// <summary> /// Paint processing that use world-space surface position. /// </summary> /// <param name="brush">Brush data.</param> /// <param name="worldPos">Point on object surface (world-space).</param> /// <param name="renderCamera">Camera to use to render the object.</param> /// <returns>The success or failure of the paint.</returns> public bool Paint(PaintBrush brush, Vector3 worldPos, Camera renderCamera = null) { Vector2 uv; if (renderCamera == null) { renderCamera = Camera.main; } Vector3 p = transform.InverseTransformPoint(worldPos); Matrix4x4 mvp = renderCamera.projectionMatrix * renderCamera.worldToCameraMatrix * transform.localToWorldMatrix; if (MeshOperator.LocalPointToUV(p, mvp, out uv)) { return(PaintUVDirect(brush, uv)); } else { Debug.LogWarning("Could not get the point on the surface."); return(PaintNearestTriangleSurface(brush, worldPos, renderCamera)); } }