• 立方体贴图shade计算


    正常的平面贴图是根据mesh顶点找到对应的uv坐标,然后根据重心坐标插值计算三角面内每个点的uv坐标值。最后根据uv坐标值查找平面贴图上的颜色值。
    立方体贴图的6个面分别为6张图片,我们怎么根据mesh面上的坐标值来计算对应平面上的uv坐标值。
    基本算法是根据原点与mesh面上点坐标(x,y,z)的射线和立方体贴图的交点作为uv坐标。

    这里介绍一下uv坐标计算的数学推导过程
    直线的表示方程为 p ⃗ = o ⃗ + t d ⃗ \vec{p}=\vec{o}+t\vec{d} p =o +td ,这里 o ⃗ \vec{o} o d ⃗ \vec{d} d 为向量, o ⃗ \vec{o} o 表示起始点,这里为原点; d ⃗ \vec{d} d 表示直线的方向,这里为mesh面上的3维点坐标与原点的方向 n o r m ( ( x , y , z ) − ( 0 , 0 , 0 ) ) = n o r m ( x , y , z ) norm((x,y,z)-(0,0,0))=norm(x,y,z) norm((x,y,z)(0,0,0))=norm(x,y,z);t为需要计算的值。 代入后直线表示方程为 p ⃗ = t ∗ n o r m ( x , y , z ) \vec{p}=t*norm(x,y,z) p =tnorm(x,y,z)
    平面的表示方程为 ( p ⃗ − p 0 ⃗ ) ⋅ n ⃗ = 0 (\vec{p}-\vec{p0})\cdot \vec{n}=0 (p p0 )n =0,其中 p ⃗ \vec{p} p 为需要求的点坐标, p 0 ⃗ \vec{p0} p0 为已知的平面上任一点; n ⃗ \vec{n} n 为平面的法向量。 以立方体贴图的右平面举例,其法向量 n ⃗ \vec{n} n 为x轴的方向(1,0,0), p 0 ⃗ \vec{p0} p0 取(1,0,0),代入后平面表示方程为 ( p ⃗ − ( 1 , 0 , 0 ) ) ⋅ ( 1 , 0 , 0 ) = 0 (\vec{p}-(1,0,0))\cdot(1,0,0)=0 (p (1,0,0))(1,0,0)=0
    直线与平面的交点表示该点同时满足直线和平面表示方程,将上述两个方程联立,得到
    ( t ∗ n o r m ( x , y , z ) − ( 1 , 0 , 0 ) ) ⋅ ( 1 , 0 , 0 ) = 0 (t*norm(x,y,z)-(1,0,0))\cdot(1,0,0)=0 (tnorm(x,y,z)(1,0,0))(1,0,0)=0,简化后得 t ∗ x n o r m − 1 = 0 t*xnorm-1=0 txnorm1=0 t = 1 / x n o r m t=1/xnorm t=1/xnorm,其中xnorm表示(x,y,z)归一化后x分量的值。
    将t代入直线方程可以得到y,z的坐标为 ynorm/xnorm、znorm/xnorm。因为在右平面上x值都为1,最后的uv坐标值为 ( y n o r m / x n o r m , z n o r m / x n o r m ) (ynorm/xnorm, znorm/xnorm) ynorm/xnorm,znorm/xnorm)
    然后再以左平面为例,左平面的法向量 n ⃗ \vec{n} n 为(-1,0,0), p 0 ⃗ \vec{p0} p0 取(-1,0,0),联立方程为 ( t ∗ n o r m ( x , y , z ) − ( − 1 , 0 , 0 ) ) ⋅ ( − 1 , 0 , 0 ) = 0 (t*norm(x,y,z)-(-1,0,0))\cdot(-1,0,0)=0 (tnorm(x,y,z)(1,0,0))(1,0,0)=0,可得 t = − 1 / x n o r m t=-1/xnorm t=1/xnorm,uv坐标值为 ( − y n o r m / x n o r m , − z n o r m / x n o r m ) (-ynorm/xnorm, -znorm/xnorm) (ynorm/xnorm,znorm/xnorm)

    综上可得简化后的计算过程如下:
    设mesh上坐标点为(x,y,z),取这3个分量中绝对值最大的分量表示位于哪个平面上,然后分别用其他两个分量除以该分量绝对值表示uv坐标。如点(3,-8,-5),表示位于立方体的下方平面上,uv坐标为(3/8,-5/8)
    在opengl中我们要根据上述计算过程来实现uv坐标的计算。在unity中有samplerCUBE,可以调用texCUBE用mesh坐标直接从立方体贴图中获取颜色值。代码如下所示,注意mesh的坐标值都是用的物体局部坐标系,不是世界坐标系。

    Shader "CubemapSampler"
    {
        Properties
        {
            _CubeMap("CubeMap", CUBE) = ""{}
        }
        SubShader
        {
            Pass
            {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
    
                #include "UnityCG.cginc"
    
                struct appdata
                {
                    float4 vertex : POSITION;   
                    float3 normal : NORMAL;
                };
    
                struct v2f
                {
                    float4 vertex : SV_POSITION;
                    float4 vertexLocal : TEXCOORD1;
                };
    
                v2f vert (appdata v)
                {
                    v2f o;
                    o.vertexLocal = v.vertex;
                    o.vertex = UnityObjectToClipPos(v.vertex);
    
                    return o;
                }
    
                samplerCUBE _CubeMap;
                fixed4 frag (v2f i) : SV_Target
                {
                    fixed4 col = texCUBE(_CubeMap, normalize(i.vertexLocal.xyz));
                    return col;
                }
                ENDCG
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
  • 相关阅读:
    计算机毕业设计Java高校企业实训系统(源码+系统+mysql数据库+Lw文档)
    【CAN】CAN基础概念5
    springboot停车场车辆定位管理可视化分析系统的设计与实现毕业设计源码101702
    作为一名普通的java程序员,我想和大家分享一下4年来的工作内容
    Git常用命令
    Java单元测试 - mock静态方法
    零信任架构分析【扬帆】
    安利一波C2工具
    鸿蒙开发游戏(一)---大鱼吃小鱼(界面部署)
    NodeJs 实践之他说
  • 原文地址:https://blog.csdn.net/lipku/article/details/127941355