目录
官方说明
Shader Level of Detail(简称Lod)
中文版说明
着色器细节级别
一、实战
编辑器功能,快速创建CubeMap
Shader Level of Detail (LOD) works by only using shaders or subshaders that have their LOD value less than a given number.
By default, allowed LOD level is infinite, that is, all shaders that are supported by the user’s hardware can be used. However, in some cases you might want to drop shader details, even if the hardware can support them. For example, some cheap graphics cards might support all the features, but are too slow to use them. So you may want to not use parallax normal mapping on them.
Shader LOD can be either set per individual shader (using Shader.maximumLOD), or globally for all shaders (using Shader.globalMaximumLOD).
In your custom shaders, use LOD command to set up LOD value for any subshader.
Built-in shaders in Unity have their LODs set up this way:
着色器细节级别(LOD)仅通过使用其LOD值小于给定数字的着色器或子着色器来工作。
默认情况下,允许的LOD级别是无限的,也就是说,可以使用用户硬件支持的所有着色器。但是,在某些情况下,即使硬件可以支持着色器详细信息,也可能要删除它们。例如,某些便宜的图形卡可能支持所有功能,但使用它们的速度太慢。因此,您可能不希望对它们使用视差法线贴图。
可以为每个着色器设置Shader LOD(使用Shader.maximumLOD),也可以为所有着色器全局设置(使用Shader.globalMaximumLOD)。
在您的自定义着色器中,使用LOD命令为任何子着色器设置LOD值。
Unity中的内置着色器通过以下方式设置其LOD:
看完后,感觉还是很懵逼,实测一下吧
漫反射 (LOD为100)、半兰伯特漫反射(LOD为200)、环境反射(LOD为300)
效果图:
Shader "Unlit/LoadTest"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_Color("Color", Color) = (1,1,1,1)
_CubeMap("CubeMap", Cube) = "_Skybox"{}
[Space(5)]
_FValue("FValue", Range(0,1)) = 0.5
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 300 //默认为100
//实现一个环境反射+漫反射+菲涅尔系数
Pass
{
Tags
{
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
fixed3 normal : NORMAL;
float4 pos : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
samplerCUBE _CubeMap;
fixed _FValue;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.normal = UnityObjectToWorldNormal(v.normal);
o.pos = mul(unity_ObjectToWorld, v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(i.pos));
fixed3 normal = normalize(i.normal);
fixed d = max(0, dot(lightDir, normal) * 0.5 + 0.5);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.pos));
fixed3 reflectDir = reflect(normal, viewDir);
fixed4 reflectCol = texCUBE(_CubeMap, reflectDir);
col.rgb = col.rgb * d * _LightColor0.rgb;
half feinier = _FValue + pow(dot(normal, viewDir), 5); //菲尼尔系数
return col * reflectCol * feinier;
}
ENDCG
}
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 200 //默认为100
//实现一个半兰伯特漫反射
Pass
{
Tags{
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
fixed3 normal : NORMAL;
float4 pos : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.normal = UnityObjectToWorldNormal(v.normal);
o.pos = mul(unity_ObjectToWorld, v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(i.pos));
fixed3 normal = normalize(i.normal);
fixed d = max(0, dot(lightDir, normal) * 0.5 + 0.5);
col.rgb = col.rgb * d * _LightColor0.rgb;
return col * _Color;
}
ENDCG
}
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 100 //默认为100
//实现一个兰伯特漫反射
Pass
{
Tags{
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
fixed3 normal : NORMAL;
float4 pos : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.normal = UnityObjectToWorldNormal(v.normal);
o.pos = mul(unity_ObjectToWorld, v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(i.pos));
fixed3 normal = normalize(i.normal);
fixed d = max(0, dot(lightDir, normal));
col.rgb = col.rgb * d * _LightColor0.rgb;
return col * _Color;
}
ENDCG
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LodTest : MonoBehaviour {
public int lod;
Shader shader;
void Start () {
//Shader.globalMaximumLOD = 500; //设置全局Lod, 比它小的Shader能够渲染
shader = gameObject.GetComponent().material.shader;
}
void Update () {
shader.maximumLOD = lod;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class AutoCreateCubeMap : EditorWindow
{
static EditorWindow window;
[MenuItem("Milk/AutoCreateCubemap")]
public static void Create()
{
window = EditorWindow.GetWindowWithRect(typeof(AutoCreateCubeMap), new Rect(200, 200, 300, 400));
window.Show();
}
private GameObject obj;
private Cubemap cubemap;
private void OnGUI()
{
GUILayout.BeginVertical();
EditorGUI.indentLevel++;
GUILayout.BeginHorizontal();
EditorGUI.indentLevel++;
obj = (GameObject)EditorGUILayout.ObjectField("Render From Position", obj, typeof(GameObject), true);
EditorGUI.indentLevel--;
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
EditorGUI.indentLevel++;
cubemap = (Cubemap)EditorGUILayout.ObjectField("Cubemap", cubemap, typeof(Cubemap), true);
EditorGUI.indentLevel--;
GUILayout.EndHorizontal();
EditorGUI.indentLevel--;
if (GUILayout.Button("Create"))
{
GameObject go = new GameObject("CameraObject");
Camera camera = go.AddComponent();
go.transform.position = obj.transform.position;
camera.RenderToCubemap(cubemap);
DestroyImmediate(go);
}
GUILayout.EndVertical();
}
}