WebGL的原生API不可能那么可爱
2014-03-14 17:43
246 查看
本文简介
通过三种方法实现同一目标来展示WebGL原生API,并引导读者入门WebGL(伪)。本文将分别使用Canvas 2D Context,Three.js,WebGL来绘制一个最简单的图形——一个6*6像素的点。
正文
当你第一次听说浏览器支持WebGL了,你可能欢呼雀跃,暗喜我大前端也有能操纵3D图形的一天。你按捺不住激动的心情拿出冰箱里百威啤酒,猛喝了一口。你潇洒的打开浏览器,Google了一下WebGL的教程,欣赏起了WebGL代码。可是就是你那惊鸿一瞥的刹那间,喷了屏幕一口泡沫/一口老血喷在屏幕上。“我的JavaScript怎么可能长这样?!”,你高声大喊道。是的,你没有看错,这货真不是JavaScript。这混合着attribute,gl_Position,precision等你从未在前端看到的词汇的怪物,到底是何方妖孽!你感到一阵眩晕,胃里也翻滚了起来,就好像你刚一口吞下了一份插着鸡毛的圣代……而本文就是为了在你伤口上撒点盐,放点葱而存在的!
说到画一个点,大概谁都会。你熟练的从书包里掏出水彩笔,在白纸的正中央用力的点了一点,骄傲的喊道:“老师,我第一个画完了!”老师在你额头上贴了一朵小红花,周围掌声雷动,连绵不息。
但是如果不能用笔呢?我们先来看看如何用Canvas 2D Context画一个点。
Canvas 2D Context
这个比较简单,就不添加注释了,下面是代码。<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <style> #cvs { border: 2px solid pink; } </style> <script> addEventListener("DOMContentLoaded", function () { var cvs = document.getElementById("cvs"); var cxt = cvs.getContext("2d"); var pointSize = 6; cxt.fillStyle = "rgba(0,0,0,1)"; cxt.fillRect(0, 0, cvs.width, cvs.height); cxt.fillStyle = "rgba(77,153,204,1)"; cxt.fillRect((cvs.width - pointSize) / 2, (cvs.height - pointSize) / 2, pointSize, pointSize); }); </script> </head> <body> <canvas id="cvs" width="800" height="600"></canvas> </body> </html>
你掰开指头算了一下,刚好七个指头。是的,用这种方法画一个点只要7行代码而已。下面的截图应该和代码在你大脑里运行的结果一样。
黑色的画布里一个蓝点。
Three.js
接下来我们来看看Three.js如何实现在浏览器里画一个简单的点。<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <style> #threejs { border: 2px solid pink; width:800px; height:600px; } </style> <script src="three.js"></script> <script> addEventListener("DOMContentLoaded", function () { var threejs = document.getElementById("threejs"); //点的尺寸 var size = 6; var width = 800, height = 600; //新建场景 var scene = new THREE.Scene(); //新建正射投影摄像机,摄像机的可视截面宽为width,高为height,近截面距离为0.1,远截面为1 var camera = new THREE.OrthographicCamera(-width / 2, width / 2, height / 2, -height / 2, 0.1, 1); //摄像机往z轴移1,才能看到物体 camera.position.z = 1; //新建渲染器 var renderer = new THREE.WebGLRenderer(); //设置渲染视口大小,你可以改成400,300试试 renderer.setSize(width, height); //添加画布到文档中 threejs.appendChild(renderer.domElement); //新建平面几何结构,宽高都为6 var geometry = new THREE.PlaneGeometry(size, size); //新建材质,颜色为蓝色 var material = new THREE.MeshBasicMaterial({ color: 0x4d99cc }); //结合物体的结构和材质 var plane = new THREE.Mesh(geometry, material); //添加到场景里才能被渲染 scene.add(plane); //开始使用给定的摄像机渲染给定的场景 renderer.render(scene, camera); }); </script> </head> <body> <div id="threejs"></div> </body> </html>
你用上了脚趾头发现three.js花了14行代码来画一点简单的点。我们的WebGL选手能不能打破Three.js的记录并夺得最繁琐画点大赛的桂冠呢?
WebGL
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <style> #webgl { border: 2px solid pink; } </style> <script id="vertexShader" type="x-shader/x-vertex"> //这部分是顶点着色器 //声明一个attribute类型的4维向量a_Position attribute vec4 a_Position; void main() { //gl_Position和gl_PointSize是预定义变量,表示顶点位置和大小 gl_Position = a_Position; gl_PointSize = 6.0; } </script> <script id="fragmentShader" type="x-shader/x-fragment"> //这部分是片段着色器 void main() { //gl_FragColor是预定义变量,表示片段的颜色 gl_FragColor = vec4(0.3, 0.6, 0.8, 1.0); } </script> <script> addEventListener("DOMContentLoaded", function () { var webgl = document.getElementById("webgl"); //获取3D上下文 var gl = webgl.getContext("webgl"); //获取顶点着色器的源代码 var vertexGLSL = document.getElementById("vertexShader").text; //创建顶点着色器 var vertexShader = gl.createShader(gl.VERTEX_SHADER); //设置顶点着色器的源代码 gl.shaderSource(vertexShader, vertexGLSL); //编译顶点着色器 gl.compileShader(vertexShader); //获取片段着色器的源代码 var fragmentGLSL = document.getElementById("fragmentShader").text; //创建片段着色器 var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); //设置片段着色器的源代码 gl.shaderSource(fragmentShader, fragmentGLSL); //编译片段着色器 gl.compileShader(fragmentShader); //创建着色器程序 var program = gl.createProgram(); //程序加入顶点着色器 gl.attachShader(program, vertexShader); //程序加入片段着色器 gl.attachShader(program, fragmentShader); //链接程序 gl.linkProgram(program); //启用程序 gl.useProgram(program); //获取attribute类型变量a_Position在内存里的位置 var a_Position = gl.getAttribLocation(program, "a_Position"); //给a_Position赋值 gl.vertexAttrib2f(a_Position, 0.0, 0.0); //将颜色缓冲区的值设置为黑色 gl.clearColor(0, 0, 0, 1); //使用颜色缓冲区的值来填充 gl.clear(gl.COLOR_BUFFER_BIT); //画点 gl.drawArrays(gl.POINTS, 0, 1); }); </script> </head> <body> <canvas id="webgl" width="800" height="600"></canvas> </body> </html>
你掰了一会儿指头,无奈的发现指头不够用了。最后你找到了一根绳子,通过打结发现一共有30行。无疑WebGL是夺冠了,你微笑着大声宣布出这个消息,并给WebGL戴上了草结的花圈……
反馈
如果你发现错误或者心存疑问,欢迎在下面留言。相关文章推荐
- 《郭大侠的妹妹不可能那么可爱》 第一章 郭大侠那可爱的妹妹?
- WebGL原生API及绘图基础
- WebGL自学课程(3):原生WebGL+ArcGIS JS API绘制旋转的地球
- Zookeeper实例原生API--异步创建节点
- 利用android提高的的insert,query,update,deleteAPI与execSql,rawQuery函数执行原生的插入,查询,更新,删除语
- 人工智能很可能在金融,医学或法律领域占据一席之地,但却不那么有利可图
- 你可能不需要 jQuery!使用原生 JavaScript 进行开发
- 项目开发,我的名字不可能这么可爱——开篇
- 腾讯云图片鉴黄集成到C# SQL Server 怎么在分页获取数据的同时获取到总记录数 sqlserver 操作数据表语句模板 .NET MVC后台发送post请求 百度api查询多个地址的经纬度的问题 try{}里有一个 return 语句,那么紧跟在这个 try 后的 finally {}里的 code 会 不会被执行,什么时候被执行,在 return 前还是后? js获取某个日期
- 9.Action类接收参数(原生的ServletAPI )
- 【偶像大师 白金星光】的【Variable Tone】技术大公开!偶像从哪里看都那么可爱,VA小组谈制作方针
- 多种方式实现(jdk原生api实现/httpClient的实现) java 发送http(post/get)请求并携带参数(讲解超详细)
- 2016年千万不要随便辞职,2017年的工作可能没那么好找
- ios网络学习------10 原生API文件上传
- ajax 原生API
- ios网络学习------10 原生API文件上传
- 原生JS实现几个常用DOM操作API
- 使用Android原生的Api进行GPS定位获取位置信息
- SpringMVC系列(五)使用 Serlvet 原生的 API 作为目标方法的参数
- iOS 【原生API NSURLSession 网络请求(重新弄一份 格式不对!!!!!!!!!!)】