zoukankan      html  css  js  c++  java
  • unity 在模型上绘画

    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.EventSystems;
    /// <summary>
    /// 在模型上绘画
    /// </summary>
    public class DrawOnModel:BaseMonoBehaviour{
    	public GameObject target;
    	[Tooltip("颜色")]
    	public Color color=Color.cyan;
    	[Tooltip("笔刷大小")]
    	public float brushSize=10f;
    	public Texture2D texture2D { get; private set; }
    
    	private Camera m_mainCamera;
    	private struct PointColor{
    		public PointColor(int x,int y,Color cor){
    			point=new Vector2Int(x,y);
    			color=cor;
    		}
    		public Vector2Int point;
    		public Color color;
    	}
    	private List<PointColor[]> m_undoList=new List<PointColor[]>();
    	private List<PointColor> m_tempUndoList;
    	private RaycastHit[] m_raycastHits=new RaycastHit[1];
    
    	protected override void Awake(){
    		base.Awake();
    		m_mainCamera=Camera.main;
    		
    		Renderer renderer=target.GetComponent<Renderer>();
    		Texture2D mainTexture=(Texture2D)renderer.material.mainTexture;
    		//创建一个副本,避免修改原纹理
    		texture2D=new Texture2D(mainTexture.width,mainTexture.height);
    		texture2D.SetPixels(mainTexture.GetPixels());
    		texture2D.Apply();
    		renderer.material.mainTexture=texture2D;
    	}
    
    	protected override void Update2(){
    		base.Update2();
    		if(Input.touchSupported){
    			if(Input.touchCount>0){
    				Touch touch=Input.GetTouch(0);
    				if(touch.phase==TouchPhase.Began){
    					DrawBegin(touch.position);
    				}else if(touch.phase==TouchPhase.Moved){
    					if(!EventSystem.current.IsPointerOverGameObject(touch.fingerId)){
    						DrawScreenPoint(touch.position);
    					}
    				}else if(touch.phase==TouchPhase.Ended||touch.phase==TouchPhase.Canceled){
    					DrawEnd();
    				}
    			}
    		}else{
    			Vector2 mousePos=Input.mousePosition;
    			if(Input.GetMouseButtonDown(0)){
    				DrawBegin(mousePos);
    			}
    			if(Input.GetMouseButton(0)&&!EventSystem.current.IsPointerOverGameObject()){
    				DrawScreenPoint(mousePos);
    			}
    			if(Input.GetMouseButtonUp(0)){
    				DrawEnd();
    			}
    		}
    	}
    
    	private void DrawBegin(Vector2 screenPos){
    		m_tempUndoList=new List<PointColor>();
    	}
    
    	private void DrawScreenPoint(Vector2 screenPos){
    		Physics.RaycastNonAlloc(m_mainCamera.ScreenPointToRay(screenPos),m_raycastHits);
    		var hit=m_raycastHits[0];
    		if(hit.collider!=null&&hit.collider.gameObject==target){
    			PointColor[] undoList=DrawCircleDot(hit.textureCoord,texture2D,color,brushSize);
    			if(undoList!=null&&undoList.Length>0){
    				m_tempUndoList.AddRange(undoList);
    			}
    		}
    	}
    
    	private void DrawEnd(){
    		if(m_tempUndoList!=null&&m_tempUndoList.Count>0){
    			m_undoList.Add(m_tempUndoList.ToArray());
    			m_tempUndoList=null;
    		}
    	}
    	
    	/// <summary>
    	/// 画圆形点
    	/// </summary>
    	/// <param name="point">坐标</param>
    	/// <param name="texture">贴图</param>
    	/// <param name="color">颜色</param>
    	/// <param name="diameter">直径</param>
    	/// <returns>返回改变的像素的旧颜色列表</returns>
    	private PointColor[] DrawCircleDot(Vector2 point,Texture2D texture,Color color,float diameter){
    		float radius=diameter*0.5f;
    		
    		point.x*=texture.width;
    		point.y*=texture.height;
    		
    		point.x-=radius;
    		point.y-=radius;
     
    		int x=Mathf.FloorToInt(point.x);
    		int y=Mathf.FloorToInt(point.y);
    
    		List<PointColor> tempList=new List<PointColor>();
    		for (int i=0;i<diameter;i++){
    			for (int j=0;j<diameter;j++){
    				float dx=i-radius;
    				float dy=j-radius;
    				float distance=Mathf.Sqrt(dx*dx+dy*dy);
    				if(distance<=radius){
    					int px=x+i;
    					int py=y+j;
    					Color oldColor=texture.GetPixel(px,py);
    					if(oldColor!=color){
    						tempList.Add(new PointColor(px,py,oldColor));
    						texture.SetPixel(px,py,color);
    					}
    				}
    			}
    		}
    		texture.Apply();
    		return tempList.ToArray();
    	}
    
    	/// <summary>
    	/// 撤消
    	/// </summary>
    	public void Undo(){
    		if(m_undoList.Count>0){
    			PointColor[] list=m_undoList[m_undoList.Count-1];
    			int len=list.Length;
    			for(int i=0;i<len;i++){
    				PointColor element=list[i];
    				texture2D.SetPixel(element.point.x,element.point.y,element.color);
    			}
    			texture2D.Apply();
    			m_undoList.RemoveAt(m_undoList.Count-1);
    		}
    	}
    
    }
    
    注意:

    1.调用Texture2D.SetPixel()和Texture2D.GetPixel()时,在纹理导入设置中,必须勾选Read/Write Enabled,纹理格式仅支持RGBA32,ARGB32,RGB24,Alpha8(动态新建的Texture2D不必处理)。
    2.调用RaycastHit.textureCoord时,如果目标网格在.fbx内,则.fbx文件的导入设置中,必须勾选Read/Write Enabled(未勾选在安卓中测试会出现秒退或始终返回0)。

  • 相关阅读:
    透视校正插值
    投影矩阵推导
    编程思想-小即是美
    Win10使用小技巧
    TotalCommander 之 快捷键
    TotalCommander 之 配置
    TotalCommander 之 日常使用技巧
    上士闻道,勤而行之;中士闻道,若存若亡;下士闻道,大笑之。不笑不足以为道。
    《诫子书》
    青春不是年华,而是心境
  • 原文地址:https://www.cnblogs.com/kingBook/p/12283840.html
Copyright © 2011-2022 走看看