下面是关于“CesiumJS源码杂谈之从光到Uniform”的完整攻略的详细讲解。
前置知识
在讲解这个话题之前,需要对一些基本的知识有一定的了解。包括:WebGL的基础知识、Shader的基础知识、CesiumJS的基础知识等。
从光开始
在WebGL的渲染过程中,光是非常重要的一个环节。CesiumJS中的光源主要有以下几种:
sun
:太阳光。moon
:月球光。pointLight
:点光源光。spotLight
:聚光灯光。
在CesiumJS中,光源的渲染是通过Shader来实现的。常见的光照Shader有PBR
和BlinnPhong
两种。
其中,BlinnPhong
是比较常用的光照模型。它可以通过Shader中的Uniform等变量来获取光源信息,并进行计算,最终得出物体在光照下的表现。
Uniform
在Shader中,Uniform是一类可以被纹理以外的外部数据修改的变量。
在CesiumJS源码中,Uniform主要是通过ShaderProgram
来实现的。其中,ShaderProgram
是一个Shader程序的封装,用于管理Shader中的变量。
在ShaderProgram
中,Uniform主要包括两种类型的变量:
- 向量类型:包括vec2、vec3、vec4等等。
- 矩阵类型:包括mat2、mat3、mat4等等。
在使用Uniform之前,首先需要在Shader中使用uniform
关键字来声明和定义这些变量。然后,在JavaScript代码中获取这些Uniform变量的位置,并通过gl.uniformXXX
系列函数来设置Uniform变量的值。
下面是一个使用Uniform的示例:
uniform mat4 u_ModelViewProjectionMatrix;
void main()
{
gl_Position = u_ModelViewProjectionMatrix * vec4(a_Position, 1.0);
}
在JavaScript代码中,获取Uniform变量的位置,并设置其值:
var modelViewProjectionMatrixLoc = gl.getUniformLocation(shaderProgram, "u_ModelViewProjectionMatrix");
gl.uniformMatrix4fv(modelViewProjectionMatrixLoc, false, modelViewProjectionMatrix);
示例说明
下面,通过两条示例来具体说明“从光到Uniform”的攻略。
示例1:添加太阳光源
在CesiumJS中,要添加太阳光源,需要在对应的UIView中创建Sun对象,并设置其属性。
在Shader中,需要通过Uniform来获取太阳光源的信息。
具体步骤如下:
- 在UIView中创建Sun对象,并设置其颜色、方向等属性。
var sun = new Cesium.Sun();
sun.color = new Cesium.Color(1.0, 1.0, 1.0);
sun.direction = Cesium.Cartesian3.normalize(new Cesium.Cartesian3(1.0, 1.0, 1.0));
- 在Shader中声明和定义uniform变量,用于接收太阳光的方向和颜色信息。
uniform vec3 u_SunDirection;
uniform vec3 u_SunColor;
- 在Shader中计算太阳光的光照强度,并将其作为输出。
vec3 sunLightColor = u_SunColor * max(dot(-v_Normal, u_SunDirection), 0.0);
- 在JavaScript代码中获取uniform变量的位置,并设置其值。
var sunDirectionLoc = gl.getUniformLocation(shaderProgram, "u_SunDirection");
var sunColorLoc = gl.getUniformLocation(shaderProgram, "u_SunColor");
gl.uniform3fv(sunDirectionLoc, sun.direction);
gl.uniform3fv(sunColorLoc, sun.color.toRgb());
示例2:实现法线贴图
在3D场景中,法线贴图(Normal Map)可以用来增强物体表面的细节感。
在CesiumJS中,要实现法线贴图,需要在ShaderProgram中添加Texture类型的Uniform,并且在Shader中计算出法向量和切向量,最终计算出使用法线贴图之后的颜色信息。
具体步骤如下:
- 在ShaderProgram中添加Texture类型的Uniform。
var program = new Cesium.ShaderProgram({
vertexShaderSource : vertexShaderSource,
fragmentShaderSource : fragmentShaderSource,
uniformMap : {
u_ColorMap: colorMap,
u_NormalMap: normalMap,
u_WorldMatrix: function() {
return Cesium.Matrix4.IDENTITY;
}
}
});
- 在Shader中声明和定义uniform变量,用于接收ColorMap和NormalMap的信息。
uniform sampler2D u_ColorMap;
uniform sampler2D u_NormalMap;
- 在Shader中计算出使用法线贴图之后的法向量和切向量,并计算出最终的颜色信息。
// 计算使用法线贴图之后的法向量和切向量
vec3 normal = texture2D(u_NormalMap, v_TexCoord).rgb * 2.0 - 1.0;
mat3 TBN = mat3(v_Tangent, v_Bitangent, v_Normal);
vec3 normalTangent = normalize(TBN * normal);
// 计算光源对物体的影响
vec3 ambient = u_AmbientColor.rgb * u_AmbientIntensity;
vec3 diffuse = texture2D(u_ColorMap, v_TexCoord).rgb * max(dot(normalTangent, u_LightDirection), 0.0);
// 计算最终的颜色信息
gl_FragColor = vec4(ambient + diffuse, 1.0);
- 在JavaScript代码中加载ColorMap和NormalMap,并设置其值。
var colorMap = new Cesium.Texture({
context: gl,
source: "/textures/colorMap.png",
flipY: false
});
var normalMap = new Cesium.Texture({
context: gl,
source: "/textures/normalMap.png",
flipY: false
});
program.uniforms.u_ColorMap = colorMap;
program.uniforms.u_NormalMap = normalMap;
以上就是从光到Uniform的攻略及两个示例的具体实现。希望可以帮助你更好地了解CesiumJS中的Shader和Uniform的使用。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:CesiumJS源码杂谈之从光到 Uniform - Python技术站