局部光照模型

提要

常见的光照模型一般包括四个部分ambient, diffuse, specular, 和emitted light. 即:

vertex color = ambient + diffuse + specular + emitted light

当有多个光源的时候,最后的颜色就是多个结果的叠加。

Ambient light:环境光,通常定义在光源的中,注意每个光源的衰减量。

Diffuse:漫反射部分,光照找到物体的表面,由于物体的表面凹凸不平而反射到各个方向的光。

Specular :相比于漫反射,一道入射光通过镜面反射只产生一个方向的Specular,遵循反射法则,即入射角和出射角相同。Diffuse和Specular的区别可以参考下面的图。

Emittion:物体的自发光。

Lambert光照模型

Lambert光照模型用于纯粹的漫反射表面的物体,比如磨砂的玻璃表面,观察者的所看到的反射光和观察的角度无关,这样的表面称为Lambertian。高端一点的说法就是他表面的亮度是各向同性的,亮度的计算遵循 Lambert‘s cosine 法则,何为 Lambert‘s cosine 法则, 看下图:

具体描述如下:一束光照在理想漫反射的物体表面,光照强度的变化由入射光线和物体表面法线的夹角决定。

在具体计算的时候,用到的公式是

Kd表示物体表面漫反射属性,Id表时入射光强。N表示入射点单位法向量,L表示从入射点指向光源的单位向量(注意是入射点指向光源,表示了入射光的方向),单位化之后相乘就得到了夹角的余弦值。在Unity中用Shader实现一下。

Shader "Custom/Lambert" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200

		CGPROGRAM
		#pragma surface surf Lamb

		sampler2D _MainTex;

		inline fixed4 LightingLamb (SurfaceOutput s, fixed3 lightDir,  fixed atten)
		{
			float diff = dot(s.Normal, lightDir);
			fixed4 c;
			c.rgb = (s.Albedo * _LightColor0.rgb * diff) ;
			c.a = 1.0;
			return c;
		}

		struct Input {
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o) {
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			o.Albedo = c.rgb;
			o.Alpha = c.a;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

Phong光照模型

对于漫反射的物体表面,使用Lambert就足够,但是实际生活中并不存在这种理想的漫反射材质,所有Bui Tuong Phong这个家伙就提出了Phong模型。如下图

最终的光照结果由Ambient环境光,Diffuse漫反射,Specular高光组成,下面来看下详细的计算过程,首先定义下面几个变量。

is表示光源的高光强度,id表示光源的漫反射强度。

Ks 材质的高光反射系数,Kd 材质的漫反射系数,Ka 环境光反射系数,α 材质反射常数,表示物体表面镜面的程度。

光照的场景如下图

对于一个灯光m

Lm 表示从表面射向光源的向量;

N 表示表面的法线方向;

Rm 表示光线的按照反射定律得出的出射光线;

V 表示从表面射向人眼的向量。

有了这些量,就可以对光照进行求解了,

其中反射光线的方向需要进行求解

还是用shader实现一遍

Shader "Custom/Phong" {
	Properties {
		_MainTint ("Diffuse Tint", Color) = (1,1,1,1)
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_SpecularColor ("Specular Color", Color) = (1,1,1,1)
		_SpecularPower ("Specular Power", Range(0, 30)) = 1
	}

	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200

		CGPROGRAM
		#pragma surface surf Phong

		float4 _MainTint;
		sampler2D _MainTex;
		float4 _SpecularColor;
		float _SpecularPower;

		inline fixed4 LightingPhong (SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
		{
			float diff = dot(s.Normal, lightDir);
			float3 reflectionVector = normalize(2.0 * s.Normal * diff - lightDir);
			float spec = pow(max(0, dot(reflectionVector, viewDir)), _SpecularPower);
			float3 finalSpec = _SpecularColor * spec;

			fixed4 c;
			c.rgb = (s.Albedo * _LightColor0.rgb * diff) + (_LightColor0.rgb * finalSpec);
			c.a = 1.0;
			return c;
		}

		 struct Input {
            float2 uv_MainTex;
        }; 

		void surf (Input IN, inout SurfaceOutput o) {
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			o.Albedo = c.rgb;
			o.Alpha = c.a;
		}

		ENDCG
	}
	FallBack "Diffuse"
}

基本上不算太复杂(只有diffuse 和 specular ,ambient是常数,先忽略)的光照模型的Render Equation(单个点光源)都可以写为

其中 Rs 称为Specular term,不同的光照模型对应于不同的Rs.

Blin-Phong光照模型

这个模型就座位Phong光照模型的改进,在表现上基本与Phong模型一致,但是性能上却优化了很多。主要是在计算specular分项的时候将 Rm?V 换成了 N?H 。H也需要计算,但简单了非常多。

则光照的计算公式就变成了

在shader中只要在上面的基础上稍微修改一下就可以了

inline fixed4 LightingPhong (SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
{
	float diff = dot(s.Normal, lightDir);
	float3 halfVector = normalize(lightDir + viewDir);
	float spec = pow(max(0, dot(halfVector, s.Normal)), _SpecularPower);
	float3 finalSpec = _SpecularColor * spec;

	fixed4 c;
	c.rgb = (s.Albedo * _LightColor0.rgb * diff) + (_LightColor0.rgb * finalSpec);
	c.a = 1.0;
	return c;
}

结果对比

Wiki上的对比结果

(所谓Higher exponent是将材质的反光系数乘以了4倍,这样看起来更加接近原始的phong计算出来的结果)

Unity中的对比结果

Cook Torrance

上面说说的三种模型都只能运用在理想的材质下,要么理想漫反射,要么理想镜面反射,这样渲染出来的物体就很假,真实的情况是漫反射和镜面反射都需要依据材质特征和物体表面微平面特征。 下图 是实际漫反射、镜面反射与理想漫反射、镜面反射的示意图。

Cook-Torrance 光照模型将物体粗糙表面( rough surface )看作由很多微小平面(微平面)组成,每一个微平面都被看作一个理想的镜面反射体,物体表面的粗糙度由微平面斜率的变化来衡量。一个粗糙表面由一系列斜率变化很大的微平面组成,而在相对平滑的表面上微平面斜率变化较小。

对于Cook-Torrance 光照模型,其Rs的计算公式为

V,H,L和上面介绍的一致,这里主要说一下DFG

- microfacet distribution ,微平面分布系数,计算公式如下

F - fresnel factor,菲涅尔系数,主要用于定义菲涅尔反射,计算公式如下

G - Geometrical attenuation ,几何衰减系数,衡量微平面自身遮蔽光强的影响,介于0到1之间。

光射到物体微表面上,会出现三种情况,

a.光被完全反射

G=1

b.一些光在反射后被阻挡

c.一些光在到达其它微面前被阻挡

则最终G的取值为

在Unity里实践一下,

Shader "CookbookShaders/Chapter03/MetallicSoft"
{
	Properties
	{
		_MainTint ("Diffuse Tint", Color) = (1,1,1,1)
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_RoughnessTex ("Roughness texture", 2D) = "" {}
		_Roughness ("Roughness", Range(0,1)) = 0.5
		_SpecularColor ("Specular Color", Color) = (1,1,1,1)
		_SpecPower ("Specular Power", Range(0,30)) = 2
		_Fresnel ("Fresnel Value", Range(0,1.0)) = 0.05
	}

	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 200

		CGPROGRAM
		#pragma surface surf MetallicSoft
		#pragma target 3.0

		sampler2D _MainTex;
		sampler2D _RoughnessTex;
		float _Roughness;
		float _Fresnel;
		float _SpecPower;
		float4 _MainTint;
		float4 _SpecularColor;

		inline fixed4 LightingMetallicSoft (SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
		{
			//Compute simple diffuse and view direction values
			float3 halfVector = normalize(lightDir + viewDir);
			float NdotL = saturate(dot(s.Normal, normalize(lightDir)));
			float NdotH_raw = dot(s.Normal, halfVector);
			float NdotH = saturate(dot(s.Normal, halfVector));
			float NdotV = saturate(dot(s.Normal, normalize(viewDir)));
			float VdotH = saturate(dot(halfVector, normalize(viewDir)));

			//Micro facets distribution
			float geoEnum = 2.0*NdotH;
			float3 G1 = (geoEnum * NdotV)/NdotH;
			float3 G2 = (geoEnum * NdotL)/NdotH;
			float3 G =  min(1.0f, min(G1, G2));

			//Sample our Spceular look up BRDF
			float roughness = tex2D(_RoughnessTex, float2(NdotH_raw * 0.5 + 0.5, _Roughness)).r;

			//Create our custom fresnel value
			float fresnel = pow(1.0-VdotH, 5.0);
			fresnel *= (1.0 - _Fresnel);
			fresnel += _Fresnel;

			//Create the final spec
			float3 spec = float3(fresnel * G * roughness * roughness) * _SpecPower;

			float4 c;
			c.rgb = (s.Albedo * _LightColor0.rgb * NdotL)+  (spec * _SpecularColor.rgb) * (atten * 2.0f);
			c.a = s.Alpha;
			return c;
		}

		struct Input
		{
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o)
		{
			half4 c = tex2D (_MainTex, IN.uv_MainTex) * _MainTint;
			o.Albedo = c.rgb;
			o.Alpha = c.a;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

代码里面用纹理来代替D的计算,结果如下

参考

Lambertian reflectance wiki - http://en.wikipedia.org/wiki/Lambertian_reflectance

Lambert‘s cosine law wiki - http://en.wikipedia.org/wiki/Lambert%27s_cosine_law

Phong reflection model wiki - http://en.wikipedia.org/wiki/Phong_reflection_model

Blinn–Phong shading model wiki  - http://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model

基于CPU实现的Cook-Torrance光照模型(Cg语言实现)- http://blog.csdn.net/liu_lin_xm/article/details/4845977

时间: 2024-10-12 20:54:06

局部光照模型的相关文章

浙江大学软件学院三维动画与交互技术考试概念整理

第一讲 1.    增强现实技术AR: --融合了三维动画.立体视觉和图像处理: --建模.渲染.位置标定.图像融合: 2.    OpenGL是一种用于创建实时3D图像的编程接口. 3.    三维这个术语表示一个正在描述或显示的物体具有三维维度:宽度.高度.深度: --计算机3D图形实质上也是平面的: --在计算机屏幕上显示的二维图像,提供深度(或第三维)的错觉: 2D+透视 = 3D 透视使人产生深度的错觉. 4.    真正的3D是通过人的两只眼睛观察同一个物体,在视网膜上生成具有视差的

Shading中的插值技术

提要 在Per Vertex shader中处理着色计算的情况计算出的是每个顶点上shading的结果,通常模型都是由三角面来构成,面上的颜色如何处理,就是今天要探讨的.常用的三种方法是Flat Shading, Gouraud Shading, Phong Shading,对于渲染一个小球,结果对比如下,从左到右依次是Flat Shading, Gouraud Shading, Phong Shading. Flat Shading 这个最简单,整个面片的颜色都是一致的,没有平滑,只有很硬的边

一步一步实现基于GPU的pathtracer(一):基础

出于3D计算机图形学和图形渲染方面的个人兴趣,脑子里便萌生出了自己实现一个渲染器的想法,主要是借助pathtracing这种简单的算法,外加GPU加速来实现,同时也希望感兴趣的朋友们能够喜欢,也欢迎提出一些更好的看法~~. (本人水平有限,若有错误也请指正~) 首先列个提纲......: 1)局部光照与全局光照简介 2)GPU并行运算在图形渲染的应用 ————————————————————————————————————————————————— 1)pathtracing算法简介: 在利用计

清华大学计算机研究生课程表

清华大学计算机研究生课程表 计算机系研究生课程介绍 组合数学课程名称:组合数学 课程编号:60240013 课内学时: 48 开课学期: 秋 任课教师:黄连生 [主要内容] 主要介绍组合数学的基本内容,包括基本记数方法.母函数与递推关系.容斥 原理与鸽巢原理.Burnside引理与Polya定理.区组设计与编码的初步概念.线性规划问题的单纯形算法. 数据结构课程名称:数据结构 课程编号:60240023 课内学时: 48 开课学期: 春秋 任课教师:严蔚敏 [主要内容] 线性表.树.图等各种基本

物理渲染-基于物理的光照模型

文章所用图片来自相关领域文献,如有侵权请联系撤除, 转载本文请注明出处 1.关于光照模型 对于图形学领域和图形学开发来说,实时渲染的光照模型是一个最最基础的问题,简单的来讲,光照模型就是用来描述在真实环境下,物体表面一点在在光照下的反射颜色值.有许许多多的光照模型试图用数学的公式来模拟这个问题,当然这即是一个物理问题,也是一个数学问题.大学时最初接触计算机图形学时,对书本上关于光照模型的推到过程就极为不解,最近为了研究基于物理的光照模型看到一篇10年siggrgrah的course,(<Phys

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

Lambert光照模型,根据光照向量与顶点发现的夹角来确定光照强度: Shader "James/VP Shader/LightModel-Lambert" { Properties { _MainTex ("MainTex", 2D) = "white" {} } SubShader { Pass { Tags { "LightMode"="ForwardBase" } CGPROGRAM #pragma

UNITY 复制对象后局部坐标和世界坐标的变化问题

void Start () { var pgo = transform.Find ("Button").gameObject; obtn = Instantiate (pgo); //obtn = Instantiate (pgo, pgo.transform.Parent);         var pos = obtn.transform.position; //obtn.transform.localPosition = Vector3.zero; Debug.LogFormat

(单链表)单链表的整体逆序和局部逆序

题目一:将单链表翻转. 思路:有三种方式. 一:用数组存储单链表的值,然后重新逆序赋值,效率较低. 二:利用三个指针,在原来的基础上进行逆序.这种方法比较实用,效率也高. 三:从第2个节点到第N个节点,依次逐节点插入到第1个节点(head节点)之后,最后将第一个节点挪到新表的表尾.需要新建一个链表,这种方法和第二种差不多. 这里我就写出第二种方法,比较实用. 代码(方法二): struct ListNode { int val; ListNode *next; ListNode(int x) :

图像算法之十二:非局部均值滤波及其Matlab实现

保边去噪算法之二: 首先谈一下什么是非局部均值滤波.在此之前,我们先来看一下均值滤波的原理. 均值滤波 均值滤波的计算非常简单,将图像像素点灰度记录在数组中,然后设置方框半径的值,然后将方框中的所有点的像素求和取平均,得到的结果就是均值滤波后对应像素点的灰度值. 优点: 计算很快而且简单 从算法可以看出,只是求了平均,并没有很复杂的计算 缺点: 得到的图像很模糊 当方框的半径越大,得到的图像中那些变化较大的地方(边缘)计算后变化就越小,即边缘不明显,即模糊 非局部均值滤波 非局部均值滤波的基本原