Unity把Texture2D复制到坐标点击处的Texture2D

今天做一个画图程序,类似给一个白纸,
然后用类似印章的图形点哪里就在哪里出现。

Unity在处理Texture2D上只有对像素进行操作,
所以要用到GL的一些方法,执行效率可能会更高。

代码比较简单,直接贴上应该能看懂。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//复制一个Texture到另外一个Texture.
public class CDrawTexture : MonoBehaviour
{
    Material nowMat;    
    Texture2D nowTexture;   //当前纹理
    RectInt nowWH;  //宽高

    Color clearColor = new Color(0f, 0f, 0f, 0f);   //清除的色值
    public void InitDrawTexture()
    {
        nowMat = PrefabList.inst.SpriteDefault;
    }

    public Texture2D CreateNewTexture(int w, int h)
    {
        Clear();
        nowWH = new RectInt(0, 0, w, h);
        nowTexture = new Texture2D(w, h);

        FillColor(nowTexture, clearColor);
        return nowTexture;
    }

    public void Clear()
    {
        if (nowTexture != null)
        {
            DestroyImmediate(nowTexture);
        }
    }

    

    public Texture2D CopyTexture(Texture2D source,Vector3 penpos)
    {
        RenderTexture renderTexture = RenderTexture.GetTemporary(nowWH.width, nowWH.height);
        RenderTexture.active = renderTexture;

        //清空 GL
        GL.Clear(false, true, clearColor);

        //把source渲染到GL
        RenderGLStuff(nowWH.width, nowWH.height, nowMat, nowTexture, nowWH.width, nowWH.height, -new Vector3(nowWH.width, nowWH.height,0f)/2);
        //把目标渲染到GL
        RenderGLStuff(nowWH.width, nowWH.height, nowMat, source, source.width, source.height, penpos * globalData.pixUnit);

        //读取 RenderTexture 到材质 nowTexture
        nowTexture.ReadPixels(new Rect(0, 0, nowWH.width, nowWH.height), 0, 0);
        nowTexture.Apply();
        RenderTexture.active = null;
        RenderTexture.ReleaseTemporary(renderTexture);
        return nowTexture;
    }
    

    //把某个颜色填充
    static void FillColor(Texture2D t, Color c)
    {
        RenderTexture renderTexture = RenderTexture.GetTemporary(t.width, t.height);
        RenderTexture.active = renderTexture;
        GL.Clear(false, true, c);
        //读取 RenderTexture 到材质 nowTexture
        t.ReadPixels(new Rect(0, 0, t.width, t.height), 0, 0);
        t.Apply();
        RenderTexture.active = null;
        RenderTexture.ReleaseTemporary(renderTexture);
    }


    
    /// <summary>
    /// 把一个Texture复制到另外一个Texture
    /// </summary>
    /// <param name="width">目标纹理大小</param>
    /// <param name="height">目标纹理大小</param>
    /// <param name="material"></param>
    /// <param name="source">复制的纹理</param>
    /// <param name="sw">复制的纹理宽</param>
    /// <param name="sh">复制的纹理高</param>
    /// <param name="penpos">鼠标位置</param>
    static void RenderGLStuff(int width, int height, Material material, Texture2D source, float sw, float sh, Vector3 penpos)
    {
        material.SetPass(0);
        GL.PushMatrix();//GL入栈
        GL.LoadPixelMatrix(0, width, height, 0);
        Graphics.DrawTexture(new Rect(0, 0, 0, 0), source);
        GL.LoadOrtho(); //转换为正交投影变换
        GL.Begin(GL.QUADS);
        float szWidth = sw / width;
        float szHeight = sh / height;
        Vector2 at = new Vector2((penpos.x + width / 2f) / width, (penpos.y + height / 2f) / height);
        GL.TexCoord2(0, 0); GL.Vertex3(at.x + 0f, at.y + 0f, 0f);   //设置纹理和顶点坐标
        GL.TexCoord2(1, 0); GL.Vertex3(at.x + szWidth, at.y + 0f, 0f);
        GL.TexCoord2(1, 1); GL.Vertex3(at.x + szWidth, at.y + szHeight, 0f);
        GL.TexCoord2(0, 1); GL.Vertex3(at.x + 0f, at.y + szHeight, 0f);
        GL.End();
        GL.PopMatrix(); //GL出栈
    }
}


在其他脚本调用:

public void PaintXY(Vector3 pos)
    {
        if (nowTool == null)
            return;
        pos.z = Mathf.Abs(nowMaskObj.transform.position.z - myCamera.transform.position.z);
        Vector3 at = myCamera.ScreenToWorldPoint(pos);
        Vector3 lo = nowMaskObj.transform.InverseTransformPoint(at);

       
        gameRoot.inst.drawTexture.CopyTexture(PrefabList.inst.tPen,lo);
        //Debug.Log("PaintXY :" + lo );
        checkValue = true;
    }

下面是写代码中遇到的一些知识点,总结在下面。

如果只是对纹理的复制,可以用下面的方法

        if (SystemInfo.copyTextureSupport == UnityEngine.Rendering.CopyTextureSupport.None)
        {
            //High GC allocs here
            Color[] pixelBuffer = source.GetPixels((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
            nowTexture.SetPixels(pixelBuffer);
            nowTexture.Apply();
        }
        else
        {
            Graphics.CopyTexture(source, 0, 0, (int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height, nowTexture, 0, 0, 0, 0);
        }

另外关于Graphics.DrawTexture的一些高级用法,也研究了下,并做一些记录。

public static void DrawTexture(Rect screenRect, Texture texture, Material mat = null, int pass = -1);
public static void DrawTexture(Rect screenRect, Texture texture, int leftBorder, int rightBorder, int topBorder, int bottomBorder, Material mat = null, int pass = -1);
public static void DrawTexture(Rect screenRect, Texture texture, Rect sourceRect, int leftBorder, int rightBorder, int topBorder, int bottomBorder, Material mat = null, int pass = -1);
public static void DrawTexture(Rect screenRect, Texture texture, Rect sourceRect, int leftBorder, int rightBorder, int topBorder, int bottomBorder, Color color, Material mat = null, int pass = -1);
Parameters

screenRect	Rectangle on the screen to use for the texture. In pixel coordinates with (0,0) in the upper-left corner.
texture	Texture to draw.
sourceRect	Region of the texture to use. In normalized coordinates with (0,0) in the bottom-left corner.
leftBorder	Number of pixels from the left that are not affected by scale.
rightBorder	Number of pixels from the right that are not affected by scale.
topBorder	Number of pixels from the top that are not affected by scale.
bottomBorder	Number of pixels from the bottom that are not affected by scale.
color	Color that modulates the output. The neutral value is (0.5, 0.5, 0.5, 0.5). Set as vertex color for the shader.
mat	Custom Material that can be used to draw the texture. If null is passed, a default material with the Internal-GUITexture.shader is used.
pass	If -1 (default), draws all passes in the material. Otherwise, draws given pass only.

这里的sourRect参数可以实现复制纹理中的部分,例如图集中的一块。
但是这里要注意,在这里踩了大坑。一直搞不对,原来这个参数的范围是0~1之间的。 文档中竟然只字未提,可恶,只是说0,0点是左下角。下来的4个Border应该是9宫格用法了,没用上,直接写0就好了。

下面是一个测试例子。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    Rect rect = new Rect(1034, 644, 445, 606);
    Rect nowWH = new Rect(0, 0, 445, 606);

    public Texture2D nowTexture;   //当前纹理

    public SpriteRenderer sprite;
	public Texture2D source;
    // Start is called before the first frame update
    void Start()
    {
        nowTexture = new Texture2D((int)nowWH.width, (int)nowWH.height, TextureFormat.ARGB32, false);
        Sprite nowMaskSprite = Sprite.Create(nowTexture, new Rect(0, 0, nowTexture.width, nowTexture.height), new Vector2(0.5f, 0.5f));
        sprite.sprite = nowMaskSprite;

    }

    

    void OnGUI()

    {

        if (Event.current.type.Equals(EventType.Repaint))
        {
            //Graphics.DrawTexture(new Rect(0f, 0f, 800, 800), text);
            RenderTexture renderTexture = RenderTexture.GetTemporary((int)nowWH.width, (int)nowWH.height, 0);

            RenderTexture.active = renderTexture;

            //清空 GL
            GL.Clear(false, true, Color.clear);

            Rect x = new Rect(rect.x / source.width, ((source.height - rect.y- rect.height) / source.height), (rect.width ) / source.width, rect.height/ source.height);

            GL.PushMatrix();//GL入栈
                            //使用Graphics类直接进行Texture绘制时,由于属于直接绘制到平面上,
                            //所以需要转换到平面像素空间内,所以需要用到LoadPixelMatrix方法
            GL.LoadPixelMatrix(0, nowWH.width, nowWH.height,0);// (int)(r.x*r.width/2048), r.width, r.height, (int)(r.y * r.height / 2048));

            //x = new Rect(0f, 0f, 1f, 1f);
            Graphics.DrawTexture(nowWH, source, x, 0, 0, 0, 0);

            GL.PopMatrix(); //GL出栈
            Rect s = new Rect(0f, 0f, 1f, 1f);
            nowTexture.ReadPixels(nowWH, 0, 0);
            nowTexture.Apply();
            RenderTexture.active = null;
            RenderTexture.ReleaseTemporary(renderTexture);
        }
    }
}

source是我做的一个测试图。
在这里插入图片描述

new Rect(1034, 644, 445, 606);
这个区域就是想获得的图片

运行效果
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值