games101:四,着色频率、纹理贴图(放大插值、缩小mipmap)+ 作业3

一,着色频率

在这里插入图片描述

1,Flat Shading----逐三角形

面块边缘明显但效率高;
但随着模型复杂度提高,效率降低、效果与其他两种差距减小,见上图。

2,Gouraud Shading----逐顶点

计算与顶点相邻所有面法向量的加权平均(权重与三角形面积有关,看具体实现)
在这里插入图片描述

3,Phong Shading----逐像素

计算出三角形3个顶点的法向量后,插值计算内部每个像素的法向量:
n = α n 0 + β n 1 + γ n 2 n = αn_{0} + βn_{1} + γn_{2} n=αn0+βn1+γn2
其中n0、n1、n2分别是三角形三个顶点的法线向量,α , β , γ为三角形面内任一点的重心坐标,↓。

3.1重心坐标

在这里插入图片描述
在这里插入图片描述

(重心坐标α , β , γ相等时,所在点为三角形重心)


面积不好算,公式可以简化为如下:
在这里插入图片描述

  • 该方法除计算法向量外还可以推广到任意图像属性
  • 重心坐标没有投影不变性!经过投影重心会产生偏移-----不能在投影后的三角形中插值,应该先插值后再投影(逆变换即可),或者使用透视矫正,如下:

3.2透视矫正插值(Perspective-Correct Interpolation)

在这里插入图片描述
以深度Z为例,如图,c->C的投影过程中明显位置有偏移。
由A、B、C与a、b、c坐标斜率相同得到3个式子,由u123坐标符合 u s = u 1 + s ( u 2 − u 1 ) u_{s} = u_{1} +s (u_{2}-u_{1}) us=u1+s(u2u1),X123坐标、Z123坐标同理得到3个式子。解6个式子,最终得
t = s Z 1 s Z 1 + ( 1 − s ) Z 2    ⟹    Z t = 1 s Z 2 + 1 − s Z 1 t = \frac{sZ_{1}}{sZ_{1} + (1-s)Z_{2}} \implies Z_{t} = \frac{1}{ \frac{s}{Z_{2}} + \frac{1-s}{Z_{1}}} t=sZ1+(1s)Z2sZ1Zt=Z2s+Z11s1
同理,重心坐标插值矫正结果:
Z t = 1 α Z A + β Z B + γ Z C Z_{t} = \frac{1}{ \frac{α}{Z_{A}} + \frac{β}{Z_{B}} + \frac{γ}{Z_{C}}} Zt=ZAα+ZBβ+ZCγ1

由以上深度Z的插值结果拓展到任意属性V的插值结果:
V t = ( V 1 Z 1 + s ( V 2 Z 2 + V 1 Z 1 ) ) V_{t} = (\frac{V_{1}}{Z_{1}} + s( \frac{V_{2}}{Z_{2}} + \frac{V_{1}}{Z_{1}} )) Vt=(Z1V1+s(Z2V2+Z1V1))
V t = ( α V A Z A + β V B Z B + γ V C Z C ) / 1 Z t V_{t} = (α\frac{V_{A}}{Z_{A}} + β\frac{V_{B}}{Z_{B}} + γ\frac{V_{C}}{Z_{C}} ) /\frac{1}{Z_{t}} Vt=(αZAVA+βZBVB+γZCVC)/Zt1

3.3模型变换中的法线向量

模型变换矩阵为M,则法向量变换矩阵为 ( M − 1 ) T (M^{-1})^T (M1)T

推导过程:
在这里插入图片描述

n T t = 0 = n T M − 1 ⋅ M ⋅ t = ( n T M − 1 ) M t    ⟹    N n T = n T M − 1    ⟹    N n = ( M − 1 ) T n n^{T}t = 0 = n^{T}M^{-1} \cdot M \cdot t=(n^{T}M^{-1})M_{t} \implies N_{n}^T = n^{T}M^{-1} \implies N_{n} = (M^{-1})^Tn nTt=0=nTM1Mt=(nTM1)MtNnT=nTM1Nn=(M1)Tn


二,纹理贴图

1,小纹理放大----双线性插值

小纹理直接放大会出现马赛克现象,一个纹理对应多个像素
在这里插入图片描述

  • 双线性插值:利用周围4个顶点,先计算u1、u2在计算u(方向先后不重要),相当于x、y两个维度插值
    在这里插入图片描述
  • 双三次插值:利用周围16个顶点,做x、y方向插值,每次用4个点做3次的差值

2,大纹理缩小----mipmap

大纹理直接缩小会出现锯齿和摩尔纹现象,多个纹理对应一个像素,采样频率问题。

  • 可以使用超采样方法,如512x超采样,效果不错但效率过低。
  • 也可以从点查询Point Query迈向区域查询Range Query,即mipmap法

mipmap----快速的、近似的、方形的范围查询

将原纹理宽高逐层缩小2倍组成的查询图(纹理内存增加三分之一):
在这里插入图片描述
在这里插入图片描述
计算过程:

  1. 计算每个像素对应的纹理范围位置的最大长度的2底对数D----插值对应的mipmap层数
  2. 对D的向上和向下取整的两个层级插值(避免由于mipmap整数层级产生过渡断层现象)
三线性插值

三线性插值:即双线性插值+mipmap层级之间插值=3个维度

ripmap----各向异性

但mipmap会产生过渡模糊的情况,因为在不规则映射下“方形”限制不太友好。ripmap可以缓解mipmap的“方形”限制,可以查询“长条形”,内存占用增加3倍纹理:
在这里插入图片描述

作业3

blinn-phong光照模型:注意a与d、s的强度不一样

Eigen::Vector3f phong_fragment_shader(const fragment_shader_payload& payload)
{
    Eigen::Vector3f ka = Eigen::Vector3f(0.005, 0.005, 0.005);
    Eigen::Vector3f kd = payload.color;
    Eigen::Vector3f ks = Eigen::Vector3f(0.7937, 0.7937, 0.7937);

    auto l1 = light{{20, 20, 20}, {500, 500, 500}};
    auto l2 = light{{-20, 20, 0}, {500, 500, 500}};

    std::vector<light> lights = {l1, l2};
    Eigen::Vector3f amb_light_intensity{10, 10, 10};
    Eigen::Vector3f eye_pos{0, 0, 10};

    float p = 150;

    Eigen::Vector3f color = payload.color;
    Eigen::Vector3f point = payload.view_pos;
    Eigen::Vector3f normal = payload.normal;

    Eigen::Vector3f result_color = {0, 0, 0};
    
    Eigen::Vector3f La = ka.cwiseProduct(amb_light_intensity);
    result_color += La;
    for (auto& light : lights)
    {
        float r = (light.position - point).norm();
        Eigen::Vector3f l = (light.position - point).normalized();
        Eigen::Vector3f h = ((eye_pos - point).normalized() + l).normalized();
        
        Eigen::Vector3f Ld = kd.cwiseProduct(light.intensity) / pow(r,2) * std::max(normal.dot(l), 0.0f);
        Eigen::Vector3f Ls = ks.cwiseProduct(light.intensity) / pow(r,2) * pow(std::max(normal.dot(h), 0.0f),p);
        
        result_color += (Ld + Ls);
    }

    return result_color * 255.f;
}

凹凸贴图模型:凹凸纹理color值代表法向量增量值,本来应该用一维图表示,这里rgb图用向量长度表示->.norm(),其他注意见作业3助教说明:
在这里插入图片描述

Eigen::Vector3f bump_fragment_shader(const fragment_shader_payload& payload)
{
    
    Eigen::Vector3f ka = Eigen::Vector3f(0.005, 0.005, 0.005);
    Eigen::Vector3f kd = payload.color;
    Eigen::Vector3f ks = Eigen::Vector3f(0.7937, 0.7937, 0.7937);

    auto l1 = light{{20, 20, 20}, {500, 500, 500}};
    auto l2 = light{{-20, 20, 0}, {500, 500, 500}};

    std::vector<light> lights = {l1, l2};
    Eigen::Vector3f amb_light_intensity{10, 10, 10};
    Eigen::Vector3f eye_pos{0, 0, 10};

    float p = 150;

    Eigen::Vector3f color = payload.color; 
    Eigen::Vector3f point = payload.view_pos;
    Eigen::Vector3f normal = payload.normal;


    float kh = 0.2, kn = 0.1;
    

    // TODO: Implement bump mapping here
    // Let n = normal = (x, y, z)
    // Vector t = (x*y/sqrt(x*x+z*z),sqrt(x*x+z*z),z*y/sqrt(x*x+z*z))
    // Vector b = n cross product t
    // Matrix TBN = [t b n]
    // dU = kh * kn * (h(u+1/w,v)-h(u,v))
    // dV = kh * kn * (h(u,v+1/h)-h(u,v))
    // Vector ln = (-dU, -dV, 1)
    // Normal n = normalize(TBN * ln)
    
    float x = normal[0];
    float y = normal[1];
    float z = normal[2];
    Eigen::Vector3f t{x*y/std::sqrt(x*x+z*z),std::sqrt(x*x+z*z),z*y/std::sqrt(x*x+z*z)};
    Eigen::Vector3f b = normal.cross(t);
    Eigen::Matrix3f TBN;
    TBN << t.x(), b.x(), normal.x(),
            t.y(), b.y(), normal.y(),
            t.z(), b.z(), normal.z();

    float w = payload.texture->width, h = payload.texture->height;
    float bumpcolor1 = payload.texture->getColor(payload.tex_coords[0],payload.tex_coords[1]).norm();
    float bumpcolor2 = payload.texture->getColor(payload.tex_coords[0]+1.0f/w,payload.tex_coords[1]).norm();
    float bumpcolor3 = payload.texture->getColor(payload.tex_coords[0],payload.tex_coords[1]+1.0f/h).norm();
    float dU = kh * kn * (bumpcolor2-bumpcolor1);
    float dV = kh * kn * (bumpcolor3-bumpcolor1);

    Eigen::Vector3f ln{-dU, -dV, 1.0f};
    normal = (TBN * ln).normalized();

    Eigen::Vector3f result_color = {0, 0, 0};
    result_color = normal;
    
    return result_color * 255.f;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值