26.反射基础实现

26.高级纹理-立方体纹理-反射-反射基础实现


26.1 知识点

实现反射基础效果

CG 中提供了内置函数 texCUBE 用于进行立方体纹理采样。

  • 函数形式:texCUBE(立方体纹理, 反射方向向量)
  • 工作原理:利用反射方向向量,从立方体中心向纹理发射向量,得到相交点并进行采样。

实现反射效果

主要步骤

  1. 属性声明

    • 声明两个关键属性:
      • 立方体纹理
      • 反射率(范围:0~1)
  2. 顶点着色器

    • 关键步骤:
      • 顶点坐标转裁剪坐标
      • 顶点法线转世界坐标
      • 顶点坐标转世界坐标
      • 计算世界空间下的视角方向
      • 视角反向逆向得到反射方向
  3. 片元着色器

    • 关键步骤:
      • 利用 texCUBE 函数进行立方体纹理采样
      • 结合反射程度返回最终颜色

新建 Shader

Shader "Unlit/Lesson26_ReflectBase"
{
    Properties {}
    SubShader
    {
        Pass {}
    }
}

声明两个属性:立方体纹理和反射率

Properties
{
    // 立方体纹理
    _Cube("Cubemap", Cube) = "" {}
    // 反射率
    _Reflectivity("Reflectivity", Range(0,1)) = 1
}

声明渲染标签、预编译指令、内置库和对应属性

SubShader
{
    Tags
    {
        "RenderType"="Opaque" // 设置渲染类型为不透明(Opaque)
        "Queue"="Geometry" // 设置渲染队列为Geometry,通常用于普通几何物体
    }
    
    Pass
    {
        // 设置LightMode标签,指定光照模式为ForwardBase
        Tags
        {
            "LightMode"="ForwardBase" // 指定使用正向渲染中的基本光照模式
        }

        CGPROGRAM
        #pragma vertex vert     // 指定顶点着色器函数为vert
        #pragma fragment frag   // 指定片元着色器函数为frag

        // 包含Unity内置的CG库和光照相关的库
        #include "UnityCG.cginc"
        #include "Lighting.cginc" 

        // 立方体纹理属性
        samplerCUBE _Cube;
        // 反射率属性
        float _Reflectivity;


        ENDCG
    }
}

声明结构体,包括裁剪空间下顶点坐标和世界空间下的反射向量

struct v2f
{
    float4 pos:SV_POSITION; //裁剪空间下的顶点坐标
    //世界空间下的反射向量
    //我们将把反射向量的计算放在顶点着色器函数中 节约性能 表现效果也不会太差 肉眼几乎分辨不出来
    float3 worldRefl:TEXCOORD0;
};

说明:反射向量的计算放在顶点着色器中以节约性能,视觉效果几乎无差别。

顶点函数中主要进行顶点坐标转换和计算反射光向量

v2f vert(appdata_base appdata_base)
{
    v2f v2f;
    
    //顶点坐标转换
    v2f.pos = UnityObjectToClipPos(appdata_base.vertex);
    
    //计算反射光向量
    //1.计算世界空间下法线向量
    float3 worldNormal = UnityObjectToWorldNormal(appdata_base.normal);
    //2.世界空间下的顶点坐标
    fixed3 worldPos = mul(unity_ObjectToWorld, appdata_base.vertex).xyz;
    //3.计算视角方向 内部是用摄像机位置 - 世界坐标位置 计算反射向量时要取反
    fixed3 worldViewDir = UnityWorldSpaceViewDir(worldPos);
    //4.计算反射向量
    v2f.worldRefl = reflect(-worldViewDir, worldNormal);

    return v2f;
}

片元函数对立方体纹理利用对应的反射向量进行采样,用采样颜色 * 反射率 决定最终的颜色效果

fixed4 frag(v2f v2f):SV_TARGET
{
    //对立方体纹理利用对应的反射向量进行采样
    fixed4 cubemapColor = texCUBE(_Cube, v2f.worldRefl);
    //用采样颜色 * 反射率 决定最终的颜色效果
    return cubemapColor * _Reflectivity;
}

使用小工具重新生成一下cuemap,创建材质赋值,可以看到镜面效果


26.2 知识点代码

Lesson26_高级纹理_立方体纹理_反射_反射基础实现.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson26_高级纹理_立方体纹理_反射_反射基础实现 : MonoBehaviour
{
    void Start()
    {
        #region 知识点一 实现反射基础效果使用的立方体纹理采样函数

        //立方体纹理采样函数
        //  CG中提供了内置函数 texCUBE 用于进行立方体纹理采样
        //  texCUBE(立方体纹理,反射方向向量) 便可以得到在立方体纹理中的采样结果
        //  原理就是利用反射方向向量,在立方体中心往纹理发射向量,得到相交点进行采样

        #endregion

        #region 知识点二 实现反射效果

        //1.属性声明
        //  我们将声明2个关键属性
        //  1-1:立方体纹理
        //  1-2:反射率(0~1)之间

        //2.顶点着色器
        //  关键步骤:
        //  2-1:顶点坐标转裁剪坐标
        //  2-2:顶点法线转世界坐标
        //  2-3:顶点坐标转世界坐标
        //  2-4:世界空间下 视角方向计算
        //  2-5:视角反向逆向得到反射方向

        //3.片元着色器
        //  关键步骤:
        //  3-1:立方体纹理采样(利用texCUBE函数)
        //  3-2:结合反射程度返回最终颜色

        #endregion
    }
}

Lesson26_ReflectBase.shader

Shader "Unlit/Lesson26_ReflectBase"
{
    Properties
    {
        //立方体纹理
        _Cube("Cubemap", Cube) = ""{}
        //反射率
        _Reflectivity("Reflectivity", Range(0,1)) = 1
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Opaque" // 设置渲染类型为不透明(Opaque)
            "Queue"="Geometry" // 设置渲染队列为Geometry,通常用于普通几何物体
        }

        Pass
        {
            // 设置LightMode标签,指定光照模式为ForwardBase
            Tags
            {
                "LightMode"="ForwardBase" // 指定使用正向渲染中的基本光照模式
            }

            CGPROGRAM
            #pragma vertex vert     // 指定顶点着色器函数为vert
            #pragma fragment frag   // 指定片元着色器函数为frag

            // 包含Unity内置的CG库和光照相关的库
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            // 立方体纹理属性
            samplerCUBE _Cube;
            // 反射率属性
            float _Reflectivity;


            struct v2f
            {
                float4 pos:SV_POSITION; //裁剪空间下的顶点坐标
                //世界空间下的反射向量
                //我们将把反射向量的计算放在顶点着色器函数中 节约性能 表现效果也不会太差 肉眼几乎分辨不出来
                float3 worldRefl:TEXCOORD0;
            };

            v2f vert(appdata_base appdata_base)
            {
                v2f v2f;
                
                //顶点坐标转换
                v2f.pos = UnityObjectToClipPos(appdata_base.vertex);
                
                //计算反射光向量
                //1.计算世界空间下法线向量
                float3 worldNormal = UnityObjectToWorldNormal(appdata_base.normal);
                //2.世界空间下的顶点坐标
                fixed3 worldPos = mul(unity_ObjectToWorld, appdata_base.vertex).xyz;
                //3.计算视角方向 内部是用摄像机位置 - 世界坐标位置 计算反射向量时要取反
                fixed3 worldViewDir = UnityWorldSpaceViewDir(worldPos);
                //4.计算反射向量
                v2f.worldRefl = reflect(-worldViewDir, worldNormal);

                return v2f;
            }

            fixed4 frag(v2f v2f):SV_TARGET
            {
                //对立方体纹理利用对应的反射向量进行采样
                fixed4 cubemapColor = texCUBE(_Cube, v2f.worldRefl);
                //用采样颜色 * 反射率 决定最终的颜色效果
                return cubemapColor * _Reflectivity;
            }
            ENDCG
        }
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏