Loading

着色2

着色

模型-投影变换:物体变为标准立方体中
视口变换:3D物体变为2D平面
光栅化:绘制物体在2D平面上
着色:对物体应用材质 -- apply a material to an object
材质在光照作用下表现出来的颜色
Bling-Phone模型光照会出现的情况:漫反射 + 高光 + 环境光照

Shading Point

考虑的光照最简模型。一个接受光照的平面,其主要有4个参数
法线:n
观测方向:v
光照方向:l
表面属性:(材质)
着色的局部性 着色不会产生阴影,他只考虑物体自己,当在考虑时,会在空间中去掉其他物体

漫反射

光照方向与Shading Point 法线的夹角余弦cosθ=ln决定了光源的吸收情况

点光源的能量在距离上的衰减

点光源周围可以看作为一圈一圈的等势线,距离光源r的点能够接受到的能量为I=I0r2

Lambertian Diffuse Shading -- 漫反射的计算结果

Ld=kdI0r2max(0,nl)

max(0,nl)表示Shading Point 能够接受到的能量,与0比大小,为了避免余弦为负值带来的无意义情况
I0r2表示能够到达Shading Point 的能量大小,随着距离衰减
kd diffuse coefficient 主要由物体材质决定
可以看出在漫反射计算公式中,并没有考虑观测向量v对结果的影响,因为对于漫反射来说从四面八方看到的结果应该是一样的

高光

观测方向接近镜面反射方向
光照方向在Shading Point 上存在一个镜面反射向量,当该向量与观测方向接近时,将表现出高光
等价于
Shading Point的法线向量与入射向量和观测向量的半程向量(两个向量组成的角的角平分线)接近

h=v+l||v+l||Ls=ksI0r2max(0,nh)p

p次幂让高光范围减小

环境光照

假设任何点接受到的环境光照是相同的Ia

La=kaIa

Blinn-Phone 着色模型

L=Ld+Ls+La=kdI0r2max(0,nl)+ksI0r2max(0,nh)p+kaIa

着色频率

flat shading

利用一个三角形面的法线来计算着色

Gouraud Shading

利用一个三角形的三个顶点法线计算顶点颜色,然后插值计算三角形内部的颜色

for(每个三角形)
{
  color P0;
  color P1;
  color P2;
  for(三角形中的每个像素)
  {
    //计算该像素在三角形中的重心坐标
    color pixelc = P0*x + P1*y + P2*z;
    setcolor(pixel,pixelc);
  }
}

根据三角形面求解顶点法线

一个顶点会被多个三角形面共用,所以该顶点法线就为 每个面法线的平均

Nv=iNi||iNi||

Phone Shading

对每个像素通过三角形的三个顶点插值计算法线,然后利用该法线计算每个像素的颜色

for(每个三角形)
{
  normal P0;
  normal P1;
  normal P2;
  for(三角形中的每个像素)
  {
    //计算该像素在三角形中的重心坐标
    normal pixeln = P0*x + P1*y + P2*z;
    setcolor(pixel,getcolor(pixeln));
  }
}

实时渲染管线

  1. 输入3D空间中的点
  2. MVP变换 + 视口变换 3D点变到2D平面上
  3. 点连接为三角形 obj文件有相应的定义
  4. 光栅化--离散三角形为像素块
  5. 对像素块着色
  6. 输出

纹理映射

定义任何一个点的属性,一般存在一个纹理贴图
以obj文件来说,obj文件内可能会定义给出每个顶点的uv坐标,可以通过读取uv坐标值,从而在纹理贴图中寻找到该点的属性
一般来说,纹理贴图的坐标是由RGB来表示的即其坐标范围在(0,255)之间,而经过变换后的物体坐标在(-1,1)之间,所以为了对应,需要对纹理坐标进行处理

x=2x2551

此时再根据之前求得的重心坐标,利用三角形的三个顶点求得每个像素点的纹理值,即可

重心坐标

用于插值计算。对于与一个三角形处于同一平面的点(x,y)都可以由三角形的三个顶点线性组合得到

(x,y)=αA+βB+γCα+β+γ=1

αβγ 就是点(x,y)对于这个三角形的重心坐标
对于在三角形内部的一点,αβγ 全为非负的

求解重心坐标

//_v为三角形三个顶点组成的数组,x,y为点
    Vector3f a (_v[1].x()-_v[0].x(),_v[2].x()-_v[0].x(),_v[0].x()-x);
    Vector3f b (_v[1].y()-_v[0].y(),_v[2].y()-_v[0].y(),_v[0].y()-y);
    //叉乘
    Vector3f c (a.y()*b.z()-a.z()*b.y(),a.z()*b.x()-a.x()*b.z(),a.x()*b.y()-a.y()*b.x());

    //点(x,y)的重心坐标
    Vector3f res (1.f-(c.x()+c.y())/c.z(),c.y()/c.z(),c.x()/c.z());

重心坐标的应用

对于三角形内部任何一个点的属性(颜色,法线等)都可以通过重心坐标与三角形的三个顶点对应属性相乘得到
重心坐标在投影变换下的属性会发生改变,对于待渲染物体的重心坐标,应当在3D空间中求得

如何应用纹理

for(每一个像素)
{
  //根据插值计算出该像素的纹理坐标u,v
  (u,v) = cal(pixel);
  //根据uv在贴图上查询颜色
  color = get_(u,v);
  //设置该像素的颜色
  set_(pixel,color);
}

纹理贴图过小-- 放大

纹理贴图较小 --> 拉伸纹理贴图至物体图像大小
--> 一个texel 对应 多个pixel --> 导致一个pixel在求取颜色时,(u,v)坐标不是整数 --> 而采用四舍五入的方法,导致图像精度的降低

解决办法:双线性插值

利用包围该pixel的4个texel进行插值求解颜色。相当于是二维平面的重心坐标。假设有当前pixel坐标为(x0,y0),可以求得

//小于x0,y0的最大整数, 大于x0,y0的最小整数
int minx;
int miny;
int maxx;
int many;

float s = x0-minx;
float t = y0-miny;
//对于在x方向可以插值
color c1 = lerp(s,cminx_miny,cmaxx_miny);
color c2 = lerp(s,cminx_maxy,cmaxx_maxy);

//然后利用c1 和 c2 在 y方向上插值
color res = lerp(t,c1,c2);

纹理贴图过大 -- 压缩

导致一个pixel 对应 多个 texel -> pixel中心求得的颜色不能代替多个texel的颜色

解决办法1:MSAA

将一个pixel划分为多个采样块

解决办法2:MipMap

将点查询变为范围查询,MipMap -- 快 不准确,方形
原理:将纹理先行处理,即不断降低1倍的分辨率,存储纹理值,得到log2(n)张图片。对于每个pixel映射到纹理贴图上的面积选择对应的MipMap那么就可以直接查询获得当前pixel的纹理值。

如何确定选择哪一张图片

对于pixel p0其上方和右方有pixel p1和p2,三点映射到纹理贴图上,可以求得u1u0 和 u2u0的距离两者距离最大值L,选择log2L的图片纹理即为当前p0的纹理。
比如当前L=4说明当前映射覆盖了4×4的texel,需要经过2次降低,才会得到1块texel,那么选择该mipmap即为平均值。

对于非整数层的MipMap

通过双线性插值求解
首先在上下两个整数层求解对于pixel的纹理,然后再通过层与层之间的重心坐标求解非整数层的纹理

MipMap问题

过度模糊

  1. 解决方法:各向异性过滤
    Mipmap是纹理长宽同比缩小,考虑一个矩阵,相当于只存储了对角线的元素,而再添加其余的缩小样本,将解决只能处理正方形区域的问题。
    但仍然不能解决斜着的映射图像。

凹凸贴图 Bump Texture

对法线的扰动实现渲染出凹凸的现象。凹凸贴图存储的是每个pixel的高度信息,使得可以通过相邻两个pixel的高度差计算得到当前pixel的法线

考虑2D平面

原始点P的法线n(p) = (0,1)
对于点P在凹凸贴图上可以求得其切线 dp = c*[h(p+1)-h(p)]
利用该条切线求得凹凸贴图影响下的 法线变换 n(p) = (-dp,1).normal;

考虑3D空间

原始点P的法线n(p) = (0,0,1)
切线有2个方向:u,v

dpdu=c1[h(u+1)h(u)]dpdv=c2[h(v+1)h(v)]

然后再根据该切线求得P点的法线 n(p) = (dpdu,dpdv,1).normal;

真实的法线

定义的原始法线都为(0,0,1),而实际法线并不是这个数值
在一个微元上,可以认为法线是(0,0,1)在求得由凹凸贴图更改的法线后,再利用原始法线的向量值进行矩阵变换求得真实改动后的法线

位移贴图 Displayment Texture

实际改变点的位置

posted @   XTG111  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示