【Unity Shader编程】之光照模型

根据Unity Shader编程的光照模型实现,光线通常可分为以下核心组成部分:

一、基础光照分量

环境光(Ambient)

全局基础照明,不依赖具体光源
实现方式:UNITY_LIGHTMODEL_AMBIENT内置变量

漫反射光(Diffuse)

兰伯特模型(Lambertian)模型:diffuse = max(0, dot(N, L))
半兰伯特模型(Half-Lambert)模型 diffuse=dot(N,L)a+b,ab可调,通常ab都为0.5
示例代码: float3 diffuse =
漫反射光强 = S_diff * m_diff * max(dot(n, l), 0)
S_diff:光源漫反射颜色(含强度)3
m_diff:材质漫反射系数(0-1,决定表面颜色)
n:表面单位法线向量
l:指向光源的单位方向向量
max():确保背光面光强不低于04
可以增加漫反射系数
漫反射光强 = S_diff * m_diff * o_diff
max(dot(n, l), 0)
o_diff:物体漫反射系数

镜面反射光(Specular)

高光反射,主要是利用,摄像机和反射角的夹角来判断,但夹角越小,说明名高光反射越强,所以利用点乘来计算,假设一下,你看着镜子,反射光直照射你的眼睛,是不是代表着反射强度越大,所以第一种phone模型一种是先求出光线反射角,然后计算光线反射角与摄像机视角的点积,但可能因夹角超过 90° 导致高光断层

phone高光模型

在这里插入图片描述

Blinn-Phong高光模型:

Blinn-Phong 模型是对 Phong 模型的优化改进,通过引入半角向量(Halfway Vector)简化计算并改善高光效果26。其光照由三部分构成:

因为R点乘v要求出反射光线R向量,虽然不是不可以,但是比较麻烦,计算量大。所以Blinn提出来了一个天才般的想法:
不去计算R与v的夹角余弦,而是去计算v和入射方向I的角平分线 与 表面法线的夹角余弦。于是就定义了这个角平分线为h。
如何衡量两个向量接近?——使用点乘
两个向量越近,点乘结果越接近1,两个向量越远,点乘结果越接近0
在这里插入图片描述
在这里插入图片描述

自发光(Emissive)

独立于外部光源的自主发光
实现方式:直接赋值颜色值
自发光原理就是颜色叠加

Shader "Custom/VertexEmission" {Properties {_MainTex ("Base Texture", 2D) = "white" {}_EmissionMap ("Emission Map", 2D) = "white" {}_EmissionColor ("Emission Color", Color) = (1,1,1,1)_EmissionIntensity ("Emission Intensity", Range(0, 5)) = 1.0 }SubShader {Pass {Tags { "RenderType"="Opaque" }LOD 200 CGPROGRAM#include "UnityCG.cginc" #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase struct appdata {float4 vertex : POSITION;float3 normal : NORMAL;float2 uv : TEXCOORD0;};struct v2f {float4 pos : SV_POSITION;float2 uv : TEXCOORD0;float3 worldNormal : TEXCOORD1;};sampler2D _MainTex;sampler2D _EmissionMap;fixed4 _EmissionColor;float _EmissionIntensity;v2f vert (appdata v) {v2f o;o.pos  = UnityObjectToClipPos(v.vertex);   // 模型空间→裁剪空间转换[1]()o.uv  = v.uv; o.worldNormal  = UnityObjectToWorldNormal(v.normal);   // 法线空间转换[2]()return o;}fixed4 frag (v2f i) : SV_Target {fixed4 baseColor = tex2D(_MainTex, i.uv); fixed4 emission = tex2D(_EmissionMap, i.uv)  * _EmissionColor*_EmissionIntensity;// 叠加自发光效果 return baseColor +emission;}ENDCG }
}FallBack "Diffuse"
}

二、扩展光照类型

1.法线贴图增强光
通过Tangent Space Normal Map修改表面细节光照
关键函数:UnpackNormal(tex2D(_BumpMap,uv))
根据法线来调整物体各个像素的颜色,那么就获取法线的值,然后进行物体颜色的叠加就可以获取到了

Shader "Custom/VertexFragmentExample"
{Properties {_MainTex ("主纹理", 2D) = "white" {}  // 材质面板可见的纹理属性 _Color ("颜色系数", Color) = (1,1,1,1) // 颜色调节参数 _BumpColor ("法线自发光颜色系数", Float) = 1 // 颜色调节参数 }SubShader {Pass {CGPROGRAM #pragma vertex vert   // 声明顶点着色器函数 #pragma fragment frag // 声明片元着色器函数 #include "UnityCG.cginc"  // 包含Unity内置函数 // 输入结构体:从Mesh数据自动获取[1]()struct appdata {float4 vertex : POSITION;   // 顶点位置(模型空间)float3 normal : NORMAL;     // 顶点法线(模型空间)float2 uv : TEXCOORD0;      // 第一套UV坐标 };// 输出结构体:顶点着色器->片元着色器的数据传递[2]()struct v2f {float4 pos : SV_POSITION;   // 必须包含的裁剪空间位置 float3 worldNormal : TEXCOORD1; // 自定义数据通道1存储世界法线 float2 uv : TEXCOORD0;      // 传递UV坐标 };sampler2D _MainTex;     // 声明纹理采样器float4 _MainTex_ST;     // 纹理的缩放偏移参数 float4 _Color;          // 颜色参数 float _BumpColor;v2f vert (appdata v){v2f o;// 核心坐标转换:模型空间->裁剪空间[3]()o.pos  = UnityObjectToClipPos(v.vertex);  // 法线转换:模型->世界空间 o.worldNormal  = UnityObjectToWorldNormal(v.normal); // 纹理坐标处理:应用缩放偏移参数 o.uv  = TRANSFORM_TEX(v.uv,  _MainTex); return o;}fixed4 frag (v2f i) : SV_Target {// 采样纹理并叠加颜色参数 fixed4 texColor = tex2D(_MainTex, i.uv)  * _Color;// 可视化法线数据(范围转换到0-1)fixed3 normalColor = i.worldNormal+_BumpColor;// 最终输出颜色(叠加法线可视化效果)return texColor * float4(normalColor, 1.0);}ENDCG }}
}

2.高光遮罩光(Specular Mask)
使用纹理Alpha通道控制高光强度
其实就是高光,只是一张贴图,通过透明通道来控制各部位高光的值

Shader "Custom/SpecularMask" {Properties {_MainTex ("Main Texture", 2D) = "white" {}_SpecularMask ("Specular Mask (Alpha)", 2D) = "white" {}_SpecularScale ("Specular Scale", Range(0, 2)) = 1.0_SpecularColor ("Specular Color", Color) = (1,1,1,1)_Gloss ("Gloss", Range(8, 256)) = 20}SubShader {Tags { "RenderType"="Opaque" "LightMode"="ForwardBase"}Pass {CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"struct appdata {float4 vertex : POSITION;float3 normal : NORMAL;float2 uv : TEXCOORD0;};struct v2f {float4 pos : SV_POSITION;float2 uv : TEXCOORD0;float3 worldNormal : TEXCOORD1;float3 viewDir : TEXCOORD2;};sampler2D _MainTex;sampler2D _SpecularMask;float4 _SpecularMask_ST;float _SpecularScale;float4 _SpecularColor;float _Gloss;v2f vert (appdata v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.uv, _SpecularMask);// 计算世界空间法线和视角方向o.worldNormal = UnityObjectToWorldNormal(v.normal);o.viewDir = normalize(_WorldSpaceCameraPos - mul(unity_ObjectToWorld, v.vertex).xyz);return o;}fixed4 frag (v2f i) : SV_Target {// 基础纹理采样fixed4 baseColor = tex2D(_MainTex, i.uv);// 高光遮罩采样fixed4 mask = tex2D(_SpecularMask, i.uv);float specularIntensity = mask.a * _SpecularScale;// 光照计算float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);float3 halfDir = normalize(lightDir + i.viewDir);// 高光计算float spec = pow(max(0, dot(normalize(i.worldNormal), halfDir)), _Gloss);float3 specular = _SpecularColor.rgb * spec * specularIntensity;// 最终颜色合成return fixed4(baseColor.rgb + specular, 1.0);}ENDCG}}FallBack "Diffuse"
}

3.边缘光(Rim Light)
基于菲涅尔效应:rim=pow(1.0-dot(N,V),_RimPower)

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

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

相关文章

dify + ollama + deepseek-r1+ stable-diffusion 构建绘画智能体

故事背景 stable-diffusion 集成进 dify 后,我们搭建一个小智能体,验证下文生图功能 业务流程 #mermaid-svg-6nSwwp69eMizP6bt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6nSwwp69eMiz…

无人机扩频技术对比!

一、技术原理与核心差异 FHSS(跳频扩频) 核心原理:通过伪随机序列控制载波频率在多个频点上快速跳变,收发双方需同步跳频序列。信号在某一时刻仅占用窄带频谱,但整体覆盖宽频带。 技术特点: 抗干扰…

【从零开始学习计算机科学】数字逻辑(九)有限状态机

【从零开始学习计算机科学】数字逻辑(九)有限状态机 有限状态机状态机的表示方法有限状态机的Verilog描述有限状态机 有限状态机(简称状态机)相当于一个控制器,它将一项功能的完成分解为若干步,每一步对应于二进制的一个状态,通过预先设计的顺序在各状态之间进行转换,状…

知识周汇 | Python操作Excel全攻略系列(四):单元格相关篇

目录 系列文章 1 重点 2 如何获取当前工作表的最大行数和最大列数 3 修改单元格的值(包括数值和格式) 4 查找特定字符的位置 5 对同一列中上下行值相同的单元格进行行合并 6 查找特定值并标记颜色 后续 系列文章 知识周汇 | Python操作Excel全攻…

KubeKey 与 KubeSphere:快速构建 Kubernetes 集群

深度解析 KubeKey 与 KubeSphere:快速构建现代化 Kubernetes 集群 一、技术栈概述 KubeKey(KK)是由 KubeSphere 团队开发的轻量级 Kubernetes 集群部署工具,其优势在于: 基于 Ansible 的安装程序具有大量软件依赖性…

C++编写Redis客户端

目录 安装redis-plus-plus库 ​编辑 编译Credis客户端 redis的通用命令使用 get/set exists del keys expire /ttl type string类型核心操作 set和get set带有超时时间 set带有NX string带有XX mset mget getrange和setrange incr和decr list类型核心操作…

从零开始实现大语言模型(十三):预训练大语言模型GPTModel

1. 前言 使用梯度下降算法通过下一个token预测任务预训练大语言模型GPTModel,前向传播流程每次会输入一个batch的长度均为context_len的训练样本,执行 batch_size context_len \text{batch\_size}\times\text{context\_len} batch_sizecontext_len次下…

JavaScript(最后一个元素的索引就是数组的长度减 1)array.length - 1

在不同的编程语言中,表示数组中最后一个元素的方法略有不同,但基本思路都是利用数组的长度或索引来实现。 以下是一些常见编程语言中获取数组最后一个元素的方法: 1. JavaScript: 使用 array.length - 1 索引: 这是最常见和传统的方法。Java…

RV1126+FFMPEG多路码流监控项目

一.项目介绍: 本项目采用的是易百纳RV1126开发板和CMOS摄像头,使用的推流框架是FFMPEG开源项目。这个项目的工作流程如下(如上图):通过采集摄像头的VI模块,再通过硬件编码VENC模块进行H264/H265的编码压缩,并把压缩后的…

Python组合数据类型(一)

目录 一、数据类型 1、基本数据类型 2、组合数据类型 二、介绍两个函数 1、 isinstance函数 2、len函数 三、Python指针 1、指针 2、is运算符和的区别 3、列表的指针 四、函数参数的传递 1、例子一 2、例子二 五、字符串详解 1、转义字符 2、字符串的切片 3、字…

Doris vs ClickHouse 企业级实时分析引擎怎么选?

Apache Doris 与 ClickHouse 同作为OLAP领域的佼佼者,在企业级实时分析引擎该如何选择呢。本文将详细介绍 Doris 的优势,并通过直观对比展示两者的关键差异,同时分享一个企业成功用 Doris 替换 ClickHouse 的实践案例,帮助您做出明…

【ThreeJS Basics 09】Debug

文章目录 简介从 dat.GUI 到 lil-gui例子安装 lil-gui 并实例化不同类型的调整改变位置针对非属性的调整复选框颜色 功能/按钮调整几何形状文件夹调整 GUI宽度标题关闭文件夹隐藏按键切换 结论 简介 每一个创意项目的一个基本方面是能够轻松调整。开发人员和参与项目的其他参与…

Android Native 之 文件系统挂载

一、文件系统挂载流程概述 二、文件系统挂载流程细节 1、Init启动阶段 众所周知,init进程为android系统的第一个进程,也是native世界的开端,要想让整个android世界能够稳定的运行,文件系统的创建和初始化是必不可少的&#xff…

Chain of Draft: 借鉴人类草稿思维让大型语言模型更快地思考

这个研究探讨了大型语言模型(LLMs)在执行复杂推理任务时面临的计算资源消耗与响应延迟问题。研究特别聚焦于思维链(Chain-of-Thought, CoT)提示范式的效率局限性。CoT虽然有效,但在推理过程中需要生成冗长、详尽的逐步…

《A++ 敏捷开发》- 18 软件需求

需求并不是关于需求 (Requirements are not really about requirements) 大家去公共图书馆寄存物品,以前都是扫二维码开箱,有些图书馆升级了使用指纹识别。 “是否新方法比以前好?”我问年轻的开发人员。 “当然用指纹识别好。新技术&#x…

【智能体架构:Agent】LangChain智能体类型ReAct、Self-ASK的区别

1. 什么是智能体 将大语言模型作为一个推理引擎。给定一个任务, 智能体自动生成完成任务所需步骤, 执行相应动作(例如选择并调用工具), 直到任务完成。 2. 先定义工具:Tools 可以是一个函数或三方 API也…

Vue进阶之Vue3源码解析(一)

Vue3源码解析 目录结构编译compiler-corepackage.jsonsrc/index.ts 入口文件src/compile.ts生成ASTsrc/parse.ts 代码转换src/transform.ts几种策略模式src/transforms/transformElement.tssrc/transforms/transformText.tssrc/transforms/transformExpression.ts 代码生成src/…

servlet tomcat

在spring-mvc demo程序运行到DispatcherServlet的mvc处理 一文中,我们实践了浏览器输入一个请求,然后到SpringMvc的DispatcherServlet处理的整个流程. 设计上这些都是tomcat servlet的处理 那么究竟这是怎么到DispatcherServlet处理的,本文将…

【我的待办(MyTodolists)-免费无内购的 IOS 应用】

我的待办(MyTodolists) 我的待办:智能任务管理助手应用说明主要功能为什么选择"我的待办"?隐私保障使用截图 我的待办:智能任务管理助手 应用说明 "我的待办"是一款智能化的任务管理应用&#x…

GCC RISCV 后端 -- C语言语法分析过程

在 GCC 编译一个 C 源代码时,先会通过宏处理,形成 一个叫转译单元(translation_unit),接着进行语法分析,C 的语法分析入口是 static void c_parser_translation_unit(c_parser *parser); 接着就通过类似递…