学习笔记——基本光照模型简单实现

Lambert光照模型,根据光照向量与顶点发现的夹角来确定光照强度:

Shader "James/VP Shader/LightModel-Lambert"
{
    Properties
    {
        _MainTex ("MainTex", 2D) = "white" {}
    }
    SubShader
    {
        Pass
        {
            Tags { "LightMode"="ForwardBase" }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            float _LightColor0;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 lightDir : TEXCOORD1;
                float3 normal : TEXCOORD2;
            };

            v2f vert(appdata_full v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                // 从顶点位置到Light的局部向量
                o.lightDir = ObjSpaceLightDir(v.vertex);
                o.normal = v.normal;
                return o;
            }

            float4 frag(v2f i) : COLOR
            {
                i.lightDir = normalize(i.lightDir);
                i.normal = normalize(i.normal);
                // 纹理采样
                float4 c = tex2D(_MainTex, i.uv);
                // 光强度,法向和光照方向的cos值
                float diffuse = max(0, dot(i.normal, i.lightDir));
                // 纹理色 * 光源色 * 强度参数
                c = c * _LightColor0 * diffuse;
                return c * 2;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

Phong光照模型,根据光照向量的反射向量与视线的夹角来计算镜面高光的强度,另外再加上漫射光的成分:

Shader "James/VP Shader/LightModel-Phong"
{
    Properties
    {
        _MainTex ("MainTex", 2D) = "white" {}
        _gloss ("Gloss", Float) = 1
    }
    SubShader
    {
        Pass
        {
            Tags { "LightMode"="ForwardBase" }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            float _LightColor0;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _gloss;

            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : TEXCOORD1;
                float3 lightDir : TEXCOORD2;            // 光照方向
                float3 reflectLightDir : TEXCOORD3;        // 光照反射方向
                float3 viewDir : TEXCOORD4;                // 视线方向
            };

            v2f vert(appdata_full v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.normal = v.normal;
                // 从顶点位置到light的局部向量
                o.lightDir = ObjSpaceLightDir(v.vertex);
                // 反射向量,注意需要使用-o.lightDir
                o.reflectLightDir = reflect(-o.lightDir, v.normal);
                // 视线,顶点到camera的局部变量
                o.viewDir = ObjSpaceViewDir(v.vertex);
                return o;
            }

            float4 frag(v2f i) : COLOR
            {
                i.normal = normalize(i.normal);
                i.reflectLightDir = normalize(i.reflectLightDir);
                i.viewDir = normalize(i.viewDir);
                // 纹理采样
                float4 c = tex2D(_MainTex, i.uv);
                // 漫射光强度
                float diffuse = max(0, dot(i.normal, i.lightDir));
                // 镜面光强度
                float specular = max(0, dot(i.reflectLightDir, i.viewDir));
                specular = pow(specular, 32) * _gloss;
                // 纹理色 * 光源色 * 强度参数
                c = c * _LightColor0 * (diffuse + specular);
                return c * 2;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

BinnPhong光照模型,根据光照向量和视线的半角向量,与顶点法线的夹角来计算镜面高光的强度,另外再加上漫射光的成分:

Shader "James/VP Shader/LightModel-BinnPhong"
{
    Properties
    {
        _MainTex ("MainTex", 2D) = "white" {}
        _gloss ("Gloss", Float) = 5
    }
    SubShader
    {
        Pass
        {
            Tags { "LightMode"="ForwardBase" }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            float _LightColor0;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _gloss;
            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : TEXCOORD1;
                float3 lightDir : TEXCOORD2;        // 光照方向
            };

            v2f vert(appdata_full v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.normal = v.normal;
                // 顶点->light的局部向量
                o.lightDir = ObjSpaceLightDir(v.vertex);
                // 顶点->camera的局部向量
                float3 viewDir = ObjSpaceViewDir(v.vertex);
                return o;
            }

            float4 frag(v2f i) : COLOR
            {
                i.lightDir = normalize(i.lightDir);
                i.normal = normalize(i.normal);
                // 半角向量,光照方向和视线的中间值
                float3 halfDir = (i.lightDir + i.normal) * 0.5;
                // 纹理采样
                float4 c = tex2D(_MainTex, i.uv);
                // 漫射光强度
                float diffuse = max(0, dot(i.normal, i.lightDir));
                // 镜面光强度
                float specular = max(0, dot(i.normal, halfDir));
                specular = pow(specular, 32) * _gloss;
                // 纹理色 * 光源色 * 强度参数
                c = c * _LightColor0 * (diffuse + specular);
                return c * 2;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

BinnPhong比Phong少计算一次反射向量,会更简洁和高效。

时间: 2024-07-30 03:12:08

学习笔记——基本光照模型简单实现的相关文章

[简明python教程]学习笔记之编写简单备份脚本

[[email protected] 0503]# cat backup_ver3.py #!/usr/bin/python #filename:backup_ver3.py import os import time #source source=['/root/a.sh','/root/b.sh','/root/c.sh'] #source='/root/c.sh' #backup dir target_dir='/tmp/' today=target_dir+time.strftime('

《大话设计模式》学习笔记系列--1. 简单工厂模式

简单工厂模式实现了一种"工厂"概念的面向对象设计模式,它可以在不指定对象具体类型的情况下创建对象.其实质是定义一个创建对象的接口,但让实现这个接口的类来决定实例化具体类.工厂方法让类的实例化推迟到子类中进行. 以书本上的计算器程序为例,其UML描述如下: 图中,AddOperator, SubtactOpertor继承算式基类Operator,而CreateOperator则是负责创建一个操作类,而不指明具体的子类类型. 下面,我们来看代码: 首先操作积累: /// <summa

【转】jmeter学习笔记——一种简单的数据库性能测试方法

前提条件:一个数据库:test   数据库下面有一张表:user   表中有两个字段:username.passworld . 要求:往数据库内大批量插入数据,1000/s 其实和之前的方法一样,为了简单,我还是把截图贴出来吧. 1.创建一个测试计划,将我们所使用的数据库驱动包导入. 2.添加一个线程组,并设置我们的虚拟用户数.启动时间.和循环次数 3.创建一个线程,并在线程下面,创建一个JDBC Connection Configuration ,设置相关信息. 4.创建一个JDBC Requ

[原创]java WEB学习笔记41:简单标签之带属性的自定义标签

本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 ---------------------------------

[原创]java WEB学习笔记40:简单标签概述(背景,使用一个标签,标签库的API,SimpleTag接口,创建一个自定义的标签的步骤 和简单实践)

本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 ---------------------------------

android菜鸟学习笔记27----Fragment的简单使用

1.Fragment的生命周期: 简单在新建一个MyFragment继承自Fragment,重写各个生命周期回调方法,各个方法中直接输出标识相关函数被调用的信息. 重写MainActivity的各个生命周期回调方法,同样输出标识信息. MyFragment.java: 1 public class MyFragment extends Fragment { 2 3 @Override 4 5 public void onActivityCreated(Bundle savedInstanceSt

hbase学习笔记1——脚本简单总结

最近学习了hbase的相关知识,也看了一下hbase的bin/目录下的脚本,很多脚本细节并不理解,大致的轮廓有个了解,做一下学习总结: ."$bin"/hbase-config.sh 调用脚本hbase-config.sh 装载相关环境变量,hbase-config.sh脚本同时调用了conf/hbase-env.sh脚本. 接下来脚本通过判断是否为分布式模式来启动不同的服务(同时调用了脚本hbase) distMode=`$bin/hbase--config "$HBASE

学习笔记CB012: LSTM 简单实现、完整实现、torch、小说训练word2vec lstm机器人

真正掌握一种算法,最实际的方法,完全手写出来. LSTM(Long Short Tem Memory)特殊递归神经网络,神经元保存历史记忆,解决自然语言处理统计方法只能考虑最近n个词语而忽略更久前词语的问题.用途:word representation(embedding)(词语向量).sequence to sequence learning(输入句子预测句子).机器翻译.语音识别等. 100多行原始python代码实现基于LSTM二进制加法器.https://iamtrask.github.

Xmemcached学习笔记二(简单使用)

首先说一下XMemcached我们简单使用时主要是做了什么事情: 当我们使用XMemcached的时候主要是用了XMemcachedClient的对象来进行插入,查找和删除缓存数据. 但是我们不采用XMemcachedClient memcachedclient=new XMemcachedClient():的方式来获取XMemcachedClient对象. 为什么呢,因为XMemcachedClient这个类里面并没有任何的参数设置,如设置分布策略,服务地址等,都没有,没有这些我们最起码的插入