通过three.js + shader 生成高度地图
使用自定义着色器读取到当前位置信息的颜色值来生成当前高度。
准备
两张图,一张展示材质,一张生成高度的材质
高度是黑白构成的一张图,通过图片的灰度来生成高度。
开始
生成地球
生成地球模型
// threejs
const options = {
radius: 100, // 地球的半径
segments: 640, // 地球的分段数 数量越高 地球精度越高
map: './images/earth.jpg', // 地球材质
bump: './images/earthbump.jpg' // 生成高度材质
};
// 生成球类几何
const geometry = new THREE.SphereBufferGeometry(options.radius, options.segments, options.segments);
// 使用自定义着色器
const material = new THREE.ShaderMaterial({
uniforms: {
u_radius: {
value: options.radius // 半径
},
u_height: {
value: 5 // 生成的高度
},
u_map: {
value: new THREE.TextureLoader().load(options.map) // 贴图
},
u_bump: {
value: new THREE.TextureLoader().load(options.bump) // 高度图
},
u_color: {
value: new THREE.Color('rgb(255, 255, 255)')
},
u_opacity: {
value: 1.0
}
},
transparent: true,
vertexShader: earthShader.vertexShader, // 顶点着色器
fragmentShader: earthShader.fragmentShader, // 片元着色器
});
const plane = new THREE.Mesh(geometry, material);
顶点与片元
const earthShader = {
vertexShader: `
varying vec4 v_color; // 用来存储当前顶点颜色
varying vec2 v_uv; // UV
uniform float u_height; // 生成的高度
uniform float u_radius; // 半径
uniform sampler2D u_bump; // 高度图
// 插值计算
float lerp(float x, float y, float t) {
return (1.0 - t) * x + t * y;
}
// 获得当前向量与中心点的距离
float glength(vec3 p) {
return sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
}
// 传入当前向量 需要返回的长度
vec3 setLength(vec3 p, float length) {
vec3 c_position = p;
float scale = length / glength(c_position);
c_position.x *= scale;
c_position.y *= scale;
c_position.z *= scale;
return c_position;
}
void main() {
v_uv = uv; // uv
v_color = texture2D(u_bump, uv); // 生成当前高度信息
float c_height = v_color.r * u_height; // 生成当前的高度 当前的灰度r值 * 基础高度
vec3 vposition = setLength(position, u_radius + c_height); // 生成新的向量 离中心距离为当前基础半径+生成的高度
// 传递position
vec4 mPosition = modelViewMatrix * vec4(vposition, 1.0);
gl_Position = projectionMatrix * mPosition;
}
`,
fragmentShader: `
uniform float u_opacity; // 透明度
uniform vec3 u_color; // 基础颜色
varying vec2 v_uv; // UV
uniform sampler2D u_map; // 基础材质
void main() {
gl_FragColor = vec4(u_color, u_opacity) * texture2D(u_map, v_uv);
}
`
}
生成
打个广告:可以进QQ群(1082834010)讨论