700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Unity shader Note :高级纹理(CubeMap反射折射菲涅尔 Rendermap镜子玻璃 程序纹理)

Unity shader Note :高级纹理(CubeMap反射折射菲涅尔 Rendermap镜子玻璃 程序纹理)

时间:2022-08-09 23:13:24

相关推荐

Unity shader Note :高级纹理(CubeMap反射折射菲涅尔 Rendermap镜子玻璃 程序纹理)

1.Cubemap–反射折射

使用脚本来创建Cubemap

①通过Camera.RenderToCubemap 把任意位置观察到的场景图制作成一张Cubemap之中

②脚本使用自定义编译窗体的命令 – ScriptableWizard

③于特定位置首先渲染好Cubemap

⑤lerp(a,b,w)函数, 根据w返回ab之间的插值,像是中混合

创建cubemap脚本

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 () {// create temporary camera for renderingGameObject go = new GameObject( "CubemapCamera");go.AddComponent<Camera>();// place it on the objectgo.transform.position = renderFromPosition.position;// render into cubemapgo.GetComponent<Camera>().RenderToCubemap(cubemap);// destroy temporary cameraDestroyImmediate( go );}[MenuItem("GameObject/Render into Cubemap")]static void RenderCubemap () {ScriptableWizard.DisplayWizard<RenderCubemapWizard>("Render cubemap", "Render!");}}

反射效果

完整代码

Shader "Unlit/Reflection"{Properties{_Color ("Color Tint",Color) =(1,1,1,1)_ReflectionColor ("Reflection Color",Color) =(1,1,1,1)_ReflectionAmount ("Reflection Amount", Range(0,1)) = 1 //反射强度初始为最大_Cubemap ("Reflection Cubemap",Cube) = "_Skybox"{}//不同于其他的纹理材质,这里的初始值是默认的天空盒子}SubShader{Tags {"RenderType"="Opaque" "Queue"="Geometry" }//后面的这个自己写的时候忘记加上了}Pass{Tags {"LigheMode"= "ForwardBase"}CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase//#include "UnityCG.cginc"#include "Lighting.cginc"#include "AutoLight.cginc"struct appdata{float4 vertex : POSITION;// float2 uv : TEXCOORD0;没有用这个float3 Normal :NORMAL;};struct v2f{float4 pos : SV_POSITION;float3 worldPos :TEXCOORD0;float3 worldNormal :TEXCOORD1 ;float3 worldRefl :TEXCOORD2 ;//忘记写视角方向float3 worldViewDir :TEXCOORD3 ;SHADOW_COORDS(4)};fixed4 _Color;fixed4 _ReflectionColor;fixed _ReflectionAmount;samplerCUBE _Cubemap; //用的是samplerCUBE,且没有偏移的那一堆v2f vert (appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);//在顶点着色器中计算o.worldPos =mul(unity_ObjectToWorld,v.vertex).xyz; //不需要w分量的数据?应该是这样o.worldNormal = UnityObjectToWorldNormal(v.Normal);o.worldViewDir =UnityWorldSpaceViewDir(o.worldPos);o.worldRefl =reflect(-o.worldViewDir, o.worldNormal); //使用reflec函数输入视角方向和法线方向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 * _ReflectionColor.rgb;fixed3 reflection = texCUBE(_Cubemap,i.worldRefl).rgb * _ReflectionColor.rgb;//通过反射方向对立方体进行采样UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);fixed3 color = ambient +lerp(diffuse,reflection,_ReflectionAmount) *atten;return fixed4(color,1.0);}ENDCG}}}

折射效果

o.worldRefr = refract(-normalize(o.worldViewDir) , normalize(o.worldNormal) , _RefractRatio);//折射函数,第一个参数是入射光线的方向,第二个是表面法线,第三个是空气和玻璃折射率的比值1/1.5//其中第一第二个参数都需要归一化

完整:

Shader "Unlit/Refraction"{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 //需要该属性来得到不同介质的透射比,初始化值是0.5,是空气和玻璃折射率的比值的近似值_Cubemap("Refraction Cubemap",Cube) = "_Skybox"{} //使用默认的天空盒子}SubShader{Tags {"RenderType"="Opaque" "Queue"="Geometry"}Pass{Tags {"LightMode"= "ForwardBase"}CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#include "Lighting.cginc"#include "AutoLight.cginc"struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0 ;float3 worldPos :TEXCOORD1 ;float3 worldViewDir :TEXCOORD2 ;float3 worldRefr : TEXCOORD3 ;SHADOW_COORDS(4) };fixed4 _Color;fixed4 _RefractColor;fixed _RefractAmount;fixed _RefractRatio;samplerCUBE _Cubemap;v2f vert (appdata 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);//折射函数,第一个参数是入射光线的方向,第二个是表面法线,第三个是空气和玻璃折射率的比值1/1.5//其中第一第二个参数都需要归一化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 * saturate(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); }ENDCG}}}

菲涅尔反射(Fresnel Reflection)
使用Schlick 菲涅尔近似式来模拟

完整代码

Shader "Unlit/Fresnel-Schlick"{Properties{_Color("Color Tinr",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{"LigheMode"="ForwardBase"}CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#include "Lighting.cginc"#include "AutoLight.cginc"struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal :TEXCOORD0 ;float3 worldPos :TEXCOORD1;float3 worldViewDir :TEXCOORD2 ;float3 worldRefl :TEXCOORD3 ;SHADOW_COORDS(4) };fixed4 _Color;fixed _FresnelScale;samplerCUBE _Cubemap;v2f vert (appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);//o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);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;}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 reflection =texCUBE(_Cubemap,i.worldRefl).rgb;fixed fresnel = _FresnelScale + (1- _FresnelScale)* pow(1-dot(worldViewDir,worldNormal),5);fixed3 diffuse = _LightColor0.rgb * _Color.rgb * saturate(dot(worldNormal,worldLightDir));UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);fixed3 color = ambient +lerp (diffuse,reflection,saturate(fresnel))* atten;return fixed4(color,1.0);}ENDCG}}}

2.渲染纹理

镜子效果

①用一个摄像机,将场景渲染到一张渲染纹理中

②创建一个渲染纹理(Render Texture)

③将创建的渲染纹理拖拽到摄像机的Target Texture 中

④使用渲染纹理作为输入属性,并在水平方向上翻转,直接显示到预先建立的Quad之上

完整代码

Shader "Unlit/Mirror_shader"{Properties{_MainTex ("Texture", 2D) = "white" {}//镜子实现通过 一个渲染纹理作为输入属性,并把该渲染纹理在水平方向上翻转后直接显示到物体上即可}SubShader{Tags {"RenderType"="Opaque" "Queue"="Geometry"}Pass{//Tags{"LightMode"="ForwardBase"}CGPROGRAM#pragma vertex vert#pragma fragment frag//#pragma multi_compile_fwdbase//#include "Lighting.cginc"sampler2D _MainTex;//不需要偏移struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 pos : SV_POSITION;};v2f vert (appdata v){v2f o;o.pos =UnityObjectToClipPos(v.vertex);o.uv = v.uv;//镜子效果需要翻转x轴o.uv.x = 1-o.uv.x;return o;}fixed4 frag (v2f i) : SV_Target{return tex2D(_MainTex,i.uv);//直接返回}ENDCG}}FallBack Off}

玻璃效果

①通过GrabPass获取屏幕图像

②注意渲染的顺序,在所有不透明物体之后渲染

③需要转换获取的屏幕坐标

完整代码

Shader "Unlit/Glass"{Properties{_MainTex ("Texture", 2D) = "white" {}_BumpMap ("Normal Map",2D) ="bump"{}_Cubemap ("Environment Cube",Cube) ="_Skybox"{} _Distortion ("Distortion",Range(0,100)) =10 //用于控制模拟折射时图像的扭曲程度_RefractionAmount("Refraction Amount",Range(0.0,1.0)) =1.0//用于控制折射程度,在制作折射的shader中也有用到//值为0时,该玻璃只包含反射效果,当为1时,只为折射效果}SubShader{Tags {"Queue"="Transparent" "RenderType"="Opaque" }//为保证不透明物体先于玻璃渲染,把渲染队列改成透明物体GrabPass{"_RefractionTex" }//通过GrabPass定义了一个抓取屏幕图像的pass,这个pass 定义了一个字符串//字符串内部的名称决定了抓取到的屏幕图像存储于哪个纹理之中-- _RefractionTex//实际上可以不声明字符串,声明可以获取更高的性能Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"sampler2D _MainTex;float4 _MainTex_ST;sampler2D _BumpMap;float4 _BumpMap_ST;samplerCUBE _Cubemap;float _Distortion;fixed _RefractionAmount;sampler2D _RefractionTex;float4 _RefractionTex_TexelSize;//TexelSize可以让我们得到该纹理的纹素大小//如它是256x512的,他的纹素大小为(1/256,1/512),需要偏移时使用该变量struct appdata{float4 vertex : POSITION;float2 texcoord : TEXCOORD0;float3 normal :NORMAL;float4 tangent :TANGENT;};struct v2f{float4 pos : SV_POSITION;float4 scrPos:TEXCOORD0 ; //float3 worldNormal :TEXCOORD1;//float3 worldTangent:TEXCOORD2 ;//float3 worldBinormal:TEXCOORD3 ;顶点着色器中使用这些来构建转换矩阵,后面无需float4 uv : TEXCOORD1 ;float4 TtoW0:TEXCOORD2 ;float4 TtoW1:TEXCOORD3 ;float4 TtoW2:TEXCOORD4 ; };v2f vert (appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.scrPos = ComputeGrabScreenPos(o.pos);//通过此函数来得到对应的被抓取的屏幕图像的坐标o.uv.xy =TRANSFORM_TEX(v.texcoord, _MainTex);o.uv.zw =TRANSFORM_TEX(v.texcoord, _BumpMap);float3 worldPos = mul (unity_ObjectToWorld,v.vertex).xyz;float3 worldNormal = UnityObjectToWorldNormal(v.normal);float3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);float3 worldBinormal = cross (worldNormal,worldTangent) * v.tangent.w; //由于使用到法线纹理,我们需要模型的法线信息//当我们通过Grabpass获取了屏幕图像之后//就使用切线空间下的法线对屏幕纹理坐标进行偏移o.TtoW0= float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);o.TtoW1= float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);o.TtoW2= float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);return o;}fixed4 frag (v2f i) : SV_Target{float3 worldPos =float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw)); //反映射法线纹理float2 offset = bump.xy * _Distortion * _RefractionTex_TexelSize.xy;//在切线空间中计算偏移量,第二个是扭曲程度,第三个是纹素大小//之所以在切线空间下计算偏移量,是因为该空间下的法线可以反映顶点局部空间下的法线方向i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy;//书上写的是 i.scrPos.xy = offset + i.scrPos.xy; ??fixed3 refrCol = tex2D( _RefractionTex , i.scrPos.xy / i.scrPos.w ).rgb;//简言之ComputeGrabScreenPos得到的屏幕空间坐标并不是真正的空间坐标//它是包含了插值之后的结果,必须除以w分量,还原出真正的视口坐标//原理是通过透视除法,得出真正的屏幕坐标//通过这样来得到反射的颜色也就是空间中所有已经渲染的不透明物体,都已经在一张贴图中bump = normalize (half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz,bump), dot(i.TtoW2.xyz, bump)));//把法线转换到世界空间fixed3 reflDir = reflect(-worldViewDir, bump);//反射方向通过 光源方向,和法线方向 计算fixed4 texColor = tex2D(_MainTex, i.uv.xy);//主纹理颜色fixed3 reflCol = texCUBE(_Cubemap,reflDir).rgb * texColor.rgb ;fixed3 finalCol = reflCol * (1 - _RefractionAmount) + refrCol * _RefractionAmount;return fixed4(finalCol,1);}ENDCG}}FallBack "Diffuse"}

结论是:GrabPass的实现比渲染纹理简单,但从效率上说渲染纹理更好于GrabPass ,GrabPass可能会对性能产生影响

3.程序纹理

①使用脚本创建材质和纹理

②可以在Inspector面板更改参数,并实时调整贴图

③使用SetProperty插件实现↑

关于如何使用SetProperty插件

Setproperty

c#代码

using System.Collections;using System.Collections.Generic;using UnityEngine;[ExecuteInEditMode]public class procedural_tex : MonoBehaviour {public Material material = null ; //一个材质private Texture2D m_generatedTexture =null; //一个纹理#region Material properties[SerializeField, SetProperty("textureWidth")]private int m_textureWidth=512;public int textureWidth{get{return m_textureWidth;}set{m_textureWidth = value;_UpdateMaterial();}}[SerializeField, SetProperty("BackgroundColor")]private Color m_backgroundColor = Color.white;public Color backgroundColor{get{return m_backgroundColor;}set{m_backgroundColor =value;_UpdateMaterial();}}[SerializeField, SetProperty("circleColor")]private Color m_circleColor = Color.yellow;public Color circleColor{get{return m_circleColor;}set{m_circleColor =value;_UpdateMaterial();}}[SerializeField, SetProperty("blurFactor")]private float m_blurFactor =2.0f;public float blurFactor {get{return m_blurFactor;}set{m_blurFactor =value;_UpdateMaterial();}}#endregion// Use this for initializationvoid Start () {if(material == null){Renderer renderer = gameObject.GetComponent<Renderer>();if (renderer == null){Debug.LogWarning("Can not find a renderer.");return;}material = renderer.sharedMaterial;}_UpdateMaterial();}// Update is called once per frameprivate void _UpdateMaterial () {if(material != null){m_generatedTexture = _GenerateProceduralTexture();material.SetTexture("_MainTex", m_generatedTexture);}//确保material 不为空,然后调用_GenerateProceduralTexture函数 生成一张程序纹理,并赋予给 m_generatedTexture 变量//之后material.SetTexture函数把纹理赋予给材质 ,材质material中需要一个名为_MainTex的纹理属性}//混合颜色的函数private Color _MixColor(Color color0, Color color1, float mixFactor){Color mixColor = Color.white;mixColor.r = Mathf.Lerp(color0.r, color1.r, mixFactor);mixColor.g = Mathf.Lerp(color0.g, color1.g, mixFactor);mixColor.b = Mathf.Lerp(color0.b, color1.b, mixFactor);mixColor.a = Mathf.Lerp(color0.a, color1.a, mixFactor);return mixColor;}private Texture2D _GenerateProceduralTexture() //产生贴图{Texture2D proceduralTexture = new Texture2D(textureWidth, textureWidth); //初始化了一张二维的纹理//在材质属性中定义了贴图的大小float circleInterval = textureWidth / 4.0f; //圆与圆之间的距离float radius = textureWidth / 10.0f; //半径 float edgeBlur = 1.0f / blurFactor; //定义模糊系数for(int w =0; w < textureWidth; w++) {for(int h= 0; h < textureWidth; h++){Color pixel = backgroundColor; //初始化背景颜色为白色for (int i = 0; i<3; i++){for(int j = 0; j<3; j++){Vector2 circleCenter = new Vector2(circleInterval * (i + 1), circleInterval * (j + 1)); //圆心位置Vector2(x,y)float dist = Vector2.Distance(new Vector2(w, h), circleCenter) - radius;//计算当前像素与圆心的距离//static function Distance (a : Vector2, b : Vector2) : float //返回a和b 之间的距离Color color = _MixColor(circleColor, new Color(pixel.r, pixel.g, pixel.b, 0.0f), Mathf.SmoothStep(0f, 1.0f, dist * edgeBlur));//模糊圆的边界pixel = _MixColor(pixel, color, color.a);}}proceduralTexture.SetPixel(w, h, pixel);}}proceduralTexture.Apply();return proceduralTexture;}}

以上啾咪

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。