Unity Shader 透明度效果

news2024/12/23 18:45:15

游戏中有以下两种达到透明度效果:

1.透明度测试

只要一个片元的透明度不满足条件(通常小于某个阈值),那么就舍弃对应的片元。被舍弃的片元不会进行任何的处理,也不会对颜色缓冲产生任何影响。否则就会按照普通的不透明物体来处理,即进行深度测试,深度写入等等。虽然简单,但是很极端,要么完全透明,要么完全不透明。

2.透明度混合

可以得到真正的半透明效果,他会使当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色。但是,透明混合需要关闭深度写入,这使得我们要非常小心物体的下渲染顺序。注意:透明度混合只关闭了深度写入,但没有关闭深度测试。这表示当使用透明度混合渲染一个片元时,还是会比较它的深度值与当前深度缓冲中的深度值,如果深度值距离摄像机更远,那么就不会在进行混合操作。比如一个不透明物体在透明物体前面,我们先渲染不透明物体,可以正常的挡住不透明物体。

说到透明度混合就需要知道:合并混合

合并,渲染过程是一个物体接着一个物体画到屏幕上,而每个像素的颜色信息被存储在一个名为颜色缓冲的地方。因此,我们执行这次渲染时,颜色缓冲中往往已经有了上次渲染之后的颜色结果,那么,我们使用这次渲染得到的颜色完全覆盖之前的结果还是进行其他处理,就是合并需要解决的。

对于不透明物体,开发者可以关闭混合(Blend)操作。这样片元着色器计算得到的颜色值就会之间覆盖掉颜色缓冲区中的像素值,但对于半透明物体,就需要混合操作来让物体看起来是透明的。

透明度混合需要 不透明物体 关闭深度写入,开启深度测试。

什么是深度写入,什么是深度测试?

如下图所示,A物体在B的前面,假设A B 深度(Z)分别为 A: 0.3 B:0.6。

假设我们不关闭深度写入的情况:

我们先渲染 B,并写入深度 Z = 0.6,

然后在渲染A,A的深度 0.3 < 缓冲区中的 Z (0.6) 通过透明度测试,并写入深度 Z = 0.3

就会得到如下混的效果。

如果这时候在来个不透名物体C 深度为 0.5 ,在A和B的中间,这个时候, 

C的深度 0.4 > 缓冲区中的 Z (0.3) 通不过透明度测试,所以不会进行渲染。

 如果关闭不透明物体的 深度写入,深度缓冲区的值 Z = 0.6, A和C都会通过透明度测试,得到下面ABC混的结果。

从上面我们发现一个问题 ,渲染B-A-C,如果我们换了渲染顺序会怎么样 B-A-C,就会出现AC都被B盖住了,最终只有B的颜色,所以渲染顺序非常重要。unity给我们设定了以下几个级别的渲染顺序:文档

Unity ShaderLab 的 混合命令:Blend

只要有关键字Blend,就代表开启混合(除Blend off 以外)

命令结构:

参数

举个例子

Blend SrcFactor DstFactor

表示 开启混合,并设置混合因子。源颜色(该片元颜色)乘以 SrcFactor,目标颜色(已经存在于颜色缓冲区的颜色)会乘以DstFactor,然后把两者相加后在存入颜色缓冲区

混合操作

原文地址:ShaderLab 命令:BlendOp - Unity 手册

常见的混合操作类型

// 正常 透明度混合

Blend SrcAlpha OneMinusSrcAlpha

// 柔和相加

Blend OneMinusDstColor One

// 正片叠底

Blend DstColor Zero

// 两倍相乘

BlendOp min

BlendOne One

// 变亮

Blend OneMinusDstColor One

Blend One OneMinusSrcColor

// 线性减淡

Blend One One

透明度测试实现

Shader "Unlit/010"
{
    Properties
    {
        // 漫反射颜色
        _Diffuse ("Diffuse",Color) = (1,1,1,1)
        // 高光反射颜色值
        _Specular ("Specular",Color) = (1,1,1,1)
        // 高光反射值
        _Gloss ("_Gloss",range(1,100)) = 5
        // 主纹理
        _MaxTex ("_MaxTex",2d) = "white" {}
        // 透明度阈值变量
        _Cutoff("Alpha Cutoff",Range(0,1)) = 0.5
    }
    SubShader
    {
        // 渲染顺序设置为透明  忽略投影组件
        Tags {"Queue"="AlphaTest" "IgnoreProjector"="True"}
        Pass
        {
            
            CGPROGRAM 
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            sampler2D _MaxTex;
            float4 _MaxTex_ST;
            float4 _Specular;
            float4 _Diffuse;
            float _Gloss;
            float _Cutoff;
            
            struct v2f
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD1;
                float3 worldNormal : TEXCOORD0;
                float3 viewDir : TEXCOORD2;
            };

            v2f vert (appdata_base v)
            {
                v2f o;
                // 将对象空间中的点变换到齐次坐标中的摄像机裁剪空间
                o.vertex = UnityObjectToClipPos(v.vertex);
                // 计算uv坐标
                o.uv = TRANSFORM_TEX(v.texcoord,_MaxTex);
                // o.uv = v.texcoord.xy * _MaxTex_ST.xy + _MaxTex_ST.zw;
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.viewDir = normalize(WorldSpaceViewDir(o.vertex));
                return o;   
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float4 texColor = tex2D(_MaxTex,i.uv);
                
                if((texColor.a - _Cutoff)<0)
                {
                    discard;
                }

                // 计算漫反射
                float3 diffuse = texColor.rgb * _LightColor0.rgb * _Diffuse.rgb * (dot(_WorldSpaceLightPos0.xyz,i.worldNormal) * 0.5 + 0.5);
                // 计算高光
                float3 halfVector = normalize(normalize(_WorldSpaceLightPos0.xyz) + i.viewDir);
                // 计算高光
                float3 specular = texColor.rgb * _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(halfVector,i.worldNormal)),_Gloss);
                
                return float4(diffuse,1);
            }
            ENDCG
        }
    }
}

shader中的漫反射、高光反射、纹理采样,不具体讲解了,有需要的可以点连接进去看,透明度测试非常简单,就是设定一个阈值 ,然后通过阈值对纹理透明度进行判断,通过的则显示,通不过的则透明。不存在半透明的情况

// 透明度阈值变量
_Cutoff("Alpha Cutoff",Range(0,1)) = 0.5

// 阈值判断

if((texColor.a - _Cutoff)<0)
{
    discard;
}

还需要注意设置下渲染队列

// 渲染顺序设置为透明  忽略投影组件
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True"}

透明度混合Shader

Shader "Unlit/011"
{
    Properties
    {
        // 漫反射颜色
        _Diffuse ("Diffuse",Color) = (1,1,1,1)
        // 高光反射颜色值
        _Specular ("Specular",Color) = (1,1,1,1)
        // 高光反射值
        _Gloss ("_Gloss",range(1,100)) = 5
        // 主纹理
        _MaxTex ("_MaxTex",2d) = "white" {}
        _AlphaScale("Alpha Scale",Range(0,1)) = 1
    }
    SubShader
    {
        // 渲染顺序设置为透明  忽略投影组件
        Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
        Zwrite Off      // 关闭深度写入
        Blend SrcAlpha OneMinusSrcAlpha   // 开启混合   
        Pass
        {
            Tags{"LightMode"="ForwardBase"}
    
            CGPROGRAM 
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            sampler2D _MaxTex;
            float4 _MaxTex_ST;
            float4 _Specular;
            float4 _Diffuse;
            float _Gloss;
            float _AlphaScale;
            
            struct v2f
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD1;
                float3 worldNormal : TEXCOORD0;
                float3 viewDir : TEXCOORD2;
            };

            v2f vert (appdata_base v)
            {
                v2f o;
                // 将对象空间中的点变换到齐次坐标中的摄像机裁剪空间
                o.vertex = UnityObjectToClipPos(v.vertex);
                // 计算uv坐标
                o.uv = TRANSFORM_TEX(v.texcoord,_MaxTex);
                // o.uv = v.texcoord.xy * _MaxTex_ST.xy + _MaxTex_ST.zw;
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.viewDir = normalize(WorldSpaceViewDir(o.vertex));
                return o;   
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float4 texColor = tex2D(_MaxTex,i.uv);

                // 计算漫反射
                float3 diffuse = texColor.rgb * _LightColor0.rgb * _Diffuse.rgb * (dot(_WorldSpaceLightPos0.xyz,i.worldNormal) * 0.5 + 0.5);
                // 计算高光
                float3 halfVector = normalize(normalize(_WorldSpaceLightPos0.xyz) + i.viewDir);
                // 计算高光
                float3 specular = texColor.rgb * _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(halfVector,i.worldNormal)),_Gloss);
                
                return float4(diffuse,texColor.a * _AlphaScale);
            }
            ENDCG
        }
    }
    FallBack "Transparent/VertexLit"
}

要注意的几个地方:

// 渲染顺序设置为透明  忽略投影组件 渲染类型设置
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
// 透明物体需要 关闭深度写入
Zwrite Off 
// 开启混合 
Blend SrcAlpha OneMinusSrcAlpha  

效果如下:

总结

代码上实际上没几句,主要还是需要理解上面 透明度测试,透明度混合,什么是深度写入,为什么要开启写入和关闭写入的原因。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

P3842 [TJOI2007] 线段

[TJOI2007] 线段 - 洛谷 #include<bits/stdc.h> using namespace std; const int N2e410; int n; int f[N][2],a[N][2]; int dis(int a,int b) {return abs(a-b); } int main() {scanf("%d",&n);for(int i1;i<n;i)scanf("%d %d",&a[i][0]…

MySQL学习笔记12

MySQL 查询语句&#xff1a; 1、查询五子句&#xff1a;&#xff08;重点&#xff09; mysql> select */字段列表 from 数据表名称 where 子句 group by 子句 having 子句 order by 子句 limit 子句; 1&#xff09;where 子句&#xff1b;条件筛选。 2&#xff09;group…

Arch挂载错误

临时解决方案&#xff1a;手动挂载 到 /run/media/sonichy 目录打开终端 sudo mkdir DATA sudo mount /dev/sda5 /run/media/sonichy/DATA

微信CRM系统在旅游行业的应用

旅游业目前存在的问题 1. 产品同质化严重 各大旅游企业推出的产品雷同率高&#xff0c;缺乏创新性与唯一性&#xff0c;旅游景点的宣传方式和体验也大都雷同&#xff0c;客户在选择去旅游的时候会对比价格问题&#xff0c;哪里价格低去哪里。 2. 获客成本高 国内旅游景点众…

光电探测器指标分析

先来看一下一个光电探测器的数据手册 第一个光电二极管类型 常用的是PIN管和APD管&#xff0c;两种管子各有优劣 PIN&#xff1a;光电二极管&#xff08; Photo Diode&#xff09;&#xff0c;当半导体中的PN结受到光照射&#xff0c;且入射光能量高于光电二极管的带隙能时&am…

R语言贝叶斯广义线性混合(多层次/水平/嵌套)模型GLMM、逻辑回归分析教育留级影响因素数据...

全文下载链接&#xff1a;http://tecdat.cn/?p24203 本教程使用R介绍了具有非信息先验的贝叶斯 GLM&#xff08;广义线性模型&#xff09; &#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。 当前教程特别关注贝叶斯逻辑回归在二元结果和计数/比例结果场景中的…

.NET 8 性能比 .NET 7 大幅提升

微软 .NET 开发团队的工程师 Stephen Toub 发表博客《Performance Improvements in .NET 8》&#xff0c;详细介绍了 .NET 8 中的性能改进。 介绍了 .NET 8 的性能表现&#xff0c;包括 JIT、原生 AOT、VM、GC、Mono、线程、文件 I/O、网络、JSON 处理、日志等。 .NET 7 was s…

数据结构与算法基础-(2)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

大模型的最大bug,回答正确率几乎为零,GPT到Llama无一幸免

目录 前言 1.名字和描述颠倒一下&#xff0c;大模型就糊涂了 2.实验及结果 3.未来展望 前言 大模型的逻辑&#xff1f;不存在的。 我让 GPT-3 和 Llama 学会一个简单的知识&#xff1a;A 就是 B&#xff0c;然后反过来问 B 是什么&#xff0c;结果发现 AI 回答的正确率竟然是…

Java正则表达式解析复杂跨行日志

Java正则表达式解析复杂跨行日志 解析内容正则使用完整代码 使用正则表达式解析日志 解析内容 String content "2023-09-23 11:31:54.705 INFO [ main] com.zlm.tools.ToolsApplication : Starting ToolsApplication using Java 1.8.0_201 on \n&qu…

SVG 基本语法

1. 概述 svg为可缩放矢量图形&#xff0c;使用 XML 格式定义图像。 2. 基础图形 2.1 矩形 &#xff08;1&#xff09; 基础语法 <rect x"20" y"20" rx"20" ry"20" width"150" height"100" fill"red&qu…

10.4Cookie和Session

一.概念: 二.相关方法: SendCookie: import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servle…

HDLBits-Edgedetect

刚开始写的代码如下&#xff1a; module top_module (input clk,input [7:0] in,output [7:0] pedge );reg [7:0] in_pre;always (posedge clk)begin in_pre < in;endassign pedge in & ~in_pre; endmodule但是提交结果是错误的。猜想原因如下&#xff1a; assign p…

关于地址存放的例题

unsigned int a 0x1234; unsigned char b *(unsigned char*)&a; 上面代码大端存储和小端存储的值分别是多少&#xff1f; 大端存储的是把高位地址存放在低位地址处&#xff0c;低位存放到高位。小端是高位存放在高位&#xff0c;低位在低位。因为a是整型&#xff0c;所…

Python 逢七拍手小游戏

"""逢七拍手游戏介绍&#xff1a;逢七拍手游戏的规则是&#xff1a;从1开始顺序数数&#xff0c;数到有7&#xff0c;或者是7的倍数时&#xff0c;就拍一手。例如&#xff1a;7、14、17......70......知识点&#xff1a;1、循环语句for2、嵌套条件语句if/elif/e…

java框架-Springboot3-基础特性+核心原理

文章目录 java框架-Springboot3-基础特性核心原理profiles外部化配置生命周期监听事件触发时机事件驱动开发SPISpringboot容器启动过程自定义starter java框架-Springboot3-基础特性核心原理 profiles 外部化配置 生命周期监听 事件触发时机 事件驱动开发 Component public c…

竞赛 基于深度学习的目标检测算法

文章目录 1 简介2 目标检测概念3 目标分类、定位、检测示例4 传统目标检测5 两类目标检测算法5.1 相关研究5.1.1 选择性搜索5.1.2 OverFeat 5.2 基于区域提名的方法5.2.1 R-CNN5.2.2 SPP-net5.2.3 Fast R-CNN 5.3 端到端的方法YOLOSSD 6 人体检测结果7 最后 1 简介 &#x1f5…

mybatis日志体系

title: “java日志体系” createTime: 2021-12-08T12:19:5708:00 updateTime: 2021-12-08T12:19:5708:00 draft: false author: “ggball” tags: [“mybatis”] categories: [“java”] description: “java日志体系” java日志体系 常用日志框架 Log4j&#xff1a;Apache …

华为云云耀云服务器L实例评测|搭建您的私人影院网站

前言 本文为华为云云耀云服务器L实例测评文章&#xff0c;测评内容是云耀云服务器L实例搭建在线视频网站&#xff0c;大家可以将这个网站作为私人影院或是分享给朋友&#xff0c;但是尽量不要更广的传播&#xff0c;因为这涉及到版权问题 系统配置&#xff1a;华为云 2核2G 3M…

PostgreSQL 16 发布,更可靠更稳健

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…