游戏开发论坛

 找回密码
 立即注册
搜索
查看: 4440|回复: 13

为什么相同的材质,在同一个平面上会有这么大的反光差

[复制链接]

3

主题

30

帖子

34

积分

注册会员

Rank: 2

积分
34
发表于 2009-9-17 19:12:00 | 显示全部楼层 |阅读模式
DX9.0c下,照着书上的例子做了个房间的场景(就是几个Box按相对的坐标,整齐地码在一起,再加一盏点光源的灯而已),可发现同样的材质,在同一个平面上时,为何会有这么大的差异。如图所示,正面的墙上开了个窗户,把原本一个Box就能表示的墙壁分割成了四个Box,然后再整齐地码在一起,问题出现了:图中窗户右侧墙壁的Box以A点和B点这条对角线为界线,反光出现明显的不同,显得很不自然,特别是当灯光从特定角度照射的时候更明显,请问什么原因会导致这样的?而且灯光只有一盏,这四堵墙采用了同一个材质,它们的正面也确实在同一个平面上,各墙壁的正面之间竞也有如此巨大的反光差别,实在是不解,特来请教各位兄弟们。在下初来乍到,还请大家指点指点。

0

主题

8

帖子

10

积分

新手上路

Rank: 1

积分
10
发表于 2009-9-18 01:39:00 | 显示全部楼层

Re: 为什么相同的材质,在同一个平面上会有这么大的反光

可能是因为三角形太大造成的,光照效果应该是通过三角形顶点进行插值计算的吧。
用更多的三角形来表示墙面,让光照效果过渡得平滑些。

3

主题

30

帖子

34

积分

注册会员

Rank: 2

积分
34
 楼主| 发表于 2009-9-18 11:09:00 | 显示全部楼层

Re:为什么相同的材质,在同一个平面上会有这么大的反光

感谢楼上兄弟的回复!这是我在Gameres上的第一个贴子,有人回复让我非常高兴和感动,尤其人家是在深更半夜里的回复!!我知道图中以点A和点B形成的对角线把组成正面的矩形分成两个三角形来渲染了,至于feiyunw朋友说可能是因为三角形太大的原因,我觉得不太象。再看我侧面另外一堵墙的情况,只有一个Box了,三角形应该比正面墙壁更大了,但它看上去过渡就比较自然,至少我看不出它的分界线(也就是对角线了),汗,才知道不能在回复中上传图片。顺便附上我相关的主要代码:
        //设置灯光
        m_Device->LightEnable(0, true);       
        m_Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
        m_Device->BeginScene();
        //为各个模型设置材质和矩阵
        //依次Draw各面墙壁
        m_Device->SetMaterial(&m_materialWall);
        m_Device->SetTransform(D3DTS_WORLD, &m_matrixWallLeft);
        m_meshWallLeft->DrawSubset(0);
        m_Device->SetTransform(D3DTS_WORLD, &m_matrixWallRight);
        m_meshWallRight->DrawSubset(0);
        m_Device->SetTransform(D3DTS_WORLD, &m_matrixWallFront[0]);
        m_meshWallFront[0]->DrawSubset(0);
        m_Device->SetTransform(D3DTS_WORLD, &m_matrixWallFront[1]);
        m_meshWallFront[1]->DrawSubset(0);
        m_Device->SetTransform(D3DTS_WORLD, &m_matrixWallFront[2]);
        m_meshWallFront[2]->DrawSubset(0);
        m_Device->SetTransform(D3DTS_WORLD, &m_matrixWallFront[3]);
        m_meshWallFront[3]->DrawSubset(0);
        m_Device->SetTransform(D3DTS_WORLD, &m_matrixWallRear[0]);
        m_meshWallRear[0]->DrawSubset(0);
        m_Device->SetTransform(D3DTS_WORLD, &m_matrixWallRear[1]);
        m_meshWallRear[1]->DrawSubset(0);
        m_Device->SetTransform(D3DTS_WORLD, &m_matrixWallRear[2]);
        m_meshWallRear[2]->DrawSubset(0);

        m_Device->EndScene();
        m_Device-&gtresent(0, 0, 0, 0);
同时让我更费解的是,正面这四个Box的面的确是在同一个数学平面上,为何会有如此巨大的光照效果差异?按插值的说法是难以解释的。请各位朋友指点一二,小子在此先谢过!

3

主题

30

帖子

34

积分

注册会员

Rank: 2

积分
34
 楼主| 发表于 2009-9-18 11:38:00 | 显示全部楼层

Re:为什么相同的材质,在同一个平面上会有这么大的反光

看了一下别人的贴子,好象他们是可以在回复中上传图片的,而且不是使用外联功能的相册,请问我要如何做才能象他们一样在回复中上传图片呢?

11

主题

650

帖子

651

积分

高级会员

Rank: 4

积分
651
发表于 2009-9-18 12:01:00 | 显示全部楼层

Re:为什么相同的材质,在同一个平面上会有这么大的反光

别用快速回复  点击“回复本主题”
然后就有上传。。。先上传。回帖成功后复制该链接地址
然后编辑该回复
在图片里写上 上传的地址 就可以贴上传的自定义图片了……

29

主题

157

帖子

163

积分

注册会员

Rank: 2

积分
163
发表于 2009-9-18 13:22:00 | 显示全部楼层

Re:为什么相同的材质,在同一个平面上会有这么大的反光

这个问题很明显,是你的法线设置的不对。看你的图片,越靠近窗户的地方越亮,越靠近里面墙的地方颜色就和其他墙越接近。所以可以确定的告诉你,你靠近窗户的那两个点的法线和远离窗户的那两点不一样。

29

主题

157

帖子

163

积分

注册会员

Rank: 2

积分
163
发表于 2009-9-18 13:32:00 | 显示全部楼层

Re:为什么相同的材质,在同一个平面上会有这么大的反光

每个顶点上光照量的计算除了材质参数外,还需要该点的法线参与计算。而一个顶点往往是多个三角面的公共顶点,且这些三角面并不共面(即它们的法线不同),此时在绘制模型的时候就要根据具体情况设置每个顶点的法线。具体情况如下:
1、如果以此顶点为公共点的三角面们需要进行光滑过渡(如球体上的面),那么该点的法线就应该是这些三角面的法线的平均值。
2、如果是这些三角面们要求棱角分明(如一个长方体上的面),那么建议你使用三角面列表的方式绘制模型,即一个三角面一个三角面的输入顶点数据,每个顶点的法线设置为三角面的法线。比如一个顶点被两个三角面公用,那么在绘制每个三角面的时候都把这个顶点和该三角面的另外两个顶点传入一次,并且把这三个顶点的法线都设置为三角面的法线。

3

主题

30

帖子

34

积分

注册会员

Rank: 2

积分
34
 楼主| 发表于 2009-9-18 20:24:00 | 显示全部楼层

Re:为什么相同的材质,在同一个平面上会有这么大的反光

感谢5楼的resplendence朋友提供在回复中上传图片的方法!
场景中这些Box我都是用D3DXCreateBox方法创建出来的,这时它各个顶点的法线应该是自动计算好了的吧,还要我们再修改吗?惭愧,在下初学D3D,懂得不多。看了楼上cO_olWinD朋友的回复后,还是花了好几个小时确认一下D3DXCreateBox创建出来的Box的顶点参数是否正确,代码如下:

        //我们来研究一下窗户右侧的墙的顶点数据
        DWORD FVF = m_meshWallFront[2]->GetFVF();        //这里得到FVF的结果为18,说明它的灵活顶点格式为:D3DFVF_XYZ | D3DFVF_NORMAL
        struct CurrentVertex
        {
                float x, y, z;
                float nx, ny, nz;
        };
        CurrentVertex *pCurrentVertex = 0;
        if(D3DFVF_XYZ | D3DFVF_NORMAL == FVF)
        {
                if(D3D_OK != m_meshWallFront[2]->LockVertexBuffer(0, (void**)&pCurrentVertex))
                        ::MessageBox(m_hWnd, "无法得到顶点的缓存!", "出错", MB_OK);
                else
                {
                        //得到组成Box的三角形的数量
                        DWORD nNumFaces = m_meshWallFront[2]->GetNumFaces();
                        D3DXVECTOR3 v0, v1, v2, nv0, nv1, nv2;                //组成三角形的顶点坐标及法线
                        char strOutput[2256] = {0};                //输出每个三角形各顶点的信息
                        WORD* index = 0;
                        m_meshWallFront[2]->LockIndexBuffer(0, (void**)&index);//得到每个顶点在顶点数组中的的索引号
                        //好了,现在可以得到每个三角形的顶点信息了
                        for(int i=0; i<nNumFaces; i++)
                        {
                                //顶点一坐标数据
                                v0.x = pCurrentVertex[index[i*3]].x;
                                v0.y = pCurrentVertex[index[i*3]].y;
                                v0.z = pCurrentVertex[index[i*3]].z;
                                //顶点二坐标数据
                                v1.x = pCurrentVertex[index[i*3+1]].x;
                                v1.y = pCurrentVertex[index[i*3+1]].y;
                                v1.z = pCurrentVertex[index[i*3+1]].z;
                                //顶点三坐标数据
                                v2.x = pCurrentVertex[index[i*3+2]].x;
                                v2.y = pCurrentVertex[index[i*3+2]].y;
                                v2.z = pCurrentVertex[index[i*3+2]].z;
                               
                                //顶点一法线数据
                                nv0.x = pCurrentVertex[index[i*3]].nx;
                                nv0.y = pCurrentVertex[index[i*3]].ny;
                                nv0.z = pCurrentVertex[index[i*3]].nz;
                                //顶点二法数据
                                nv1.x = pCurrentVertex[index[i*3+1]].nx;
                                nv1.y = pCurrentVertex[index[i*3+1]].ny;
                                nv1.z = pCurrentVertex[index[i*3+1]].nz;
                                //顶点三法数据
                                nv2.x = pCurrentVertex[index[i*3+2]].nx;
                                nv2.y = pCurrentVertex[index[i*3+2]].ny;
                                nv2.z = pCurrentVertex[index[i*3+2]].nz;
                                //输出信息
                                sprintf(strOutput, "顶点一坐标(%f, %f, %f),\n顶点一法线(%f, %f, %f)。\n\n顶点二坐标(%f, %f, %f),\n顶点二法线(%f, %f, %f)。\n\n顶点三坐标(%f, %f, %f),\n顶点三法线(%f, %f, %f)。\n\n",
                                        v0.x, v0.y, v0.z, nv0.x, nv0.y, nv0.z,
                                        v1.x, v1.y, v1.z, nv1.x, nv1.y, nv1.z,
                                        v2.x, v2.y, v2.z, nv2.x, nv2.y, nv2.z);
                                ::MessageBox(m_hWnd, strOutput, "三角形信息", MB_OK);
                        }
                        m_meshWallFront[2]->UnlockIndexBuffer();
                        m_meshWallFront[2]->UnlockVertexBuffer();
                }
        }
        else
        {
                ::MessageBox(m_hWnd, "顶点的格式不是D3DFVF_XYZ | D3DFVF_NORMAL的!", "出错", MB_OK);
        }

显示结果表明,每个顶点的法线都是正确无误的,包括组成正面墙壁的其他几个Box的各个顶点的法线也是对的,看来:这里也不是因为顶点法线不正确造成光照效果的差异。那是什么原因呢,继续请教各位兄弟们!

0

主题

8

帖子

10

积分

新手上路

Rank: 1

积分
10
发表于 2009-9-19 01:49:00 | 显示全部楼层

Re: 为什么相同的材质,在同一个平面上会有这么大的反光

是不是这个原因:
http://www.pcveke.cn/article/158/32999.asp
用D3DXCreateBox()产生的box一共有24个顶点,而不是通常的8个。  
也就是说每个面用4个独立的顶点来表示。  
除非手动修改所有顶点的法向量,否则这样的box是没法产生渐变的光照效果的。

3

主题

30

帖子

34

积分

注册会员

Rank: 2

积分
34
 楼主| 发表于 2009-9-19 11:41:00 | 显示全部楼层

Re: 为什么相同的材质,在同一个平面上会有这么大的反光

Box的确是用24个顶点来表示Mesh的,每个顶点都有三个不同方向的法线向量。仔细看了下楼上feiyunw朋友的回复后,我特别修改了一个Box顶点的法线,把所有24个顶点的向量都改成朝向我们关心的正面(即0.0f,0.0f,-1.0f)以后,还是会出现这种光照不自然的问题。
我在场景中的墙壁表面又整齐地码了一层瓷砖(一块块小的Box),再把灯光改成一盏聚光灯,此时这个光照效果的问题就非常明显地不正常,墙壁上本该是抛物线形的灯光轮廓极其不自然,在每块瓷砖的表面都反映出光照的问题。我觉得这个现象大家应该都会遇到啊,不知道兄弟们是如何解决的呢?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-6-20 17:02

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表