directx11第七篇光照模型——环境光

m雪夜m m雪夜m     2022-12-05     264

关键词:

      本系列文章主要翻译和参考自《Real-Time 3D Rendering with DirectX and HLSL》一书(感谢原书作者),同时会加上一点个人理解和拓展,文章中如有错误,欢迎指正。
      这里是书中的代码和资源。

      本文所有的环境和工具使用都基于之前的文章,如有不明白的地方请先参考本系列之前的几篇文章。

本文索引:



关于灯光

      在现实世界中,没有光我们将看不见任何东西,你所看见的物体或者是反射了光源的光或者是本身就能自发光。在计算机渲染的过程中,你将模拟灯光与物体的交互,并以此增加3D物体表面的细节。但是灯光的相互影响是一个非常复杂的过程,在目前的技术中并不能达到在一个可交互的帧率范围内进行这样大量的重复计算。因此,一般会采用一种近似算法,用一种描述灯光与3D模型如何交互的灯光模型来为你的感官增加更多可感受的细节。这篇文章中将介绍最基础的光照模型——环境光的计算模型。


Ambient Lighting: 环境光

      环境光是看起来在明亮环境中无所不在的光。比如说,看下你的桌底,尽管没有光源直接照射,你似乎还是可以看到桌下的深远地方并且描绘出其外形。这种光是通过物体表面与光线的不断交互产生的(比如不断反射、折射叠加产生的)。当光线到达物体表面时,他们会被部分或完全的反射、吸收掉,这个过程会持续无数次。所以还是会有光线可以到底你的桌底,即使只是很小的一部分。
      你可以通过设置一个数值来调整每个像素的颜色,以此来模拟一个最简单的环境光。你可以将这个数值看成是明亮度或光线强度过滤,这个数值通常在[0, 1]范围内并通过与每个像素的颜色值相乘达到效果(相当于color中的alpha通道)。如果环境光强度接近0,物体看起来就会更黑。另外,你还可以增加颜色到环境光模型中,来模拟一个不是纯白的光源。这就需要对像素中的每个通道进行调整。下面的代码段是环境光效果的代码实现。

代码段Listing 6.1 AmbientLighting.fx

#define FLIP_TEXTURE_Y 1

cbuffer CBufferPerFrame

    float4 AmbientColor : AMBIENT<
        string UIName = "Ambient Light";
        string UIWidget = "Color";
    > = 1.0f, 1.0f, 1.0f, 1.0f;


cbuffer CBufferPerObject

    float4x4 WorldViewProjection : WORLDVIEWPROJECTION<
        string UIWidget="None";
    >;  


Texture2D ColorTexture<
    string ResourceName = "default_color.dds";
    string UIName = "Color Texture";
    string ResourceType = "2D";
>;

SamplerState ColorSampler

    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
;

RasterizerState DisableCulling

    CullMode = NONE;    
;

/********************* struct *********************/
struct VS_INPUT

    float4 ObjectPosition : POSITION;
    float2 TextureCoordinate : TEXCOORD;
;

struct VS_OUTPUT

    float4 Position : SV_Position;
    float2 TextureCoordinate : TEXCOORD;
;

/********************* Utility function *********************/
float2 get_corrected_texture_coordinate(float2 textureCoordinate)

    #if FLIP_TEXTURE_Y
        return float2(textureCoordinate.x, 1.0 - textureCoordinate.y);
    #else
        return textureCoordinate;
    #endif


/********************* Vertex Shader *********************/
VS_OUTPUT vertex_shader(VS_INPUT IN)

    VS_OUTPUT OUT = (VS_OUTPUT)0;

    OUT.Position = mul(IN.ObjectPosition, WorldViewProjection);
    OUT.TextureCoordinate = get_corrected_texture_coordinate(IN.TextureCoordinate);

    return OUT;


/********************* Pixel Shader *********************/
float4 pixel_shader(VS_OUTPUT IN) : SV_Target

    float4 OUT = (float4)0;

    OUT = ColorTexture.Sample(ColorSampler, IN.TextureCoordinate);
    OUT.rgb *= AmbientColor.rgb * AmbientColor.a;//Color(.rgb) * intensity(.a)

    return OUT;


/********************* Techniques *********************/
technique10 main10

    pass p0
    
        SetVertexShader(CompileShader(vs_4_0, vertex_shader()));
        SetGeometryShader(NULL);
        SetPixelShader(CompileShader(ps_4_0, pixel_shader()));

        SetRasterizerState(DisableCulling);
       

(1) AmbientColor Shader Constant : 着色器中的AmbientColor常量

      上面的这段代码和上一篇文章中的代码非常类似,但加入了一些基础环境光的内容。
      首先,我们在这段代码中加入了AmbientColor这个着色器常量,这是一个float4类型的常量,代表了环境光的颜色和强度。光源的颜色保存在该常量的RGB通道中,强度保存在常量的Alpha通道中。注意,这个量被包含在了一个新的名为CBufferPerFrame的cbuffer声明中。在本系列的第五篇文章 Hello,Shaders!中提到过,cbuffer是用来根据所包含数据的更新频率组织数据常量的。在这个例子中AmbientColor的数值会被多个物体共享,并且需要在每一帧更新数据。这不同于包含在CBufferPerObject中的WorldViewProjection对象,每个使用AmbientLighting效果的对象这个值都不同。
      其次,注意关联到AmbientColor常量的AMBIENT注解字符串。和其他所有的shader常量一样,这个注解字符串是可选的,但把这个注解字符串加入并不是什么坏事,用注解将常量联系起来后CPU可以通过语义获得常量值而不需要通过一个硬编码的常量名。
      最后,AmbientColor常量在声明时已经对其赋予的初始化值1.0f, 1.0f, 1.0f, 1.0f。这会产生一个纯白色,并且带有全光照强度的环境光,这样的设置并不会改变你场景中物体的输出颜色。代码其余部分都和上一篇文章中的相同,除了像素着色器外。

(2) Ambient Lighting Pixel Shader : 像素着色器中的环境光

      像素着色器中对纹理进行颜色采样然后调整其输出。准确的来说像素着色器中通过采样器获得像素的颜色值后和AmbientColor.rgb * AmbientColor.a相乘。AmbientColor中的rgb将分别和a相乘最后得到一个三维向量值。所以环境光首先和光强度相乘得到一个调整的带有光强度和颜色和结果,这个结果在和从采样器中取得的像素颜色值相乘。

(3) Ambient Lighting Output : 环境光输出效果

      下图展示了一个带有环境光影响的shader的渲染效果。左图是一个纯白色颜色值为(1, 1, 1)带有0.5光强度的球体,右图是一个纯红色颜色值为(1, 0, 0)带有全光强度的球体。

      你可以在FX Composer中改变环境光的颜色来查看不同效果,如下图所示:

      注意,你可以调节环境光的颜色是因为之前在shader代码中关联了UIName和UIWidget注解,这是FX Composer提供的功能,如果你不在这个软件中的话这些注解可能是没用的,需要你自己去实现对应功能。


注意
      一般来说,不要将从常量缓冲区中获得的数据再在shader中进行数学运算,而应该在CPU端做好这种运算再传输过来。例如,这段代码中ambientColor*ambient这个运算应该在CPU端就已经做好。在这里是由于FX Compose这个软件只提供了这样的接口来提供常量传输,如果是自己写的接口,例如用DirectX API就不需要这样。


总结

      这篇文章中讲解了最基础的环境光模型,他的计算方式很简单,但这个模型是所有光照模型的基础,不管后面介绍多少种光照模型,很多都需要和环境光模型相结合。

directx11第九篇光照模型——高光

...    本系列文章主要翻译和参考自《Real-Time3DRenderingwithDirectXandHLSL》一书(感谢原书作者),同时会加上一点个人理解和拓展,文章中如有错误,欢迎指正。      这里是书中的代码和资源。      本文... 查看详情

directx11第八篇光照模型——漫反射

...    本系列文章主要翻译和参考自《Real-Time3DRenderingwithDirectXandHLSL》一书(感谢原书作者),同时会加上一点个人理解和拓展,文章中如有错误,欢迎指正。      这里是书中的代码和资源。      本文... 查看详情

directx11第九篇光照模型——高光

...    本系列文章主要翻译和参考自《Real-Time3DRenderingwithDirectXandHLSL》一书(感谢原书作者),同时会加上一点个人理解和拓展,文章中如有错误,欢迎指正。      这里是书中的代码和资源。      本文... 查看详情

directx11第八篇光照模型——漫反射

...    本系列文章主要翻译和参考自《Real-Time3DRenderingwithDirectXandHLSL》一书(感谢原书作者),同时会加上一点个人理解和拓展,文章中如有错误,欢迎指正。      这里是书中的代码和资源。      本文... 查看详情

4种基本光照模型

1.Lambert模型(漫反射)环境光:Iambdiff=Kd*Ia其中Ia表示环境光强度,Kd(0<K<1)为材质对环境光的反射系数,Iambdiff是漫反射体与环境光交互反射的光强。方向光:Ildiff=Kd*Il*Cos(θ)其中Il是点光源强度,θ是入射光方向与顶点法线的夹... 查看详情

directx11第十篇其他灯光类型——点光源

...    本系列文章主要翻译和参考自《Real-Time3DRenderingwithDirectXandHLSL》一书(感谢原书作者),同时会加上一点个人理解和拓展,文章中如有错误,欢迎指正。      这里是书中的代码和资源。      本文... 查看详情

opengles之基础光照模型的实现(代码片段)

一、OpenGLES基础光照模型OpenGLES目前还无法模拟现实世界的复杂光照效果,为了在效果要求和实现难度之间做一个平衡,往往采用一些简化的模型来模拟光照效果。冯氏光照模型(PhongLightingModel)便是其中常用的一个光照模型,... 查看详情

第五章unity中的基础光照(代码片段)

目录1.Unity中的环境光和自发光2.在UnityShader中实现漫反射光照模型2.1实践:逐顶点光照2.2实践:逐像素光照2.3半兰伯特模型1.Unity中的环境光和自发光在标准光照模型中,环境光和自发光的计算是最简单的。在Unity中,场景中的环... 查看详情

rendermonkey练习第二天opengl光照模型

光照模型3D渲染中,物体表面的光照计算公式为:I=环境光(Iambient)+漫反射光(Idiffuse)+镜面高光(Ispecular); 其中,环境光(ambient)计算公式为:Iambient=Aintensity*Acolor;            (Ain 查看详情

phong和blinn-phong光照模型

参考技术A光照=环境光+漫反射+高光环境光=环境光颜色乘以环境光强度float3ambient=_LightColor0*_AmbientStrength;漫反射=光线入射方向点乘法线方向,再乘以漫反射光颜色乘以漫反射光强度float3diff=dot(i.normal,_WorldSpaceLightPos0)*_LightColor0*_Diff... 查看详情

opengl4种光照模型

...有:Ildiff=Kd*Il*dot(N,L)最后综合环境光和方向光源,Lambert光照模型可以写成:Idiff=Iambdiff+Ildiff=Kd*Ia+Kd*Il*dot(N,L)  2.Phong模型(镜面反射)Phong模型认为镜面反射的光强与反射光线和视线的夹角相关:Ispec=Ks*Il*(dot(V,R))^Ns其中Ks为镜... 查看详情

光照计算

1.Lambert模型(漫反射)环境光:Iambdiff=Kd*Ia其中Ia表示环境光强度,Kd(0<K<1)为材质对环境光的反射系数,Iambdiff是漫反射体与环境光交互反射的光强。方向光:Ildiff=Kd*Il*Cos(θ)其中Il是点光源强度,θ是入射光方向与顶点法线的夹... 查看详情

unity_urp_renderingdebugger调试入门之解构环境光反射光等lit光照模型的代码逻辑(代码片段)

目录光照模型代码代码还是从Panel代码入手明显得,各种光照用了mask做叠加(多选,左移进位)设置mask之后,是在哪里注入debug呢?同样地不管fog的开关,很快就找到masklit开关的debug实现分别看看各种光的... 查看详情

unity全局光照

全局光照由两部分组成:直接光照和间接光照。直接光照由直接光照射到物体上以后直接弹射到人眼接收到的光照。间接光照为直接光照照射到物体上又弹射到其它物体上面以后多次弹射才被人眼接收的光照(两次及以... 查看详情

cg基本光照模型备忘

Blinn-Phong光照模型:其中、、分别是光源的环境光(ambient)、漫反射光(diffuse)、镜面反射光(specular)亮度,、、则描述了物体材质对这几类光的反射系数,是表面法线,-L是光的方向,是物体表面都eye的单位向量,是入射光... 查看详情

光照模型

要模拟真实的光照环境来生成一张图像,需要考虑三种物理现象:  1、光线从光源中被发射出来  2、光线和场景中的一些物体相交:一些光线被物体吸收了,而另一些光线被散射到其他方向  3、摄像机吸收了一些光,产... 查看详情

《逐梦旅程windows游戏编程之从零开始》笔记8——光照与材质

第14章绘制出质感的世界——光照与材质1.光照与光源在Direct3D中的光源类型和光照类型是不同的两个概念,光照模型描述的是光线的反射特征,而光源类型主要强调的是能够产生这些光照模型的方式以及光线的位置,方向,强度... 查看详情

lambert光照模型

lambert光照模型只考虑环境光和漫反射光的影响。因此在计算的时候,你只需要知道光源的位置和物体上受光点法线的方向即可,而无需知道视点在哪里。650)this.width=650;"src="http://s3.51cto.com/wyfs02/M02/86/E0/wKioL1fN-u_SS7xUAAEfk8H9684951.png-w... 查看详情