理论、技巧、辅助记录文档

向量点积:|a||b|*sin

点积还有数学表现的形式,如下:数学形式:x*x' + y*y' +z*z'


向量叉积:|a||b|*cos
叉积还有矩阵表现的形式,如下:
给定直角坐标系的单位向量i,j,k满足下列等式:
i×j=k;
j×k=i ;
k×i=j ;
通过这些规则,两个向量的叉积的坐标可以方便地计算出来,不需要考虑任何角度:设
a= [a1, a2, a3] =a1i+ a2j+ a3k;
b= [b1,b2,b3]=b1i+ b2j+ b3k ;
则a × b= [a2b3-a3b2,a3b1-a1b3, a1b2-a2b1]。

与数量积的区别
注:向量积 ≠向量的积(向量的积一般指点乘)
一定要清晰地区分开向量积(矢积)与数量积(标积)。见下表。
中国官方账号。深入浅出、直观明了地分享数学之美。资助页面:www.patreon.com/3blue1brown


左手右手坐标系
首先我们看看下图,认识什么是左手坐标系,右手坐标系。

左边是左手坐标系,右边就是右手坐标系了。其实,左手还是右手的选择都没关系,只是一个简单的转换。回忆化设备坐标使用的左手坐标系统,而在OpenGL的早期版本,默认使用的却是右手系统,其使用z的负值增加表示距离增加。这就是为什么Android的Matrix会默认生成反转z的矩阵。所以Android系统默认情况都是用 右手坐标系


光栅化
OpenGL通过光栅化的过程把每个点、直线以及三角形分解成大量的小片段,他们可以映射到移动设备显示屏的像素上,从而生成一幅图像。这些片段类似于显示屏上的像素,每一个都包含单一的纯色。为了表示颜色,每个片段都有4个分量:其中红色、绿色、蓝色用来表示颜色,阿尔法(alpha)分量用于表示透明度;
下图可以见到OpenGL怎样把一条直线光栅化为了一个片段集合。显示系统通常会把这些片段直接映射到屏幕上的像素,结果一个片段就对应一个像素;然而,并不总是这样,一个超高分辨率的设备可能需要使用较大的片段,以减少GPU工作负荷。





一些基本的glsl概念
1.attribute变量
attribute变量是只能在vertex(顶点着色器) shader中使用的变量。(不能在fragment shader中声明attribute变量,
也不能被fragment shader中使用)
vec4的时候,默认前三个分量是0,第四个分量是1
一般用attribute变量来表示一些顶点的数据,如:顶点坐标,法线,纹理坐标,顶点颜色等。
在application中,一般用函数glBindAttribLocation()来绑定每个attribute变量的位置,然后用函数
glVertexAttribPointer()为每个attribute变量赋值。

2.uniform变量
uniform变量是外部application程序传递给(vertex和fragment)shader的变量。因此它是application通过
函数glUniform**()函数赋值的。在(vertex和fragment)shader程序内部,uniform变量就像是C语言里面
的常量(const ),它不能被shader程序修改。(shader只能用,不能改)
如果uniform变量在vertex和fragment两者之间声明方式完全一样,则它可以在vertex和fragment共享使用。
(相当于一个被vertex和fragment shader共享的全局变量)
vec4的时候,默认都是0
uniform变量一般用来表示:变换矩阵,材质,光照参数和颜色等信息。

3.varying变量
varying变量是vertex和fragment shader之间做数据传递用的。一般vertex shader修改varying变量的值,
然后fragment shader使用该varying变量的值。因此varying变量在vertex和fragment shader二者之间的声
明必须是一致的。application不能使用此变量。

4、shader内置变量:

gl_Position: 用于vertex shader, 写顶点位置;被图元收集、裁剪等固定操作功能所使用;其内部声明是:highp vec4 gl_Position;

gl_PointSize: 用于vertex shader, 写光栅化后的点大小,像素个数;其内部声明是:mediump float gl_Position;

gl_FragColor: 用于Fragment shader,写fragment color;被后续的固定管线使用;mediump vec4 gl_FragColor;

gl_FragData: 用于Fragment shader,是个数组,写gl_FragData[n] 为data n;被后续的固定管线使用;mediump vec4 gl_FragData[gl_MaxDrawBuffers];

gl_FragColor和gl_FragData是互斥的,不会同时写入;

gl_FragCoord: 用于Fragment shader,只读, Fragment相对于窗口的坐标位置 x,y,z,1/w; 这个是固定管线图元差值后产生的;z 是深度值; mediump vec4 gl_FragCoord;

gl_FrontFacing: 用于判断 fragment是否属于 front-facing primitive;只读;bool gl_FrontFacing;   

gl_PointCoord: 仅用于 point primitive; mediump vec2 gl_PointCoord;


5、shader内置常量:

const mediump int gl_MaxVertexAttribs = 8;

const mediump int gl_MaxVertexUniformVectors = 128;

const mediump int gl_MaxVaryingVectors = 8;

const mediump int gl_MaxVertexTextureImageUnits = 0;

const mediump int gl_MaxCombinedTextureImageUnits = 8;

const mediump int gl_MaxTextureImageUnits = 8;

const mediump int gl_MaxFragmentUnitformVectors = 16;

const mediump int gl_MaxDrawBuffers = 1;


6、shader内置函数:

    一般默认都用弧度;

radians(degree) : 角度变弧度;

degrees(radian) : 弧度变角度;

sin(angle), cos(angle), tan(angle)

asin(x): arc sine, 返回弧度 [-PI/2, PI/2];

acos(x): arc cosine,返回弧度 [0, PI];

atan(y, x): arc tangent, 返回弧度 [-PI, PI];

atan(y/x): arc tangent, 返回弧度 [-PI/2, PI/2];

   

pow(x, y): x的y次方;

exp(x): 指数, log(x):

exp2(x): 2的x次方, log2(x):

sqrt(x): x的根号; inversesqrt(x): x根号的倒数

abs(x): 绝对值

sign(x): 符号, 1, 0 或 -1

floor(x): 底部取整

ceil(x): 顶部取整

fract(x): 取小数部分

mod(x, y): 取模, x - y*floor(x/y)

min(x, y): 取最小值

max(x, y): 取最大值

clamp(x, min, max):  min(max(x, min), max);

mix(x, y, a): x, y的线性混叠, x(1-a) + y*a;

length(x): 向量长度

distance(p0, p1): 两点距离, length(p0-p1);

dot(x, y): 点积,各分量分别相乘 后 相加

cross(x, y): 差积,x[1]*y[2]-y[1]*x[2], x[2]*y[0] - y[2]*x[0], x[0]*y[1] - y[0]*x[1]

normalize(x): 归一化, length(x)=1;

faceforward(N, I, Nref): 如 dot(Nref, I)< 0则N, 否则 -N

reflect(I, N): I的反射方向, I -2*dot(N, I)*N, N必须先归一化

refract(I, N, eta): 折射,k=1.0-eta*eta*(1.0 - dot(N, I) * dot(N, I)); 如k<0.0 则0.0,否则 eta*I - (eta*dot(N, I)+sqrt(k))*N

matrixCompMult(matX, matY): 矩阵相乘, 每个分量 自行相乘, 即 r[i][j] = x[i][j]*y[i][j];矩阵线性相乘,直接用 *

lessThan(vecX, vecY): 向量 每个分量比较 x < y

lessThanEqual(vecX, vecY): 向量 每个分量比较 x<=y

greaterThan(vecX, vecY): 向量 每个分量比较 x>y

greaterThanEqual(vecX, vecY): 向量 每个分量比较 x>=y

equal(vecX, vecY): 向量 每个分量比较 x==y

notEqual(vecX, vexY): 向量 每个分量比较 x!=y

any(bvecX): 只要有一个分量是true, 则true

all(bvecX): 所有分量是true, 则true

not(bvecX): 所有分量取反

   

texture2D(sampler2D, coord): texture lookup

texture2D(sampler2D, coord, bias): LOD bias, mip-mapped texture

texture2DProj(sampler2D, coord):

texture2DProj(sampler2D, coord, bias):

texture2DLod(sampler2D, coord, lod):

texture2DProjLod(sampler2D, coord, lod):

textureCube(samplerCube, coord):

textureCube(samplerCube, coord, bias):

textureCubeLod(samplerCube, coord, lod):   





把三维顶点视为三元组(x,y,z)。现在引入一个新的分量w,得到向量(x,y,z,w)。请先记住以下两点(稍后我们会给出解释):
若w==1,则向量(x, y, z, 1)为空间中的点。
若w==0,则向量(x, y, z, 0)为方向。
(请务必将此牢记在心。)



着色器自定义的输入变量是区分大小写的
viewModelProjectionMatrix
视图 模型 投影
视图矩阵:用于改变观察视觉的位置。一般第一人称射击游戏的场景移动和滚轮缩放就是改变视图矩阵
模型矩阵:一般是针对物体而言的放大缩小平移选择的操作。
投影矩阵:一般用于窗口大小变化引起的长宽比例尺所造成的物体变形,然后使用投影矩阵来弥补比例尺改变的差距。





一些基本的矩阵数学概念
单位矩阵(Identity matrix)
单位矩阵很特殊,它什么也不做。单位矩阵的身份和自然数”1”一样基础而重要,因此在这里要特别提及一下。

用C++表示:
glm::mat4 myIdentityMatrix = glm::mat4(1.0);

平移矩阵(Translation matrices)
平移矩阵是最简单的变换矩阵。平移矩阵是这样的:

用C++,GLM表示:
glm::mat4 myMatrix = glm::translate(10.0f, 0.0f, 0.0f);
glm::vec4 myVector(10.0f, 10.0f, 10.0f, 0.0f);
glm::vec4 transformedVector = myMatrix * myVector; 

缩放矩阵(Scaling matrices)
缩放矩阵也很简单:
例如把一个向量(点或方向皆可)沿各方向放大2倍:
用C++表示:
// Use #include <glm/gtc/matrix_transform.hpp> and #include <glm/gtx/transform.hpp>
glm::mat4 myScalingMatrix = glm::scale(2.0f, 2.0f ,2.0f);

旋转矩阵(Rotation matrices)
旋转矩阵比较复杂。这里略过细节,因为日常应用中,您并不需要知道矩阵的内部构造。 想了解更多,请看 “矩阵和四元组常见问题” (这个资源很热门,应该有中文版吧)。
用C++表示:
// Use #include <glm/gtc/matrix_transform.hpp> and #include <glm/gtx/transform.hpp>
glm::vec3 myRotationAxis( ??, ??, ??);
glm::rotate( angle_in_degrees, myRotationAxis );

累积变换
前面已经学习了如何旋转、平移和缩放向量。把这些矩阵相乘就能将它们组合起来,例如:
TransformedVector = TranslationMatrix * RotationMatrix * ScaleMatrix * OriginalVector;
!!!注意!!!这行代码 首先 执行缩放, 接着 旋转, 最后 才是平移。这就是矩阵乘法的工作方式。
变换的顺序不同,得出的结果也不同。您不妨亲自尝试一下: - 向前一步(小心别磕着爱机)然后左转; - 左转,然后向前一步
实际上,上述顺序正是你在变换游戏角色或者其他物体时所需的:先缩放;再调整方向;最后平移。例如,假设有个船的模型(为简化,略去旋转):
  • 错误做法:
  • 按(10, 0, 0)平移船体。船体中心目前距离原点10个单位。
  • 将船体放大2倍。以原点为参照,每个坐标都变成原来的2倍,就出问题了。最后您得到的是一艘放大的船,但其中心位于2*10=20。这并非您预期的结果。
  • 正确做法:
  • 将船体放大2倍,得到一艘中心位于原点的大船。
  • 平移船体。船大小不变,移动距离也正确。
用C++,GLM表示:
glm::mat4 myModelMatrix = myTranslationMatrix * myRotationMatrix * myScaleMatrix;
glm::vec4 myTransformedVector = myModelMatrix * myOriginalVector;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值