当前位置: 首页 > article >正文

Unity学习之Shader总结(一)

一、Lesson1

1、渲染流水线

(1)应用阶段

模型->模型处理(应用阶段)–>输入结构
应用阶段主要操作:粗粒度剔除、进行渲染设置、准备基本数据、输出到几何阶段

(2)几何阶段

输入结构->顶点shader(几何阶段)->输出结构
几何阶段主要操作:顶点着色器->裁剪->屏幕映射
在这里插入图片描述

(3)光栅化阶段、逐片元阶段

输出结构->像素shader(光栅化阶段、逐片元阶段)->渲染结果
在这里插入图片描述
i、光栅化阶段主要操作:三角形设置(知道三角形三条边)、三角形遍历(检查片元是否被三角形覆盖,考虑对片元的保存和去除)、抗锯齿处理
ii、逐片元阶段主要操作:片元着色、透明度测试、深度测试、模板测试、混合
在这里插入图片描述

(5)后处理

2、Lambert模型与半Lambert

(1)Lambert

(i)效果展示

在这里插入图片描述

(ii)计算公式

Lambert=max(0,dot(光照方向反方向,法线))

(iii)实现代码
//Lambert逐顶点光照
Shader "MyCustom/Diffuse_Lambert_Vertex"
{
    Properties
    {
        //材质的漫反射颜色
        _Color("Base Color", color) = (1.0, 1.0, 1.0, 1.0)
        //漫反射系数
        _kD("kD", Range(0, 1)) = 1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog
            //引入Unity内置的一些变量
            #include "UnityCG.cginc"

            //UnityCG.cginc中定义了结构体appdata_base,appdata_tan,appdata_full用于顶点着色器输入
            //这里自定义appdata类型,只包含需要的数据
            struct appdata
            {
                float4 vertex : POSITION; //顶点位置
                float3 normal : NORMAL;   //法线
            };

            //顶点着色器输出
            struct v2f
            {
                //SV_POSITION是裁剪空间中的顶点坐标,它是DirectX 10中引入的系统数值语义,在大多数平台上,它和POSITION语义是等价的,
                //但在某些平台(例如PS4)上必须使用SV_POSITION来修饰顶点着色器的输出,否则无法让Shader正常工作
                //SV_POSITION一旦被作为顶点着色器的输出语义,那么顶点位置就被固定了,后续不能再被改变它的空间位置
                float4 vertex : SV_POSITION;
                float4 col : COLOR;
            };

            //为了使用Properties语义块中声明的属性,需要定义一个和该属性类型相匹配的变量
            //由于颜色属性的范围在0到1之间,因此我们可以使用fixed精度的变量来存储它
            float4 _Color;
            float _kD;
            //表示这个变量的初始值来自于外部的其他环境
            uniform float4 _LightColor0;

            v2f vert (appdata v)
            {
                v2f o;

                //Unity内置 模型 * 世界 * 投影矩阵 UNITY_MATRIX_MVP,把顶点位置从模型空间转换到裁剪空间中
                o.vertex = UnityObjectToClipPos(v.vertex);

                //在计算法线和光线之间的点积时,只有两者处于同一坐标系下,它们的点积才有意义,
                //所以需要把顶点的法线从模型空间转到世界空间,unity_WorldToObject是4*4
                float3 worldNormal = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz);
                //也可以这么写
                // float3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));

                //获取光源方向(们假设场景中只有一个光源且该光源的类型是平行光)
                float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

                //当法线和光线之间夹角大于90时,光线是在照射物体的背面,此时光照强度为0
                float lambert = max(dot(worldNormal, worldLight), 0.0);
                //也可以使用saturate函数把参数截取到[0, 1]的范围内,防止负值
                // float lambert = saturate(dot(worldNormal, worldLight));
                
                float3 diffuse = _kD * lambert * _Color.rgb * _LightColor0.rgb;

                //环境光
                float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                float3 finalColor = diffuse + ambient;
                o.col = float4(finalColor, 1.0);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return i.col;
            }
            ENDCG
        }
    }
}
//Lambert逐像素光照
Shader "MyCustom/Diffuse_Lambert_Pixel"
{
    Properties
    {
        _Color("Base Color", color) = (1.0, 1.0, 1.0, 1.0)
        _kD("kD", Range(0, 1)) = 1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                //顶点着色器中计算世界空间下法线,传递给片元着色器
                float3 worldNormal : TEXCOORD0;
            };

            float4 _Color;
            float _kD;
            uniform float4 _LightColor0;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
                return o;
            }

            //将光照的计算转移到片元着色器中
            fixed4 frag (v2f i) : SV_Target
            {
                float3 worldNormal = i.worldNormal;
                float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

                float lambert = max(dot(worldNormal, worldLight), 0.0);
                float3 diffuse = _kD * lambert * _Color.rgb * _LightColor0.rgb;
                float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                float3 finalColor = diffuse + ambient;

                return float4(finalColor, 1.0);
            }
            ENDCG
        }
    }
}

(2)半Lambert

(i)效果展示

在这里插入图片描述

(ii)计算公式

半Lambert=dot(光照方向反方向,法线)*0.5+0.5

(iii)实现代码
//半Lambert逐像素光照
Shader "MyCustom/HalfLambert"
{
    Properties
    {
        _Color ("Base Color", color) = (1.0, 1.0, 1.0, 1.0)
        _kD ("kD", Range(0, 1)) = 1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
            };

            float4 _Color;
            float _kD;
            uniform float4 _LightColor0;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 worldNormal = i.worldNormal;
                float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                
                // 广义上的半兰伯特 half lambert = light * diffuse * (α* (n * l) + β)
                // half lambert = light * diffuse * (0.5 * (n * l) + 0.5)
                float halfLambert = 0.5 * dot(worldNormal, worldLight) + 0.5;
                
                float3 diffuse = _kD * halfLambert * _Color.rgb * _LightColor0.rgb;
                float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                float3 finalColor = diffuse + ambient;

                return float4(finalColor, 1.0);
            }
            ENDCG
        }
    }
}

(3)实践

半兰伯特+映射贴图+描边,实现简单的卡渲效果
在这里插入图片描述

二、Lesson2

1、Shader代码简易模板

// Shader created with Shader Forge v1.40 
// Shader Forge (c) Freya Holmer - http://www.acegikmo.com/shaderforge/
// Note: Manually altering this data may prevent you from opening it in Shader Forge
/*SF_DATA;ver:1.40;sub:START;pass:START;ps:flbk:,iptp:0,cusa:False,bamd:0,cgin:,cpap:True,lico:0,lgpr:1,limd:0,spmd:1,trmd:0,grmd:0,uamb:True,mssp:True,bkdf:False,hqlp:False,rprd:False,enco:False,rmgx:True,imps:True,rpth:0,vtps:0,hqsc:True,nrmq:0,nrsp:0,vomd:0,spxs:False,tesm:0,olmd:1,culm:0,bsrc:0,bdst:1,dpts:2,wrdp:True,dith:0,atcv:False,rfrpo:True,rfrpn:Refraction,coma:15,ufog:False,aust:True,igpj:False,qofs:0,qpre:1,rntp:1,fgom:False,fgoc:False,fgod:False,fgor:False,fgmd:0,fgcr:0.5,fgcg:0.5,fgcb:0.5,fgca:1,fgde:0.01,fgrn:0,fgrf:300,stcl:False,atwp:False,stva:128,stmr:255,stmw:255,stcp:6,stps:0,stfa:0,stfz:0,ofsf:0,ofsu:0,f2p0:False,fnsp:False,fnfb:False,fsmp:False;n:type:ShaderForge.SFN_Final,id:3138,x:32719,y:32712,varname:node_3138,prsc:2|emission-5693-OUT;n:type:ShaderForge.SFN_Vector3,id:5693,x:32526,y:32812,varname:node_5693,prsc:2,v1:1,v2:0.4605795,v3:0;pass:END;sub:END;*/

Shader "AP01/L03/FlatCol_SF" {
    Properties {
    }
    SubShader {
        Tags {
            "RenderType"="Opaque"
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
            
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0
            struct VertexInput {
                float4 vertex : POSITION;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.pos = UnityObjectToClipPos( v.vertex );
                return o;
            }
            float4 frag(VertexOutput i) : COLOR {
// Lighting:
// Emissive:
                float3 emissive = float3(1,0.4605795,0);
                float3 finalColor = emissive;
                return fixed4(finalColor,1);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
    CustomEditor "ShaderForgeMaterialInspector"
}

2、实践

实现可以平滑调整模型明暗调子的效果
在这里插入图片描述


http://www.kler.cn/a/590494.html

相关文章:

  • Docker入门篇2:查看容器、运行容器、启动和停止容器、删除容器
  • Android PC 要来了?Android 16 Beta3 出现 Enable desktop experience features 选项
  • 【STM32】NVIC(嵌套向量中断控制器)
  • Android之RecyclerView列表拖动排序
  • Vue3项目白屏问题深度解析:从AI辅助诊断到性能优化实战
  • 《灵珠觉醒:从零到算法金仙的C++修炼》卷三·天劫试炼(49)万鸦壶焚网络 - 网络延迟时间(Bellman-Ford)
  • Spring boot+mybatis的批量删除
  • 【AI】深度学习与人工智能应用案例详解
  • LIMS系统在纸制品制造的应用 内检实验室LIMS系统提升纸制品质控
  • Postman发送GET请求示例及注意事项
  • Vue.js 事件处理与修饰符详解
  • 2. qt写带有槽的登录界面(c++)
  • 玩转python:通俗易懂掌握高级数据结构-collections模块之UserDict
  • 人工智能之数学基础:从线性变换理解矩阵范数和矩阵行列式
  • 第一中标人!晶科能源入围大唐集团19.5GW光伏组件集采
  • 遥感新态势:Sentinel - 2多光谱指数与AI深度融合
  • 卡内基梅隆大学研究人员推出 PAPRIKA:一种微调方法,使语言模型能够发展出不局限于特定环境的通用决策能力
  • 基于javaweb的SpringBoot博客商城管理系统设计与实现(源码+文档+部署讲解)
  • 通过 Python 爬虫提高股票选股胜率
  • Linux快速安装mysql