shader篇-立方体纹理

本文介绍了立方体纹理的基本概念及其在游戏开发中的多种应用,包括天空盒、反射、折射和菲涅尔反射等效果的实现。通过Unity脚本生成立方体纹理,并详细解释了如何在着色器中配置这些效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

shader篇-立方体纹理


简介

立方体纹理是环境映射的一种实现方式。
立方体纹理包含6张图像,对应立方体6个面。
优点:实现快速简单,效果好
缺点:经常需要重新生成立方体纹理。仅可以反射环境。

天空盒

天空盒是立方体纹理的一种应用,游戏里常用它模拟背景。让整个场景包裹在一个立方体内。
Unity5中创造立方体纹理的方法有三种。
一、直接由一些特殊布局的纹理创建。
二、手动创建一个cubemap资源,再把6张图赋给它。
三、脚本直接生成。

如果希望根据物体在场景中位置的不同,生成各自不同的立方体纹理。我们需要利用脚本生成。

using UnityEngine;
using UnityEditor;
using System.Collections;

public class RenderCubemapWizard : ScriptableWizard {

    public Transform renderFromPosition;
    public Cubemap cubemap;

    void OnWizardUpdate () {
        helpString = "Select transform to render from and cubemap to render into";
        isValid = (renderFromPosition != null) && (cubemap != null);
    }

    void OnWizardCreate () {

        GameObject go = new GameObject( "CubemapCamera");
        go.AddComponent<Camera>();
        //在renderFromPosition(用户指定位置)创建一个摄像头
        go.transform.position = renderFromPosition.position;
       //把当前位置观察到的图像渲染到用户指定的立方体纹理中
        go.GetComponent<Camera>().RenderToCubemap(cubemap);


        DestroyImmediate( go );
    }

    [MenuItem("GameObject/Render into Cubemap")]
    static void RenderCubemap () {
        ScriptableWizard.DisplayWizard<RenderCubemapWizard>(
            "Render cubemap", "Render!");
    }
}

反射

反射能让物体看起来像镀了层金属一样。
配置

Properties {
    _Color ("Color Tint", Color) = (1, 1, 1, 1)

    //控制反射颜色
    _ReflectColor ("Reflection Color", Color) = (1, 1, 1, 1)
    //控制反射程度
    _ReflectAmount ("Reflect Amount", Range(0, 1)) = 1
    _Cubemap ("Reflection Cubemap", Cube) = "_Skybox" {}
    }
    SubShader {
    Tags { "RenderType"="Opaque" "Queue"="Geometry"}

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

        CGPROGRAM

        #pragma multi_compile_fwdbase

        #pragma vertex vert
        #pragma fragment frag

        #include "Lighting.cginc"
        #include "AutoLight.cginc"

        fixed4 _Color;
        fixed4 _ReflectColor;
        fixed _ReflectAmount;
        samplerCUBE _Cubemap;

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

        struct v2f {
            float4 pos : SV_POSITION;
            float3 worldPos : TEXCOORD0;
            fixed3 worldNormal : TEXCOORD1;
            fixed3 worldViewDir : TEXCOORD2;
            fixed3 worldRefl : TEXCOORD3;
            SHADOW_COORDS(4)
        };

顶点着色器
选择在顶点着色器中计算反射方向
在片元着色器计算更细腻,但差别比较小,在顶点着色器计算性能消耗小。

v2f vert(a2v v) {
    v2f o;

    o.pos = UnityObjectToClipPos(v.vertex);

    o.worldNormal = UnityObjectToWorldNormal(v.normal);

    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

    o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);

    // 用CG内置的reflect函数计算反射方向
    o.worldRefl = reflect(-o.worldViewDir, o.worldNormal);

    TRANSFER_SHADOW(o);

    return o;
}

片元着色器

fixed4 frag(v2f i) : SV_Target {
    fixed3 worldNormal = normalize(i.worldNormal);
    fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));      
    fixed3 worldViewDir = normalize(i.worldViewDir);        

    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

    fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0, dot(worldNormal, worldLightDir));

    //立方体纹理采样
    fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb * _ReflectColor.rgb;

    UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

    fixed3 color = ambient + lerp(diffuse, reflection, _ReflectAmount) * atten;

    return fixed4(color, 1.0);
}

折射

接下来模拟折射

配置

Properties {
_Color ("Color Tint", Color) = (1, 1, 1, 1)
_RefractColor ("Refraction Color", Color) = (1, 1, 1, 1)
_RefractAmount ("Refraction Amount", Range(0, 1)) = 1

//折射率
_RefractRatio ("Refraction Ratio", Range(0.1, 1)) = 0.5
_Cubemap ("Refraction Cubemap", Cube) = "_Skybox" {}
}
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry"}

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

    CGPROGRAM

    #pragma multi_compile_fwdbase   

    #pragma vertex vert
    #pragma fragment frag

    #include "Lighting.cginc"
    #include "AutoLight.cginc"

    fixed4 _Color;
    fixed4 _RefractColor;
    float _RefractAmount;
    fixed _RefractRatio;
    samplerCUBE _Cubemap;

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

    struct v2f {
        float4 pos : SV_POSITION;
        float3 worldPos : TEXCOORD0;
        fixed3 worldNormal : TEXCOORD1;
        fixed3 worldViewDir : TEXCOORD2;
        fixed3 worldRefr : TEXCOORD3;
        SHADOW_COORDS(4)
    };

顶点着色器

v2f vert(a2v v) {
    v2f o;
    o.pos = UnityObjectToClipPos(v.vertex);

    o.worldNormal = UnityObjectToWorldNormal(v.normal);

    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

    o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);

    //计算折射方向
    o.worldRefr = refract(-normalize(o.worldViewDir), normalize(o.worldNormal), _RefractRatio);

    TRANSFER_SHADOW(o);

    return o;
    }

片元着色器

fixed4 frag(v2f i) : SV_Target {
    fixed3 worldNormal = normalize(i.worldNormal);
    fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
    fixed3 worldViewDir = normalize(i.worldViewDir);

    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

    fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0, dot(worldNormal, worldLightDir));

    fixed3 refraction = texCUBE(_Cubemap, i.worldRefr).rgb * _RefractColor.rgb;

    UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

    fixed3 color = ambient + lerp(diffuse, refraction, _RefractAmount) * atten;

    return fixed4(color, 1.0);
}

菲涅尔反射

光线照射到物体表面上,一部分被反射,一部分进入内部,反射折射或散射。
最直接的例子是你看水面,近处的能清楚水底的小鱼和石头,但远处的水面你几乎看不到水底的环境

实例

配置和顶点着色器

Properties {
_Color ("Color Tint", Color) = (1, 1, 1, 1)
_FresnelScale ("Fresnel Scale", Range(0, 1)) = 0.5
_Cubemap ("Reflection Cubemap", Cube) = "_Skybox" {}
}
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry"}

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

    CGPROGRAM

    #pragma multi_compile_fwdbase

    #pragma vertex vert
    #pragma fragment frag

    #include "Lighting.cginc"
    #include "AutoLight.cginc"

    fixed4 _Color;
    fixed _FresnelScale;
    samplerCUBE _Cubemap;

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

    struct v2f {
        float4 pos : SV_POSITION;
        float3 worldPos : TEXCOORD0;
        fixed3 worldNormal : TEXCOORD1;
        fixed3 worldViewDir : TEXCOORD2;
        fixed3 worldRefl : TEXCOORD3;
        SHADOW_COORDS(4)
    };

    v2f vert(a2v v) {
        v2f o;
        o.pos = UnityObjectToClipPos(v.vertex);

        o.worldNormal = UnityObjectToWorldNormal(v.normal);

        o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

        o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);

        o.worldRefl = reflect(-o.worldViewDir, o.worldNormal);

        TRANSFER_SHADOW(o);

        return o;
    }

片元着色器
Schlick菲涅尔近似等式

F(v,n)=F0+(1F0)(1vn)5

fixed4 frag(v2f i) : SV_Target {
    fixed3 worldNormal = normalize(i.worldNormal);
    fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
    fixed3 worldViewDir = normalize(i.worldViewDir);

    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

    UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

    fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb;

    fixed fresnel = _FresnelScale + (1 - _FresnelScale) * pow(1 - dot(worldViewDir, worldNormal), 5);

    fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0, dot(worldNormal, worldLightDir));

    fixed3 color = ambient + lerp(diffuse, reflection, saturate(fresnel)) * atten;

    return fixed4(color, 1.0);
}

_FrensenelScal 为1时完全反射CUbemap,为0则是个具有边缘光照效果的漫反射物体

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值