注:转载请注明出处
在《WebGL自学课程(3):原生WebGL+ArcGIS JS API绘制旋转地球》一文中讲述了如何利用地图数据绘制地球的轮廓,但是缺少色彩。本文就是想通过贴图的方式让地球穿上一层靓丽的外衣,并可以通过鼠标拖拽等对绘制的地球进行交互式操作。由于本人《WebGL自学课程(4):WebGL矩阵、Camera基础操作》一文中构建了本人自己常用的代码,封装到World.js中,所以在以后的自学课程中都会在文档中引入World.js,以提高开发效率。
本课程所使用的二维贴图如下:
运行效果截图如下:
本文代码.如下:
<!doctype html> <html> <head> <title>第一个纹理Demo</title> <meta http-equiv="Content-Type" content="text/html" /> <meta name="charset" content="utf-8"/> <style type="text/css"> html,body,div{margin:0;padding:0} </style> <script type="text/javascript" src="http://localhost/arcgis_js_api/library/2.7/jsapi/"></script> <script type="text/javascript" src="World.js"></script> <script id="shader-vs" type="x-shader/x-vertex"> attribute vec3 aPosition; attribute vec2 aTextureCoord; varying vec2 vTextureCoord; uniform mat4 uModelView; uniform mat4 uProj; void main() { gl_Position = uProj * uModelView * vec4(aPosition,1.0); vTextureCoord = aTextureCoord; } </script> <script id="shader-fs" type="x-shader/x-fragment"> precision mediump float; varying vec2 vTextureCoord; uniform sampler2D uSampler; void main() { gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)); } </script> <script type="text/javascript"> var R = 10; var canvas = null; var gl = null; var shaderProgram = null; var aPositionLocation; var aTextureCoordLocation; var uModelViewLocation; var uProjLocation; var uSamplerLocation; var vertexPositionBuffer; var textureCoordBuffer; var modelMatrix = new Matrix(); var camera = new PerspectiveCamera(90,1,1.0,200.0); camera.look(new Vertice(0,0,1.5*R),new Vertice(0,0,0),new Vector(0,1,0)); var texture; var bImageLoaded = false; var bMouseDown = false; var handleMouseMove; var previousX=-1; var previousY=-1; function initWebGL(canvas){ try{ gl = canvas.getContext("experimental-webgl",{antialias:true}); } catch(e){ alert("浏览器不支持WebGL!"); } if(!gl) alert("浏览器不支持WebGL!"); } function getShader(gl,id){ var shaderScript = document.getElementById(id); if(!shaderScript) return null; var shader = null; if(shaderScript.type=="x-shader/x-vertex"){ shader = gl.createShader(gl.VERTEX_SHADER); } else if(shaderScript.type=="x-shader/x-fragment"){ shader = gl.createShader(gl.FRAGMENT_SHADER); } else{ return null; } gl.shaderSource(shader,shaderScript.text); gl.compileShader(shader); if(!gl.getShaderParameter(shader,gl.COMPILE_STATUS)){ alert(gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return null; } return shader; } function initShaders(){ var vertexShader = getShader(gl,"shader-vs"); var fragmentShader = getShader(gl,"shader-fs"); shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram,vertexShader); gl.attachShader(shaderProgram,fragmentShader); gl.linkProgram(shaderProgram); if(!gl.getProgramParameter(shaderProgram,gl.LINK_STATUS)){ alert("Could not link program"); gl.deleteProgram(shaderProgram); gl.deleteShader(vertexShader); gl.deleteShader(fragmentShader); return; } gl.useProgram(shaderProgram); aPositionLocation = gl.getAttribLocation(shaderProgram,"aPosition"); gl.enableVertexAttribArray(aPositionLocation); aTextureCoordLocation = gl.getAttribLocation(shaderProgram,"aTextureCoord"); gl.enableVertexAttribArray(aTextureCoordLocation); uModelViewLocation = gl.getUniformLocation(shaderProgram,"uModelView"); uProjLocation = gl.getUniformLocation(shaderProgram,"uProj"); uSamplerLocation = gl.getUniformLocation(shaderProgram,"uSampler"); } function initBuffer(){ vertexPositionBuffer = gl.createBuffer(); textureCoordBuffer = gl.createBuffer(); } function initTexture(name){ texture = gl.createTexture(); texture.image = new Image(); texture.image.onload = function () { handleLoadedTexture(texture); }; texture.image.src = name; } function handleLoadedTexture(texture) { gl.bindTexture(gl.TEXTURE_2D, texture); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.bindTexture(gl.TEXTURE_2D, null); bImageLoaded = true; } function drawEarth(column,row){ var eachLog = 180 / column; var eachLat = 90 / row; for(var i = 0;i < column;i++){ for(var j = 0;j < row;j++){ var log1 = eachLog * i; var log2 = eachLog * (i+1); var lat1 = eachLat * j; var lat2 = eachLat * (j+1); var p1 = getXYZ(log1,lat1,R); var p2 = getXYZ(log2,lat1,R); var p3 = getXYZ(log1,lat2,R); var p4 = getXYZ(log2,lat2,R); var vertices; var textureCoords; //东北半球 vertices = [p1[0],p1[1],p1[2],//左下角点 p2[0],p2[1],p2[2],//右下角点 p3[0],p3[1],p3[2],//左上角点 p4[0],p4[1],p4[2]];//右上角点 textureCoords = [0.5+log1/360,0.5+lat1/180,//左下角点 0.5+log2/360,0.5+lat1/180,//右下角点 0.5+log1/360,0.5+lat2/180,//左上角点 0.5+log2/360,0.5+lat2/180];//右上角点 drawFace(vertices,textureCoords); //东南半球 vertices = [p3[0],-p3[1],p3[2], p4[0],-p4[1],p4[2], p1[0],-p1[1],p1[2], p2[0],-p2[1],p2[2]]; textureCoords = [0.5+log1/360,0.5-lat2/180, 0.5+log2/360,0.5-lat2/180, 0.5+log1/360,0.5-lat1/180, 0.5+log2/360,0.5-lat1/180]; drawFace(vertices,textureCoords); //西北半球 vertices = [-p2[0],p2[1],p2[2], -p1[0],p1[1],p1[2], -p4[0],p4[1],p4[2], -p3[0],p3[1],p3[2]]; textureCoords = [0.5-log2/360,0.5+lat1/180, 0.5-log1/360,0.5+lat1/180, 0.5-log2/360,0.5+lat2/180, 0.5-log1/360,0.5+lat2/180]; drawFace(vertices,textureCoords); //西南半球 vertices = [-p4[0],-p4[1],p4[2], -p3[0],-p3[1],p3[2], -p2[0],-p2[1],p2[2], -p1[0],-p1[1],p1[2]]; textureCoords = [0.5-log2/360,0.5-lat2/180, 0.5-log1/360,0.5-lat2/180, 0.5-log2/360,0.5-lat1/180, 0.5-log1/360,0.5-lat1/180]; drawFace(vertices,textureCoords); } } } function drawFace(vertices,textureCoords){ gl.bindBuffer(gl.ARRAY_BUFFER,vertexPositionBuffer); gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(vertices),gl.STATIC_DRAW); gl.vertexAttribPointer(aPositionLocation,3,gl.FLOAT,false,0,0); gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer); gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(textureCoords),gl.STATIC_DRAW); gl.vertexAttribPointer(aTextureCoordLocation,2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, texture); gl.uniform1i(uSamplerLocation, 0); gl.drawArrays(gl.TRIANGLE_STRIP,0,4); } function getXYZ(longitude,latitude,r){ var vertice = []; var radianLog = Math.PI/180*longitude; var radianLat = Math.PI/180*latitude; var sin1 = Math.sin(radianLog); var cos1 = Math.cos(radianLog); var sin2 = Math.sin(radianLat); var cos2 = Math.cos(radianLat); var x = r*sin1*cos2; var y = r*sin2; var z = r*cos1*cos2; vertice.push(x); vertice.push(y); vertice.push(z); return vertice; } function drawScene(){ gl.viewport(0,0,canvas.width,canvas.height); gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT); gl.uniformMatrix4fv(uModelViewLocation,false,camera.getViewMatrix().multiply(modelMatrix).elements); gl.uniformMatrix4fv(uProjLocation,false,camera.projMatrix.elements); if(bImageLoaded){ drawEarth(20,10); } } function initRequestAnimationFrame(){ window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame || function(callback) { setTimeout(callback, 1000 / 60); }; } function tick() { window.requestAnimationFrame(tick); drawScene(); } function canvasMouseDown(){ bMouseDown = true; handleMouseMove = dojo.connect(dojo.byId("iCanvas"),"onmousemove","canvasMouseMove"); } function canvasMouseMove(e){ var x = e.layerX||e.offsetX; var y = e.layerY||e.offsetY; if(previousX > 0 && previousY > 0){ var changeX = x - previousX; var changeY = y - previousY; var horCameraAngle = canvas.width / canvas.height * camera.fov; var changeHorAngle = changeX / canvas.width * horCameraAngle; var changeVerAngle = changeY / canvas.height * camera.fov; camera.worldRotateY(-changeHorAngle*Math.PI/180); camera.worldRotateX(-changeVerAngle*Math.PI/180); } previousX = x; previousY = y; } function canvasMouseUp(){ bMouseDown = false; dojo.disconnect(handleMouseMove); previousX = -1; previousY = -1; } function startWebGL(){ canvas = document.getElementById("iCanvas"); initWebGL(canvas); initShaders(); initBuffer(); initTexture("earth.jpg"); gl.clearColor(0.9,0.9,0.9,1.0); gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); gl.enable(gl.CULL_FACE);//一定要启用裁剪,否则显示不出立体感 gl.cullFace(gl.BACK);//裁剪掉背面 initRequestAnimationFrame(); tick(); } function init(){ dojo.connect(dojo.byId("iCanvas"),"onmousedown","canvasMouseDown"); dojo.connect(dojo.byId("iCanvas"),"onmouseup","canvasMouseUp"); startWebGL(); } </script> </head> <body onload="init();"> <canvas id="iCanvas" width="600" height="600" style="margin-left:100px;margin-top:30px;border:1px solid #000;"></canvas> </body> </html>
注:转载请注明出处