游戏开发论坛

 找回密码
 立即注册
搜索
查看: 5569|回复: 10

关于Bump Mapping, 高手再给指点指点

[复制链接]

17

主题

85

帖子

85

积分

注册会员

Rank: 2

积分
85
发表于 2005-6-13 00:34:00 | 显示全部楼层 |阅读模式
这些天也看了一些关于bump mapping的原理和代码
但还有很多困惑的东西,毕竟一个人学真是太费劲了
下面是自己的理解以及一些困惑的地方 希望大家帮忙

原理方面:
Bump Mapping是通过利用per-pixel light来实现的,属于pixel shader范畴
也就是求每个像素点的光照,而不是通过传统的光照模型进行插值得到
这里主要是需要记算每个像素的L*N,
L可以通过计算光源到顶点的位置得到该向量,然后将该向量变换到“切线坐标系”中
(当然也可以将N变换到世界坐标系中,总之L和N要处于同一个坐标系中)

对N的计算我不是很明白,好像有很多中方法
我看NeHe教程22中是通过记算L向量在S和T轴上(纹理横纵轴上)的分量来得到一个offset的东西,这里不是很名白,希望大家说说或者别的计算N的方法

代码方面:
下面是NeHe22中的一段代码
既然是per-pixel light怎么感觉还是只计算了几个顶点的法向量
glBegin(GL_QUADS);
    // Front Face
    n[0]=0.0f;
    n[1]=0.0f;
    n[2]=1.0f;
    s[0]=1.0f;
    s[1]=0.0f;
    s[2]=0.0f;
    t[0]=0.0f;
    t[1]=1.0f;
    t[2]=0.0f;
    for (i=0; i<4; i++) {       //这里只循环了四次,计算前表面四个顶点的相关信息,那么其它
         c[0]=data[5*i+2];    //像素信息在哪计算的(不是说per-pixel lighting吗)?
         c[1]=data[5*i+3];
         c[2]=data[5*i+4];
         SetUpBumps(n,c,l,s,t);  //这里主要是为了计算那个offset
         glTexCoord2f(data[5*i]+c[0], data[5*i+1]+c[1]);
         glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
    }
    // Back Face
    ……………………
glEnd();


关于Bump Mapping还想问几点?
是必须要通过扩展才能实现吗?
Bump Mapping是硬件加速吗?
还有什么好的资料能给介绍一些,最好是中文

谢谢!!

190

主题

1801

帖子

2096

积分

金牌会员

Rank: 6Rank: 6

积分
2096
QQ
发表于 2005-6-13 00:43:00 | 显示全部楼层

Re:关于Bump Mapping, 高手再给指点指点

shading在哪里呢?

17

主题

85

帖子

85

积分

注册会员

Rank: 2

积分
85
 楼主| 发表于 2005-6-13 10:31:00 | 显示全部楼层

Re: 关于Bump Mapping, 高手再给指点指点

哪部分shading?
下面是该教程代码的连接地址
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=22
如果不方便我可以把代码贴出来 就是比较多

昨天又看了一下DP3 Bump Mapping,感觉比较好理解
但是对这里的Bump Mapping不是很明白
尤其是将L变换到“切线坐标系”中计算那个offset

190

主题

1801

帖子

2096

积分

金牌会员

Rank: 6Rank: 6

积分
2096
QQ
发表于 2005-6-13 17:49:00 | 显示全部楼层

Re:关于Bump Mapping, 高手再给指点指点

好长好长,过两天看^_^!

139

主题

2005

帖子

2057

积分

金牌会员

Rank: 6Rank: 6

积分
2057
QQ
发表于 2005-6-13 18:12:00 | 显示全部楼层

Re:关于Bump Mapping, 高手再给指点指点

VS中通过光源数据等计算出L,然后传出到PS里使用.
N查表

17

主题

85

帖子

85

积分

注册会员

Rank: 2

积分
85
 楼主| 发表于 2005-6-13 18:32:00 | 显示全部楼层

Re: Re:关于Bump Mapping, 高手再给指点指点

wingser: Re:关于Bump Mapping, 高手再给指点指点

好长好长,过两天看^_^!



^_^ 这个确实很长,而且我也查了一些资料
但是还是没太高明白,下面是一些资料的链接地址
有兴趣可以再看看
http://freespace.virgin.net/hugo.elias/graphics/x_polybm.htm
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndrive/html/directx11192001.asp
http://www.paulsprojects.net/tutorials/simplebump/simplebump.html

17

主题

85

帖子

85

积分

注册会员

Rank: 2

积分
85
 楼主| 发表于 2005-6-13 18:34:00 | 显示全部楼层

Re: Re:关于Bump Mapping, 高手再给指点指点

♂樱♀: Re:关于Bump Mapping, 高手再给指点指点

VS中通过光源数据等计算出L,然后传出到PS里使用.
N查表


你说的N查表是不是利用Cube Map,也就是DOT3 Bump Mapping
(感觉这个理解起来还不是很费劲)
不过我上面说的这段代码并没有用到Cube Map,是另一种Bump Mapping

2

主题

29

帖子

29

积分

注册会员

Rank: 2

积分
29
发表于 2005-6-13 18:40:00 | 显示全部楼层

Re:关于Bump Mapping, 高手再给指点指点

首先实现bump mapping一个重点是tangent space,
要把灯光方向向量和视觉向量转化到tangent space去,
可以| Tx Ty Tz |
      |  Bx By Bz |  把灯光方向向量和视觉向量转化到tangent space去
      |  Nx Ny Ny |
其中T是顶点切线, B是顶点副法线, N是顶点法线
通过读取法线图来获得法线,
这样就可以这几个变量在pixel shader中计算了..
下面是代码:
// 顶点着色器输入结构
struct VS_INPUT
{
        float4 Position : POSITION0;
        float3 Normal   : NORMAL0;       // 顶点法线
        float2 Texcoord : TEXCOORD0;
        float3 Binormal : TEXCOORD1;   // 顶点副法线
        float3 Tangent  : TEXCOORD2;  // 顶点切线
};
// 顶点着色器输出结构, 实现漫反射光照, 有凸凹效果
struct VS_OUTPUT_DIFFUSE_BUMP
{
        float4 Position  : POSITION0;
        float2 BaseTexcd : TEXCOORD0;   // 表面纹理坐标
        float2 BumpTexcd : TEXCOORD1;  // 法线纹理坐标
        float3 LightDir  : TEXCOORD2;       // 变换到tangent space的灯光向量
};
// 漫反射凸凹光照顶点着色器函数
VS_OUTPUT_DIFFUSE_BUMP DiffuseBump_VS_Main(VS_INPUT Input)
{
        VS_OUTPUT_DIFFUSE_BUMP Output;
       
        Output.Position  = mul(Input.Position, g_mWorldViewProj);
        Output.BaseTexcd = Input.Texcoord;
        Output.BumpTexcd = Input.Texcoord;
       
        float3 vP = mul(Input.Position, g_mWorld); // 顶点位置
        float3 vL = g_vLightPos - vP;                     // 灯光方向向量
       
        float3 vN = mul(float4(Input.Normal, 1.0f), g_mWorld).xyz;
        float3 vB = mul(float4(Input.Binormal, 1.0f), g_mWorld).xyz;
        float3 vT = mul(float4(Input.Tangent, 1.0f), g_mWorld).xyz;       
       
                // 把 vL 转化到tangent space去
        float x = dot(vL, vT);  
        float y = dot(vL, vB);
        float z = dot(vL, vN);
       
        Output.LightDir = normalize(float3(x, y, z));       
       
        return Output;
}
// 像素着色器输入结构, 实现漫反射光照, 有凸凹效果
struct PS_INPUT_DIFFUSE_BUMP
{
        float2 BaseTexcd : TEXCOORD0;
        float2 BumpTexcd : TEXCOORD1;
        float3 LightDir  : TEXCOORD2;
};
// 漫反射凸凹光照像素着色器函数
float4 DiffuseBump_PS_Main(PS_INPUT_DIFFUSE_BUMP Input) : COLOR0
{
        float3 vL = Input.LightDir;
        float3 vN = normalize(tex2D(BumpSampler, Input.BumpTexcd).xyz * 2.0f -1.0f));
       
        float4 vDiffuse = g_vLightCol * (g_vMatrlAmbient + max(0, dot(vN, vL)) * g_vMatrlDiffuse);
       
        return saturate(tex2D(BaseSampler, Input.BaseTexcd) * vDiffuse);
}

在这些问题中, 要计算顶点的法线, 副法线, 切线.
可以通过下面的方法来计算:
E,F,G分别是每一个面的顶点, <sE, tE>, <sF, tF>, <sG, sG>要按照顺序的
P = F - E;   Q = G - E;
<s1, t1> = <sF - sE, tF - tE>
<s2, t2> = <sG - sE, tG - tE>
| Tx Ty Tz |                                |  t2  -t1 | |  Px Py Pz |
|  Bx By Bz | = (1 / s1*t2 - s2*t1)  | -s2  s1 |  | Qx Qy Qz |
T = T - ( N . T)N;
B = N * T;
      | Tx Ty Tz |
      |  Bx By Bz | 就是 tangent space 矩阵了
      |  Nx Ny Ny |
下面是我用D3D写的代码:

                struct sVertexBump
                {
                        D3DXVECTOR3 Position;
                        D3DXVECTOR3 Normal;
                        float u, v;
                        D3DXVECTOR3 Binormal;
                        D3DXVECTOR3 Tangent;

                        static const DWORD FVF;
                };
const DWORD CBumpMesh::sVertexBump::FVF =
                                 D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX3 |
                                                         D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1) |
                                                             D3DFVF_TEXCOORDSIZE3(2);
//------------------------------
// 计算 tangent, binormal
//------------------------------
HRESULT CBumpMesh::ComputeTangentAndBinormal(IDirect3DDevice9 *pd3dDevice)
{
        HRESULT hr;

        // 创建一个有 tangent, binormal 的mesh
    ID3DXMesh* pTempMesh;
    V(m_pMesh->CloneMeshFVF(m_pMesh->GetOptions(),
                                                        sVertexBump::FVF,
                            pd3dDevice, &pTempMesh));
    V(D3DXComputeNormals(pTempMesh, NULL));

    SAFE_RELEASE(m_pMesh);
    m_pMesh = pTempMesh;

        // 计算 tangent, binormal
        WORD* tri = NULL;
        sVertexBump* pVertex = NULL;
        V(m_pMesh->LockIndexBuffer( D3DLOCK_READONLY, (void**)&tri));
        V(m_pMesh->LockVertexBuffer( D3DLOCK_DISCARD, (void**)&pVertex));

        DWORD dwTotalVertex = m_pMesh->GetNumVertices();
        DWORD dwTotalTri    = m_pMesh->GetNumFaces();
        //WORD* wNumShared    = new WORD[dwTotalVertex];
        D3DXVECTOR3* tan1   = new D3DXVECTOR3[dwTotalVertex];
        memset(tan1, 0, dwTotalVertex * sizeof(D3DXVECTOR3));

                // 计算 tangent, binormal
        for ( DWORD i=0; i<dwTotalTri; i++ )
        {
                int nOffset = 3 * i;
                int idxVertex0 = tri[nOffset];
                int idxVertex1 = tri[nOffset + 1];
                int idxVertex2 = tri[nOffset + 2];
            
                D3DXVECTOR3 v0 = D3DXVECTOR3(pVertex[idxVertex0].Position);
                D3DXVECTOR3 v1 = D3DXVECTOR3(pVertex[idxVertex1].Position);
                D3DXVECTOR3 v2 = D3DXVECTOR3(pVertex[idxVertex2].Position);

                D3DXVECTOR2 w0 = D3DXVECTOR2(pVertex[idxVertex0].u, pVertex[idxVertex0].v);
                D3DXVECTOR2 w1 = D3DXVECTOR2(pVertex[idxVertex1].u, pVertex[idxVertex1].v);
                D3DXVECTOR2 w2 = D3DXVECTOR2(pVertex[idxVertex2].u, pVertex[idxVertex2].v);
            
                float x1 = v1.x - v0.x;
                float x2 = v2.x - v0.x;
                float y1 = v1.y - v0.y;
                float y2 = v2.y - v0.y;
                float z1 = v1.z - v0.z;
                float z2 = v2.z - v0.z;
            
                float s1 = w1.x - w0.x;
                float s2 = w2.x - w0.x;
                float t1 = w1.y - w0.y;
                float t2 = w2.y - w0.y;
                float r = 1.0f / (s1 * t2 - s2 * t1);

                D3DXVECTOR3 sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
                D3DXVECTOR3 tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
          
                //++(wNumShared[idxVertex0]);
                //++(wNumShared[idxVertex1]);
                //++(wNumShared[idxVertex2]);

                tan1[idxVertex0] += sdir;
                tan1[idxVertex1] += sdir;
                tan1[idxVertex2] += sdir;
        }

        for( i = 0; i < dwTotalVertex; i ++ )
        {
                D3DXVECTOR3 &N = pVertex.Normal;
                D3DXVECTOR3 &T = tan1/* / wNumShared*/;
                D3DXVec3Normalize(&T, &T);
                float a = D3DXVec3Dot(&N, &T);
                D3DXVec3Normalize(&pVertex.Tangent, &(T - N * a));
                D3DXVECTOR3 temp;
                D3DXVec3Cross(&temp, &N, &pVertex.Tangent);
                D3DXVec3Normalize(&pVertex.Binormal, &temp);
        }

        //delete[] wNumShared;
        delete[] tan1;

        m_pMesh->UnlockIndexBuffer();
        m_pMesh->UnlockVertexBuffer();

        return S_OK;
}

190

主题

1801

帖子

2096

积分

金牌会员

Rank: 6Rank: 6

积分
2096
QQ
发表于 2005-6-14 00:33:00 | 显示全部楼层

Re:关于Bump Mapping, 高手再给指点指点

我是刚学了一个钟头,汗!
做bump map首先是要高度图吧?是吧?寒!我真不知道
我的材料上是这么计算normal的
从这个图上取一个点,设其高度是Hg,取它正上方的点,设其高度为Ha,再取Ha右边的点为Hr
那么计算这个点的normal:
                                     <Hg-Hr , Hg-Ha , 1>
normal=         ---------------------------------------------------
                              ((Hg-Hr)^2 + (Hg-Ha)^2+1)^0.5
^2的意思是平方
要是没有上边或右边的点的话,取<0,0,1>就得了,说明是边上了,这个笔直向上应该没啥影响,这是我自个想的&_&!

然后弄成纹理2号,丢到fragment program里,就是大哥您说的ps里面

17

主题

85

帖子

85

积分

注册会员

Rank: 2

积分
85
 楼主| 发表于 2005-6-14 21:53:00 | 显示全部楼层

Re: Re:关于Bump Mapping, 高手再给指点指点

260013004: Re:关于Bump Mapping, 高手再给指点指点
首先实现bump mapping一个重点是tangent space,
要把灯光方向向量和视觉向量转化到tangent space去,

感觉原理上还是比较明白的
就像你说的主要两步:第一是将L变换到切线坐标系中
第二是读出每个pixel的发向量,通过L*N计算该点的光照强度

下面这篇文章介绍了四种bump mapping(很多地方我也没看明白)
http://www.pvrdev.com/pub/PC/doc/f/Bump%20Mapping%20Comparison.htm
NeHe22是用的其中的第一种 Embossed Bump Mapping

我现在的问题是:
一是关于每个pixel的光照方向L,我现在的理解是我们还是只需要计算每个顶点的L,其它pixel的L值通过插值得到,毕竟bump mapping用的还是openGL的光照模型,不知这样理解对吗?
二是关于每个pixel的 法向量N(这个每个pixel是不同了,所以才产生亮度差异),很多不同的bump mapping方法主要是这里对于N的获取不同
Embossed Bump Mapping通过利用灰度图来读取N,还有利用每个像素的alpha值计算N的,Dot Product Bump Mapping利用颜色的RGB向量在Cube Map中计算N
我现在比较困惑的是为什么通过alpha值,通过RGB向量(<r,g,,b>向量)就可以确定该点的法向量朝向?

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2025-12-26 00:38

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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