当前位置: 首页 > news >正文

【Unity功能集】TextureShop纹理工坊(五)选区

项目源码:在终章发布

索引

  • 选区
    • PS选区
      • 选区功能点提炼
    • TextureShop选区
      • 方形区域
      • 中间镂空
      • 边框的流动虚线
      • SelectedRegion类
        • 选择选区
        • 更新选区

选区

选区,也既是在当前选中图层中,已选择的编辑区域,我们后续的所有图像编辑操作,都将针对此选中的区域(了解PS选区)。

此功能是TextureShop的核心功能,毕竟我们后续的所有操作都将针对选区展开,那么本章我们将探讨如何实现这个功能点。

PS选区

我们先来看看PS中的选区:

在这里插入图片描述

选区功能点提炼

TextureShop选区功能将完全参照PS选区来实现,所以我们首先来提炼PS选区的功能特点:

1.选区为一个方形区域;
2.选区内部为无色透明(也即是中间镂空);
3.选区边框为流动的虚线;

如上即为实现选区后的功能点,如果你了解unity shader,这三个功能点对你来说并不难。

TextureShop选区

那么现在,让我们来循序展开吧。

方形区域

首先我们要实现的是代表已选取的方形区域,实现的方式依然是借助shader

众所周知,在图形学领域,可用来代表已选取(未选取)这样一个开关属性的参数,通常是用图像的alpha通道来表示,如下图像,白色区域(alpha=1)即可代表已选取区域,棋盘格区域(alpha=0)即可代表未选取区域:

在这里插入图片描述

shader中实现它时,首先需要传入这张代表选区状态的图像:

Shader "Hidden/TextureShop/Region"
{Properties{[HideInInspector] _RegionTex("区域纹理", 2D) = "black" {}}
}

然后在片元处理方法中实现对已选取(未选取)区域的甄别:

		fixed4 frag(FragData IN) : SV_Target{//读取代表选区状态的图像数据half texA = tex2D(_RegionTex, IN.texcoord).a;//texA=1 为已选取区域,输出半透明白色//texA=0 为未选取区域,输出纯透明白色half4 color = half4(1, 1, 1, texA * 0.5);return color;}

看看效果(如何构建这个代表选区状态的图像数据,将在后面讲解):

在这里插入图片描述

很明显,选区的方形区域效果是OK了。

中间镂空

接下来我们要实现选区的内部区域不可见(中间镂空),为此,我们引入参数边框大小,方形区域四周需要显示的部分称作边框,由边框大小来决定其尺寸,而除去边框以外的部分即为中间区域,都将不可见:

Shader "Hidden/TextureShop/Region"
{Properties{[HideInInspector] _RegionTex("区域纹理", 2D) = "black" {}[HideInInspector] _BrushSize("边框大小", int) = 1	}
}

在片元处理方法中:

		fixed4 frag(FragData IN) : SV_Target{float2 uv = IN.texcoord;half texA = tex2D(_RegionTex, uv).a;//基准alpha值half alpha = 1;//遍历边框四周颜色for (int i = -_BrushSize; i <= _BrushSize; i++){for (int j = -_BrushSize; j <= _BrushSize; j++){//将四周的alpha值,累乘到基准alpha值//实现的效果如下://如果四周的alpha值都为1(已选取),则最终基准alpha值也为1(表示此区域为中间区域)//如果四周的alpha值存在0(未选取),则最终基准alpha值也为0(表示此区域为边框区域)float2 borderUV = float2(uv.x + i * _RegionTex_TexelSize.x, uv.y + j * _RegionTex_TexelSize.y);half borderA = tex2D(_RegionTex, borderUV).a;alpha *= borderA;}}half4 color = half4(1, 1, 1, 1);//1 - alpha,将基准alpha值取反,中间区域将为0(输出纯透明色),边框区域将为1(输出白色)color.a = texA * (1 - alpha);return color;}

看看效果:

在这里插入图片描述

边框的流动虚线

接下来我们要实现选区边框区域的流动虚线,我们的第一想法肯定是使用黑白棋盘格图片来实现,为此,我们引入参数边框纹理(棋盘格图片),边框流动速度

Shader "Hidden/TextureShop/Region"
{Properties{[HideInInspector] _RegionTex("区域纹理", 2D) = "black" {}[HideInInspector] _BrushSize("边框大小", int) = 1	[HideInInspector] _BorderTex("边框纹理", 2D) = "black" {}[HideInInspector] _BrushSpeed("边框流动速度", float) = 0.3	}
}

使用此边框纹理(棋盘格图片):

在这里插入图片描述

在片元处理方法中,将边框纹理(棋盘格图片)输出到边框区域,并随时间流动uv:

		fixed4 frag(FragData IN) : SV_Target{//......//half4 color = half4(1, 1, 1, 1);//将原本的边框颜色(白色),改为读取边框纹理颜色,并随时间流动,流动方向:左上角到右下角float2 realUV = float2(uv.x - _Time.x * _BrushSpeed, uv.y + _Time.x * _BrushSpeed);half4 color = tex2D(_BorderTex, realUV * 20);//......}

看看效果:

请添加图片描述

效果有点奇怪,由于棋盘格图片是斜着向右下方移动的,所以每移动一个单位,就会有翻滚一下的效果(图片边缘),因为我们的棋盘格是正方格的图片。

所以需要改进棋盘格图片,使用如下的图片作为边框纹理

在这里插入图片描述

再次运行看效果:

请添加图片描述

OK,没问题了,边框纹理与边框流动方向相同后,流动的虚线效果更加顺眼。

SelectedRegion类

选区的展现效果实现后,接下来新建一个类SelectedRegion,用它来驱动选区逻辑,构建并传入代表选区状态的图像到shader中:

    /// <summary>/// 选区/// </summary>public sealed class SelectedRegion{private RectTransform _rectTransform;private Material _material;private RawImage _target;private Texture2D _texture;private bool _isTextureDirty = false;/// <summary>/// 选区/// </summary>/// <param name="width">选区宽度</param>/// <param name="height">选区高度</param>/// <param name="parent">选区所属父级</param>/// <param name="borderTex">选区边框纹理</param>public SelectedRegion(int width, int height, RectTransform parent, Texture2D borderTex){//创建选区实体(用于显示选区流动的虚线效果)_rectTransform = Utility.CreateRectTransform("SelectedRegion", parent, true);//创建选区材质(使用我们上文创建的shader)_material = new Material(Utility.RegionShader);_material.hideFlags = HideFlags.HideAndDontSave;//使用RawImage作为渲染器_target = _rectTransform.gameObject.AddComponent<RawImage>();_target.raycastTarget = false;_target.material = _material;//构建选区状态图像_texture = new Texture2D(width, height, TextureFormat.RGBA32, false);_texture.SetPixels(new Color[width * height]);_texture.wrapMode = TextureWrapMode.Clamp;_texture.name = "SelectedRegion";//传入选区状态图像到shader_material.SetTexture("_RegionTex", _texture);//传入边框纹理到shader(上文的棋盘格图片)_material.SetTexture("_BorderTex", borderTex);//标记选区状态为脏的,将触发选区更新_isTextureDirty = true;}}
选择选区

矩形选区可由左上角右下角两个点位描述其位置信息,所以我们如此编写选择选区的方法:

    /// <summary>/// 选区/// </summary>public sealed class SelectedRegion{private Vector2Int _leftUp = new Vector2Int(-1, -1);private Vector2Int _rightDown = new Vector2Int(-1, -1);/// <summary>/// 选择选区【矩形选取】/// </summary>/// <param name="leftUp">区域左上角</param>/// <param name="rightDown">区域右下角</param>/// <param name="isImmediatelyUpdate">是否立即更新选区</param>internal void SetRegion(Vector2Int leftUp, Vector2Int rightDown, bool isImmediatelyUpdate = false){_leftUp = leftUp;_rightDown = rightDown;_isTextureDirty = true;if (isImmediatelyUpdate){//更新选区状态OnUpdate();}}}
更新选区
    /// <summary>/// 选区/// </summary>public sealed class SelectedRegion{/// <summary>/// 是否选取任意区域/// </summary>public bool IsSelected { get; private set; } = false;/// <summary>/// 选区更新(OnUpdate帧更新方法由TextureShop编辑器统一调用)/// </summary>public void OnUpdate(){//如果本帧内选区状态为脏的,将触发更新一次if (_isTextureDirty){_isTextureDirty = false;int count = 0;for (int i = 0; i < _texture.width; i++){for (int j = 0; j < _texture.height; j++){if (i >= _leftUp.x && i <= _rightDown.x && j <= _leftUp.y && j >= _rightDown.y){//将处于选区(左上角-右下角)内的像素设置为白色(代表已选取)_texture.SetPixel(i, j, Color.white);count += 1;}else{//将未处于选区(左上角-右下角)内的像素设置为无色(代表未选取)_texture.SetPixel(i, j, Color.clear);}}}//是否存在任意已选取的区域IsSelected = count > 0;//更新选区状态图像,此图像已在构造方法中传递给shader,其将依据此状态图像更新选区展示效果_texture.Apply();}}}

那么至此,矩形选区的功能就实现了。

相关文章:

【Unity功能集】TextureShop纹理工坊(五)选区

项目源码&#xff1a;在终章发布 索引 选区PS选区选区功能点提炼 TextureShop选区方形区域中间镂空边框的流动虚线SelectedRegion类选择选区更新选区 选区 选区&#xff0c;也既是在当前选中图层中&#xff0c;已选择的编辑区域&#xff0c;我们后续的所有图像编辑操作&#x…...

Spring Cloud OpenFeign快速入门demo

一、应用场景 Spring Cloud OpenFeign 是一个声明式的 HTTP 客户端&#xff0c;旨在简化微服务之间的通信。它使得开发者能够通过简单的接口定义和注解来调用 RESTful API&#xff0c;极大地减少了样板代码。以下是一些典型的应用场景&#xff1a; 微服务间调用&#xff1a;在…...

研发效能DevOps: Vite 使用 Element Plus

目录 一、实验 1.环境 2.初始化前端项目 3.安装 vue-route 4.安装 pinia 5.安装 axios 6.安装 Element Plus 7.gitee创建工程 8. 配置路由映射 9.Vite 使用 Element Plus 二、问题 1.README.md 文档推送到gitee未自动换行 2.访问login页面显示空白 3.表单输入账户…...

sfnt-pingpong -测试网络性能和延迟的工具

sfnt-pingpong 是一个用于测试网络性能和延迟的工具&#xff0c;通常用于测量不同网络环境下的数据包传输性能、吞吐量、延迟等指标。 它通常是基于某种网络协议&#xff08;如 TCP&#xff09;执行“ping-pong”式的测试&#xff0c;即客户端和服务器之间相互发送数据包&…...

Kubernetes、Docker 和 Docker Registry 关系是是什么?

Kubernetes&#xff08;常简称为 k8s&#xff09;、Docker 和 Docker Registry 是现代云原生应用中三个关键的组件&#xff0c;它们各自承担不同的职责&#xff0c;但在容器化部署和管理过程中紧密协作。以下是它们之间关系的详细解释&#xff1a; 一、核心概念简介 1. Docker…...

docker部署微信小程序自动构建发布和更新

通过 Jenkins 和 Docker 部署微信小程序&#xff0c;并实现自动构建、发布和版本更新&#xff0c;主要涉及以下几个步骤&#xff1a; 设置 Jenkins 环境配置 GitLab 与 Jenkins 的集成构建 Docker 镜像部署和发布微信小程序配置 Jenkins 自动构建 以下是详细的步骤说明&#…...

模仿elementui的Table,实现思路

vue2子组件使用render&#xff0c;给子子组件插槽传值 和elementui的Table一样使用render 在 Vue 2 中&#xff0c;子组件使用render函数向子子组件插槽传值可以通过以下步骤实现&#xff1a; 1、创建子组件 首先创建一个子组件&#xff0c;在子组件中使用render函数来渲染内容…...

Unity中使用环形缓冲区平滑抖动值

环形缓冲数据结构&#xff0c;就是如下图一样的一个收尾相接的列表 在index指针指到4时&#xff0c;再往里添加数据&#xff0c;index就会指向0&#xff0c;并覆盖已有数据。 如何绘制Sin函数&#xff0c;请看下面一篇文章 Unity中如何实现绘制Sin函数图像-CSDN博客 接下来要…...

【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?

文章目录 前言问题描述问题分析问题解决1.允许所有用户上传驱动文件2.如果是想只上传白名单的驱动 前言 该方法适合永洪BI系列产品&#xff0c;包括不限于vividime desktop&#xff0c;vividime z-suit&#xff0c;vividime x-suit产品。 问题描述 当我们连接数据源的时候&a…...

SpringBoot使用 AOP 实现自定义日志记录并保存在Mysql

本文主要介绍在 Spring Boot 中使用 AOP 实现自定义日志记录并保存在 Mysql 的方法。先阐述记录日志的重要性及传统方式的弊端&#xff0c;提出新方式&#xff0c;即通过创建自定义注解、切面类等&#xff0c;将重要日志存到数据库&#xff0c;还给出了创建日志表、注解类、切面…...

谷歌开源最强天气预报AI模型 GenCast

谷歌 DeepMind 开源新一代天气预测 AI 模型 GenCast&#xff0c;GenCast 以最先进的精度预测天气和极端条件的风险 天气预报对人们生活和决策至关重要&#xff0c;但传统 NWP 模型存在不确定性&#xff0c;且计算资源需求大、运行慢。机器学习在天气预报中虽有进展&#xff0c;…...

C++打造局域网聊天室第十课: 客户端编程及数据发送

文章目录 前言一、补充内容&#xff0c;设置显示框换行二、客户端编程三、封装消息发送函数四、所处的身份状态总结 前言 C打造局域网聊天室第十课&#xff1a; 客户端编程及数据发送 一、补充内容&#xff0c;设置显示框换行 编辑框的显示内容默认是不会换行的&#xff0c;这…...

Nginx整合Lua脚本

Nginx-Lua Nginx整合Lua脚本 Lua环境搭建 下载地址 linux环境下 yum install lua安装后验证 lua -vLua脚本执行 lua xxx.luaNginx整合Lua nginx需要添加lua模块 嵌入内容 示例如下 修改nginx.conf如下 location /lua {default_type text/plain;content_by_lua ngx.sa…...

【C++】C++11 STL容器emplace方法原理剖析

在 C 11 STL 容器中&#xff0c;push/insert > emplace 新的方法&#xff0c;push 和 emplace 的区别在于&#xff1a; 1. push push 通常用于将一个元素添加到容器的末尾&#xff08;在 std::vector、std::deque 等序列容器中&#xff09;&#xff0c;或者在关联容器中插入…...

QT-简单视觉框架代码

文章目录 简介1. 整体架构2. 关键类功能概述3. 详细代码实现hikcameraworker.h 和 hikcameraworker.cpp&#xff08;海康相机工作线程类&#xff09;imageviewerwidget.h 和 imageviewerwidget.cpp&#xff08;图像查看部件类&#xff09;构造函数 ImageViewerWidget析构函数 ~…...

AI新书推荐:深度学习和大模型原理与实践(清华社)

本书简介 在这个信息爆炸、技术革新日新月异的时代&#xff0c;深度学习作为人工智能领域的重要分支&#xff0c;正引领着新一轮的技术革命。《深度学习和大模型原理与实践》一书&#xff0c;旨在为读者提供深度学习及其大模型技术的全面知识和实践应用的指南。 本书特色在于…...

[spring]处理器

我们可以通过spring来管理我们的类&#xff0c;之后我们可以通过spring的容器来获取我们所需要的Bean类对象。Spring的处理器是Spring对外开发的重要扩展点&#xff0c;它允许我们介入到Bean的整个实例化流程中来&#xff0c;可以动态添加、修改BeanDefinition、动态修改Bean 首…...

重温设计模式--中介者模式

中介者模式介绍 定义&#xff1a;中介者模式是一种行为设计模式&#xff0c;它通过引入一个中介者对象来封装一系列对象之间的交互。中介者使得各个对象之间不需要显式地相互引用&#xff0c;从而降低了它们之间的耦合度&#xff0c;并且可以更方便地对它们的交互进行管理和协调…...

重温设计模式--设计模式七大原则

文章目录 1、开闭原则&#xff08;Open - Closed Principle&#xff0c;OCP&#xff09;定义&#xff1a;示例&#xff1a;好处&#xff1a; 2、里氏替换原则&#xff08;Liskov Substitution Principle&#xff0c;LSP&#xff09;定义&#xff1a;示例&#xff1a;好处&#…...

LeetCode429周赛T4

最小化二进制字符串中最长相同子字符串的长度 在处理二进制字符串问题时&#xff0c;优化字符串结构以满足特定条件是一项常见的挑战。本文将探讨一个具体的问题&#xff1a;给定一个长度为 n 的二进制字符串 s 和一个整数 numOps&#xff0c;通过最多 numOps 次位翻转操作&am…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

Docker 本地安装 mysql 数据库

Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker &#xff1b;并安装。 基础操作不再赘述。 打开 macOS 终端&#xff0c;开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏

一、引言 在深度学习中&#xff0c;我们训练出的神经网络往往非常庞大&#xff08;比如像 ResNet、YOLOv8、Vision Transformer&#xff09;&#xff0c;虽然精度很高&#xff0c;但“太重”了&#xff0c;运行起来很慢&#xff0c;占用内存大&#xff0c;不适合部署到手机、摄…...