DirectX 3D_基础之光照 材质 顶点法线 光源 纹理映射 纹理坐标 多级纹理 纹理过滤

              每日一语: 

 

              总有一些人,总在感叹社会的不公,总在那里,嫉妒别人,诅咒别人,完全不从自身找原因。社会总是相对的公平,从来都不会有绝对的公平,记住一句话,如果你不能改变这个社会,你就应该主动改变自己,让自己融入它,主动的去适应它,这样这个社会才会主动的接纳你。如果你没办法适应它,就注定被社会抛弃,淘汰。

             

              正文:

 

              光照:


              为了增强所绘场景的真是性,我们可以为场景增加光照。光照也有助于描述实体形状和立体感。使用光照时,我们无需自行指定顶点的颜色值:Direct3D会将顶点送入光照计算引擎,依据光源类型,材质以及物体表面相对于光源的朝向,计算出每个顶点的颜色值。基于某种光照模型计算出各顶点的颜色,会使绘制结构更加逼真。


              光照的组成:

             

              光照一般分为三种类型:


              环境光(Ambient Light): 这种类型的光经其他表面反射到达物体表面,并照亮整个场景。例如,物体的某些部分被一定程度地照亮,而物体并没有出入光源的直接照射下。要想以较低代价粗略地模拟这类反射光,环境光是一个很好的选择。


              漫射光(Diffuse Light): 这种类型的光沿着特定的方向传播。当它到达某一表面时,将沿着各个方向均匀反射。由于漫射光沿所有方向都均匀反射,无论从哪个方位观察,表面亮度均相同,所以采用该模型时,无须考虑观察者的位置。这样,漫射光方程中,仅需考虑光传播方向以及表面的朝向。从一个光源发出的光一般都是这个类型   。
             

              镜面光(Specular Light):这种类型的光沿着特定的方向传播。当此类光到达一个表面时 ,将严格地沿着另一个方向反射,从而形成只能在一定角度范围内才能观察到的高亮度照射。因为在这种模型中,光线均沿着同一个方向反射,所以在镜面光照方程中,不仅需要考虑光线的入射方向和图元的表面朝向,而且还要考虑观察点的位置。镜面光可用于模拟物体的高光点。


             每种类型的光都可以用结构D3DCOLORVALUE和D3DXCOLOR来表示,这种类型描述了光线的颜色,描述光线的颜色时,D3DXCOLOR类中的Alpha值都将被忽略。


             D3DXCOLOR redAmbient(1.0f,0.0f,0.0f,1.0f)


             D3DXCOLOR blueDiffuse(1.0f,0.0f,0.0f,1.0f)


             D3DXCOLOR whiteSpecular(1.0f,0.0f,0.0f,1.0f)


             材质:


             在现实世界里,我们所观察到的物体的颜色是由该物体所反射光的颜色决定的。例如,一个纯红色的球体反射了全部的红色入射光。并吸收了所有非红色的光,所以该物体呈现为红色。Direct3D通过定义物体的材质来模拟同样的现象。材质允许我们定义物体表面对各种颜色光的反射比例。在Direct3D中,材质用结构D3DMATERIAL9来表示:
              typedef struct D3DMATERIAL9{
                       D3DCOLORVALUE Diffuse;
                       D3DCOLORVALUE Ambient;
                       D3DCOLORVALUE Specular;
                       D3DCOLORVALUE Emissive;
                      float Power;
              }D3DMATERIAL9,*LPD3DMATERIAL9;

 

              下面就其参数进行说明:


               Diffuse: 指定材质对漫射光的反射率。


               Ambient:指定材质对环境光的反射率。


               Specular:指定材质对镜面光的反射率。


 

               Emissive:该分量用于增强物体的亮度,使之看起来好像可以自己发光。


 

               Power:指定镜面高光点的锐度,该值越大,高光点的锐度越大。


               顶点法线:


               面法线是一个描述多边形朝向的向量。
               顶点法线正是基于上述思路而产生的,但它并不用于指定每个多边形的法向量。顶点法线描述的是构成多边形的各个顶点的法线。Direct3D需要知道顶点的法线方向,以确定光线到达表面时的入射角。而且,由于光照计算是对每个顶点进行的。所以Direct3D需要知道表面在每个顶点处的局部朝向(法线方向),请注意,顶点法线与表面法线不一定相同。

 
               光源:


               Direct3D支持3中类型的光源。


               点光源:该光源中世界坐标系中有固定的位置,并向所有的方向发射光线。


               方向光:该光源没有位置信息,所发射的光线相互平行的沿某一特定的方向传播。


 

               聚光灯:这种类型的光源与手电筒类似,该光源有位置信息,其发射的光线呈锥形沿着特定方向传播。该锥形可用两个角度描述。内部锥形,和外部锥形。


               在程序代码中,光源用结构D3DLIGHT9表示:


               typedef struct D3DLIGHT9{
                                  D3DLIGHTTYPE Type;
                                  D3DCOLORVALUE Diffuse;
                                  D3DCOLORVALUE Specular;
                                  D3DCOLORVALUE Ambient;
                                  D3DVECTOR Position;
                                  D3DVECTOR Direction;
                                  float Range;
                                  float Falloff;
                                  float Attenuation0;  
                                  float Attenuation1;
                                  float Attenuation2;
                                  float Theta;
                                  float Phi;
                  }D3DLIGHT9,*LPD3DLIGHT9;

                 

                   下面就其参数进行说明:


                   Type: 定义我们要创建的光源类型。D3DLIGHT_POINT,D3DLIGHT_SPOT,D3DLIGHT_DIRECTIONNAL.
                  

                    Diffuse: 该光源所发出的漫射光的颜色。


                    Specular:该光源所发出的镜面光的颜色。


                    Ambient:该光源所发出的环境光的颜色。


                    Position:描述光源在世界坐标系中位置的向量。对方向光无效。


                    Direction:一个描述光在世界坐标系中传播方向的向量。对点光源无效。


                    Range:光线消亡前,所能达到的最大光程。对方向光,该参数无效。


                    Falloff:该值仅用于聚光灯。该参数定义了光强从内锥形到外锥形衰减方式,一般设为1.0f.


                    Attenuation0,Attenuation1,Attenuation2这些衰减变量定义了光强随距离衰减的方式。这些变量仅用于点光源和聚光灯。变量Attenuation0,Attenuation1,Attenuation2分别表示光的常量,线性,2次衰减系统。
                                                           1
                              attenuation = ------------------
                                              A0 + A1*D + A2*D平方


                               D为顶点到光源的距离。


                    Theta:  仅用于聚光灯,指定了内部锥形的圆锥角,单位为弧度。


                     Phi:      仅用于聚光灯,指定了外部锥形的圆锥角,单位为弧度。


                     为一个场景添加光照的步骤如下:


                    1,启用光照.


                     2, 为每个物体创建一种材质,并在绘制相应物体前应用该材质。


                    3,创建一种或多种光源,设置并启用。


                     4,启用所有其余的光照状态,如镜面高光。

 

                    纹理映射:


 

                    借助纹理映射技术(texture mapping),我们可以将图像数据映射到三角形单元中,这中功能可以显著地增加所绘制场景的细节和真实感。


                    在Direct3D中,纹理用接口IDirect3DTexture9表示。纹理是类似于表面的一个像素矩阵,与表面不同的是它可被映射到三角形单元中。


                    纹理坐标:


                    Direct3D所使用的纹理坐标系由沿水平方向的u轴和沿垂直方向的v轴构成。用坐标对(u,v)标识的纹理元素称为纹理元。还有一点要注意,为了能够处理不同尺寸的纹理,Direct3D将纹理坐标做了规范化处理,使之限定在区间[0,1]中。
                    对于每个3D三角形单元,我们可以在纹理中定义一个相应的三角形区域,然后将该三角形区域内的纹理映射到该3D三角形单元中。


                     为了实现该映射,我们需要再次修改顶点结构,为之添加一个纹理坐标对以标识纹理中的顶点。
       
                      struct Vetex{
                                   float _x,_y,_z;
                                   float _nx,_ny,_nz;
                                   float _u,_v;
                                   static const DWORD FVF;
                      };


                     const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;


                     D3DFVF_TEX1增加,说顶点结构中包含了一对纹理坐标。


                     现在,由3个顶点对象构成的每个三角形都在该纹理坐标系中定义了一个相应的纹理三角形。
                     虽然,我们为一个3D三角形指定了相应的纹理三角形,但直到光栅化时,即该3D三角形已被变换至屏幕坐标系时,纹理映射才会进行。


                     创建并启用纹理:


                     纹理数据通常从磁盘中的图像文件读入,然后再加载到IDirect3DTexture9中。为了实现这一点,可使用如下的D3DX函数:


                     HRESULT D3DXCreateTextureFromFile(
                                          LPDIRECT3DDEVICE9 pDevice,
                                          LPCTSTR pSrcFile,
                                          LPDIRECT3DTEXTURE9 **ppTexture
                     )


                    注意在Direct3D中,最多可以设置8层纹理,可以对这些纹理进行组合以创建一副更细致的图像。这称为多重纹理。


                   纹理过滤器:

 
                   如前所述,纹理将被映射到屏幕空间中。通常,纹理三角形于屏幕三角形的大小并不一致。当纹理三角形比屏幕三角形小时,纹理三角形必须被放大。反之,需要缩小。在上述两种情形下,都有畸变产生,为了从某种程度上克服这种畸变,Direct3D采用了一项称为纹理过滤的技术。


                    Direct3D提供了3中类型的纹理过滤器,每种过滤器提供了一种质量水平。质量越高,运算开销就越大,处理速度就越慢。


                   最近点采样:这是Direct3D中默认使用的过滤方式。该方式的处理速度最快,但效果最差,下面的代码表示将最近点采样方式设置为放大过滤器和缩小过滤器。


                             Device->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_POINT)
                             Device->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_POINT)


                   线性纹理过滤:该类型的过滤方式可以产生相当好的效果,速度适中,下面代码演示了将线性纹理过滤设置为放大过滤器和 缩小过滤器。


                             Device->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR)
                             Device->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR)


                    各向异性纹理过滤:该类型的过滤方式可以产生最好的效果,下面代码演示了将各向异性纹理过滤设置为放大过滤器和
缩小过滤器。
                             Device->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_ANISOTROPIC)
                             Device->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_ANISOTROPIC)


                             使用各向异性纹理过滤时,我们必须对D3DSAMP_MAXANISOTROPIC水平值进行设定,该值决定了各向异性过滤的质量水平。该值越大,图像效果越好。请调用IDirect3DDevice9::GetDeviceCaps函数检查返回的D3DCAPS9结构参数,以获得硬件支持的值的合法取值范围。


                             Device->SetSamplerState(0,D3DSAMP_MAXANISOTROPIC,4)

 

                      多级渐进纹理:


                       为了尽量消除由二者尺寸差异带来的影响,我们可为纹理创建一个多级渐进纹理链。方法是,由某一纹理创建一系列分辨率逐渐减小的纹理图像,并且对每种分辨率下的纹理采用的过滤方式进行定制,以便保留哪些较重要的细节。
                       Device->SetSamplerState(0,D3DSAMP_MIPFILTER,Filter)


                       其中Filter可取以下值:


                       D3DTEXF_NONE:  禁用多级渐变纹理过滤器。


                       D3DTEXF_POINT: 通过使用该过滤器,Direct3D将选择尺寸与屏幕三角形最接近的那一级纹理。一旦选择了某一级纹理,Direct3D就会用指定的放大过滤器和缩小过滤器对该级纹理进行过滤。

 

                      D3DTEXF_LINEAR:  通过使用该过滤器,Direct3D将选择尺寸与屏幕三角形最接近的两个纹理级。Direct3D就用指定的放大过滤器和缩小过滤器对每级纹理进行过滤,然后再将这两级纹理进行线性组合,从而形成最终的颜色值。
           
                        寻址模式:


                        在前面的部分中,我们说过纹理坐标必须限制在区间[0,1]内。从技术上来说,这是有问题的。因为有时候坐标可能超出该范围。Direct3D定义了4种用来处理纹理坐标值超出[0,1]区间的纹理映射模式。它们分别为,重复寻址模式,边界寻址模式, 钳位寻址模式寻找模式,镜像寻址模式。


                        添加纹理映射的步骤:


                        1,构造组成物体的顶点,并为其指定纹理坐标。


                        2,用函数D3DXCreateTextureFromFile为IDirect3DTexture9接口加载一种纹理。

 

                       3,设置缩小过滤器,放大过滤器和多级渐进纹理过滤器。


                        4,绘制物体前,用函数IDirect3DDeive9::SetTexture来设定与该物体关联的纹理。
       
 
                         

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要合并多个OBJ模型并处理顶点法线纹理坐标信息,可以采用以下步骤: 1. 将多个OBJ文件加载到内存中,可以使用第三方库如Assimp.NET进行加载。 2. 遍历每个OBJ文件的顶点法线纹理坐标信息,将它们存储到一个大的顶点缓冲区中。 3. 对于每个OBJ文件的面信息,将其转换为三角形,并计算每个三角形的法线向量。 4. 对于每个OBJ文件的材质信息,将其转换为纹理,并将纹理ID存储到顶点缓冲区中。 5. 将所有的顶点法线纹理坐标信息组成一个大的顶点数组,并将其存储到一个新的OBJ文件中。 6. 将新的OBJ文件保存到硬盘中,可以使用第三方库如ObjLoader进行保存。 以下是一个示例代码: ``` using System.Collections.Generic; using Assimp; using ObjLoader.Loader.Loaders; using ObjLoader.Loader.Data.Elements; using ObjLoader.Loader.Data.VertexData; using ObjLoader.Loader.Loaders.Loaders; // 加载多个OBJ文件 List<Mesh> meshes = new List<Mesh>(); var importer = new AssimpContext(); foreach (var objFile in objFiles) { var scene = importer.ImportFile(objFile); var mesh = scene.Meshes[0]; meshes.Add(mesh); } // 合并顶点法线纹理坐标信息 List<VertexPositionNormalTexture> vertices = new List<VertexPositionNormalTexture>(); List<uint> indices = new List<uint>(); foreach (var mesh in meshes) { for (int i = 0; i < mesh.VertexCount; i++) { var vertex = mesh.Vertices[i]; var normal = mesh.Normals[i]; var textureCoordinate = mesh.TextureCoordinateChannels[0][i]; vertices.Add(new VertexPositionNormalTexture( new Vector3(vertex.X, vertex.Y, vertex.Z), new Vector3(normal.X, normal.Y, normal.Z), new Vector2(textureCoordinate.X, textureCoordinate.Y))); } for (int i = 0; i < mesh.FaceCount; i++) { var face = mesh.Faces[i]; indices.Add(face.Indices[0]); indices.Add(face.Indices[1]); indices.Add(face.Indices[2]); } } // 将顶点法线纹理信息存储到新的OBJ文件中 var objData = new Obj(); for (int i = 0; i < vertices.Count; i++) { var vertex = vertices[i]; objData.Vertices.Add(new Vertex(vertex.Position.X, vertex.Position.Y, vertex.Position.Z)); objData.Normals.Add(new Normal(vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z)); objData.TextureVertices.Add(new TextureVertex(vertex.TextureCoordinate.X, vertex.TextureCoordinate.Y)); objData.Groups.Add(new Group("Group", true, i * 3, i * 3 + 2)); } var objExporter = new ObjExporter(); objExporter.Export(objData, "merged.obj"); ``` 这段代码使用Assimp.NET库加载每个OBJ文件,然后遍历每个文件的顶点法线纹理坐标信息,并将它们存储到一个大的顶点数组中。接着,遍历每个文件的面信息,将其转换为三角形,并计算每个三角形的法线向量。最后,将所有的顶点法线纹理坐标信息组成一个大的顶点数组,并将其存储到一个新的OBJ文件中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值