• Unity中Shader立方体纹理Cubemap



    前言

    Unity中Shader立方体纹理Cubemap


    一、什么是立方体纹理

    立方体纹理,也被叫做Cubemap。通常用来做反射效果

    在Unity中,如果全都使用实时反射,那么对于设备性能的消耗是比较大的,所以使用一种投机取巧的方式实现的反射效果

    在这里插入图片描述


    二、立方体纹理的生成方式

    1、使用6个面的生成方式

    在这里插入图片描述
    在这里插入图片描述
    一般选择Auto即可,会自动适配

    2、使用单张图片的生成方式

    在这里插入图片描述
    在这里插入图片描述
    一般选择Auto即可,会自动适配


    三、Cubemap的采样方式

    在这里插入图片描述
    由模型顶点向Cubemap发射射线,射线经过的Cubemap哪个点,那个点就是采样点


    四、在Unity中看一下Cubemap

    在纹理的 Inspector,按如下设置,就可以把普通纹理类型修改为立方体纹理
    在这里插入图片描述
    请添加图片描述


    五、在Shader中,对立方体纹理进行采样使用

    我们使用上一篇文章的Shader继续测试:

    1、我们在属性面板定义一个Cube类型的变量来存放立方体纹理

    _CubeMap(“CubeMap”,Cube) = “white” {}

    2、使用前在Pass中,声明一下该变量

    samplerCUBE _Cubemap;

    3、在片元着色器中,对其纹理采样

    这里进行纹理采样时,由其原理可知,需要使用顶点的本地坐标。

    在这里插入图片描述

    所以,这里使用 appdata 传入的顶点数据来采样即可。

    • 我们先在 v2f 中定义一个变量来存储应用程序阶段传入的数据

    我们只需要顶点的 xyz 即可

    float3 localPos : TEXCOORD1;

    • 然后,在顶点着色器阶段,把 appdata 的顶点 xyz 传给 v2f 中的 localPos

    o.localPos = v.vertex.xyz;

    • 返回一下采样的结果看看(已经有了采样的结果)

    fixed4 cubemap = texCUBE(_CubeMap,i.localPos);
    return cubemap;

    在这里插入图片描述

    4、模拟真实的反射效果 (Cubemap的环境映射)

    要模拟出真实的反射效果,不能向之前一样,采样眼睛处的Cubemap

    而是需要采样视线的反射视线经过Cubemap的点

    在这里插入图片描述

    5、计算视线的反射向量

    因为需要计算视线的反射向量,所以需要准备一些数据:

    摄像机的世界坐标、模型顶点的世界坐标、法线的世界坐标

    • 准备摄像机的世界坐标

    _WorldSpaceCameraPos

    • 准备模型顶点的世界坐标

    1、在 v2f 中,定义一个变量存储顶点的世界信息
    float3 worldPos : TEXCOORD2;
    2、在顶点着色器中,进行顶点坐标转化
    o.worldPos = mul(unity_ObjectToWorld,v.vertex);

    • 准备法线的世界坐标

    1、在 appdata 中传入法线信息
    half3 normal : NORMAL;
    2、在 v2f 中,定义一个变量存储法线世界坐标
    half3 worldNormal : NORMAL;
    3、在顶点着色器中,进行法线坐标转化
    o.worldNormal = UnityObjectToWorldNormal(v.normal);

    • 准备最后的计算

    1、计算世界坐标下 视线单位向量 V
    fixed3 V = normalize(i.worldPos - _WorldSpaceCameraPos);
    2、计算世界坐标下 法线单位向量 N
    fixed3 N = normalize(i.worldNormal);
    3、计算世界坐标下 反射向量R
    fixed3 R = reflect(V,N);
    4、用 R 对Cubemap进行纹理采样
    fixed4 cubemap = texCUBE(_CubeMap,R);


    六、最终效果

    请添加图片描述

    最终代码:

    //纹理的多级渐远 Mipmap
    //纹理的环绕方式
    Shader "MyShader/P2_1_5"
    {
        Properties
        {
            _MainTex ("Texture", 2D) = "white" {}
            
            [KeywordEnum (Repeat,Clamp)]_WrapMode("WrapMode",int) = 0
            [IntRange]_Mipmap ("Mipmap",Range(0,10)) = 0
            //在属性面板定义立方体纹理
            _CubeMap("CubeMap",Cube) = "white" {}
        }
        SubShader
        {
            Tags { "RenderType"="Opaque" }
            LOD 100
    
            Pass
            {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma shader_feature _WRAPMODE_REPEAT _WRAPMODE_CLAMP
                #include "UnityCG.cginc"
                
                struct appdata
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                    half3 normal : NORMAL;
                };
    
                struct v2f
                {
                    float2 uv : TEXCOORD0;
                    float4 vertex : SV_POSITION;
                    float3 localPos : TEXCOORD1;
                    float3 worldPos : TEXCOORD2;
                    half3 worldNormal : NORMAL;
                };
    
                sampler2D _MainTex;
                float4 _MainTex_ST;
                half _Mipmap;
                samplerCUBE _CubeMap;
                v2f vert (appdata v)
                {
                    v2f o;
                    
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                    o.localPos = v.vertex.xyz;
                    o.worldPos = mul(unity_ObjectToWorld,v.vertex);
                    o.worldNormal = UnityObjectToWorldNormal(v.normal);
                    return o;
                }
    
                fixed4 frag (v2f i) : SV_Target
                {
                    //WrapMode
                    #if _WRAPMODE_REPEAT
                    i.uv = frac(i.uv);
                    #elif _WRAPMODE_CLAMP
                        //法一:
                        //i.uv = clamp(i.uv,0,1);
                        //法二:
                        i.uv = saturate(i.uv);
                    #endif
                    float4 uvMipmap = fixed4(i.uv,0,_Mipmap);
                    fixed4 col = tex2Dlod(_MainTex, uvMipmap);
    
                    //Cube
                    fixed4 cubemap = texCUBE(_CubeMap,i.localPos);
                    //V,N,R
                    fixed3 V = normalize(i.worldPos - _WorldSpaceCameraPos);
                    fixed3 N = normalize(i.worldNormal);
                    fixed3 R = reflect(V,N);
                    cubemap = texCUBE(_CubeMap,R);
                    
                    return cubemap;
                    
                    return col;
                }
                ENDCG
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
  • 相关阅读:
    JavaEE-文件IO操作
    【C语言航路】第六站:指针初阶
    协程理解1
    NVIDIA GPU MIG
    java — 认识String类的常用方法(上)
    Java内存区域
    做着做着感觉自媒体做不下去了?
    科学计算三维可视化笔记(第七周 运算)
    15_人间大道是清醒
    【Gradle】二、全新项目构建工具Gradle的体验
  • 原文地址:https://blog.csdn.net/qq_51603875/article/details/134480070