UnityShader(十二)实现标准光照模型中的高光反射

news2024/11/22 19:05:41

目录

基本光照模型中的高光反射公式:

逐顶点光照

逐像素光照


基本光照模型中的高光反射公式:

c_{specular}=\left ( c_{light}\cdot m_{specular} \right )max\left ( 0,\widehat{v},\widehat{r} \right )^{m_{gloss}}

从公式可以看出 要计算高光反射需要知道四个参数:入射光线的颜色和强度clight,材质的高光反射系数mspecular,视角方向v以及反射方向r。其中,反射方向r可以由表面法线n和光源方向l计算得到

即:

\widehat{r}=\widehat{l}-2\left ( \widehat{n}\cdot \widehat{l} \right )\widehat{n}

上述公式很简单,Cg也提供了计算反射方向的函数reflect

函数:reflect(i,n)

参数:i:入射方向;n:法线方向。可以是float,float2,float3等类型。

描述:当给定入射方向i和法线方向n时,reflect函数可以返回反射方向

逐顶点光照

//给Shader命名
Shader "MyShader/SpecularVertex"
{
    //_Specular控制材质的高光反射属性,_Gloss控制高光区域的大小
    Properties
    {
        _Diffuse("Diffuse",color)=(1,1,1,1)
        _Specular("Specular",color)=(1,1,1,1)
        _Gloss("Gloss",Range(8.0,256))=20
    }

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

            CGPROGRAM

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

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v
            {
                float4 vertex:POSITION;
                float3 normal:NORMAL;
            };

            struct v2f
            {
                float4 pos:SV_POSITION;
                fixed3 color:COLOR;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos=UnityObjectToClipPos(v.vertex);
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;

                fixed3 worldNormal=normalize(mul(v.normal,(float3x3)unity_WorldToObject));
                fixed3 worldLightDir=normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLightDir));

                /*对于高光反射部分,先计算入射光线方向关于表面法线的反射方向reflectDir
                由于Cg的reflect函数的入射方向要求是由光源指向交点处,因此需要对worldLightDir取反后再传给reflect函数。
                然后通过_WorldSpaceCameraPos得到世界空间中的摄像机位置,再把顶点位置从模型空间变换到世界空间下,
                再通过和_WorldSpaceCameraPos相减得到世界空间下的视角方向。*/
                fixed3 reflectDir=normalize(reflect(-worldLightDir,worldNormal));
                fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-mul(unity_ObjectToWorld,v.vertex).xyz);
                fixed3 specular=_LightColor0.rgb*_Specular.rgb*pow(saturate(dot(reflectDir,viewDir)),_Gloss);

                o.color=ambient+diffuse+specular;
                return o;
            }

            fixed4 frag(v2f i):SV_TARGET
            {
                return fixed4(i.color,1.0);
            }

            ENDCG
        }    
    }

    FallBack "Specular"
}

效果:

 

使用逐顶点的方法得到的效果有较大的问题。我们可以看到高光部分并不平滑,这是因为高光反射部分的计算是非线性的,而在顶点着色器中计算光照再进行插值的过程是线性的,破坏了原计算的非线性关系。因此我们就需要采用逐像素的方法计算高光反射。 

逐像素光照

//给Shader命名
Shader "MyShader/SpecularPiexl"
{
    //_Specular控制材质的高光反射属性,_Gloss控制高光区域的大小
    Properties
    {
        _Diffuse("Diffuse",color)=(1,1,1,1)
        _Specular("Specular",color)=(1,1,1,1)
        _Gloss("Gloss",Range(8.0,256))=20
    }

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

            CGPROGRAM

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

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v
            {
                float4 vertex:POSITION;
                float3 normal:NORMAL;
            };

            //修改顶点着色器的输出结构体
            struct v2f
            {
                float4 pos:SV_POSITION;
                fixed3 worldNormal:TEXCOORD0;
                fixed3 worldPos:TEXCOORD1;
            };

            //顶点着色器只需要计算世界空间下的法线方向和顶点坐标并传递给片元着色器
            v2f vert(a2v v)
            {
                v2f o;
                o.pos=UnityObjectToClipPos(v.vertex);
                o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject);
                o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
             
                return o;
            }

            fixed4 frag(v2f i):SV_TARGET
            {
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;

                fixed3 worldNormal=normalize(i.worldNormal);
                fixed3 worldLightDir=normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLightDir));

                fixed3 reflectDir=normalize(reflect(-worldLightDir,worldNormal));
                fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz);
                fixed3 specular=_LightColor0.rgb*_Specular.rgb*pow(saturate(dot(reflectDir,viewDir)),_Gloss);

                return fixed4(ambient+diffuse+specular,1.0);
            }

            ENDCG
        }    
    }

    FallBack "Specular"
}

效果:

可以看出,按照逐像素的方式处理光照可以得到更加平滑的高光效果。 

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

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

相关文章

怿星科技荣膺星河智联“2023年度卓越供应商”,共创智能座舱新未来

1月19日,在星河智联2023年度卓越供应商评选活动中,怿星科技凭借卓越的产品和优质的服务,以及在项目管理、设计开发和成本控制等多方面的出色表现,荣获了“年度卓越供应商”的荣誉称号。 添加图片注释,不超过 140 字&am…

UML/SysML建模工具更新情况(截至2024年1月)(2)Papyrus 6.6.0

工具最新版本:drawio-desktop 23.0.2 更新时间:2024年1月25日 工具简介 开源绘图工具,用Electron编写,跨平台,支持UML。桌面版和在线版现在版本号已统一。在线版:Flowchart Maker & Online Diagram S…

oracle数据库慢查询SQL

目录 场景: 环境: 慢SQL查询一: 问题一:办件列表查询慢 分析: 解决方法: 问题二:系统性卡顿 分析: 解决方法: 慢SQL查询二 扩展: 场景: 线…

Uniapp登录页面获取头像、昵称的最新方法的简单使用

前言 写小程序写到登录页面的时候,发现官方文档中原来的wx.getUserInfo和wx.getUserProfile不太能用了,学习了相对比较新的方法,这种方法的文档链接如下: https://developers.weixin.qq.com/miniprogram/dev/framework/open-abil…

免费的ChatGPT网站 ( 7个 )

ChatGPT的核心功能是基于用户在输入时的语言或文本生成相应的回复或继续内容。此外,它还能够完成多种任务,如撰写邮件、视频脚本、文案、翻译、代码编写以及撰写论文等。 博主归纳总结了7个国内非常好用,而且免费的chatGPT网站,AI…

Camunda ScriptTask SendTask ReceiveTask操作

文章目录 开始脚本任务(ScriptTask)发送任务(SendTask)接收任务(ReceiveTask)流程图xml 开始 前面我们已经介绍了Camunda最基本的操作和常见的监听器,如果不熟悉Camunda,可以先看一下,方便搭建环境,亲手测试。 Camunda组件与服务…

轻量式RPC调用日志链路设计方案

导语: 调用链跟踪系统,又称为tracing,是微服务设计架构中,从系统层面对整体的monitoring和profiling的一种技术手 背景说明 由于我们的项目是微服务方向,中后台服务调用链路过深,追踪路径过长,其中某个服务报错或者异…

YOLOv5改进芒果首发:24年最新论文Shift-ConvNets:稀疏/移位操作让小卷积核也能达到大卷积核效果,来打造新颖YOLOv5检测器

💡本篇内容:YOLOv5改进芒果首发:24年最新论文Shift-ConvNets:稀疏/移位操作让小卷积核也能达到大卷积核效果,来打造新颖YOLOv5检测器 💡附改进源代码及教程,用来改进作为 🚀改进Shift-ConvNets 深圳大学出品!!24年最新论文 Shift-ConvNets地址:https://arxiv.o…

c/c++串的链式操作

文章目录 1.链式串的定义2.初始化3.赋值为04.赋值操作5.打印操作6.源码 本篇博客中都是带头结点的串。 1.链式串的定义 这里的数据域是4个字节,是为了节省空间。 typedef struct StringNode{char ch[4]; //按串长分配存储区,ch指向串的基地址struct S…

史诗级详细离线更新centos系统的openssh,升级到9.3p1!!

离线更新openssh步骤 文章目录 前言一、openssh是什么?二、更新步骤 1.查看相关组件版本是否存在(代码包已全部打包)2.进行openssh离线更新总结(安装时可能出现的问题等)前言 对于可能很多人在离线更新openssh时都没找到一篇能解决实际问题的文章,那么今天它来了,请往下看…

安卓相对布局RelativeLayout

<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"150dp"><TextViewandroid…

PostgreSql和Oracle的事务机制区别以及对程序的影响

前言 几年前IT信息产业的一些核心技术包括架构、产品以及生态都是国外制定&#xff0c;然而自从“遥遥领先”公司被制裁后&#xff0c;国家开始大力支持信息产业“新基建”&#xff0c;自2020年开始市场上涌现出了大量的国产化软件&#xff0c;就国产化数据库而言我所在的公司…

vue2+html2pdf下载PDF,PDF分页切割

问题: PDF下载下来后,文档内容被暴力分割。 解决方案: HTML <!-- 打印按钮 --> <el-button type="primary" size="small" class="el-icon-download right_btn" @click="downloadPDF">PDF</el-button><!-- …

Windows存储空间不足局域网文件共享 Dism备份系统空间不足

问题情景 在日常使用中难免遇到Windows的空间不足的情况&#xff0c;常用办法是清理垃圾释放空间&#xff0c;部分场景例如我们需要使用Dism备份完整系统&#xff0c;所以需要非常大的存储空间不够&#xff0c;如果空间不够什么才是最有效的方案呢&#xff1f; 我们假设身边没有…

字符串转换const char* , char*,QByteArray,QString,string相互转换,支持中文

文章目录 1.char * 与 const char * 的转换2.QByteArray 与 char* 的转换3.QString 与 QByteArray 的转换4.QString 与 string 的转换5.QString与const string 的转换6.QString 与 char* 的转换 在开发中&#xff0c;经常会遇到需要将数据类型进行转换的情况&#xff0c;下面依…

伪原创生成器手机版,移动端上写文章更方便!

伪原创生成器虽然不少&#xff0c;但我们大家见到最多的还是电脑使用版&#xff0c;然而提及到伪原创生成器手机版的资源却不是那么多&#xff0c;特别是对于现在手机端也成为了大家办公的一大途径&#xff0c;这主要也是因为手机的便携性&#xff0c;它可以做到让大家随时随地…

【图例】直观的感受MySQL事务的隔离级别分别解决了什么问题?以及如何查看和设置事务隔离级别!

目录 前言一、读未提交&#xff08;Read Uncommitted&#xff09;二、读已提交&#xff08;Read Committed&#xff09;三、可重复读&#xff08;Repeatable Read&#xff09;四、串行化&#xff08;Serializable&#xff09; 前言 在MySQL中&#xff0c;事务的隔离级别决定了…

如何本地搭建Emby影音管理服务并结合内网穿透实现远程访问本地影音库

文章目录 1.前言2. Emby网站搭建2.1. Emby下载和安装2.2 Emby网页测试 3. 本地网页发布3.1 注册并安装cpolar内网穿透3.2 Cpolar云端设置3.3 Cpolar内网穿透本地设置 4.公网访问测试5.结语 1.前言 在现代五花八门的网络应用场景中&#xff0c;观看视频绝对是主力应用场景之一&…

UE4 C++ 结构体

先在UCLASS()前写入&#xff1a; USTRUCT(BlueprintType) struct FMyStruct //必须以"F"开头 {GENERATED_BODY() //必须添加“GENERATED_BODY()”UPROPERTY(EditAnywhere, BlueprintReadWrite, Category "MyStruct1")int32 Health;UPROPERTY(EditAnywher…

【算法】拦截导弹(线性DP)

题目 某国为了防御敌国的导弹袭击&#xff0c;发展出一种导弹拦截系统。 但是这种导弹拦截系统有一个缺陷&#xff1a;虽然它的第一发炮弹能够到达任意的高度&#xff0c;但是以后每一发炮弹都不能高于前一发的高度。 某天&#xff0c;雷达捕捉到敌国的导弹来袭。 由于该系…