shader入门16 立方体纹理

介绍

1.什么是立方体纹理?
简单的说就是6张纹理组成的一个方块形状的纹理.像骰子一样,有六个面.
在这里插入图片描述
2.立方体纹理有什么用?
立方体纹理通常用于作为反射源,以及环境反射来实现玻璃,金属的效果
3.为什么立方体纹理要做成这个形状?
以立方体的中心为原点,向任意方向投射射线,可以与立方体6个面相交,得到不同的采样值.
可以根据方向对纹理进行采样,这就是立方体纹理的意义.

天空盒

天空盒是模拟游戏背景的一种常用方法,它所使用的原理就是立方体纹理.
利用立方体纹理不同方向的纹理采样值,来达到3D背景的效果.

如何使用天空盒

新建一个材质,选择天空盒的shader
在这里插入图片描述
为6个纹理面赋值,纹理的wrap mode设置为clamp防止衔接处不匹配
在这里插入图片描述
打开光照菜单,设置天空盒材质,Skybox Material,把我们刚刚创建的材质拖给它就可以.此时设置的是全局相机的天空盒
在这里插入图片描述
另外,相机要设置天空盒模式才可以看到效果.如果多个相机使用不同天空盒的话,要添加skybox组件进行覆盖.

如何获取立方体纹理

1.向美工要立方体纹理
2.在project里右键create,legacy,cubemap.创建一个立方体纹理,然后找6张纹理拖上去.
3.实时渲染.
实时渲染以场景中任意一个物体的为相机,分别拍摄6个方向组成一个立方体纹理.
代码如下
1.注意这个类要放在Editor目录下,否则unity不把它当做编辑器处理
2.渲染出的cubemap是根据场景烘焙成的,无法拷贝到其他项目中,也无法修改.

using UnityEditor;
using UnityEngine;

public class CubemapGenerator : 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>();//添加相机组件
        go.transform.position = renderFromPosition.position;//设置渲染位置
        go.transform.rotation = Quaternion.identity;//设置旋转
        go.GetComponent<Camera>().RenderToCubemap(cubemap);//烘焙到cubemap
        DestroyImmediate(go);//销毁相机
    }
    [MenuItem("GameObject/Render into Cubemap")]
    static void RenderCubemap()
    {
        ScriptableWizard.DisplayWizard<CubemapGenerator>(
            "Render cubemap", "Render!");
    }
}

立方体纹理的采样

代码
Shader "Unlit/NewUnlitShader"
{
	Properties
	{
		_CubeMap("CubeMap", CUBE) = ""{}//立方体纹理
	}
	SubShader
	{
		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			samplerCUBE _CubeMap;
			struct a2v
			{
				float4 vertex : POSITION;//模型空间位置
			};
			struct v2f
			{
				float4 pos : SV_POSITION;//剪裁空间位置
				float3 modelDir : TEXCOORD1;//模型空间方向
			};
			v2f vert(a2v v)
			{
				v2f f;
				f.pos = UnityObjectToClipPos(v.vertex);
				f.modelDir = normalize(v.vertex.xyz);
				return f;
			}
			fixed4 frag(v2f f) : SV_Target
			{
				return texCUBE(_CubeMap, f.modelDir);//立方体纹理采样
			}
			ENDCG
		}
	}
}

效果

场景有点暗,效果不是很好,可以看到场景被渲染到这个cube上了
在这里插入图片描述

反射

加入反射的立方体纹理看起来更像是金属的质感

代码
Shader "Unlit/NewUnlitShader"
{
	Properties
	{
		_DiffuseColor("DiffuseColor",Color) = (1,1,1,1)//漫反射颜色
		_ReflectColor("ReflectColor",Color)=(1,1,1,1)//环境反射
		_ReflectValue("ReflectValue",Range(0,1))=1//环境反射系数
		_CubeMap("CubeMap", CUBE) = ""{}//立方体纹理
	}
	SubShader
	{
		Pass
		{
			Tags{ "LightMode" = "ForwardBase" }
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			samplerCUBE _CubeMap;
			fixed4 _DiffuseColor;
			fixed4 _ReflectColor;
			fixed _ReflectValue;
			struct a2v
			{
				float4 vertex : POSITION;//模型空间位置
				float3 normal : NORMAL;//模型空间法线
			};
			struct v2f
			{
				float4 pos : SV_POSITION;//剪裁空间位置
				float3 worldNormal: TEXCOORD0;
				float3 worldPos : TEXCOORD1;
				float3 worldViewDir : TEXCOORD2;
				float3 worldReflectDir : TEXCOORD3;//世界坐标系 环境反射方向
				SHADOW_COORDS(4)
			};
			v2f vert(a2v v)
			{
				v2f f;
				f.pos = UnityObjectToClipPos(v.vertex);
				f.worldNormal = UnityObjectToWorldNormal(v.normal);
				f.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;//模型空间到世界坐标系位置
				f.worldViewDir = UnityWorldSpaceViewDir(f.worldPos);
				f.worldReflectDir = reflect(-f.worldViewDir, f.worldNormal);
				TRANSFER_SHADOW(f);//计算阴影纹理坐标
				return f;
			}
			fixed4 frag(v2f f) : SV_Target
			{
				fixed3 worldNormal = normalize(f.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(f.worldPos));
				fixed3 worldViewDir = normalize(f.worldViewDir);
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				fixed3 diffuse = _LightColor0.rgb * _DiffuseColor.rgb *max(0,dot(worldNormal,worldLightDir));
				fixed3 reflection = texCUBE(_CubeMap, f.worldReflectDir).rgb * _ReflectColor.rgb;//立方体纹理采样
				UNITY_LIGHT_ATTENUATION(atten, f, f.worldPos);//计算阴影和光照衰减
				fixed3 color = ambient + lerp(diffuse, reflection, _ReflectValue)*atten;
				return fixed4(color,1);//立方体纹理采样
			}
			ENDCG
		}
	}
	FallBack "Diffuse"
}

效果

在这里插入图片描述

折射

简单的修改一下上面的代码,可以编写一个模拟水面折射的效果

代码
Shader "Unlit/NewUnlitShader"
{
	Properties
	{
		_DiffuseColor("DiffuseColor",Color) = (1,1,1,1)//漫反射颜色
		_RefractColor("RefractColor",Color)=(1,1,1,1)//环境折射
		_RefractValue("RefractValue",Range(0,1))=1//环境折射系数
		_RefractRatio("RefractRatio",Range(0.1,1))=0.5//透射比
		_CubeMap("CubeMap", CUBE) = ""{}//立方体纹理
	}
	SubShader
	{
		Pass
		{
			Tags{ "LightMode" = "ForwardBase" }
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			samplerCUBE _CubeMap;
			fixed4 _DiffuseColor;
			fixed4 _RefractColor;
			fixed _RefractValue;
			fixed _RefractRatio;
			struct a2v
			{
				float4 vertex : POSITION;//模型空间位置
				float3 normal : NORMAL;//模型空间法线
			};
			struct v2f
			{
				float4 pos : SV_POSITION;//剪裁空间位置
				float3 worldNormal: TEXCOORD0;
				float3 worldPos : TEXCOORD1;
				float3 worldViewDir : TEXCOORD2;
				float3 worldRefractDir : TEXCOORD3;//世界坐标系 环境折射方向
				SHADOW_COORDS(4)
			};
			v2f vert(a2v v)
			{
				v2f f;
				f.pos = UnityObjectToClipPos(v.vertex);
				f.worldNormal = UnityObjectToWorldNormal(v.normal);
				f.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;//模型空间到世界坐标系位置
				f.worldViewDir = UnityWorldSpaceViewDir(f.worldPos);
				f.worldRefractDir = refract(-f.worldViewDir, f.worldNormal,_RefractRatio);//计算折射方向
				TRANSFER_SHADOW(f);//计算阴影纹理坐标
				return f;
			}
			fixed4 frag(v2f f) : SV_Target
			{
				fixed3 worldNormal = normalize(f.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(f.worldPos));
				fixed3 worldViewDir = normalize(f.worldViewDir);
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				fixed3 diffuse = _LightColor0.rgb * _DiffuseColor.rgb *max(0,dot(worldNormal,worldLightDir));
				fixed3 refraction = texCUBE(_CubeMap, f.worldRefractDir).rgb * _RefractColor.rgb;//立方体纹理采样
				UNITY_LIGHT_ATTENUATION(atten, f, f.worldPos);//计算阴影和光照衰减
				fixed3 color = ambient + lerp(diffuse, refraction, _RefractValue)*atten;
				return fixed4(color,1);//立方体纹理采样
			}
			ENDCG
		}
	}
	FallBack "Diffuse"
}

效果

在这里插入图片描述

菲涅尔反射

菲涅尔反射效果可以描述更接近现实的效果,即一部分发生反射,一部分发生折射.
近处的水面几乎看不到反射,只有折射效果;而远处的水面则只有反射效果,看不到折射效果
现实中的菲涅尔反射公式非常复杂,我们在代码中使用的是菲涅尔近似等式.

代码
Shader "Unlit/NewUnlitShader"
{
	Properties
	{
		_DiffuseColor("DiffuseColor",Color) = (1,1,1,1)//漫反射颜色
		_FresnelScale("FresnelScale",Range(0,1))=0.5//菲涅尔系数
		_CubeMap("CubeMap", CUBE) = ""{}//立方体纹理
	}
	SubShader
	{
		Pass
		{
			Tags{ "LightMode" = "ForwardBase" }
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			samplerCUBE _CubeMap;
			fixed4 _DiffuseColor;
			fixed _FresnelScale;
			struct a2v
			{
				float4 vertex : POSITION;//模型空间位置
				float3 normal : NORMAL;//模型空间法线
			};
			struct v2f
			{
				float4 pos : SV_POSITION;//剪裁空间位置
				float3 worldNormal: TEXCOORD0;
				float3 worldPos : TEXCOORD1;
				float3 worldViewDir : TEXCOORD2;
				float3 worldReflectDir : TEXCOORD3;//世界坐标系 环境反射方向
				SHADOW_COORDS(4)
			};
			v2f vert(a2v v)
			{
				v2f f;
				f.pos = UnityObjectToClipPos(v.vertex);
				f.worldNormal = UnityObjectToWorldNormal(v.normal);
				f.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;//模型空间到世界坐标系位置
				f.worldViewDir = UnityWorldSpaceViewDir(f.worldPos);
				f.worldReflectDir = reflect(-f.worldViewDir, f.worldNormal);//计算反射方向
				TRANSFER_SHADOW(f);//计算阴影纹理坐标
				return f;
			}
			fixed4 frag(v2f f) : SV_Target
			{
				fixed3 worldNormal = normalize(f.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(f.worldPos));
				fixed3 worldViewDir = normalize(f.worldViewDir);
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				fixed3 diffuse = _LightColor0.rgb * _DiffuseColor.rgb *max(0,dot(worldNormal,worldLightDir));
				fixed3 reflection = texCUBE(_CubeMap, f.worldReflectDir).rgb;//立方体纹理采样
				fixed3 fresnel = _FresnelScale + (1 - _FresnelScale)*pow(1 - dot(worldViewDir, worldNormal), 5);//菲涅尔近似等式
				UNITY_LIGHT_ATTENUATION(atten, f, f.worldPos);//计算阴影和光照衰减
				fixed3 color = ambient + lerp(diffuse, reflection, saturate(fresnel))*atten;
				return fixed4(color,1);//立方体纹理采样
			}
			ENDCG
		}
	}
	FallBack "Diffuse"
}

效果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值