zoukankan      html  css  js  c++  java
  • Directx11教程(42) 纹理映射(12)简单的bump mapping

         有时候,我们只有一个粗糙的模型,但是我们想渲染纹理细节,比如一个砖墙,我们如何在只有一个平面的时候,渲染出砖墙凹凸的效果。

       比如只有这样的墙:

     

    但是我们想要这样的效果:

    怎么办呢?这时候,我们可以考虑对第一张图进行处理,生成它的法向图,存储在一张纹理中,生成法向图的主要算法是:

    image

          对于一张图片,假设像素排列如上图所示,Hg,Hr,Ha分别表示这些点的RGB(或灰度)值,我们得到第一个向量(1,0,Hr-Hg),第二个向量(0,1,Ha-Hg),则法向可以通过它们的差积得到:

    image

     对所有的像素进行处理,我们可以得到一个纹理的法向图,比如第一张墙纹理贴图,经过计算,它的法向图为:

    image

          在物体表面,每个点都都有一个(T,N,B)的局部坐标系,分别对应切向、法向,副法向,有了纹理图后,我们可以通过公式

    bumpNormal = normal + bumpMap.x * tangent + bumpMap.y * binormal; 得到最终的法向。其中bumpMap为前面计算得到的法向贴图,或者说normal map。

    1、首先我们改写CubeModelClass类,设置顶点格式为:

    struct VertexType

    {
    D3DXVECTOR3 position;
    D3DXVECTOR3 normal; //法向
    D3DXVECTOR3 tangent; //切向
    D3DXVECTOR3 binormal; //副法向
    D3DXVECTOR2 texture; //纹理坐标
    D3DXVECTOR4 Kd; //材质漫反射系数
    D3DXVECTOR4 Ks;  //材质的高光系数
    };

    增加了切向和副法向的计算,主要通过顶点的uv坐标以及顶点值求得

    void CubeModelClass::CalculateTangentBinormal(TempVertexType vertex1, TempVertexType vertex2, TempVertexType vertex3,
        VectorType& tangent, VectorType& binormal)
        {
        float vector1[3], vector2[3];
        float tuVector[2], tvVector[2];
        float den;
        float length;


        // 计算2个向量.
        vector1[0] = vertex2.x - vertex1.x;
        vector1[1] = vertex2.y - vertex1.y;
        vector1[2] = vertex2.z - vertex1.z;

        vector2[0] = vertex3.x - vertex1.x;
        vector2[1] = vertex3.y - vertex1.y;
        vector2[2] = vertex3.z - vertex1.z;

        // 计算tu和tv向量.
        tuVector[0] = vertex2.tu - vertex1.tu;
        tvVector[0] = vertex2.tv - vertex1.tv;

        tuVector[1] = vertex3.tu - vertex1.tu;
        tvVector[1] = vertex3.tv - vertex1.tv;


        den = 1.0f / (tuVector[0] * tvVector[1] - tuVector[1] * tvVector[0]);

        tangent.x = (tvVector[1] * vector1[0] - tvVector[0] * vector2[0]) * den;
        tangent.y = (tvVector[1] * vector1[1] - tvVector[0] * vector2[1]) * den;
        tangent.z = (tvVector[1] * vector1[2] - tvVector[0] * vector2[2]) * den;

        binormal.x = (tuVector[0] * vector2[0] - tuVector[1] * vector1[0]) * den;
        binormal.y = (tuVector[0] * vector2[1] - tuVector[1] * vector1[1]) * den;
        binormal.z = (tuVector[0] * vector2[2] - tuVector[1] * vector1[2]) * den;

        length = sqrt((tangent.x * tangent.x) + (tangent.y * tangent.y) + (tangent.z * tangent.z));

        // 归一化
        tangent.x = tangent.x / length;
        tangent.y = tangent.y / length;
        tangent.z = tangent.z / length;

        // 计算向量的长度.
        length = sqrt((binormal.x * binormal.x) + (binormal.y * binormal.y) + (binormal.z * binormal.z));

       // 归一化向量
        binormal.x = binormal.x / length;
        binormal.y = binormal.y / length;
        binormal.z = binormal.z / length;

        return;
        }

    得到面的法向、切向以及副法向后,把他们赋值给顶点。

    然后我们在LightTex2ShaderClass中,改变layout,然后修改lighttex2.vs和lighttex2.ps

    特别是ps中,我们改变normal的计算方式:

    float3 N;
    float4 textureColor;
    float4 textureColor1 = shaderTexture[0].Sample(SampleType, input.tex);
    float4 textureColor2 = shaderTexture[1].Sample(SampleType, input.tex);

    float4 bumpMap;
    float3 bumpNormal;

    //从范围[0,1]转换到[-1,1],因为默认法向图我们用[0,1]的这种方式打开
    bumpMap  = (textureColor2 * 2.0f) - 1.0f;
    N = input.worldnormal + bumpMap.x*input.worldtangent + bumpMap.y*input.worldbinormal;
    N = normalize(N);

    程序执行后,我们按R键,可以得到下面的结果:

    image

    因为使用的是面法向,我们再看侧面,有着不同效果,:

    image

    完整的代码请参考:

    工程文件myTutorialD3D11_37

    代码下载:

    https://files.cnblogs.com/mikewolf2002/d3d1127-28.zip

    https://files.cnblogs.com/mikewolf2002/pictures.zip

  • 相关阅读:
    Struts2快速后台验证 使用
    Python发送邮件
    【Python】【Flask】前端调用后端方法
    后台参数验证的几种方式
    使用 jQuery 进行前端验证
    postman接口测试——笔记
    安全测试
    jQuery 是javascript的一个库(常用插件、处理器)
    javascript 的 事件类型(事件)
    JavaScript的 基本数据类型---对象
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/2461372.html
Copyright © 2011-2022 走看看