首页 > 其他分享 >着色2

着色2

时间:2024-03-09 16:11:06浏览次数:30  
标签:贴图 法线 cdot 纹理 着色 三角形 pixel

着色

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

Shading Point

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

漫反射

光照方向与Shading Point 法线的夹角余弦\(cos\theta = l \cdot n\)决定了光源的吸收情况

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

点光源周围可以看作为一圈一圈的等势线,距离光源r的点能够接受到的能量为\(I =\frac{I_0}{r^2}\)

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

\[L_d = k_d \cdot \frac{I_0}{r^2} \cdot max(0,n \cdot l) \]

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

高光

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

\[半程向量:h = \frac{v+l}{||v+l||} 高光强度:L_s = k_s \cdot \frac{I_0}{r^2} \cdot max(0,n \cdot h)^p \]

p次幂让高光范围减小

环境光照

假设任何点接受到的环境光照是相同的\(I_a\)

\[L_a = k_a \cdot I_a \]

Blinn-Phone 着色模型

\[L = L_d + L_s + L_a\\ = k_d \cdot \frac{I_0}{r^2} \cdot max(0,n \cdot l) + k_s \cdot \frac{I_0}{r^2} \cdot max(0,n \cdot h)^p + k_a \cdot I_a \]

着色频率

flat shading

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

Gouraud Shading

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

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

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

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

\[N_v = \frac{\sum_iN_i}{||\sum_iN_i||} \]

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 = \frac{2*x}{255}-1 \]

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

重心坐标

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

\[(x,y) = \alpha A + \beta B + \gamma C \alpha + \beta + \gamma = 1 \]

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

求解重心坐标

//_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坐标为\((x_0,y_0)\),可以求得

//小于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倍的分辨率,存储纹理值,得到\(log_2(n)\)张图片。对于每个pixel映射到纹理贴图上的面积选择对应的MipMap那么就可以直接查询获得当前pixel的纹理值。

如何确定选择哪一张图片

对于pixel p0其上方和右方有pixel p1和p2,三点映射到纹理贴图上,可以求得u1u0 和 u2u0的距离两者距离最大值L,选择\(log_2L\)的图片纹理即为当前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

\[\frac{dp}{du} = c_1*[h(u+1)-h(u)]\\ \frac{dp}{dv} = c_2*[h(v+1)-h(v)] \]

然后再根据该切线求得P点的法线 n(p) = \((-\frac{dp}{du},-\frac{dp}{dv},1)\).normal;

真实的法线

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

位移贴图 Displayment Texture

实际改变点的位置

标签:贴图,法线,cdot,纹理,着色,三角形,pixel
From: https://www.cnblogs.com/XTG111/p/18062868

相关文章

  • 着色
    着色模型-投影变换:物体变为标准立方体中视口变换:3D物体变为2D平面光栅化:绘制物体在2D平面上着色:对物体应用材质--applyamaterialtoanobject材质在光照作用下表现出来的颜色Bling-Phone模型光照会出现的情况:漫反射+高光+环境光照ShadingPoint考虑的光照最简模......
  • 内置着色器
    内置着色器(普通渲染管线)FX:光照和玻璃特效。GUI和UI:用于显示用户界面图形。移动端(Mobile):适用于移动设备的简化高性能着色器。大自然(Nature):用于树木和地形。粒子(Particles):粒子系统特效。天空盒(Skybox):用于渲染所有几何体后面的背景环境精灵(Sprites):与2D精灵系统结......
  • 增加颜色和着色
    一.平滑着色  我们已经知道,在OpenGL中,我们只能画点,直线和三角形,并且所有物体都是以他们为基础构建的。既然受限于这三个基本图元,那么我们如何用许多不同的颜色和着色表达更复杂的场景呢?我们能使用的一个方法就是使用上百万个小三角形,每个三角形的颜色都不同,这样就可以看到一副......
  • 编译着色器并在屏幕上绘图
    一.前言  本篇文章会继续上一篇文章开始的工作,在这篇文章中,我们首先会加载并编译前面定义的着色器,然后把他们链接在一起放在OpenGL的一个程序里,接下来就可以使用这个着色器程序在屏幕上绘制空气曲棍球桌子结构了。 二.加载着色器1.我们已经为着色器写了代码,下一步则要把......
  • Threejs利用着色器编写动态飞线特效
    一、导语动态飞线特效是可视化数据地图中常见的需求之一,鼠标点击的区块作为终点,从其他区块飞线至点击区块,附带颜色变换或者结合粒子动画二、分析利用创建3点来构成贝塞尔曲线,形成线段利用着色器材质来按照线段以及时间点变化来变化线段的颜色形成动画三、上基础代码//贝塞尔曲线......
  • 计算机图形:可编程着色器
    目录OpenGL渲染流水线固定功能流水线可编程功能流水线顶点着色器片元着色器几何着色器曲面细分着色器OpenGL着色语言(GLSL)着色器结构OpenGL中使用着色器基本数据类型矢量矩阵结构、数组控制结构GLSL函数与OpenGL通信OpenGL渲染流水线图形API提供对硬件操作的标准接口,对程序员提......
  • Chrome浏览器对不同标签页进行着色
    方法1:使用标签组Chrome浏览器的标签组功能允许您将标签分组在一起,并为每个组分配不同的颜色。要创建标签组,请右键单击一个标签,然后选择“添加到新组”。您还可以将标签拖放到另一个标签上以将其添加到组中。要更改标签组的颜色,请单击标签组的圆点,然后选择“更改颜色”。您可以......
  • 着色器
    概念:attribute用于向顶点着色器,传输几何图形待处理的各种属性,例如:顶点坐标,UV坐标等等注意:attribute只能用于顶点着色器中,值在运行时会从几何图形属性中取值点击查看代码functioncreateBasic(){//目标:着色器变量-attribute使用//作用:用于向顶点着色器中传入几......
  • threejs的坐标渲染和着色
    点击查看代码functioncreateBasic(){//目标:了解顶点坐标绘制正方形//1.准备BufferGemotry缓冲几何图形//2.准备32位浮点数的数组,定义矩形的顶点位置//3.准备BufferAttribute属性缓冲对象,保存几何图形的属性值//4.把属性设置给几何图形对象//......
  • OpenGL 着色器详解
    1.GLSL语言glsl语言是用来编写着色器的,通过一段一段包含main函数的程序片段,告诉渲染引擎怎么去渲染内容。glsl语言的语法有点类似c语言风格,只是增加了一些特有的关键字来修饰变量,下面是一个着色器基本的程序结构:首先声明的是GLSL的版本号和模式,然后就是声明变量。像其他语言......