草庐IT

Blinn-Phong光照模型详解

dx1313113 2024-01-17 原文

        Blinn-Phong光照模型,又称为Blinn-phong反射模型(Blinn–Phong reflection model)或者 phong 修正模型(modified Phong reflection model),是由 Jim Blinn于 1977 年在文章中对传统 phong 光照模型基础上进行修改提出的。它是一个经验模型,并不完全符合真实世界中的光照现象,但由于实现起来简单方便,并且计算速度和得到的效果都还不错,因此在早期被广泛的使用。

 

它将进入摄像机的光线分为三个部分,每个部分使用一种方法来计算它的贡献度,这三个部分分别是环境光(Ambient)漫反射(Diffuse)高光反射(Specular)

 

在计算之前,我们先定义一些基本的向量,因为只表示方向,默认它们都为单位向量。

  • Viewer direction,观察方向,使用v表示
  • Surface normal,法线方向,使用n表示
  • Light direction,光线方向,使用l(小写的L)表示
  • Surface parameters ,一些其他参数


 下面首先先介绍一下环境光、漫反射和高光反射的定义

  • 环境光

        环境光也称间接光,为了防止画面在没有光照条件下为一片漆黑的状态而引入的一种定义,可以当做物体自发光。是一个常量。

  • 漫反射

        当光线照射到一个点时,该光线会被均匀的反射到各个方向,这种反射称为漫反射。也就是说,在漫反射中,视角的位置是不重要的,因为反射是完全随机的,因此可以认为漫反射光在任何反射方向上的分布都是一样的,如下图所示

那影响漫反射光照强度的因素有哪些呢?

  • 入射光线与法线的夹角(入射光线角度)
  • 入射光线自身的强度

入射光线与法线的夹角

假设有一块很小的区域dA。当法线向量n与光照向量L平行时,区域dA受到的光线照射最多。随着n和L之间的夹角θ逐渐增大,区域dA*受到的光线照射量会越来越少 (因为很多光线都无法照射到dA表面上了)。冬天的时候我们觉得很冷,夏天又非常热,主要也是太阳光线与地面形成的夹角变化造成的。

兰伯特余弦定律(Lambert Consine Law)中指出,漫反射的大小取决于表面法线和光线的夹角,当夹角越大时,漫反射分量越小,当夹角接近90度时,我们认为漫反射几乎为零。

也就是说,反射光线的强度与表面法线和光源方向之间夹角的余弦值成正比。当表面法线与光线的夹角大于90度,它们的余弦值小于0,这没有实际意义,因此将其置为0,可以用下面的公式表示

f(θ)=max(0,cosθ)=max(0,L•n)

L•n就是求Ln上的投影,下面是该函数的图像表示

入射光线强度

灯光的强度会随着距离的增加而衰减,这是显而易见的。假设我们有一个光源,在距离它单位1的圆上(图中最内圈)每一个点接收到光的强度是I。那么根据能量守恒定律,且不考虑衰减,在距离光源r位置的圆上每个点接收到光的强度就是I/r2

现在我们可以得出漫反射的公式:

其中Ld为漫反射光照,kd为物体表面的反射系数(reflection coefficient),I/r2是当前点接受的光照强度,max(0,L•n)是当前点接受到的能量。

什么是反射系数?
反射系数指光(入射光)投向物体时,其表面反射光的强度与入射光的强度之比值(有多少入射光能够被反射出去,其值介于0~1之间),受入射光的投射角度、强度、波长、物体表面材料的性质以及反射光的测量角度等因素影响。一般来讲,在颜色系列中,黑色的反射系数较小,为0.03,白色的反射系数较大,为0.8。(百度百科)

 随着漫反射系数的增大,图像的变化如下图所示:

  •  高光反射(Specular)

        高光反射也称为镜面反射,若物体表面很光滑,当平行入射的光线射到这个物体表面时,仍会平行地向一个方向反射出来。

        下图中一根入射光线l,照射在光滑的平面上,会沿着R方向反射,由于平面并非完全光滑,所以反射光的方向并非只有R一个点,而是R周边的一小块区域,只要眼睛(摄像机)在R附近都可以看得到,越靠近R反射光照强度越大。我们可以得出一条结论:高光反射和观察角度有关。

 phong模型中认为,高光反射的强度与反射光线R和观察角度v之间夹角的余弦值成正比。计算它的强度,相当于是求向量vR上的投影。怎么求R呢?

使用半程向量(Bisector)

计算反射光线R虽然不是很难,但还是有点繁琐,有没有其他方法计算呢?Blinn提出了一个简单的修改方法来得到类似的效果,通过对向量l和向量v取平均然后归一化得到一个新的向量h,其中h被称为半程向量(bisector),使用h与法线n点乘来计算高光,这样就可以避免计算R

 h为半程向量

 使用半程向量计算的公式和之前类似,不过计算的时候简单了一些,具体公式如下:

 参考文章

 参考视频

有关Blinn-Phong光照模型详解的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  5. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  6. ruby-on-rails - 如何将验证与模型分开 - 2

    我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:

  7. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  8. ruby-on-rails - Rails - 从另一个模型中创建一个模型的实例 - 2

    我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案

  9. ruby-on-rails - Ruby 中的内存模型 - 2

    ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序

  10. ruby-on-rails - Rails 3.1 中具有相同形式的多个模型? - 2

    我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#

随机推荐