一、原理
1.绘制圆形点,计算到圆心的距离
2.绘制球背面剔除
//开启背面剔除
gl.enable(gl.CULL_FACE)
3.开启多边形偏移解决球遮挡点问题
二、效果
三、代码
//顶点着色器
var VSHADER_SOURCE = /*glsl*/`
attribute vec2 a_Uv;
attribute vec4 a_Position;
uniform mat4 u_MvpMatrix;
varying vec2 v_Uv;
void main(){
vec4 clip_Position=u_MvpMatrix*a_Position;
gl_Position=clip_Position;
v_Uv=a_Uv;
}`;
//片元着色器
var FSHADER_SOURCE = /*glsl*/`
#ifdef GL_ES
precision mediump float;
#endif
uniform sampler2D u_Texture;
varying vec2 v_Uv;
void main(){
vec4 baseColor=texture2D(u_Texture,vec2(fract(1.00-v_Uv.x),v_Uv.y));
gl_FragColor=baseColor;
}`;
var point_VShader =/*glsl*/`
attribute vec3 a_Position;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjectMatrix;
void main(){
gl_Position=u_ProjectMatrix*u_ViewMatrix*vec4(a_Position,1.0);
gl_PointSize=10.0;
}
`
var point_FShader =/*glsl*/`
#ifdef GL_ES
precision mediump float;
#endif
void main(){
float dist=distance(gl_PointCoord,vec2(0.5));
if(dist>0.5){
discard;
}
gl_FragColor=vec4(1.0,0.0,0.0,1.0);
}
`
//声明js需要的相关变量
var canvas = document.getElementById("canvas");
var gl = getWebGLContext(canvas);
//设置视角矩阵的相关信息(视点,视线,上方向)
var viewMatrix = new Matrix4();
//设置透视投影矩阵
var projMatrix = new Matrix4();
projMatrix.setPerspective(30, canvas.width / canvas.height, 0.1, 10);
const rotateViewMatrix = new Matrix4()
let value = 4
var currentAngle = [0, 0]
var program, pointProgram
async function main() {
if (!gl) {
console.log("你的浏览器不支持WebGL");
return;
}
program = createProgram(gl, VSHADER_SOURCE, FSHADER_SOURCE)
if (!program) {
console.error('创建着色器程序失败')
return
}
gl.program = program
gl.useProgram(program)
getVariableLocation()
//绘制球形
const sphereGeometry = new SphereGeometry(gl, 1, 180, 90)
const sphere = sphereGeometry.create()
//绘制纹理
const texture = Texture2D.initTexture(gl, './image/earth.jpg', 0)
pointProgram = createProgram(gl, point_VShader, point_FShader)
if (!pointProgram) {
console.error('创建点着色器失败!')
return
}
gl.program = pointProgram
gl.useProgram(pointProgram)
getVariableLocation()
const arr = []
cities.forEach(city => {
const p = Cartertion3FromDegrees(1, city.value[0] * 1, city.value[1] * 1, 0)
arr.push(p.x, p.y, p.z)
})
// const p1=Cartertion3FromDegrees(1,116,40,0)
// const p2=Cartertion3FromDegrees(1,-100,40,0)
const data = new Float32Array(arr)
//
// console.log(p,p1,p2)
const point_positionBuffer = initArrayBuffer(gl, data, 3, gl.FLOAT, gl.position)
//
var tick = function () {
//设置底色
gl.clearColor(0.0, 0.0, 0.0, 1.0);
viewMatrix.setLookAt(0, 0, value, 0, 0, 0, 0, 1, 0);
rotateViewMatrix.setRotate(currentAngle[1], 1, 0, 0)
rotateViewMatrix.rotate(currentAngle[0], 0, 1, 0)
viewMatrix.multiply(rotateViewMatrix)
draw(gl, sphere, point_positionBuffer)
requestAnimationFrame(tick)
}
tick()
registerMouseEvent()
}
/**
*
* 注册鼠标事件
* */
function registerMouseEvent() {
//是否按下
let isDown = false
let last_X = 0, last_Y = 0
canvas.onmousedown = function (e) {
//获取当前鼠标位置
const x = e.clientX, y = e.clientY
//获取canvas边界范围
const bound = e.target.getBoundingClientRect()
if (bound.left < x && bound.right > x && bound.top < y && bound.bottom > y) {
last_X = x
last_Y = y
isDown = true
}
}
canvas.onmousemove = function (e) {
// console.log('鼠标移动',e)
const x = e.clientX, y = e.clientY
if (isDown) {
const offset_X = x - last_X
const offset_Y = y - last_Y
currentAngle[0] += offset_X / 10
currentAngle[1] += offset_Y / 10
}
last_X = x
last_Y = y
}
canvas.onmouseup = function (e) {
isDown = false
}
canvas.onwheel = function (e) {
if (e.wheelDeltaY === 120) {
value += 0.1
} else {
value -= 0.1
}
}
}
function draw(gl, sphere, point_positionBuffer) {
gl.useProgram(program)
gl.program = program
//设置模型矩阵的相关信息
var modelMatrix = new Matrix4();
var mvpMatrix = new Matrix4()
mvpMatrix.set(projMatrix)
mvpMatrix.multiply(viewMatrix.multiply(modelMatrix));
//将试图矩阵传给u_ViewMatrix变量
gl.uniformMatrix4fv(gl.program.mvpMatrix, false, mvpMatrix.elements);
//开启隐藏面清除
gl.enable(gl.DEPTH_TEST);
//开启背面剔除
gl.enable(gl.CULL_FACE)
//开启多边形偏移
gl.enable(gl.POLYGON_OFFSET_FILL)
//计算偏移量
/*
void WINAPI glPolygonOffset(
GLfloat factor,
GLfloat units
);
*/
gl.polygonOffset(5.0, 1.0)
//清空颜色和深度缓冲区
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const arrayBuffers = sphere.arrayBuffers
arrayBuffers.forEach(arrayBuffer => {
if (arrayBuffer) {
writeAttributeVariable(gl, arrayBuffer.attribute, arrayBuffer)
}
});
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sphere.indexBuffer);
const length = sphere.length
//绘制图形
gl.drawElements(gl.TRIANGLES, length, gl.UNSIGNED_SHORT, 0);
gl.useProgram(pointProgram)
gl.program = pointProgram
//将试图矩阵传给u_ViewMatrix变量
gl.uniformMatrix4fv(gl.program.viewMatrix, false, viewMatrix.elements);
gl.uniformMatrix4fv(gl.program.projectMatrix, false, projMatrix.elements);
writeAttributeVariable(gl, point_positionBuffer.attribute, point_positionBuffer)
gl.drawArrays(gl.POINTS, 0, 360)
}
function toRadian(degree) {
return degree * Math.PI / 180
}
//经纬度转世界坐标
function Cartertion3FromDegrees(r, lon, lat, height) {
const theta = toRadian(90 - lat)
const phi = toRadian(180 - lon)
const x = r * Math.sin(theta) * Math.cos(phi)
const y = r * Math.cos(theta)
const z = r * Math.sin(theta) * Math.sin(phi)
return { x, y, z }
}