渲染纹理的玻璃效果

1. 玻璃效果基本原理

要实现玻璃效果,可能会联想到使用透明相关知识来进行制作。透明固然可以制作出玻璃透明的效果,但是它在许多地方有所缺陷,比如:

  • 透明无法表现出复杂的光学效果,玻璃不仅仅是透明的,它还具有反射、折射等光学效果,使用透明无法简单的实现这些效果
  • 透明物体往往会遇到深度排序问题,渲染顺序不正确时,会导致视觉错误

使用 渲染纹理 来制作玻璃效果,基本原理是:
渲染玻璃效果物体之前,先获取到当前屏幕图像,将当前屏幕图像存储在渲染纹理之中,之后在真正处理玻璃效果物体时,再利用该渲染纹理来实现 透明、折射 等等效果。

该过程中并不会使用混合,而是直接进行颜色相乘或相加来进行颜色叠加

 总结:在渲染玻璃效果之前,先捕获当前屏幕内容并保存到一张渲染纹理当中,在之后的Shader处理中利用该渲染纹理进行采样,参与最终的颜色计算,实现各种玻璃效果

这里需要用到:特殊渲染通道 GrabPass、内置函数 ComputeGrabScreenPos、 模拟折射的自定义计算规则

特殊渲染通道 GrabPass

GrabPass 的作用是捕获当前屏幕上已经渲染的内容,并将其存储到一张纹理中
它需要包含在SubShader语句块中
它的用法有两种:
(1)大括号中什么都不写,默认会把屏幕内容写入一个叫做 _GrabTexture 的纹理变量中
直接在CG语句中声明_GrabTexture 纹理变量即可直接使用抓取的渲染纹理

(2)大括号中写入自定义变量名,会把对应屏幕内容写入该自定义纹理变量中
在CG语句中声明对应纹理变量即可使用抓取的渲染纹理

内置函数 ComputeGrabScreenPos

该内置函数可以用于计算屏幕空间位置,传入顶点的裁剪空间位置,返回一个 float4 结果,该float4中的内容分别代表:

  • X:屏幕空间X坐标
  • Y:屏幕空间Y坐标
  • Z:裁剪空间深度值,一般表示顶点距离摄像机的相对深度
  • W:裁剪空间的W分量,通常用于透视除法,即 X或Y/W 后 X或Y的范围将在 0~1之间

我们可以利用该函数得到顶点相对屏幕的坐标,从而从捕获的渲染纹理中进行采样

模拟折射的自定义计算规则

为了模拟出玻璃折射的效果,我们一般不会使用立方体纹理中采样,我们往往会自定义一些计算规则,来模拟计算出折射的效果。
总体的设计思路,就是在对捕获纹理进行采样时,进行一些偏移计算。

2、如何让玻璃效果对象滞后渲染 

在实现玻璃效果之前,需要先捕获当前屏幕内容并保存到一张渲染纹理当中,那么要保证玻璃效果对象后面的内容正确渲染,我们必须保证玻璃对象能够滞后渲染,想要让一个对象滞后渲染,那么可以使用渲染标签Tags中的 渲染队列Queue

因此对于玻璃效果对象,虽然它本质上是一个不透明物体吗,但是我们完全可以将它的渲染队列设置为 Transparent(透明的),保证它晚于 背景队列、几何队列、透明测试队列 之后再进行渲染,这时我们捕获的屏幕内容,将包含这些更早渲染的内容信息,便可以利用GrabPass捕获到相对正确的内容了

Shader "ShaderProj/6/GlassBase"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Cube ("Cube", Cube) = "" {}
        //折射程度 0~1 0代表完全反射(完全不折射)1代表完全折射(透明效果 相当于光全部进入了内部)
        _RefractAmount ("RefractAmount", Range(0, 1)) = 1
    }
    SubShader
    {
        //将渲染队列改为透明的 目的是让玻璃对象 滞后渲染
        //能够捕获到之前正确的屏幕图像
        Tags { "RenderType"="Opaque" "Queue"="Transparent"}

        //使用它来捕获当前屏幕内容 并存储到默认的渲染纹理变量中
        GrabPass{}

        Pass
        {
            Tags {"LightMode" = "ForwardBase"}

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            struct v2f
            {
                float4 pos:SV_POSITION;
                float4 grabPos:TEXCOORD0; //用于存储从屏幕图像中采样的坐标(顶点相对于屏幕的位置)
                float2 uv:TEXCOORD1;
                float3 worldRefl:TEXCOORD2;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            samplerCUBE _Cube;
            float _RefractAmount;
            //GrabPass默认存储的纹理变量 这个是规则
            sampler2D _GrabTexture;

            v2f vert (appdata_base v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.pos);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                float3 worldNormal = UnityObjectToWorldNormal(v.normal);
                float3 worldPos = mul(unity_ObjectToWorld, v.vertex);
                float3 worldViewDir = UnityWorldSpaceViewDir(worldPos);
                o.worldRefl = reflect(-worldViewDir, worldNormal);

                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 mainTex = tex2D(_MainTex, i.uv);
                //将反射颜色和主纹理颜色进行叠加
                fixed4 reflColor = texCUBE(_Cube, i.worldRefl) * mainTex;

                //折射相关的颜色
                //其实就是从抓取的 屏幕渲染纹理中进行采样 参与计算
                //抓取纹理中的颜色信息 相当于是这个玻璃对象后面的颜色

                // 自定义折射规则
                float2 offset = 1 - _RefractAmount;
                i.grabPos.xy = i.grabPos.xy - offset / 10;

                //利用透视除法 将屏幕坐标转换到 0~1范围内 然后再进行采样
                fixed2 screenUV = i.grabPos.xy / i.grabPos.w;
                fixed4 grabColor = tex2D(_GrabTexture, screenUV);

                float4 color = lerp(reflColor, grabColor, _RefractAmount);
                    
                return color;
            }
            ENDCG
        }
    }
}

 3、带法线纹理的玻璃效果

对 Cube 加上法线向量后,需要修改反射向量计算规则,由于法线需要从法线纹理中获取,因此需要将反射向量的计算放入到片元着色器中

利用切线空间法线来计算折射偏移

(1)加入一个控制折射扭曲程度的新属性_Distortion 取值范围可以大一些
(2)利用切线空间下法线来计算偏移值,加入两行关键代码
第一行:float2 offset = tangentNormal.xy * _Distortion;
使用切线空间下法线的xy* 扭曲值得到一个偏移量,代表光线经过法线方向扰动后的偏移程度,确定光线折射的方向和强度

第二行:屏幕坐标.xy = offset * 屏幕坐标.z + 屏幕坐标.xy;
用偏移量和屏幕空间深度值相乘,模拟出真实的折射效果,深度值越大(即距离相机越远),折射效果越明显。 这样可以实现近大远小的效果,使得物体在不同深度上的折射效果有所差异

Shader "ShaderProj/6/GlassRefraction"
{
     Properties
    {
        _MainTex("MainTex", 2D) = ""{}
        _BumpMap("BumpMap", 2D) = ""{}
        _Cube("Cubemap", Cube) = ""{}
        _RefractAmount("RefractAmount", Range(0,1)) = 1
        //控制折射扭曲程度的变量
        _Distortion("Distortion", Range(0,10)) = 0
    }
    SubShader
    {
        Tags{"RenderType"="Opaque" "Queue"="Transparent"}
        GrabPass{}

        Pass
        {
            Tags{"LightMode"="ForwardBase"}
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _BumpMap;
            float4 _BumpMap_ST;
            samplerCUBE _Cube;
            float _RefractAmount;
            sampler2D _GrabTexture;
            float _Distortion;

            struct v2f
            {
                float4 pos:SV_POSITION;
                float4 grabPos:TEXCOORD0;
                float4 uv:TEXCOORD1;
                float4 TtoW0:TEXCOORD3;
                float4 TtoW1:TEXCOORD4;
                float4 TtoW2:TEXCOORD5;
            };

            v2f vert(appdata_full v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.pos);
                o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.uv.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);
                //计算反射光向量
                float3 worldNormal = UnityObjectToWorldNormal(v.normal);
                fixed3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                float3 worldTangent = UnityObjectToWorldDir(v.tangent);
                float3 worldBinormal = cross(normalize(worldTangent), normalize(worldNormal)) * v.tangent.w;

                o.TtoW0 = float4(worldTangent.x, worldBinormal.x,  worldNormal.x, worldPos.x);
                o.TtoW1 = float4(worldTangent.y, worldBinormal.y,  worldNormal.y, worldPos.y);
                o.TtoW2 = float4(worldTangent.z, worldBinormal.z,  worldNormal.z, worldPos.z);

                return o;
            }

            fixed4 frag(v2f i):SV_TARGET
            {
                float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
                fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
                float4 packedNormal = tex2D(_BumpMap, i.uv.zw);
                float3 tangentNormal = UnpackNormal(packedNormal);
                float3 worldNormal = float3(dot(i.TtoW0.xyz, tangentNormal), dot(i.TtoW1.xyz, tangentNormal), dot(i.TtoW2.xyz, tangentNormal));

                fixed4 mainTex = tex2D(_MainTex, i.uv);
                float3 refl = reflect(-viewDir, worldNormal);
                fixed4 reflColor = texCUBE(_Cube, refl) * mainTex;
                
                //折射相关的颜色
                float2 offset = tangentNormal.xy * _Distortion;
                i.grabPos.xy = offset*i.grabPos.z + i.grabPos.xy; 

                fixed2 screenUV = i.grabPos.xy / i.grabPos.w;
                fixed4 grabColor = tex2D(_GrabTexture, screenUV);

                float4 color = lerp(reflColor, grabColor, _RefractAmount);

                return color;
            }

            ENDCG
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智慧社区Web解决方案:Spring Boot框架探索

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的管理显得特别重要。因此,使用计算机来管理基于web的智慧社区设计与实现的相关信息成…

SpringBoot中的Component和ComponentScan注解工作原理

Spring IoC 容器的工作是通过管理对象的生命周期和配置来保持业务逻辑清晰,但是 Spring 容器并不会自动知道要管理哪些 bean。所以我们来告诉 Spring 应该处理哪些 bean 以及如何处理,很简单这就是 Spring 的 Component 和 ComponentScan 注释的作用所在…

Docker 安装sql server 登陆失败

错误: Sqlcmd: Error: Microsoft ODBC Driver 18 for SQL Server : SSL Provider: [error:0A000086:SSL routines::certificate verify failed:self-signed certificate]. Sqlcmd: Error: Microsoft ODBC Driver 18 for SQL Server : Client unable to establish co…

IDEA使用Alibaba Cloud Toolkit插件自动化部署jar包

一、下载插件 二、添加服务器主机 三、填写自己服务器配置 四、添加配置 五、配置说明 六、选择maven打包模块 七、maven打包后的jar包位置配一下 八、点击运行发现成功

sap abap 为何某字段不可以使用统计功能

查看是否字段错误了 以上图为例,wmeng 并不存在于 vbap表中, 而是存在于 vbep 表中,所以改成vbep表就可以成功了

Llama3-Factory模型部署新手指南

一、介绍 为了保持其公司在人工智能开源大模型领域的地位,社交巨头Meta推出了旗下最新开源模型。当地时间4月18日,Meta在官网上宣布公布了旗下最新大模型Llama 3。目前,Llama 3已经开放了80亿(8B)和700亿(…

谷歌-BERT-第四步:模型部署

1 需求 需求1:基于gradio实现大模型的WEB UI交互界面 2 接口 3 示例 import gradio as gr from transformers import *classifier pipeline("text-classification", model"./model", tokenizer"./model")gr.Interface.from_pipel…

个性化图像生成新SOTA!阿里开源MIP-Adapter,可将无需微调的IP-Adapter推广到同时合并多个参考图像。

今天给大家介绍阿里最近开源的个性化图像生成的新方法MIP-Adapter,将无需微调的预训练模型(IP-Adapter)推广到同时合并多个参考图像。MIP-Adapter会根据每个参考图像与目标对象的相关性来给这些图像分配不同的“重要性分数”。这样&#xff0…

借老系统重构我给jpa写了个mybatis风格的查询模块

因为公司老系统是用hibernate3开发的,重构自然过渡到使用Spring Data JPA。由于系统中对sql的使用方式还是手动为主,这就造成在service层存在大量的sql拼接方式,后续维护比较困难。 因为怀念以往项目对sql驱动的持久层开发用的mybatis的时光&…

HTB:Bashed[WriteUP]

目录 连接至HTB服务器并启动靶机 1.How many open TCP ports are listening on Bashed? 2.What is the relative path on the webserver to a folder that contains phpbash.php? 3.What user is the webserver running as on Bashed? 执行命令:whoami 4.S…

【前端】如何制作一个自己的网页(8)

以下内容接上文。 CSS的出现,使得网页的样式与内容分离开来。 HTML负责网页中有哪些内容,CSS负责以哪种样式来展现这些内容。因此,CSS必须和HTML协同工作,那么如何在HTML中引用CSS呢? CSS的引用方式有三种&#xff1…

构建后端为etcd的CoreDNS的容器集群(六)、编写自动维护域名记录的代码脚本

本文为系列测试文章,拟基于自签名证书认证的etcd容器来构建coredns域名解析系统。 一、前置文章 构建后端为etcd的CoreDNS的容器集群(一)、生成自签名证书 构建后端为etcd的CoreDNS的容器集群(二)、下载最新的etcd容…

Linux C接口编程入门之ioctl操作

ioctl函数用于系统调用操作特殊文件的底层设备参数。例如终端的许多操作特性可以用ioctl()请求来控制。不能用于read()、write()、open()、close()函数表示的I/O操作通常都能用ioctl表示。 fd参数为某个设备或文件已打开的文件描述符; request参数指定了将在fd上执…

大数据测试:Charles修改响应数据

上一篇大数据测试:Fiddler修改响应数据-CSDN博客 ,有同学反馈有没有Charles的方式修改响应数据,本篇就是Charles修改数据操作步骤,相比较fiddler,Charles相对简单,便捷,我很喜欢 1、背景&…

web网页---新浪网页面

代码&#xff1a; <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>新浪网</title> </head> <style>ul.menu > li{list-style: none; } …

DC系列靶机-DC6

一&#xff0c;环境的搭建 VM17 官网下载 kali 2023.4版 https://mirrors.tuna.tsinghua.edu.cn/kali-images/kali-2023.4/ 靶场文件 https://download.vulnhub.com/dc/DC-5.zip 二&#xff0c;攻略 首先进行主机发现&#xff1b; 接下来进行端口扫描&#xff1b; 开放了2…

手撕数据结构 —— 栈(C语言讲解)

目录 1.认识栈 什么是栈 栈的示意图 2.如何实现栈 3.栈的实现 Stack.h中接口总览 具体实现 结构的定义 初始化栈 销毁栈 入栈 出栈 取栈顶元素 获取有效元素的个数 判断栈是否为空 4.完整代码附录 Stack.h Stack.c 1.认识栈 什么是栈 栈是一种特殊的线性表…

CSS面试真题 part2

CSS面试真题 part2 11、css3新增了哪些新特性&#xff1f;12、css3动画有哪些&#xff1f;13、介绍一下grid网格布局14、说说flexbox&#xff08;弹性盒布局模型&#xff09;&#xff0c;以及使用场景&#xff1f;15、说说设备像素、css像素、设备独立像素、dpr、ppi之间的区别…

详解mac系统通过brew安装mongodb与使用

本文目录 一、通过brew安装MongoDB二、mongodb使用示例1、启动数据库2、创建/删除数据库3、创建/删除集合 三、MongoDB基本概念1&#xff09;数据库 (database)2&#xff09;集合 &#xff08;collection&#xff09;3) 文档&#xff08;document&#xff09;4&#xff09;mong…

WPFDeveloper正式版发布

WPFDeveloper WPFDeveloper一个基于WPF自定义高级控件的WPF开发人员UI库&#xff0c;它提供了众多的自定义控件。 该项目的创建者和主要维护者是现役微软MVP 闫驚鏵: https://github.com/yanjinhuagood 该项目还有众多的维护者&#xff0c;详情可以访问github上的README&…