2022-10-28 webgl操作地球
2022-10-28 本文已影响0人
MrSwilder
一、原理
1.在canvas上鼠标拖拽时,根据距离设置相对于初始化的x和y角度
2.在每一帧绘制时,根据角度生成旋转矩阵,用视图矩阵乘以旋转矩阵
二、效果

三、代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>地球</title>
<style>
body {
margin: 0;
text-align: center;
}
#canvas {
margin: 0;
}
</style>
</head>
<body onload="main()">
<canvas id="canvas" height="800" width="1200"></canvas>
</body>
<script src="/lib/webgl-utils.js"></script>
<script src="/lib/webgl-debug.js"></script>
<script src="/lib/cuon-utils.js"></script>
<script src="/lib/cuon-matrix.js"></script>
<script src="/lib/helper.js"></script>
<script src="/geometry/SphereGeometry.js"></script>
<script src="/texture/Texture2D.js"></script>
<script>
//顶点着色器
var VSHADER_SOURCE = /*glsl*/`
attribute vec2 a_Uv;
attribute vec4 a_Position;
uniform mat4 u_MvpMatrix;
varying vec2 v_Uv;
void main(){
gl_Position = u_MvpMatrix*a_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(){
gl_FragColor = texture2D(u_Texture,vec2(v_Uv.x,1.0-v_Uv.y));
// gl_FragColor=vec4(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, 100);
const rotateViewMatrix=new Matrix4()
var currentAngle = [0,0]
async function main() {
if (!gl) {
console.log("你的浏览器不支持WebGL");
return;
}
const 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,30,30)
const sphere= sphereGeometry.create()
//绘制纹理
const texture=Texture2D.initTexture(gl,'./image/earth.jpg', 0)
//设置底色
gl.clearColor(0.0, 0.0, 0.0, 1.0);
var tick = function () {
viewMatrix.setLookAt(0, 0, 5, 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)
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
}
}
function draw(gl, sphere) {
//设置模型矩阵的相关信息
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.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const length=sphere.length
//绘制图形
gl.drawElements(gl.TRIANGLES, length, gl.UNSIGNED_SHORT, 0);
}
</script>
</html>