AFrame中渲染器的写法
渲染器在AFrame中作为材质的一个属性使用,全局注册后可以作为一种材质配置在material下
我们知道WebGL是基于OpenGL的,而OpenGL用GLSL(OpenGL Shading Language)这一着色器语言完成着色器工作,因此,WebGL的着色器程序大致与GLSL相同。着色器通常分为几何着色器(Geometry Shader)、顶点着色器(Vertex Shader)、片元着色器(Fragment Shader)等等。由于WebGL基于OpenGL ES 2.0,因此WebGL支持的着色器只有顶点着色器与片元着色器。
渲染器的全局注册
AFRAME.registerShader('my-custom', {
// 用户自定义参数的定义 可以通过Material传参数
schema: {
color: {type: 'color', is: 'uniform', default: 'red'},
opacity: {type: 'number', is: 'uniform', default: 1.0}
},
// 点元着色器
vertexShader:
` varying vec2 vUv;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`,
// 片元着色器
fragmentShader:
` varying vec2 vUv;
// 定义的方法
// 数据类型 方法名(){}
// 主函数
void main() {
gl_FragColor = vec4( color, opacity );
}`,
});
- Aframe中本身使用的数据格式为下表中的 A-Frame Type,即Schema中定义的type格式
- 着色器是一段在GPU中执行的一种Clike语法,顶点着色器对于每个顶点调用一次,片元着色器对于每个片元调用一次。但着色器(点元、片元)语法是GLSL的数据类型。在声明时要注意对应。
- 一些变量的声明方法:
uniform 数据类型 变量名 通常用于用户自定义的参数,每个顶点/片元对应相同的值(CPU 和GPU的桥梁)
varying 数据类型 变量名 只能在点元着色器中获取/计算的参数,最终要传给片元着色器
attribute 数据类型 变量名 从JavaScript代码传递到顶点着色器中,每个顶点对应不同的值
常量用const声明就可以 - 定义时间参数时,GLSL是以毫秒为单位,需要进行转化后再使用
- float 型和 int型不会进行自动转换,浮点数写成 *.0
- precision定义精度
Aframe中支持的数据结构
- 没错 基于three.js开发的Aframe使用的两种数据类型一个是AFrame本身的数据类型。一个是OpenGL的数据类型。和three.js没有半毛钱的关系
A-Frame Type | THREE Type | GLSL Shader Type |
---|---|---|
array | v3 | vec3 |
color | v3 | vec3 |
int | i | int |
number | f | float |
map | t | map |
time | f | float (milliseconds) |
vec2 | v2 | vec2 |
vec3 | v3 | vec3 |
vec4 | v4 | vec4 |
定义在渲染器外的常量
定义在渲染器外且也符合GLSL语法的常量在点元/片元着色器中也可以使用
以点元着色器举例:
const pnoise3 = `……`
vertexShader:
pnoise3 +`
// 点元着色器的内容
`
内置参数
three.js中的一些默认参数,在Aframe中不用声明,可以直接使用,声明会报错,仅限点元着色器
至少我现在还没有用到过attribute声明变量的情况
- attribute vec3 position 顶点在物体中的坐标位置
- attribute vec3 normal 法向量
- attribute vec2 uv uv 坐标,可用 uv.x 和 uv.y 分别获取顶点的横纵坐标
- uniform mat3 normalMatrix; 法向矩阵,modelViewMatrix 的反转
- uniform mat4 model modelMatrix; 模型空间矩阵
- uniform mat4 viewMatrix; 视图空间矩阵
- uniform mat4 modelViewMatrix; 模型空间矩阵和视图空间矩阵的组合 (viewMatrix * modelMatrix)
- uniform mat4 projectionMatrix; 投影矩阵,用于转换 3D 坐标到 2D 平面
- uniform vec3 cameraPosition; 镜头在 world space 中的位置
点元着色器
- uv 横纵坐标
点元着色器中可以直接获得uv(不需要声明), 但是片元着色器中没有,需要通过varying方法抛出。
它代表了该顶点在UV映射时的横纵坐标。简单地说,一个物体的模型可能很复杂,对其贴图的一个简单有效的方法就是UV映射,将每个面片贴的图统一映射到一张纹理上,记录每个面片贴图在纹理上对应的位置。
uv的计算原理:
vec2 uv = fragCoord.xy / iResolution.xy // 将坐标转换到【0,1】之间
uv = 2.0 * uv - 1.0;// 将坐标转换到[-1,1]之间
- normal 法线
vec3 vNormal = normalize(normalMatrix * normal);//归一化将法向量映射到 [0,1] 间
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
利用投影矩阵、模型矩阵计算三维模型在二维显示屏上的坐标。position也没有预先定义过,position也是Three.js为我们提供的一个方便。position是顶点在物体坐标系(而不是世界坐标系)中的位置。这就意味着,一个正方体位于世界坐标系的(2, 0, 0)与位于(0, 0, 0)将不会改变任何顶点的position,这个position是相对于正方体的锚点而言的。
通过调节position调节着色器的渲染位置,通过后面的参数(1.0)调节模型渲染的大小
//一些光照属性在点元着色器中的应用
uniform vec3 u_LightColor;
uniform vec3 u_LightDirction;
uniform vec3 u_AmbientLight;
uniform vec3 u_Color;
varying vec4 v_Color;
void main(){
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
//计算变换后的法向量并归一化
vec3 newnormal=normalize(vec3(normalMatrix*normal));
//计算光线方向和法向量的点积
float nDotL=max(dot(u_LightDirction,newnormal),0.0);
//计算漫反射光的颜色
vec3 diffuse=u_LightColor*u_Color.rgb*nDotL;
//计算环境光产生的反射光的颜色
vec3 ambient=u_AmbientLight*u_Color.rgb;
//将以上两者相加作为最终的颜色,需要传给片元着色器渲染
v_Color=vec4(diffuse+ambient,1.0);
片元着色器
由于Aframe单一Buffer好像没什么需要介绍的
一些没有验证的猜想:
- 转换顶点坐标到视图空间
void main(){
vec3 vertex = vec3(1.0,1.0,1.0);
vec4 vertexCameraSpace = modelViewMatrix * vec4(vertex,1.0);
}
void main() {
vec3 light = vec3(1.0,1.0,1.0);
vec4 lightCameraSpace = viewMatrix * vec4(vertex,1.0);
}
- 计算光照
//顶点着色器
varying vec3 vNormal;
void main(){
vNormal = normal;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
//片元着色器
varying vec3 vNormal;
void main() {
vec3 color = vec3(1, 1, 0);
vec3 light = normalize(vec3(0, 10, 10));
float dProd = max(0.0,dot(vNormal, light));
gl_FragColor = vec4(color.r * dProd, color.g * dProd, color.b * dProd, 1.0);
}