第六章 Lighting Models

第六章 Lighting Models

在现实世界中,没有光照是无法看见东西的;一个物体能被看见,要么是通过反射光源,要么是自身发光。在使用计算机渲染时,模拟光线的交互可以使3D objects更逼真。但是光照的交互是一个非常复杂的过程,不能简单的在各种交叉的帧率之间进行复制(至少目前阶段还不行)。因此,使用光照与3D objects交互的近似值或光照模型,在场景中实现更多的细节。本章主要介绍一些基础的光照模型。

Ambient Lighting(环境光)

在一个光照环境中,环境光看起来远处不在。例如,即使没有光源直接照向桌底下最远的角落里,你依然可以看清角落的细节。这种环境光,是由物体表面上无数种光线相互作用的结果。当一束光照射到物体表面时,光线的全部或部分要么被反射要么被吸收,而且会一直持续。因此部分光线能照射到桌底的角落里,即使只有一点点。
通过改变一些常量值来修改某个pixel的颜色值可以实现环境光的简单近似。可以把这些常量看成光照亮度或强度系数,介于0和1之间,每一个pixel都与该系数相乘就能得到环境光的近似值。环境光强度值越接近于0,物体看起来就越暗。此外,可以在环境光模型中包含一种颜色,用于模拟非纯白色的光源。这需要计算一个pixel的红,绿,蓝各个通道值。列表6.1列出了一种环境光effect的代码。
列表6.1 AmbientLighting.fx
/************* Resources *************/
#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;
};

/************* Data Structures *************/
struct VS_INPUT
{
	float4 ObjectPosition : POSITION;
	float2 TextureCoordinate : TEXCOORD;
};

struct VS_OUTPUT
{
	float4 Position : SV_Position;
	float2 TextureCoordinate : TEXCOORD;
};

/************* Utility Functions *************/
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);
	}
}



AmbientColor Shader Constant

可能你已经注意到了这段代码与上一章纹理映射effect中的大部分代码都一样。使用以前的effects代码,是为了更好的学习后面的知识。
第一处与上一章不同的是,增加了一个float4类型的shader常量AmbientColor,表示环境的颜色和强度。光的颜色值存储在RGB通道中,而且强度值存储在alpha通道中。而且AmbientColor使用一种新cbuffer,CBufferPerFrame。回顾一下第四章,“Hello,Shaders”所讨论的constant buffers,通常是根据cbuffer中包含的数据所期望的更新频率来选择cbuffers类型。在本例中,AmbientColor值不仅要用于多个objects中,还要于每一帧都进行更新。这与WorldViewProjection对象中使用的CBufferPerObject相反,CBufferPerObject表示把AmbientLighting effect用于每个object,而不是每一帧。
AmbientColor常量有一个对应的AMBIENT语义。与其他任何shader常量一样,AMBIENT语义也是可选的,但给变量设置语义是一种好的习惯,因为有了语义CPU端的应用程序就可以通过语义访问该变量值,而不是使用hard-coded name。
最后需要注意的是,AmbientColor常量被初始化为{1.0f, 1.0f, 1.0f, 1.0f}。表示这是一个纯白色,最大强度的环境光,不会改变objects的输出颜色。因此,即使在CPU端的应用程序中忽略该变量,对输出结果也没有负面影响。
其余的代码,都与纹理映射effect中的代码一样,直到pixel shaderf才有差异。

Ambient Lighting Pixel Shader

环境光照模型的pixel shader首先sample纹理颜色,然后计算光照输出。具体地说,就是对于纹理采样所输出的颜色的RGB通道值都要与AmbientColor.rgb * AmbientColor.a的乘积相乘。一个向量(AmbientColor.rgb float3类型)与一个标量(AmbientColor.a float类型)相乘,要对向量的每一个分量都与标量相乘。因此,环境光的颜色首先通过光照强度进行调整(也就是光照颜色与光照强度相乘),然后再把采样输出的RGB通道值与该乘积相乘。

Ambient Lighting Output

图6.1是在纹理映射effect的基础上再加上ambient lighting effect应用到一个sphere的输出结果。左图中使用了纯白色的光,并且光照强度系数为0.5(即alpha通道值为0.5)。而右图中,则是红色光(红色通道值为1.0,绿色和蓝色通道值为0),强度为1(alpha通道值为1.0)。
第六章 Lighting Models_第1张图片
图6.1 AmbientLighting.fx applied to a sphere with the texture of Earth with a pure-white,
half-intensity ambient light (left) and a pure-red, full-intensity ambient light (right). (Original texture from
Reto Stöckli, NASA Earth Observatory. Additional texturing by Nick Zuccarello, Florida Interactive
Entertainment Academy.)


可以在NVIDIA FX Composer的Properties panel中修改环境光的颜色值(如图6.2所示)。在Properties panel中AmbientColor显示的名称为Ambient Light,与UIName标注中设置的一样,另外,因为设置了UIWidget标注,所以color picker控件是可以编辑的。
第六章 Lighting Models_第2张图片
图6.2 NVIDIA FX Composer’s Properties panel showing the Ambient Light constant and color picker
dialog.



注意:
一般情况下,在一个shader内部只产生常量值的情况下不应用进行数学运算。比如,环境光color和强度的乘法运算应该由应用程序在CPU中执行,再把乘积传递给shader常量 ambient color。当前这个例子之所以会在shader中运算,是因为使用了NVIDIA FX Composer工具作为CPU端的应用程序,在shader执行之前没有权限访问该常量,也就无法执行运算。

你可能感兴趣的:(第六章 Lighting Models)