zoukankan      html  css  js  c++  java
  • CubeMap视线反射方向计算详解

    其基本原理很多例子上有讲到。下面给出一些比较合适的链接

    http://developer.nvidia.com/object/cube_map_ogl_tutorial.html    NVIDIA官网上的 Opengl Cube texture mapping
    http://www.zwqxin.com/archives/shaderglsl/review-cube-mapping-shader.html  某位兄弟的个人BLOG。
    以上两位都适合OPENGL控。
    本文给出一个DX HLSL例子。并解释了反射方向计算的数学模型。希望能给大家一定的帮助。
    CUBE映射主要分为两步:
    一、在VS中根据法线和观察位置计算反射方向,并且得到观察空间中的反射方向。
    反射方向有两种计算方法。
    1、在世界坐标系空间中计算,然后再将计算到的反射方向转换到观察空间。 这要求我们转入观察位置。
    2、在观察空间中进行计算,此时观察位置已经为0,0,0,于是不需要传入观察位置,并且得到的向量即为所求。本文的代码采用此种方式。


    值得说明的一点是。在进行计算时,入射方向和反射方向以及法线方向并未要求一定要单位化。
    二、用这个反射方向在PS中对CUBE纹理进行采样。

    下面是一个对反射向量计算的通用求解过程。

    我们假设顶点位置为Pos 即点O,视点为Eye 即点A (均为同一坐标系空间)
    那么,我们的观察方向便是Pos-Eye, 即AO。而我们的反射方向便是OC。 法线为OB或OD方向。
    下面我们来看看反射方向的求法
    而由上图可知,OC = AD ;
    而又由OA+AD = OD;OD = 2*OB;可得
     OC = 2*OB-OA;
    而OA = Eye-Pos;
    可得,OC = 2*OB-(Eye-Pos);
    那么,最后我们可以看出,只要求出OB,则可以求出OC。
    而从图上我们可以看到OB即为OA在(法线)OD上的投影。 由此可知, OB = dot(OA,Normal);
    于是可以写出如下公式。
    float3 EyeR = Eye - Pos;  float3 reflectVec = 2*dot(EyeR,Normal)*Normal - EyeR;

    当然,你也可以使用高级语言中的reflect函数来求反射
    在HLSL中。
    ret reflect(i, n)

    v = i - 2 * dot(i, n) * n

    上面的公式中。i为入射方向,v为反射方向,n为法线。
    由于EyeR 为观察方向的反方向,即入射方向的反方向
    所以 reflectVec = reflect(-EyeR,Normal)即可求得。

    最后将reflectVec转换到观察空间,然后对CUBE纹理进行采样即可。

    下面是HLSL中我使用的代码。该代码在D3D SDK的HDRCubeMap.fx中可见。

    //VS
    float4x4 matView;
    float4x4 matProjection;
    struct VS_INPUT 
    {
       float4 Position : POSITION0;
       float2 Texcoord : TEXCOORD0;
       float3 Normal :NORMAL;
    }
    ;

    struct VS_OUTPUT 
    {
       float4 Position : POSITION0;
       float3 Texcoord : TEXCOORD0;
    }
    ;

    VS_OUTPUT vs_main( VS_INPUT Input )
    {
       VS_OUTPUT Output;
       Output.Position 
    = mul(Input.Position,matView);
       
       float3 vN 
    = mul(Input.Normal,matView);
       float3 vEyeR 
    = -normalize(Output.Position);
      
       Output.Texcoord 
    = 2 * dot( vEyeR, vN ) * vN - vEyeR;
       
       Output.Position 
    = mul(Output.Position,matProjection);
       
    return( Output );
    }


    //PS
    samplerCUBE baseMap;

    struct PS_INPUT 
    {
       float3 Texcoord : TEXCOORD0;
       
    }
    ;

    float4 ps_main( PS_INPUT Input ) : COLOR0
    {
       
    return texCUBE( baseMap, Input.Texcoord );
       
    }


    在此对float3 vEyeR = -normalize(Output.Position);作一下解释。
    我们上面讲到的 EyeR的计算为Eye- Pos。 但是,由于N和Pos已转入摄相机空间。则此时的Eye为(0,0,0)。 并且,不一定要单位化vEyeR
    所以上面的解法可以让你不用再传入观察点。
    最后,我们来围观一下效果。




    我是在RenderMonkey中测试的SHADER,所以,上面贴出来的,即为原码。
    下面是用到的cubemap图的样子


    OK,谢谢欣赏,欢迎交流
    GMAIL :BoYueGame

  • 相关阅读:
    使用git pull文件时和本地文件冲突怎么办?
    Git回滚代码到某个commit
    PHP如何在页面中原样输出HTML代码
    git 创建本地分支、提交到远程分支
    php mysqli扩展之预处理
    htmlspecialchars() 函数过滤XSS的问题
    PHP json_encode里面经常用到的 JSON_UNESCAPED_UNICODE和JSON_UNESCAPED_SLASHES
    javascript学习笔记——Array
    javascript学习笔记——Object
    javascript的底层实现学习总结
  • 原文地址:https://www.cnblogs.com/qilinzi/p/1929667.html
Copyright © 2011-2022 走看看