Unity中实现UI的质感和圆角

质感思路有两种:

一种是玻璃质感的做法,抓取UI后面的图像做模糊(build是GrabPass,urp抓图像我有写过在往期文章),这个方式网络上有很多就不写了;

另外一种是使用CubeMap的方式去模拟质感,这种用贴图的方式会更省性能,我这里主要讲的是第二种,其中需要注意的点是给CubeMap采样的时候需要将顶点转换为世界坐标,不然会出现极坐标的情况(上图为极坐标,下图是正常的);

Unity UI质感和圆角

如果你用shaderGraph可能需要用自定义节点去写转换,黑盒似乎也会出现极坐标,具体的你可以自行测试;

关键代码:

vert:output.worldPos = mul(unity_ObjectToWorld,input.vertex);----------------------------------------------------------Frag:
float3 viewDir  = normalize(UnityWorldSpaceViewDir(input.worldPos.xyz));
float3 vrDirWS = reflect(-viewDir, input.worldNormal);
float3 var_Cubemap = texCUBElod(_Cubemap,float4(vrDirWS,6));
color.rgb += var_Cubemap;

全部代码如下:

Shader "Unlit/RoundedBoxUI"
{Properties{[PerRendererData] _MainTex ("Texture", 2D) = "white" {}_Color ("Tint", Color) = (1,1,1,1)_Cubemap ("HDRTex", cube) = "white" {} // 输入HDR单图//YJJ//_CubemapMip("_CubemapMip",Range(0,7)) = 6_RotationY ("RotationY", Range(0, 360)) = 0[HideInInspector] _StencilComp		("Stencil Comparison", Float) = 0[HideInInspector] _Stencil			("Stencil ID", Float) = 0[HideInInspector] _StencilOp		("Stencil Operation", Float) = 0[HideInInspector] _StencilWriteMask	("Stencil Write Mask", Float) = 255[HideInInspector] _StencilReadMask	("Stencil Read Mask", Float) = 255_ColorMask ("Color Mask", Float) = 15[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0_BorderWidth ("Border Width", Float) = 0[Enum(NoBorder,0,OnlyBorder,1,Both,2)] _BorderColorType ("Border Type", Int) = 0[Toggle(IMAGE_SDF)] _UseImageAsSDF ("Use Image as SDF", Float) = 0[Enum(Off,0,On,1)]_ZWrite ("ZWrite", Float) = 1.0}SubShader{Tags{"Queue"="Transparent""IgnoreProjector"="True""RenderType"="Transparent"}Stencil{Ref [_Stencil]Comp [_StencilComp]Pass [_StencilOp]ReadMask [_StencilReadMask]WriteMask [_StencilWriteMask]}Cull OffLighting OffZWrite [_ZWrite]ZTest [unity_GUIZTestMode]Blend SrcAlpha OneMinusSrcAlpha, OneMinusDstAlpha OneColorMask [_ColorMask]Pass{Name "Default"CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma target 2.0#pragma multi_compile __ UNITY_UI_CLIP_RECT#pragma multi_compile __ UNITY_UI_ALPHACLIP#pragma multi_compile __ IMAGE_SDF#include "UnityCG.cginc"#include "UnityUI.cginc"#include "Box2DSignedDistance.cginc"struct vertexInput{float4 vertex : POSITION;float4 color : COLOR;float4 texcoord : TEXCOORD0;//--- Customfloat4 borderRadius : TEXCOORD1;float3 normal : NORMAL;UNITY_VERTEX_INPUT_INSTANCE_ID};struct fragmentInput{float4 vertex : SV_POSITION;fixed4 color : COLOR;float4 texcoord : TEXCOORD0;float4 worldPosition : TEXCOORD1;//--- Customfloat4 borderRadius : TEXCOORD2;float3 worldNormal : TEXCOORD3;float3 worldPos : TEXCOORD4;UNITY_VERTEX_OUTPUT_STEREO};sampler2D _MainTex;float4 _MainTex_ST;fixed4 _Color;fixed4 _TextureSampleAdd;float4 _ClipRect;float _BorderWidth;int _BorderColorType;   samplerCUBE _Cubemap; float _RotationY; //float _CubemapMip; float4 RotateAroundYInDegrees (float4 vertex, float degrees){float alpha = degrees * 3.14 / 180.0;float sina, cosa;sincos(alpha, sina, cosa);float2x2 m = float2x2(cosa, -sina, sina, cosa);return float4(mul(m, vertex.xz), vertex.yw).xzyw;}float4 RotateAroundXInDegrees (float4 vertex, float degrees){float alpha = degrees * 3.14 / 180.0;float sina, cosa;sincos(alpha, sina, cosa);// 创建绕X轴的旋转矩阵float2x2 m = float2x2(cosa, -sina, sina, cosa);// 创建完整的旋转矩阵float4x4 rotationMatrix = float4x4(1.0, 0.0, 0.0, 0.0,0.0, cosa, -sina, 0.0,0.0, sina, cosa, 0.0,0.0, 0.0, 0.0, 1.0);// 旋转顶点并返回return mul(rotationMatrix, vertex);}float4 RotateAroundZInDegrees (float4 vertex, float degrees){float alpha = degrees * 3.14 / 180.0;float sina, cosa;sincos(alpha, sina, cosa);// 创建绕Z轴的旋转矩阵float4x4 rotationMatrix = float4x4(cosa, -sina, 0.0, 0.0,sina, cosa, 0.0, 0.0,0.0, 0.0, 1.0, 0.0,0.0, 0.0, 0.0, 1.0);// 旋转顶点并返回return mul(rotationMatrix, vertex);}fragmentInput vert(vertexInput input){fragmentInput output;UNITY_INITIALIZE_OUTPUT(fragmentInput, output);UNITY_SETUP_INSTANCE_ID(input);UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);output.worldPosition = input.vertex;output.worldPos = mul(unity_ObjectToWorld,input.vertex);//YJJ//给CubeMap采样使用output.vertex = UnityObjectToClipPos(output.worldPosition);output.texcoord = input.texcoord;output.color = input.color * _Color;output.borderRadius = input.borderRadius;output.worldNormal = UnityObjectToWorldNormal(input.normal);return output;}fixed4 frag (fragmentInput input) : SV_Target{float2 rectSize = input.texcoord.zw;float2 uv = input.texcoord.xy * rectSize;uv = uv - rectSize * 0.5;float dist = sdRoundBox(uv, rectSize * 0.5 - (_BorderWidth).xx, input.borderRadius);float2 ddDist = float2(ddx(dist), ddy(dist));float ddDistLen = length(ddDist);float alpha = saturate(((dist - _BorderWidth) / ddDistLen) + 1.0);float borderParam = saturate((dist) / ddDistLen);half4 color = half4(0.0, 0.0, 0.0, 0.0);#ifdef IMAGE_SDFfloat4 texSample = tex2D(_MainTex, input.texcoord) + _TextureSampleAdd;float c_dist = texSample.x - 0.1;float c_mask = smoothstep(0.00, 0.2, c_dist);color = input.color;color.a *= 1.0 - alpha;color.a *= saturate(c_mask);#elsecolor = (tex2D(_MainTex, input.texcoord) + _TextureSampleAdd) * input.color;color.a *= 1.0 - alpha;#endif//描边YJJ//color.a = 1;//挤出描边//描边Endif (_BorderColorType == 1) {color.a *= borderParam;}//color.rgb *= 1.0 - borderParam;//color.a *= c_dist;#ifdef UNITY_UI_CLIP_RECTcolor.a *= UnityGet2DClipping(input.worldPosition.xy, _ClipRect);#endif#ifdef UNITY_UI_ALPHACLIPclip (color.a - 0.001);#endif//魔改反射效果float3 viewDir  = normalize(UnityWorldSpaceViewDir(input.worldPos.xyz));//float3 vDirWS=normalize(_WorldSpaceCameraPos.xyz - input.worldPosition.xyz);float3 vrDirWS = reflect(-viewDir, input.worldNormal);vrDirWS = RotateAroundZInDegrees(float4(vrDirWS,1),0).xyz;float3 var_Cubemap = texCUBElod(_Cubemap,float4(vrDirWS,6));color.rgb += var_Cubemap;//return float4(var_Cubemap,1);return color;}ENDCG}}
}

脚本:

using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;public class RoundedBoxUIProperties : UIBehaviour, IMeshModifier
{private Image _image;public Vector4 borderRadius;[Range(0,7)]public float CubemapMip = 6;#if UNITY_EDITORprotected override void OnValidate(){if (_image == null){_image = gameObject.GetComponent<Image>();if (_image == null) return;}_image.SetAllDirty();}
#endifprotected override void OnEnable(){_image = gameObject.GetComponent<Image>();}protected override void OnDisable(){_image = null;}protected override void Start(){StartCoroutine(DelayVertexGeneration());}IEnumerator DelayVertexGeneration(){yield return new WaitForSeconds(0.1f);if (_image == null){_image = gameObject.GetComponent<Image>();if (_image == null) yield break;}_image.SetAllDirty();}public void ModifyMesh(Mesh mesh){}public void ModifyMesh(VertexHelper verts){if (_image == null){_image = gameObject.GetComponent<Image>();if (_image == null) return;}var rectTransform = (RectTransform)transform;var rect = rectTransform.rect;var offset = new Vector4(rect.x, rect.y, Mathf.Abs(rect.width), Mathf.Abs(rect.height));UIVertex vert = new UIVertex();for (int i = 0; i < verts.currentVertCount; i++){verts.PopulateUIVertex(ref vert, i);var uv0 = vert.uv0;uv0.z = offset.z;uv0.w = offset.w;vert.uv0 = uv0;vert.uv1 = borderRadius * 0.5f;verts.SetUIVertex(vert, i);}}// [ContextMenu("UI模糊调整")]// public void UIMipBlur(){//     Shader.SetGlobalFloat("_CubemapMip",CubemapMip);//     float Test =  Shader.GetGlobalFloat("_CubemapMip");//     Debug.Log("" + Test);// }
}

Box2DSignedDistance.cginc

float sdRoundBox( in float2 p, in float2 b, in float4 r )
{// We choose the radius based on the quadrant we're in// We cap the radius based on the minimum of the box half width/heightr.xy = (p.x>0.0)?r.xy : r.zw;r.x = (p.y>0.0)?r.x : r.y;r.x = min(2.0f*r.x, min(b.x, b.y));float2 q = abs(p)-b+r.x;return min(max(q.x,q.y),0.0) + length(max(q,0.0)) - r.x;
}

其中shader部分写了一些矩阵用于调整角度的方法,可以自行删减冗余;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/42936.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[异步监听事件、异步绑定属性]通过vue的this.$refs.组件.$props和.$on实现异步绑定组件属性和事件监听

child.vue <template><div><el-button type"primary" click.stop"$emit(get, data)">点击传参</el-button></div> </template> <script> export default { name: "child", props: ["data"…

第六届 蓝桥杯 嵌入式 省赛

参考 第六届蓝桥杯嵌入式省赛程序设计题解析&#xff08;基于HAL库&#xff09;_蓝桥杯嵌入式第六届真题-CSDN博客 一、分析功能 RTC 定时 1&#xff09;时间初始化 2&#xff09;定时上报电压时间 ADC测量 采集电位器的输出电压信号。 串行功能 1&#xff09;传送要设置…

为什么要将项目部署到外部tomcat

一、是什么 指将你的Java Web应用程序&#xff08;如WAR包&#xff09;安装并运行在一个独立安装的、位于项目外部的Tomcat服务器上&#xff0c;而不是使用内嵌的或开发环境自带的服务器。 外部Tomcat 指独立安装的Tomcat服务器&#xff08;如从Apache官网下载的Tomcat&#…

企业级全栈开发终极指南:Spring Boot+Vue3+Kubernetes实战,从0到上线高并发系统

简介 本文以电商系统为例,完整呈现从需求分析到上线运维的企业级开发全流程。包含12个关键步骤、30+代码示例、5个架构设计图,以及完整的Docker/Kubernetes部署方案。所有代码均符合企业级规范,可直接用于生产环境。 企业级开发的终极挑战 行业痛点: 90%的开发者在企业级…

蓝桥杯嵌入式赛道复习笔记8(eeprom读写)

原理学习 自己看一下江科大的存储器的读取&#xff0c;原理是一样的。只是使用了IIC原理是不变的 代码 cubeMX的配置 代码 eeprom层代码的书写 #include "eeprom_display.h" uint8_t data; uint8_t eeprom_read(uint8_t addr){I2CStart();I2CSendByte(0xa0);I2…

IP数据报报文格式

一 概述 IP数据报由两部分组成&#xff1a;首部数据部分。首部的前一部分是固定长度&#xff0c;一共20字节大小&#xff0c;是所有IP数据报文必须具有的&#xff1b;固定部分后面是一些可选字段&#xff0c;其长度是可变的。 二 首部固定部分各字段意义 &#xff08;1&…

高光谱工业相机+LED光源系统助力材料分类和异物检测、实现高速在线检测

检测光源包括可见光&#xff0c;如红光、蓝光和绿光以及其他波长的光&#xff0c;如紫外和红外波长&#xff0c;可以选择与检测对象物相应的波长。但由于能够照射的波长较窄&#xff0c;例如受到同色异物混入或多个素材的材质分类等&#xff0c;可能需要使用可照射多种波长的光…

如何快速解决django存储session变量时出现的django.db.utils.DatabaseError错误

我们在学习django进行web编程的时候&#xff0c;有时需要将一些全局变量信息存储在session中&#xff0c;但使用过程中&#xff0c;却发现会引起数据库的报错。通过查看django源码信息&#xff0c;发现其对session信息进行了ORM映射&#xff0c;如果数据库中不存在对应的表信息…

kubeadm部署k8s-1.32版本集群(1个master,1个worker)

使用最新版的kubeadm部署一个最小版的k8s集群&#xff0c;只有一个master和1个worker&#xff0c;这种部署方式&#xff0c;不满足高可用&#xff0c;仅限于本地学习使用&#xff0c;不可以放到生产上用&#xff0c;先看一下文章的目录。 文章目录 1、基本信息1.1、服务器基本…

阀门流量控制系统MATLAB仿真PID

以下是一个基于MATLAB的PID控制仿真程序&#xff0c;用于模拟智能阀门流量控制系统。该程序包含系统模型、PID控制器以及饱和限制处理。 % 石油管道流量PID控制仿真 % 系统参数 valve_min 4; % 阀门最小电流 (mA) valve_max 25; % 阀门最大电流 (mA) max_flow 10…

UE4学习笔记 FPS游戏制作30 显示击杀信息 水平框 UI模板(预制体)

文章目录 一制作单条死亡信息框水平框的使用创建一个水平框添加子元素调整子元素顺序子元素的布局插槽尺寸填充对齐 制作UI 根据队伍&#xff0c;设置文本的名字和颜色声明变量 将变量设置为构造参数根据队伍&#xff0c;设置文本的名字和颜色在构造事件中&#xff0c;获取玩家…

机器学习——LightGBM

LightGBM(light gradient boosting machine&#xff0c;轻量梯度提升机)是对XGBoost进行改进的模型版本&#xff0c;其三者之间的演变关系为&#xff1a;GBDT-》XGBoost-》LightGBM&#xff0c;依次对性能进行优化&#xff0c;尽管XGBoost已经很高效了&#xff0c;但是仍然有缺…

什么是SQL作业

SQL作业是在数据库服务器上按特定时间或间隔自动执行的计划任务或流程&#xff0c;这些作业由Microsoft SQL Server中的SQL Server代理管理&#xff0c;对于自动执行日常任务&#xff08;如数据库系统中的备份、数据导入和报告生成&#xff09;以及确保及时准确地处理和更新数据…

小程序内表格合并功能实现—行合并

功能介绍&#xff1a;支付宝小程序手写表格实现行内合并&#xff0c;依据动态数据自动计算每次需求合并的值&#xff0c;本次记录行内合并&#xff0c;如果列内合并&#xff0c;同理即可实现 前端技术&#xff1a;grid布局 display&#xff1a;grid 先看实现效果: axml&…

CD19.【C++ Dev】类和对象(10) 日期类对象的成员函数(日期+天数)

目录 日期天数 需要考虑的几个问题 1.天数加在日上,有可能会溢出,需要进位 2.对月进位,也有可能导致月会溢出,需要进位 3.对年进位,需要考虑是否为闰年 代码设计 取得指定月的天数GetMonthDay函数 方法1:if判断或switch/case 方法2:查表 版本1 版本2 operator 初始…

从零构建大语言模型全栈开发指南:第二部分:模型架构设计与实现-2.2.3实战案例:在笔记本电脑上运行轻量级LLM

👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 实战案例:在笔记本电脑上运行轻量级LLM2.2.3 模型架构设计与实现1. 环境与工具准备1.1 硬件要求1.2 软件栈选择2. 轻量级模型架构设计2.1 模型参数配置2.2 关键技术优化3. 实战流程3.1 数据准备流程3.2…

新手村:逻辑回归-理解04:熵是什么?

新手村&#xff1a;逻辑回归04&#xff1a;熵是什么? 熵是什么? 前置条件 在开始学习逻辑回归中的熵理论之前&#xff0c;需要掌握以下基础知识&#xff1a; 概率论与统计学&#xff1a; 概率分布&#xff08;如伯努利分布、正态分布&#xff09;。条件概率和贝叶斯定理。期…

linux》》docker 、containerd 保存镜像、打包tar、加载tar镜像

Linux》》docker: 默认情况下&#xff0c;Docker镜像保存在/var/lib/docker/目录下。 当您使用docker pull命令从Docker Hub或私有镜像仓库中拉取镜像时&#xff0c;Docker会自动将镜像文件保存在/var/lib/docker/image/目录下。 每个镜像都由一个或多个层组成&#xff0c;这些…

Processor System Reset IP 核 v5.0(vivado)

这个IP的作用&#xff0c;我的理解是&#xff0c;比普通按键复位更加高效灵活&#xff0c;可以配置多个复位输出&#xff0c;可以配置复位周期。 1、输入信号&#xff1a; 重要的信号有时钟clk信号&#xff0c;一般连接到系统时钟&#xff1b;输入复位信号&#xff0c;一般是外…

SQL中累计求和与滑动求和函数sum() over()的用法

[TOC](SQL中累计求和与滑动求和函数sum() over()的用法) 一、窗口函数功能简介 sum(c) over(partition by a order by b) 按照一定规则汇总c的值&#xff0c;具体规则为以a分组&#xff0c;每组内按照b进行排序&#xff0c;汇总第一行至当前行的c的加和值。 sum()&#xff1a…