材料 (Direct3D 9)

材料描述多边形如何在 3D 场景中反射光或看起来发出光。 材料属性详细说明了材料的漫射反射、环境反射、光发射和反射高光特征。 Direct3D 使用 D3DMATERIAL9 结构来携带所有材料属性信息。 除反射属性外,每个属性都描述为 RGBA 颜色,该颜色表示它反射的给定类型光的红色、绿色和蓝色部分的量,以及 alpha 混合因子。

漫射和环境反射

D3DMATERIAL9 结构的漫射和环境成员描述材料如何在场景中反射环境和漫射光。 由于大多数场景包含的漫射光比环境光多得多,因此漫射反射在确定颜色方面起着最大的作用。 此外,由于漫射光是定向的,漫射光的入射角会影响反射的整体强度。 当光线射向与顶点法线平行的顶点时,漫射反射效果最大。 随着角度的增加,漫射反射的效果会减弱。 反射的光量是入射光与顶点法线之间的角度的余弦值,如下图所示。

反射光量的插图

与环境光一样,环境反射是非定向的。 环境反射对渲染对象的明显颜色的影响较小,但它确实会影响整体颜色,当材料反射很少或没有漫射光时,环境反射最明显。 通过使用 D3DRS_AMBIENT 标志调用 IDirect3DDevice9::SetRenderState 方法,材料的环境反射受场景的环境光集的影响。

漫射和环境反射协同工作以确定物体的感知颜色,并且通常是相同的值。 例如,若要呈现蓝色晶体对象,请创建一个材料,该材料仅反射漫射光和环境光的蓝色分量。 当放置在有白光的房间里时,水晶似乎是蓝色的。 然而,在只有红光的房间里,同样的晶体看起来是黑色的,因为它的材料不会反射红光。

排放

材料可用于使呈现的对象看起来是自发光的。 D3DMATERIAL9 结构的 Emissive 成员用于描述发出的光的颜色和透明度。 放射会影响对象的颜色,使暗材质显得更亮并在一定程度上呈现出放射光的颜色。

可以使用材质的发射属性来添加物体正在发出光线的错觉,而不会造成向场景添加光的计算开销。 对于蓝色水晶,如果想要使晶体看起来亮起,但不向场景中的其他对象投射光,则发射属性非常有用。 请记住,具有发射属性的材料不会发出可由场景中其他对象反射的光。 若要实现这种反射光,需要在场景中放置额外的光。

镜面反射

镜面反射在对象上创建突出显示,使其看上去闪亮。 D3DMATERIAL9 结构包含两个成员,用于描述反射高光颜色以及材料的整体光泽度。 通过将 Specular 成员设置为所需的 RGBA 颜色(最常见的颜色为白色或浅灰色)来建立高光点的颜色。 在 Power 成员中设置的值控制反射效果的锐度。

高光可以产生戏剧性的效果。 再次绘制蓝色水晶的类比:更大的功率值创造更尖锐的反射高光,使水晶看起来相当闪亮。 较小的值会增加效果的面积,产生沉闷的反射,使水晶看起来霜冻。 若要使对象真正哑光,请将 Power 成员设置为零,将“反射”中的颜色设置为黑色。 尝试不同级别的反射,以生成符合需求的逼真外观。 下图显示了两个相同的模型。 左侧的一个使用 10 的反射功率:右侧的模型没有反射。

反射模型的插图

设置材料属性

Direct3D 呈现设备一次可以使用一组材料属性进行渲染。

在 C++ 应用程序中,通过准备 D3DMATERIAL9 结构,然后调用 IDirect3DDevice9::SetMaterial 方法,设置系统使用的材料属性。

若要准备 D3DMATERIAL9 结构以供使用,请在结构中设置属性信息以在呈现期间创建所需的效果。 下面的代码示例为具有尖锐白色高光的紫色材料设置 D3DMATERIAL9 结构。

D3DMATERIAL9 mat;

// Set the RGBA for diffuse reflection.
mat.Diffuse.r = 0.5f;
mat.Diffuse.g = 0.0f;
mat.Diffuse.b = 0.5f;
mat.Diffuse.a = 1.0f;

// Set the RGBA for ambient reflection.
mat.Ambient.r = 0.5f;
mat.Ambient.g = 0.0f;
mat.Ambient.b = 0.5f;
mat.Ambient.a = 1.0f;

// Set the color and sharpness of specular highlights.
mat.Specular.r = 1.0f;
mat.Specular.g = 1.0f;
mat.Specular.b = 1.0f;
mat.Specular.a = 1.0f;
mat.Power = 50.0f;

// Set the RGBA for emissive color.
mat.Emissive.r = 0.0f;
mat.Emissive.g = 0.0f;
mat.Emissive.b = 0.0f;
mat.Emissive.a = 0.0f;

准备 D3DMATERIAL9 结构后,通过调用呈现设备的 IDirect3DDevice9::SetMaterial 方法应用属性。 此方法接受已准备的 D3DMATERIAL9 结构的地址作为其唯一参数。 可以根据需要使用新信息调用 IDirect3DDevice9::SetMaterial 以更新设备的材料属性。 下面的代码示例演示了在代码中可能的外观。

// This code example uses the material properties defined for 
// the mat variable earlier in this topic. The pd3dDev is assumed
// to be a valid pointer to an IDirect3DDevice9 interface.
HRESULT hr;
hr = pd3dDev->SetMaterial(&mat);
if(FAILED(hr))
{
    // Code to handle the error goes here.
}

创建 Direct3D 设备时,当前材料将自动设置为下表中显示的默认值。

成员 Value
漫射 (R:0、G:0、B:0、A:0)
反射 (R:0、G:0、B:0、A:0)
环境 (R:0、G:0、B:0、A:0)
放射 (R:0、G:0、B:0、A:0)
强力 (0.0)

 

检索材料属性

通过为设备调用 IDirect3DDevice9::GetMaterial 方法,检索呈现设备当前正在使用的材料属性。 与 IDirect3DDevice9::SetMaterial 方法不同, IDirect3DDevice9::GetMaterial 不需要准备。 IDirect3DDevice9::GetMaterial 方法接受 D3DMATERIAL9 结构的地址,并在返回之前用描述当前材料属性的信息填充所提供的结构。

// For this example, the pd3dDev variable is assumed to 
// be a valid pointer to an IDirect3DDevice9 interface.
HRESULT hr;
D3DMATERIAL9 mat;

hr = pd3dDev->GetMaterial(&mat);
if(FAILED(hr))
{
    // Code to handle the error goes here.
}

注意

如果应用程序未指定用于呈现的材料属性,则系统会使用默认材料。 默认材料反射所有漫射光(例如白色),没有环境反射或反射反射,也没有发射颜色。

 

灯和材料