- 浏览: 357014 次
文章分类
最新评论
-
Morgan0916:
我也发现 android-m2e 安装不上,楼主先安装了什么插 ...
maven部署android项目(1) -
Aaronic:
ITEye的堕落实在太难以让人忍受了,想把ITEye搞砸也不用 ...
360的困兽之斗——重新探讨奇虎商业模式 -
songbgi:
大婶你文章没有完全拷贝过来 这都上首页了
360的困兽之斗——重新探讨奇虎商业模式 -
zlex:
不是说 360 么?扯 QQ 做什么?
360的困兽之斗——重新探讨奇虎商业模式 -
crazywen2011:
有些东西还是很不错的,只是标题有些怪怪的
java内存泄露问题分析
WebGL自学课程(8):WebGL+ArcGIS JS API实现TerrainMap
转载请注明出处
以前在Esri的博客上看到了一篇用Silverlight+Balder实现TerrainMap的文章,实现的功能是将指定的二维投影地理范围转换成三维地形图,这是链接地址http://maps.esri.com/sldemos/terrainmap/default.html,感觉很有意思,最近在看WebGL,所以就想用WebGL重新进行实现,其中用ArcGIS JS API获取图片和高程数据,用WebGL进行三维显示。由于对WebGL框架不是很熟悉,所以开始的时候就想用原生的WebGL进行开发,后来发现越写越多,干脆萌生了一个将这些代码封装成自己的WebGL图形库的想法,取名World.js,我现在设置的World.js的版本是World0.3.1,World0.3.1的源码链接地址http://blog.csdn.net/sunqunsunqun/article/details/7885639,做这个TerrainMap的一个主要目的就是熟习WebGL,正好顺便把常用的WebGL代码封装成框架,以便增加代码的复用率。
现在这个Demo还有诸多不足,需要以后改正。
下图是二维界面:
下面是用WebGL实现的TerrainMap:
下面是Demo的组织结构:
World0.3.1的源码链接地址http://blog.csdn.net/sunqunsunqun/article/details/7885639。
下面是前端代码:
<!DOCTYPE HTML> <html> <head> <title>WebGL Terrain Map</title> <meta http-equiv="Content-Type" content="text/html"/> <meta name="charset" content="utf-8"/> <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.1/js/dojo/dijit/themes/claro/claro.css"> <!--<link rel="stylesheet" type="text/css" href="http://localhost/arcgis_js_api/library/3.1/jsapi/js/dojo/dijit/themes/claro/claro.css">--> <style type="text/css"> html, body { margin: 0; padding: 0; width: 100%; height: 100% ;font-family:"Times New Roman",Georgia,Serif;} div { margin: 0; padding: 0 } .head{width:100%; height:25px; background-color:#5998DD;color:#ffffff;font-size:13px; line-height:25px;border-top-left-radius:5px;border-top-right-radius:5px;-webkit-border-top-left-radius:5px; -webkit-border-top-right-radius:5px;-moz-border-radius-topleft:5px;-moz-border-radius-topright:5px;} .tip{font-size:8px;display:block;height:8px;margin-left:3px;margin-top:9px;} </style> <script src='http://serverapi.arcgisonline.com/jsapi/arcgis/?v=3.1' data-dojo-config='parseOnLoad: true'></script> <!--<script src='http://localhost/arcgis_js_api/library/3.1/jsapi/' data-dojo-config='parseOnLoad: true'></script>--> <script type="text/javascript" src="World0.3.4.js"></script> <script type="text/javascript" src="CanvasEventHandler.js"></script> <script type="text/javascript"> dojo.require("esri.map"); dojo.require("esri.tasks.geometry"); dojo.require("dojo.parser"); dojo.require("dijit.form.HorizontalSlider"); dojo.require("dijit.layout.BorderContainer"); dojo.require("dijit.layout.ContentPane"); var elevationData = [],imageName = ""; var vertexShaderContent,fragmentShaderContent,camera,scene,renderer,heightMap; var map,dynamicLayer,bMap2D = true,previousExtent = null;; var mapServiceUrl = "http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"; var streetMapUrl = "http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"; var topoMapUrl = "http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"; var squareCenterExtent; var geometryServiceUrl = "http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer"; var getElevationDataUrl = "http://sampleserver4.arcgisonline.com/ArcGIS/rest/services/Elevation/ESRI_Elevation_World/MapServer/exts/ElevationsSOE/ElevationLayers/1/GetElevationData"; function getShaderContent(shaderType){ var shaderUrl; if(shaderType == "VERTEX_SHADER"){ shaderUrl = "VertexShader.txt"; } else if(shaderType == "FRAGMENT_SHADER"){ shaderUrl = "FragmentShader.txt"; } var xhrArgs = { url:shaderUrl, handleAs:"text", sync:true, preventCache:true, load:function(data){ if(shaderType == "VERTEX_SHADER"){ vertexShaderContent = data; } else if(shaderType == "FRAGMENT_SHADER"){ fragmentShaderContent = data; } }, error:function(error){ alert("获取ShaderContent出错!"); } }; dojo.xhrGet(xhrArgs); } function getDefaultElevationData(dataName){ var xhrArgs = { url:"ElevationData/"+dataName, handleAs:"text", sync:true, preventCache:true, load:function(data){ elevationData = []; var strElevationArray = data.split(','); for(var i=0;i<strElevationArray.length;i++){ elevationData.push(parseFloat(strElevationArray[i])); } }, error:function(error){ alert("加载默认高程数据出错!") } }; dojo.xhrGet(xhrArgs); } function startWebGL(){ getShaderContent("VERTEX_SHADER"); getShaderContent("FRAGMENT_SHADER"); //getDefaultElevationData("50X50.txt"); renderer = new World.WebGLRenderer(dojo.byId("canvasId"),vertexShaderContent,fragmentShaderContent); //World.enableAmbientLight(); //World.enableParallelLlight(new World.Vector(0,-30,-50),new World.Vertice(0,0,0.8)); World.disableAmbientLight(); World.disableParallelLlight(); camera = new World.PerspectiveCamera(90,1,1.0,200.0); camera.look(new World.Vertice(0,30,50),new World.Vertice(0,-30,-50)); scene = new World.Scene(); //heightMap = new World.HeightMap(rowCount,columnCount,elevationData,"MapImages/"+"terrain512.jpg"); //scene.add(heightMap); renderer.bindScene(scene); renderer.bindCamera(camera); renderer.setIfAutoRefresh(false); } function judgeExtentEqual(ext1,ext2){ if(ext1 && ext2){ var sr1 = ext1.spatialReference; var sr2 = ext2.spatialReference; function judgeNumberEqual(a,b){ var c = Math.abs(a-b); if(c <= 100) return true; } if(judgeNumberEqual(ext1.xmin,ext2.xmin) && judgeNumberEqual(ext1.ymin,ext2.ymin) && judgeNumberEqual(ext1.xmax,ext2.xmax) && judgeNumberEqual(ext1.ymax,ext2.ymax) && sr1.wkid == sr2.wkid){ return true; } } return false; } function getSquareCenterExtent(){ var offset = 0; if (map.extent.getHeight() < map.extent.getWidth()) { offset = map.extent.getHeight() / 2; } else { offset = map.extent.getWidth() / 2; } var p = map.extent.getCenter(); var squareExtent = esri.geometry.Extent(p.x - offset, p.y - offset, p.x + offset, p.y + offset, map.extent.spatialReference) return squareExtent; } function showTerrain3D(bUpdate,row,column,elevations,mapImageName){ if(bUpdate == true){ scene.remove(heightMap); var scale = parseFloat(dojo.byId("labelStretch").innerHTML); heightMap = new World.HeightMap(row, column, elevations, "MapImages/"+mapImageName,scale); scene.add(heightMap); } renderer.setIfAutoRefresh(true); dojo.byId("mapId").style.display = "none"; dojo.byId("canvasId").style.display = "block"; dojo.byId("iSpring").style.visibility = "visible"; dojo.byId("btnSwitch").innerHTML = "转换为2D视图"; dojo.byId("btnSwitch").disabled = false; dijit.byId("sliderStretch")._setDisabledAttr(false); previousExtent = map.extent; bMap2D = false; } function startSwitch(bSwitchTo3D){ squareCenterExtent = getSquareCenterExtent(); if(bSwitchTo3D == true){ setIfDisableControls(true); var currentExtent = map.extent; //第一个判断的顺序要放在首位 if(judgeExtentEqual(currentExtent,previousExtent)){ showTerrain3D(false); } else{ var imageSize = dojo.byId("selectImageSize").value; getMapImageUrl(dynamicLayer,squareCenterExtent,imageSize,imageSize); } } else{ renderer.setIfAutoRefresh(false); setIfDisableControls(false); dojo.byId("canvasId").style.display = "none"; dojo.byId("iSpring").style.visibility = "hidden"; dojo.byId("mapId").style.display = "block"; dojo.byId("btnSwitch").innerHTML = "转换为3D视图"; dijit.byId("sliderStretch")._setDisabledAttr(true); bMap2D = true; } } function setIfDisableControls(bDisable){ dojo.byId("btnSwitch").disabled = bDisable; dojo.byId("btnFullExtent").disabled = bDisable; dojo.byId("radioSatelite").disabled = bDisable; dojo.byId("radioStreet").disabled = bDisable; dojo.byId("radioTopo").disabled = bDisable; dijit.byId("sliderGridSize")._setDisabledAttr(bDisable); dojo.byId("selectImageSize").disabled = bDisable; } function getMapImageUrl(dynamicLayer,extent,imageWidth,imageHeight){ var imageParameters = new esri.layers.ImageParameters(); imageParameters.bbox = extent; imageParameters.format = "jpeg"; imageParameters.width = imageWidth; imageParameters.height = imageHeight; imageParameters.imageSpatialReference = map.spatialReference; dynamicLayer.exportMapImage(imageParameters,function(mapImage){ tryStoreMapImage(mapImage.href); }); } function tryStoreMapImage(imageUrl){ var xhrArgs = { url:"proxy.ashx?requestType=getImage&imageUrl="+imageUrl, handleAs:"text", sync:false, preventCache:true, load:function(data){ imageName = data; //alert("存储图像完成!"); var gridSize = Math.round(dijit.byId("sliderGridSize").value); getCurrentElevationData(gridSize,gridSize); }, error:function(error){ alert("存储图像出错!"); startSwitch(false); } }; dojo.xhrGet(xhrArgs); } function getCurrentElevationData(rows,columns){ var extent = squareCenterExtent; var xhrArgs = { url:"proxy.ashx?requestType=getElevation", content:{ Rows:rows, Columns:columns, xmin:extent.xmin, ymin:extent.ymin, xmax:extent.xmax, ymax:extent.ymax, wkid:extent.spatialReference.wkid }, handleAs:"text", sync:false, preventCache:true, load:function(data){ //alert("获取高程数据完成!"); succeedGetElevationData(data); }, error:function(error){ alert("获取高程出错!"); startSwitch(false); } }; dojo.xhrGet(xhrArgs); } function succeedGetElevationData(data){ var info = data.split(";"); var row = parseFloat(info[0]);//一定要将string转换成float var column = parseFloat(info[1]);//一定要将string转换成float var strElevations = info[2]; elevationData = []; var strElevationArray = strElevations.split(','); for(var i=0;i<strElevationArray.length;i++){ elevationData.push(parseFloat(strElevationArray[i])); } showTerrain3D(true,row,column,elevationData,imageName); } function initLayout(){ var sliderGridSize = new dijit.form.HorizontalSlider({ name: "sliderGridSize", value: 50, minimum: 1, maximum: 100, intermediateChanges: true, style: "width:175px;float:left;", onChange:function(value){ dojo.byId("labelGridSize").innerHTML = Math.round(value); } }, "sliderGridSize"); var sliderStretch = new dijit.form.HorizontalSlider({ name:"sliderStretch", value:1, minimum:0, maximum:4, intermediateChanges:true, style:"width:175px;float:left;", onChange:function(value){ var scale = Math.round(value*10)/10;//var scale = Math.round(value); dojo.byId("labelStretch").innerHTML = scale; heightMap.heightScale = scale; } },"sliderStretch"); sliderStretch._setDisabledAttr(true);//开始的时候要禁用拉伸滑块 var clientWidth = document.body.clientWidth < 1024 ? 1024:document.body.clientWidth; var clientHeight = document.body.clientHeight < 600 ? 600:document.body.clientHeight; var height = clientHeight - 10 - 10;// var viewerWidth = clientWidth - 220 - 10;// document.getElementById("controls").style.height = height+"px"; document.getElementById("controlsContent").style.height = (height - 25) + "px"; document.getElementById("viewer").style.height = height+"px"; document.getElementById("mapId").style.height = (height-25)+"px"; document.getElementById("canvasId").height = height-25; document.getElementById("viewer").style.width = viewerWidth + "px"; document.getElementById("mapId").style.width = viewerWidth + "px"; document.getElementById("canvasId").width = viewerWidth; } function initMap(){ map = new esri.Map("mapId"); var basemap = new esri.layers.ArcGISTiledMapServiceLayer(mapServiceUrl); map.addLayer(basemap); dynamicLayer = new esri.layers.ArcGISDynamicMapServiceLayer(mapServiceUrl,{imageFormat:"jpg"}); dojo.connect(dynamicLayer,'onError',function(){ alert("载入动态图层出错!"); }); dojo.connect(map, 'onLoad',function(theMap){ dojo.connect(dojo.byId('mapId'),'onresize',map, map.resize); dojo.connect(theMap, "onMouseDown",function(evt){ console.log(evt.mapPoint); }); }); } function initEvents(){ dojo.connect(dojo.byId("canvasId"),"mousedown",onMouseDown); dojo.connect(dojo.byId("canvasId"),"onmouseup",onMouseUp); dojo.connect(dojo.byId("canvasId"),'mousewheel',onMouseWheel); dojo.connect(dojo.byId("canvasId"),'DOMMouseScroll',onMouseWheel); } function initAll(){ initLayout(); initEvents(); initMap(); startWebGL(); } function showTest3D(){ getDefaultElevationData("Test.txt"); showTerrain3D(true,50,50,elevationData,"Test.jpg"); } dojo.addOnLoad(initAll); </script> </head> <body class="claro" style="background-color:#D8DCE0;"> <div id="main"> <div id="controls" style="width:200px;height:650px;position:absolute;left:10px;top:10px;"> <div class="head" style="text-align:left;"> Controls</div> <div id="controlsContent" style="height:624px;position:relative;background-color:#ffffff;"> <div style="width:100%;height:40px;padding-top:5px;background-color:LightBlue;"> <button id="btnSwitch" style="display:block;height:30px;margin-left:auto;margin-right:auto;" onclick="javascript:bMap2D==true?startSwitch(true):startSwitch(false);">转换为3D视图</button> </div> <span class="tip">导航</span> <image src="Images/horizontal.png" /> <button id="btnFullExtent" style="display:block;height:30px;" onclick="map.setExtent(getFullExtent());">全图</button> <span class="tip">地图</span> <image src="Images/horizontal.png" /> <input type="radio" id="radioSatelite" name="radioMap"/>Satelite<br/> <input type="radio" id="radioStreet" name="radioMap"/>Street<br/> <input type="radio" id="radioTopo" name="radioMap"/>Topo<br/> <span class="tip">高程格网大小</span> <image src="Images/horizontal.png" /> <div id="sliderGridSize"></div><label id="labelGridSize" style="float:left;">50</label></br> <span class="tip">图像大小</span> <image src="Images/horizontal.png" /> <select id="selectImageSize" style="display:block;width:190px;margin:0 auto;"> <option value="64">64</option> <option value="128">128</option> <option value="256">256</option> <option value="512" >512</option> <option value="1024" selected>1024</option> <option value="2048">2048</option> </select> <a href="http://cn.khronos.org/" target="_blank" style="display:block;position:absolute;bottom:0px;"> <div style="width:116px;height:77px;background-image:url(Images/WebGL.png);"></div> </a> <span class="tip">拉伸系数</span> <image src="Images/horizontal.png" /> <div id="sliderStretch"></div><label id="labelStretch" style="float:left;">1</label> </div> </div> <div id="viewer" style="width:1040px;height:650px;position:absolute;left:220px;top:10px;"> <div class="head"> Viewer <a href="http://weibo.com/iispring" target="_blank" style="float:right;text-decoration:none;color:#ffffff;margin-right:7px;text-align:center;line-height:25px;">About iSpring</a> </div> <div id="mapId" style="width:1040px;height:625px;background-color:#666666;"></div> <canvas id="canvasId" width="1040" height="625" style="display:none;"></canvas> <a id="iSpring" style="visibility:hidden;diaplay:block;position:absolute;bottom:0px;right:0px;" href="http://weibo.com/iispring" target="_blank"> <div style="width:81px;height:50px;background-image:url(Images/iSpring.png);"></div> </a> </div> </div> </body> </html>
下面是用于进行三维漫游操作的代码CanvasEventHandler.js:
var bMouseDown = false; var handleMouseMove; var previousX=-1; var previousY=-1; var MODE = "ROTATE"; function onMouseDown(evt){ previousX=evt.layerX||evt.offsetX; previousY=evt.layerY||evt.offsetY; bMouseDown = true; handleMouseMove = dojo.connect(dojo.byId("canvasId"),"onmousemove","onMouseMove"); } function onMouseMove(evt){ var currentX=evt.layerX||evt.offsetX; var currentY=evt.layerY||evt.offsetY; if(MODE == "PAN"){ if(bMouseDown){ onPanMouseMove(currentX,currentY); } } else if(MODE == "ROTATE"){ if(bMouseDown){ onRotateMouseMove(currentX,currentY); } } previousX = currentX; previousY = currentY; } function onRotateMouseMove(currentX,currentY){ if(previousX > 0 && previousY > 0){ var changeX = currentX - previousX; var changeY = currentY - previousY; var horCameraAngle = World.canvas.width / World.canvas.height * camera.fov; var changeHorAngle = changeX / World.canvas.width * horCameraAngle; var changeVerAngle = changeY / World.canvas.height * camera.fov; camera.worldRotateY(-changeHorAngle*Math.PI/180); var lightDir = camera.getLightDirection(); //if(Math.abs(lightDir.z)>0.01){ var plumbVector = getPlumbVector(lightDir,false); camera.worldRotateByVector(-changeVerAngle*Math.PI/180,plumbVector); //} } } function onPanMouseMove(currentX,currentY){ var position = camera.getPosition(); var target = camera.getTarget(); //左右平移 if(currentX != previousX){ var bLeft = currentX < previousX ? true:false; var plumbVector = getPlumbVector(camera.getLightDirection(), bLeft); position.x += plumbVector.x; position.z += plumbVector.z; target.x += plumbVector.x; target.z += plumbVector.z; } //前后平移 if(currentY != previousY){ var bForward = currentY < previousY ? true:false; var forwardVector = getForwardVector(camera.getLightDirection(), bForward); position.x += forwardVector.x; position.y += forwardVector.y; position.z += forwardVector.z; target.x += forwardVector.x; target.y += forwardVector.y; target.z += forwardVector.z; } camera.look(position,target); } function onMouseWheel(evt){ var scale = 0.0; if (evt.wheelDelta ){ if(evt.wheelDelta > 0){ scale = 0.9; } else if(evt.wheelDelta < 0){ scale = 1.1; } } else if(evt.detail){ if(evt.detail < 0){ scale = 0.9; } else if(evt.detail > 0){ scale = 1.1; } } var distance = camera.getViewFrustumDistance(); camera.setViewFrustumDistance(distance*scale,true); } function onMouseUp(evt){ bMouseDown = false; dojo.disconnect(handleMouseMove); previousX = -1; previousY = -1; } function getPlumbVector(direction,bLeft){ direction.y = 0; direction.normalize(); var plumbVector = new World.Vector(-direction.z,0,direction.x); plumbVector.normalize(); /*var K = direction.z / direction.x; if (bLeft) { if (plumbVector.z < K * plumbVector.x){ plumbVector.x *= -1; plumbVector.z *= -1; } } else { if (plumbVector.z > K * plumbVector.x) { plumbVector.x *= -1; plumbVector.z *= -1; } }*/ return plumbVector; } function getForwardVector(direction,bForward){ direction.y = 0; direction.normalize(); if (bForward){ direction.x *= -1; direction.z *= -1; } return direction; }/** * Created with JetBrains WebStorm. * User: iSpring * Date: 12-8-9 * Time: 下午3:28 * To change this template use File | Settings | File Templates. */
下面是所使用的代理proxy.ashx
<%@ WebHandler Language="C#" Class="proxy" %> using System; using System.Web; using System.IO; using System.Drawing; using System.Text; public class proxy : IHttpHandler { public void ProcessRequest(HttpContext context) { string requestType = context.Request["requestType"]; if (requestType == "getImage") { string url = context.Request["imageUrl"]; System.Net.WebRequest request = System.Net.WebRequest.Create(new Uri(url)); request.Method = context.Request.HttpMethod; request.ContentType = "application/x-www-form-urlencoded"; System.Net.WebResponse response = request.GetResponse(); Stream stream = response.GetResponseStream(); Image img = Image.FromStream(stream); int index = url.LastIndexOf('/'); string imageName = url.Remove(0, index + 1); string baseDirectory = System.AppDomain.CurrentDomain.BaseDirectory; string physicPath = baseDirectory + "\\MapImages\\" + imageName; img.Save(physicPath); context.Response.Write(imageName); context.Response.End(); } else if (requestType == "getElevation") { string Rows = context.Request["Rows"]; string Columns = context.Request["Columns"]; string xmin = context.Request["xmin"].Trim(); ; string ymin = context.Request["ymin"].Trim(); ; string xmax = context.Request["xmax"].Trim(); string ymax = context.Request["ymax"].Trim(); string wkid = context.Request["wkid"]; string baseUrl = "http://sampleserver4.arcgisonline.com/ArcGIS/rest/services/Elevation/ESRI_Elevation_World/MapServer/exts/ElevationsSOE/ElevationLayers/1/GetElevationData"; string paras = "?Extent=%7B%22xmin%22%3A" + xmin + "%2C%0D%0A%22ymin%22%3A" + ymin + "%2C%0D%0A%22xmax%22%3A" + xmax + "%2C%0D%0A%22ymax%22%3A" + ymax + "%2C%0D%0A%22spatialReference%22%3A%7B%22wkid%22%3A" + wkid + "%7D%7D&Rows=" + Rows + "&Columns=" + Columns + "&f=pjson"; string url = baseUrl + paras; System.Net.WebRequest request = System.Net.WebRequest.Create(new Uri(url)); request.Method = context.Request.HttpMethod; request.ContentType = "application/x-www-form-urlencoded"; System.Net.WebResponse response = request.GetResponse(); Stream stream = response.GetResponseStream(); StreamReader sr = new StreamReader(stream); string strResponse = sr.ReadToEnd(); int index1 = strResponse.LastIndexOf('[') + 1; string str = strResponse.Remove(0, index1); int index2 = str.LastIndexOf(']'); string result = str.Remove(index2); result = result.Replace("\r\n", "").Replace(" ", "");//类似于这样32767,32767,-3175,384,1983,-208 //假设高程6500对应着地球投影面长宽的1/10 float width = int.Parse(Rows); string[] results = result.Split(','); StringBuilder LastOutput = new StringBuilder(); LastOutput.Append(Rows + ";" + Columns + ";"); for (int i = 0; i < results.Length; i++) { string strElevation = results[i]; int Elevation = int.Parse(strElevation); if (Elevation == 32767) { Elevation = 0; } float handledElevation = width / 10 * Elevation / 6500; string strHandledElevation = handledElevation.ToString(); if (i != results.Length - 1) { LastOutput.Append(strHandledElevation + ","); } else { LastOutput.Append(strHandledElevation); } } context.Response.ContentType = "text/plain"; context.Response.Write(LastOutput.ToString()); context.Response.End(); } } public bool IsReusable { get { return false; } } }
转载请注明出处
相关推荐
webgl2-2d WebGL2 中的画布 API 实现用法 // const ctx = canvas.getContext('2d') // origin canvas 2D contextconst ctx = canvas . getContext ( 'webgl2-2d' ) // WebGL2 implementation清单参考: : ...
基于three.js 和ArcGIS JS API meshline
Three.js可视化企业实战WEBGL视频教程(源码+课件+素材+48章全+2024年1月升级版)
webgl相关 cuon-matrix.js+cuon-utils.js+webgl-debug.js+webgl-utils.js
网页链接node.js + webgl + mac os 运行 webgl-main.js 服务器使用 webgl 实例创建 html 并打开浏览器包括 webglBrowser.app 瓦西里·舍夫恰克
使用pixi和webgl实现的交通模拟器源码+项目说明(模拟城市交通、汽车行驶、等红绿灯场景).zip使用pixi和webgl实现的交通模拟器源码+项目说明(模拟城市交通、汽车行驶、等红绿灯场景).zip使用pixi和webgl实现的交通...
HTML5 WebGL+Three.js+Cannon.js实现的3D立体十字关卡碰撞动画源码.zip
WebGL基础水教程如果您有任何疑问或遇到任何绊脚石,请随时! # You can use any static file server that properly sets the# `application/wasm` mime typecargo install ...
适用于Unity WebGL的JsonNet,普通的JsonNet是不能运行在webgl上的
与大多数WebGL课程不同,这些课程并非基于OpenGL。 OpenGL已经20岁了。 OpenGL的课程与WebGL不太匹配。 API更改太多了。 OpenGL和OpenGL教程的思想在WebGL,OpenGL ES 3.0和着色器领域已过时。 我认为WebGL实际...
cast-webgl-demo Chromecast 上 WebGL + WebRTC 的一个小演示
【WebGL连载教程三】的项目源文件 https://blog.csdn.net/sjt223857130/article/details/80064400
本资源是用于本博客webgl分类的学习资料,主要是为了学习webgl的同学课后练习所用,不能作为商业用途 不知道怎么才能设置不要分,最低分是1分 如果没分的同学可以加群,里面有电子档书籍
分享一套视频教程,名字叫:WebGL 可视化3D绘图框架:Three.js 零基础上手实战,非常棒的一套课程,喜欢的同学可以下载参考一下,附源码和课件
Requirements - Android: API Level 23+ - iOS: iOS 8+ - Windows: Windows 8+ - macOS: macOS 10.13+ - WebGL: Chrome 47+, Safari 27+, Firefox 25+
next-webgl 像2018年一样使用OpenGL。 这个程序演示了如何在React中使用WebGL。 现代JavaScript和热重装使其非常适合快速原型制作和在线演示。 借助Next.js导出功能,可以轻松将其部署到静态Web托管中。堆:入门安装...