29.高级纹理-立方体纹理-折射-折射基础实现
29.1 知识点
折射向量计算函数
在 CG 中,内置函数 refract
用于计算折射向量:
- 函数原型:
refract(入射方向单位向量, 顶点法线单位向量, 入射介质折射率/射入介质折射率)
- 计算原理:利用斯涅耳定律计算折射向量。
通过调用此函数,可以直接获取目标介质中的折射向量,无需额外编写逻辑计算。
折射的基础实现
主要步骤
关键属性
定义以下四个关键属性:- 介质 A 的折射率。
- 介质 B 的折射率。
- 立方体纹理贴图。
- 折射程度。
关键流程
- 编译指令、内置文件、属性映射、结构体相关
- 顶点着色器
- 顶点坐标转裁剪坐标。
- 顶点法线转世界坐标。
- 顶点坐标转世界坐标。
- 计算视角方向(世界空间)。
- 利用折射函数计算折射向量。
- 片元着色器
- 使用
texCUBE
函数进行立方体纹理采样。 - 结合折射程度返回最终颜色。
- 使用
创建一个新的 Shader,命名为 Lesson29_RefractionBase
:
Shader "Unlit/Lesson29_RefractionBase"
{
}
声明属性,包括介质A折射率、介质B折射率、立方体纹理贴图和折射程度,已经对应映射属性。同时包括渲染标签编译指令以及内置文件等
Shader "Unlit/Lesson29_RefractionBase"
{
Properties
{
//立方体纹理贴图
_Cube("Cubemap", Cube) = ""{}
//介质A折射率
_RefractiveIndexA("RefractiveIndexA", Range(1,2)) = 1
//介质B折射率
_RefractiveIndexB("RefractiveIndexB", Range(1,2)) = 1.3
//折射程度
_RefracAmount("RefracAmount", Range(0,1)) = 1
}
SubShader
{
Tags
{
"RenderType"="Opaque" // 设置渲染类型为不透明(Opaque)
"Queue"="Geometry" // 设置渲染队列为Geometry,通常用于普通几何物体
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
samplerCUBE _Cube;
fixed _RefractiveIndexA;
fixed _RefractiveIndexB;
fixed _RefracAmount;
ENDCG
}
}
}
声明v2f结构体,包括裁剪空间下顶点坐标和折射向量
struct v2f
{
//裁剪空间下顶点坐标
float4 pos:SV_POSITION;
//折射向量
float3 worldRefr:TEXCOORD0;
};
顶点函数中,得到顶点裁剪坐标和世界坐标的折射向量
v2f vert(appdata_base appdata_base)
{
v2f v2f;
//顶点坐标转换
v2f.pos = UnityObjectToClipPos(appdata_base.vertex);
//法线转世界
fixed3 worldNormal = UnityObjectToWorldNormal(appdata_base.normal);
//顶点转世界
fixed3 worldPos = mul(unity_ObjectToWorld, appdata_base.vertex).xyz;
//视角方向获取 摄像机 - 顶点位置 计算反射向量时要取反
fixed3 worldViewDir = UnityWorldSpaceViewDir(worldPos);
//计算折射向量
//第三个参数一定是 介质A/介质B的结果 我们可以声明一个变量在外部算好传进来 这里我们用两个变量只是为了讲解知识
v2f.worldRefr = refract(-normalize(worldViewDir), normalize(worldNormal),
_RefractiveIndexA / _RefractiveIndexB);
return v2f;
}
片元函数中,使用折射向量采样
fixed4 frag(v2f v2f):SV_TARGET
{
//立方体纹理采样
fixed4 cubemapColor = texCUBE(_Cube, v2f.worldRefr);
//结合折射程度进行计算返回
return cubemapColor * _RefracAmount;
}
创建材质,使用小工具生成正方体纹理进行测试,可以看到折射效果
29.2 知识点代码
Lesson29_高级纹理_立方体纹理_折射_折射基础实现.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson29_高级纹理_立方体纹理_折射_折射基础实现 : MonoBehaviour
{
void Start()
{
#region 知识点一 折射向量计算函数
//折射向量计算函数
// CG中提供了内置函数 refract 用于进行折射向量的计算
// refract(入射方向单位向量, 顶点法线单位向量, 入射介质折射率/射入介质折射率)
// 便可以得到在目标介质中的折射向量
// 该函数内部就是利用了斯涅耳定律进行的计算
// 我们无需再自己写逻辑计算了
#endregion
#region 知识点二
//1.属性声明
// 我们将声明4个关键属性
// 1-1:介质A折射率
// 1-2:介质B折射率
// 1-3:立方体纹理贴图
// 1-4:折射程度
//2.编译指令、内置文件、属性映射、结构体相关
//3.顶点着色器
// 关键步骤:
// 3-1:顶点坐标转裁剪坐标
// 3-2:顶点法线转世界坐标
// 3-3:顶点坐标转世界坐标
// 3-4:世界空间下 视角方向计算
// 3-5:利用折射函数计算折射向量
//4.片元着色器
// 关键步骤:
// 3-1:立方体纹理采样(利用texCUBE函数)
// 3-2:结合折射程度返回最终颜色
#endregion
}
}
Lesson29_RefractionBase.shader
Shader "Unlit/Lesson29_RefractionBase"
{
Properties
{
//立方体纹理贴图
_Cube("Cubemap", Cube) = ""{}
//介质A折射率
_RefractiveIndexA("RefractiveIndexA", Range(1,2)) = 1
//介质B折射率
_RefractiveIndexB("RefractiveIndexB", Range(1,2)) = 1.3
//折射程度
_RefracAmount("RefracAmount", Range(0,1)) = 1
}
SubShader
{
Tags
{
"RenderType"="Opaque" // 设置渲染类型为不透明(Opaque)
"Queue"="Geometry" // 设置渲染队列为Geometry,通常用于普通几何物体
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
samplerCUBE _Cube;
fixed _RefractiveIndexA;
fixed _RefractiveIndexB;
fixed _RefracAmount;
struct v2f
{
//裁剪空间下顶点坐标
float4 pos:SV_POSITION;
//折射向量
float3 worldRefr:TEXCOORD0;
};
v2f vert(appdata_base appdata_base)
{
v2f v2f;
//顶点坐标转换
v2f.pos = UnityObjectToClipPos(appdata_base.vertex);
//法线转世界
fixed3 worldNormal = UnityObjectToWorldNormal(appdata_base.normal);
//顶点转世界
fixed3 worldPos = mul(unity_ObjectToWorld, appdata_base.vertex).xyz;
//视角方向获取 摄像机 - 顶点位置 计算反射向量时要取反
fixed3 worldViewDir = UnityWorldSpaceViewDir(worldPos);
//计算折射向量
//第三个参数一定是 介质A/介质B的结果 我们可以声明一个变量在外部算好传进来 这里我们用两个变量只是为了讲解知识
v2f.worldRefr = refract(-normalize(worldViewDir), normalize(worldNormal),
_RefractiveIndexA / _RefractiveIndexB);
return v2f;
}
fixed4 frag(v2f v2f):SV_TARGET
{
//立方体纹理采样
fixed4 cubemapColor = texCUBE(_Cube, v2f.worldRefr);
//结合折射程度进行计算返回
return cubemapColor * _RefracAmount;
}
ENDCG
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com