首页 > 其他分享 >着色

着色

时间:2023-10-01 15:11:09浏览次数:24  
标签:法线 像素 着色 shading 纹理 pixel

着色 shading

对于每一个shading point
赋予每个像素点:明暗或者颜色
对一个物体添加材质的过程
着色过程是只考虑单独物体,不考虑其他物体造成的光线遮挡,所以着色完成后之后有明暗,颜色,不会有阴影
考虑局部
image
shading point所在的平面的法线与光线的夹角(法线向量与光线向量的夹角)导致了这个表面的明暗变化

Blinn-Phone反射模型:漫反射+高光+环境光照

漫反射

光在漫反射的平面上反射后是均匀的,观察效果与观察位置无关
光源到反射平面的能量在平面上的作用后
Lambertian(Diffuse)Shading

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

Ld:人眼接受的漫反射光 diffusely reflected light
kd:diffuse coefficient(color) 着色点的吸收率
max(0,n·l):着色点能接受到的能量
I/r²:光到达着色点的能量,
点光源能量守恒,在一个球体内,每个球面的能量相同
image

高光 specular

image
高光产生原因:对于一个shading point 镜面反射方向与观察方向足够接近的时候会表现出高光。

为了求解高光的数学表达,引入h向量,该向量为入射向量和观测向量的角平分线,其与shading point的法线方向的夹角,就是镜面反射向量与观测向量的夹角。由于其数学表达式易求。
image

\[h = \frac{l+v}{||l+v||}\\ L_s = k_s (\frac{I}{r^2})max(0,n\cdot h)^p \]

注意到这个角度有一个指数,添加这个指数的原因是为了使得高光更加贴合实际,比如如果角度为45°,应该没有什么高光效果,但其余弦仍然是一个较大的值。
image

环境光照

假设任何一个点从各处环境接受的光照是相同的

\[L_a = k_a \cdot I_a \]

与入射方向和观测方向无关,一般为一个常数

Blinn Phone模型

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

image
观测点对shading point的距离是不会影响效果,而光源对shading point的距离会影响效果

着色频率

对所有shading point 进行着色
三种处理方式

  • Flat shading
    将物体分为多个平面,如果将这个平面视为shading point进行shading得到的着色效果
    image

  • Gouraud shading
    对每个平面的顶点当作shading point进行着色,然后对平面内的点进行插值计算颜色
    image

  • Phone shading
    对平面内每一个像素当作shading point进行着色,其法线方向主要是通过平面顶点的法线插值得到,从而进行着色
    image

三者随着平面的划分越多,差别越小
image

求取顶点的法线

  • 当目标模型是一个圆或者球时,顶点的法线就是圆心(球心)与该点的连线的单位向量
  • 对于一般的目标模型,一个顶点一般为多个三角形(划分的平面)的顶点,可以求出每个三角形平面的法线方向,然后加权平均得到该顶点的法线

\[N_v = \frac{\sum _i N_i}{||\sum _i N_i||} \]

image

每个像素的法线

已知顶点求取两点中间的各点法线,利用重心坐标

渲染(实时渲染)管线

管线pipeline:从场景到图片的过程
输入空间的点->投影->点形成三角形->光栅化形成像素->对像素着色->最终屏幕上的图片颜色
image

Shader->控制顶点或者像素是如何着色的代码

  • 一些管线步骤下的具体操作:
    vetex processing: MVP变换,gouraud shading,纹理(贴图Texture mapping)
    rasterization: 采样,反走样
    fragment processing: Z-buffer,phone shading,纹理(贴图Texture mapping)

Shader Programs

GPU允许自己编程控制顶点或者像素如何着色,这个shader应该是通用的,不需要调用for循环。下面以一个opengl的简洁版对像素点只用漫反射的着色举例

//全局变量
uniform sampler2D myTexture;
uniform vec3 lightDir;
//定义法线
varing vec3 norm;
//uv为纹理上的坐标
varing vec2 uv;
//每个像素如何着色
void diffuseShader(){
  //计算漫反射系数
  vec3 kd;

  //与纹理相关
  kd = texture2d(myTextur,uv);
  //与入射光线和法线的夹角余弦相乘,其余两个变量均为1
  kd *= clamp(dot(-lightDir, norm),0.0,1.0);
  //返回到opengl的变量中输出该像素的颜色
  gl_FragColor = vec4(kd,1.0);
}

在线shader编程

纹理Texture Mapping

作用:定义物体上任何一个点的特有的属性
纹理为一张二维图,贴图。
将一个三维物体展开为二维物体,并且使得每一个划分的三角形与二维贴图上的三角形一一对应,这样就获得了三维图形的每一个三角形的纹理就是它的属性。
二维贴图一般的范围是1×1的正方形大小。每一个三角形在纹理上对应了一个坐标uv。良好的纹理是可以复用的,并且前后左右相互可以完美拼接。

插值

求得三角形顶点值后,如何求取平滑的内部值,使用重心坐标,计算三角形内的点与顶点关系,然后将这个关系应用到其他情况(比如纹理,深度等)
一个与三角形同平面的点可以这样表示

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

如果\(\alpha,\beta,\gamma\)都是非负的,那么这个点就在三角形内部。
有两种方法来计算\(\alpha,\beta,\gamma\)的值,第一种是利用面积比
image

第二种是利用坐标,其实就是将叉积面积求解展开

\[\alpha = \frac{-(x-x_B)(y_C-y_B)+(y-y_B)(x_C-x_B)}{-(x_A-x_B)(y_C-y_B)+(y_A-y_B)(x_C-x_B)}\\ \beta = \frac{-(x-x_C)(y_A-y_C)+(y-y_C)(x_A-x_C)}{-(x_B-x_C)(y_A-y_C)+(y_B-y_C)(x_A-x_C)}\\ \gamma = 1-\alpha-\beta \]

接下来就要利用\(\alpha,\beta,\gamma\)来插值三角形内部的属性,比如着色,深度,纹理等\(V = \alpha V_A+\beta V_B+\gamma V_C\)
注意:重心坐标在投影变换后会发生改变,对于深度的插值,所使用的重心坐标应当是投影之前在三维空间的重心坐标。

理想情况下,对于每一个像素点恰好有一个对应的纹理,我们只需要把纹理坐标(u,v)的值赋值给像素坐标(x,y)就可以了,但实际情况比较复杂,主要有两种情况:第一种为纹理图案的尺寸比整个屏幕小,第二种情况就是纹理图案的尺寸比整个屏幕大

为了方便处理,我们将纹理也分成块状称为texel

纹理图案小的情况

不经过处理,可能会导致多个像素pixel使用同一个texel,图像锯齿状严重。
一种简单的处理方式为Bilinear,双线性插值,对于下方这样一个pixel中心点(红点),在texel上的位置,如果不处理,那么这个texel所包含的所用pixel中心点都会被赋以相同的颜色,而为了求取相对准确的pixel,利用将它围住的4个texel做双线性插值。
image

定义相关的texel和一些间距如下图
image

插值相关公式\(lerp(x,v_0,v_1) = v_0+x(v_1-v_0)\),所以先求取纵坐标方向上的插值

\[u_0 = lerp(s,u_{00},u_{01})\\ u_1 = lerp(s,u_{01},u_{11}) \]

最终坐标就是\((x,y) = lerp(t,u_0,u_1)\),这个(x,y)就是pixel相对准确的纹理值

纹理图案较大的情况

具体表现为在近处,因为一个像素无法包含一个纹理,导致锯齿状,在远处一个像素包含了多个纹理,而最终表现仅仅是区域内中间纹理的值,导致摩尔纹的出现
image

可以发现实际上就是采样问题,只不过之前是物体投影在pixel上被采样,现在是pixel在texel上被采样,其实也是物体投影,因为物体投影经过光栅化后,就通过pixels来组成了。
如果利用超分辨率,是可以解决的,但是消耗过大,超分辨其实就是利用将一个pixel分成多个子Pixel,然后子pixel去寻找合适的texel然后平均。那么有没有一种方法可以直接获得一个区域的平均值呢?
那就是范围查询,范围查询和点查询都是属于查询类算法,点查询就如同之前的双线性插值,根据多个点求解一个点的值。而范围查询就是查找这个范围的平均值,最大值,最小值等。
我们现在主要利用mipmap来求解平均值--fast approx.(not accurate) only square

mipmap

利用一张图生成一系列的图,每一张图都是上一张图的一半。
image

除去原始的第一张,剩余缩小的图加起来所需的多余容量为1/3,然后mimap相当于一个散列表,将每次的图片存储起来,索引值为层数。原始图片为0.
image

如何使用mipmap在纹理映射中

image

上图左边为光栅化图形,uv为纹理坐标,右边为像素点映射到纹理坐标上的结果,我们利用Mipmap求取的就是图中红点和蓝点的纹理值。那么如何确定该像素点在纹理图上的覆盖区域呢。
使用红点举例,左下角的红点,在光栅化图上有上和右两个红点,投影在纹理图上也是相似位置,然后求取在纹理图上上点与该点的距离,右点与该点的距离,选择最大值,成为该点的square边长
image
求取这个正方形边长后,就需要根据这个正方形的边长L,在mipmap中查询平均值,平均值就是当Mipmap的square变为1×1时。而什么时候变成1×1呢,层数\(D = log_2L\)。
例如,当L是包含了4×4个texel时,通过Mipmap,第一次之后变为2×2,第二次变为1×1,此时的mipmap图像就是该边长为L的square的平均值。

回到实际中,当物体离我们比较近,一个square的包含的可能就是1×1的texel不需要平均,我们看到也比较清晰,而当离我们比较远,一个square包含的可能就是n×n的texel通过mipmap,就显得模糊。那么随之而来的又有两个问题,第一个是变换不连续,第二个是远处会非常模糊。

  • 解决不连续问题:利用插值
    不连续问题的原因:我们的层数是整数分散的,0,1,2,...但图片是连续的。
    解决:比如求解1.8层,首先在光栅化上每个点在每一层纹理投影上都有自己的位置,我们对代求的光栅化上的一个点它的实际mipmap层数是1.8层,那么我们通过双线性插值,求得他在第1层和第2层上的值,然后再利用这两个值,在层与层之间插值
    image

该图为光栅化图,不是纹理uv图,图中黑点表示pixel的中心点,红点表示任意非pixel中心点的点

  • 远处模糊问题 overblur
    image

主要原因:远处一个像素实际投影在uv图上的为一个细长的斜的长方形,导致其所需要的square的L较大,使得其模糊过度。
image

解决方法:

  1. 部分解决:各向异性过滤,就是增加按长 ,宽分别缩小而不是等比例缩小
    image

mipmap的作用实际是对角线,相当于增加分析情况(pixel),来避免模糊,可查询的内容更多
内存开销是原本的3倍。
2. EWA :对于斜着的长方形
将每个图形分割为多个圆形,然后每次查询都是多次查询

标签:法线,像素,着色,shading,纹理,pixel
From: https://www.cnblogs.com/XTG111/p/17738862.html

相关文章

  • openGL学习<四>、着色器
    1//2//Createdbysryon2021/7/6.3//4#include<glad/glad.h>5#include<GLFW/glfw3.h>6#include<iostream>7#include<cmath>8usingnamespacestd;910voidframebuffer_size_callback(GLFWwindow*window,......
  • kitti彩色地图拼接<二>、单帧着色
    一、数据准备与处理这里使用的是kitti数据集中:2011_10_03_drive_0047_sync.zip、2011_10_03_calib.zip。直接在命令行解压上述两个压缩包:1unzip2011_10_03_calib.zip2unzip2011_10_03_drive_0047_sync.zip解压后效果如下:   三个txt文件分别是相关外参数,即:相机......
  • 乳胶漆着色防踩坑
     乳胶漆什么颜色好看?  你自己喜欢什么颜色就是好看,  乳胶漆千万别跟风刷网红色,很容易过时和后悔,  装修一套房子,至少住好几年,  1,所有的乳胶漆颜色都是以白色为底,以红黄蓝三原色进行调制  大部分网红色都加了黄,而且最后容易退色也是黄 ......
  • 【配色优化】基于遗传算法进行图形着色优化附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • OpenGL入门——着色器类
    着色器的编写、编译、管理是个很繁琐的事。所以就需要写一个类,这个类可以从文件读取着色器源码,可以编译链接它们,可以对它们进行错误检测,可以设置Uniform值。 1.类的声明#pragmaonce#include<glad/glad.h>#include<string>#include<fstream>#include<sstream>#inc......
  • OpenGL入门——着色器
    前面几节简单使用了一下着色器 现在详细解释一下着色器和着色器语言(GLSL) 1.着色器着色器是运行在GPU上的小程序,它们之间不能互相通信,唯一的沟通只有输入和输出。 2.GLSL着色器的开头是声明版本,接着是输入和输出变量、uniform和main函数。每个着色器的入口点都是mai......
  • 【论文翻译】线图、着色与色数近似
    前言在港中文的暑研快结束的时候,由于大家快没事干了,一个本地的同学就给我分享了一个简单但不失趣味的图论定理,于是记在这里。记号与约定除特殊约定外,下文中所有变量均取正整数。对于图\(G\),称\(V_G,E_G\)为其点集和边集。在上下文明了的情况下,下标\(G\)会被忽略。为了......
  • 表面着色器的一些问题
    问题①:在表面着色器中修改顶点信息——#pragmasurfacesurfLambertvertex:vert/***********/voidvert(inoutappdata_fullv,outInputo){UNITY_INITIALIZE_OUTPUT(Input,o);/**********/}appdata_full是unity给我们的输入结构体,另外还有一些unity......
  • 5.Shading(着色与渲染管线)
    着色(shading)定义作用于一个物体的材质。着色不考虑其他物体的存在,所以着色不考虑阴影。布林冯反射模型Blinn-PhongReflectanceModel最基础的反射模型Specularhighlights(镜面反射)Diffusereflection(漫反射)Ambientlighting(环境照明)定义观测基础信息开展研......
  • 记录--Threejs-着色器实现一个水波纹
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助hree.js是一个基于WebGL的JavaScript3D库,用于创建和渲染3D图形场景。一、图像渲染过程1、webGLwebGL:WebGL是一种基于JavaScriptAPI的图形库,它允许在浏览器中进行高性能的3D图形渲染。webGL的......