1. 首页
  2. IT资讯

「WebGL基础」:第一部分

“u003Cdivu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp3.pstatp.comu002Flargeu002Fdfic-imagehandleru002F8c127c7b-4f40-4904-878d-48cf4a81cdf0″ img_width=”1024″ img_height=”768″ alt=”「WebGL基础」:第一部分” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003EWebGL是一种基于OpenGL的浏览器内置3D渲染器,它可以让你在HTML5页面中直接显示3维内容。 在本教程中,我会介绍你使用此框架所需的所有基础内容。u003Cu002Fpu003Eu003Cpu003E介绍u003Cu002Fpu003Eu003Cpu003E开始学习之前,有几件事你是需要了解的。 WebGL是将3D内容渲染到HTML5的canvas元素上的一种JavaScript API。 它是利用”3D世界”中称为着色器的两种脚本来实现这一点的。 这两种着色器分别是:u003Cu002Fpu003Eu003Culu003Eu003Cliu003E顶点着色器u003Cu002Fliu003Eu003Cliu003E片元着色器u003Cu002Fliu003Eu003Cu002Fulu003Eu003Cpu003E听到这些名词时也不要过于惊慌;它们只不过是”位置计算器”和”颜色选择器”的另一种说法罢了。 片元着色器容易理解;它只是告诉WebGL,模型上的指点定应该是什么颜色。 而顶点着色器解释起来就需要点技术了,不过基本上它起到将3维模型转变为2维坐标的作用。 因为所有的计算机显示器都是2维平面,当你在屏幕上看3维物体时,它们只不过是透视后的幻象。u003Cu002Fpu003Eu003Cpu003E如果你想完整地理解这个计算过程,你最好是问一个数学家,因为这个过程中用到了高级的4×4矩阵乘法,实在是有点超过我们这个”基础”教程的范围呀。 幸运的是,你并不需要知道它所有的工作原理,因为WebGL会处理背后大部分的细节。 那么,我们开始吧。u003Cu002Fpu003Eu003Cpu003E第一步:设置WebGLu003Cu002Fpu003Eu003Cpu003EWebGL有许多细微的设置,而且每次你要在屏幕画什么东西之前都要设置一遍。 为了节约时间,并使代码整洁一些,我们把所有”幕后”的代码包装成一个JavaScript对象,并存于一个独立的文件中。 现在我们要开始了,先创建一个新文件’WebGL.js’,并写入如下代码:u003Cu002Fpu003Eu003Cpreu003Efunction WebGL(CID, FSID, VSID){u003Cbru003E var canvas = document.getElementById(CID);u003Cbru003E if(!canvas.getContext(“webgl”) && !canvas.getContext(“experimental-webgl”))u003Cbru003E alert(“Your Browser Doesn’t Support WebGL”);u003Cbru003E elseu003Cbru003E {u003Cbru003E this.GL = (canvas.getContext(“webgl”)) ? canvas.getContext(“webgl”) : canvas.getContext(“experimental-webgl”);u003Cbru003E this.GL.clearColor(1.0, 1.0, 1.0, 1.0); u002Fu002F this is the color u003Cbru003E this.GL.enable(this.GL.DEPTH_TEST); u002Fu002FEnable Depth Testingu003Cbru003E this.GL.depthFunc(this.GL.LEQUAL); u002Fu002FSet Perspective Viewu003Cbru003E this.AspectRatio = canvas.width u002F canvas.height;u003Cbru003E u002Fu002FLoad Shaders Hereu003Cbru003E }u003Cbru003E} u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E这个构造函数的参数是canvas无形的ID,以及两个着色器对象。 首先,我们要获得canvas元素,并确保它是支持WebGL的。 如果支持WebGL,我们就将WebGL上下文赋值给一个局部变量,称为”GL”。 清除颜色(clearColor)其实就是设置背景颜色,值得一提的是,WebGL中大部分参数的取值范围都是0.0到1.0,所以我们需要让通常的rgb值除以255。 所以,我们的示例中,1.0,1.0,1.0,1.0表示背景为白色,且100%可见 (即无透明)。 接下来两行要求WebGL计算深度和透视,这样离你近的对象会挡住离你远的对象。 最后,我们设置宽高比,即canvas的宽度除以它的高度。u003Cu002Fpu003Eu003Cpu003E继续前行之前,我们要准备好两个着色器。 我把这些着色器写到HTML文件里去,这个HTML文件里还包含了我们的画布元素 (canvas)。 创建一个HTML文件,并将下面的两个script元素放在body标签之前。u003Cu002Fpu003Eu003Cpreu003E<script id=”VertexShader” type=”x-shaderu002Fx-vertex”>u003Cbru003E attribute highp vec3 VertexPosition;u003Cbru003E attribute highp vec2 TextureCoord;u003Cbru003E uniform highp mat4 TransformationMatrix;u003Cbru003E uniform highp mat4 PerspectiveMatrix;u003Cbru003E varying highp vec2 vTextureCoord;u003Cbru003E void main(void) {u003Cbru003E gl_Position = PerspectiveMatrix * TransformationMatrix * vec4(VertexPosition, 1.0);u003Cbru003E vTextureCoord = TextureCoord;u003Cbru003E}u003Cbru003E<u002Fscript>u003Cbru003E<script id=”FragmentShader” type=”x-shaderu002Fx-fragment”>u003Cbru003E varying highp vec2 vTextureCoord;u003Cbru003Euniform sampler2D uSampler;u003Cbru003Evoid main(void) {u003Cbru003E highp vec4 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));u003Cbru003E gl_FragColor = texelColor;u003Cbru003E}u003Cbru003E<u002Fscript>u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E先来看顶点着色器,我们定义了两个属性 (attributes):u003Cu002Fpu003Eu003Culu003Eu003Cliu003E顶点位置,它存储了当前顶点 (你的模型上的点) 的位置,包括x,y,z坐标。u003Cu002Fliu003Eu003Cliu003E纹理坐标,即赋给这个点的纹理在纹理图像中的位置u003Cu002Fliu003Eu003Cu002Fulu003Eu003Cpu003E接下来,我们创建变换和透视矩阵等变量。 它们被用于将3D模型转化为2D图像。 下一行是创建一个与片元着色器共享的变量vTextureCoord,在主函数中,我们计算gl_Position (即最终的2D位置)。 然后,我们将’当前纹理坐标’赋给这个共享变量vTextureCoord。u003Cu002Fpu003Eu003Cpu003E在片元着色器中,我们取出定义在顶点着色器中的这个坐标,然后用这个坐标来对纹理进行’采样’。 基本上,通过这个过程,我们得到了我们几何体上的当前点处的纹理的颜色。u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002F7fd4b3617c7d4ababc22de1e69111b26″ img_width=”600″ img_height=”250″ alt=”「WebGL基础」:第一部分” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E现在写完了着色器,我们可回过头去在JS文件中加载这些着色器。 将”u002Fu002FLoad Shaders Here”换成如下代码:u003Cu002Fpu003Eu003Cpreu003Evar FShader = document.getElementById(FSID);u003Cbru003Evar VShader = document.getElementById(VSID);u003Cbru003Eif(!FShader || !VShader)u003Cbru003E alert(“Error, Could Not Find Shaders”);u003Cbru003Eelseu003Cbru003E{u003Cbru003E u002Fu002FLoad and Compile Fragment Shaderu003Cbru003E var Code = LoadShader(FShader);u003Cbru003E FShader = this.GL.createShader(this.GL.FRAGMENT_SHADER);u003Cbru003E this.GL.shaderSource(FShader, Code);u003Cbru003E this.GL.compileShader(FShader);u003Cbru003E u002Fu002FLoad and Compile Vertex Shaderu003Cbru003E Code = LoadShader(VShader);u003Cbru003E VShader = this.GL.createShader(this.GL.VERTEX_SHADER);u003Cbru003E this.GL.shaderSource(VShader, Code);u003Cbru003E this.GL.compileShader(VShader);u003Cbru003E u002Fu002FCreate The Shader Programu003Cbru003E this.ShaderProgram = this.GL.createProgram();u003Cbru003E this.GL.attachShader(this.ShaderProgram, FShader);u003Cbru003E this.GL.attachShader(this.ShaderProgram, VShader);u003Cbru003E this.GL.linkProgram(this.ShaderProgram);u003Cbru003E this.GL.useProgram(this.ShaderProgram);u003Cbru003E u002Fu002FLink Vertex Position Attribute from Shaderu003Cbru003E this.VertexPosition = this.GL.getAttribLocation(this.ShaderProgram, “VertexPosition”);u003Cbru003E this.GL.enableVertexAttribArray(this.VertexPosition);u003Cbru003E u002Fu002FLink Texture Coordinate Attribute from Shaderu003Cbru003E this.VertexTexture = this.GL.getAttribLocation(this.ShaderProgram, “TextureCoord”);u003Cbru003E this.GL.enableVertexAttribArray(this.VertexTexture);u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E你的纹理必须是偶数字节大小,否则会出错。。。比如2×2,4×4,16×16,32×32。。。u003Cu002Fpu003Eu003Cpu003E首先,我们要确保这些着色器是存在的,然后,我们逐一地加载它们。 这个过程基本上是:得到着色器源码,编译,附着到核心的着色程序上。 从HTML文件中提取着色器源码的代码,封装到了一个函数中,称为LoadShader;稍后会讲到。 我们使用这个’着色器程序’将两个着色器链接起来,通过它,我们可以访问到着色器中的变量。 我们将数据储存到定义在着色器中的属性;然后,我们就可以将几何体输入到着色器中了。u003Cu002Fpu003Eu003Cpu003E现在,让我们看一下LoadShader函数,你应该将它置于WebGL函数之外。u003Cu002Fpu003Eu003Cpreu003Efunction LoadShader(Script){u003Cbru003E var Code = “”;u003Cbru003E var CurrentChild = Script.firstChild;u003Cbru003E while(CurrentChild)u003Cbru003E {u003Cbru003E if(CurrentChild.nodeType == CurrentChild.TEXT_NODE)u003Cbru003E Code += CurrentChild.textContent;u003Cbru003E CurrentChild = CurrentChild.nextSibling;u003Cbru003E }u003Cbru003E return Code;u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E基本上,这个函数通过遍历着色器来收集源码。u003Cu002Fpu003Eu003Cpu003E第二步:“简单”立方体u003Cu002Fpu003Eu003Cpu003E为了在WebGL中画出对象,你需要如下三个数组:u003Cu002Fpu003Eu003Culu003Eu003Cliu003E顶点 (vertices):构造你的对象的那些点u003Cu002Fliu003Eu003Cliu003E三角形 (triangles):告诉WebGL如何将顶点连接成面u003Cu002Fliu003Eu003Cliu003E纹理坐标 (texture coordinates):定义顶点如何被映射到纹理图像上u003Cu002Fliu003Eu003Cu002Fulu003Eu003Cpu003E这个过程称为UV映射。 我们的例子是构造一个简单的立方体。 我将这个立方体分成4个顶点一组,每一组又连成两个三角形。 我们可以用一个变量来存储立方体的这些数组。u003Cu002Fpu003Eu003Cpreu003Evar Cube = {u003Cbru003E Vertices : [ u002Fu002F X, Y, Z Coordinatesu003Cbru003E u002Fu002FFrontu003Cbru003E 1.0, 1.0, -1.0,u003Cbru003E 1.0, -1.0, -1.0,u003Cbru003E -1.0, 1.0, -1.0,u003Cbru003E -1.0, -1.0, -1.0,u003Cbru003E u002Fu002FBacku003Cbru003E 1.0, 1.0, 1.0,u003Cbru003E 1.0, -1.0, 1.0,u003Cbru003E -1.0, 1.0, 1.0,u003Cbru003E -1.0, -1.0, 1.0,u003Cbru003E u002Fu002FRightu003Cbru003E 1.0, 1.0, 1.0,u003Cbru003E 1.0, -1.0, 1.0,u003Cbru003E 1.0, 1.0, -1.0,u003Cbru003E 1.0, -1.0, -1.0,u003Cbru003E u002Fu002FLeftu003Cbru003E -1.0, 1.0, 1.0,u003Cbru003E -1.0, -1.0, 1.0,u003Cbru003E -1.0, 1.0, -1.0,u003Cbru003E -1.0, -1.0, -1.0,u003Cbru003E u002Fu002FTopu003Cbru003E 1.0, 1.0, 1.0,u003Cbru003E -1.0, -1.0, 1.0,u003Cbru003E 1.0, -1.0, -1.0,u003Cbru003E -1.0, -1.0, -1.0,u003Cbru003E u002Fu002FBottomu003Cbru003E 1.0, -1.0, 1.0,u003Cbru003E -1.0, -1.0, 1.0,u003Cbru003E 1.0, -1.0, -1.0,u003Cbru003E -1.0, -1.0, -1.0u003Cbru003E ],u003Cbru003E Triangles : [ u002Fu002F Also in groups of threes to define the three points of each triangleu003Cbru003E u002Fu002FThe numbers here are the index numbers in the vertex arrayu003Cbru003E u002Fu002FFrontu003Cbru003E 0, 1, 2,u003Cbru003E 1, 2, 3,u003Cbru003E u002Fu002FBacku003Cbru003E 4, 5, 6,u003Cbru003E 5, 6, 7,u003Cbru003E u002Fu002FRightu003Cbru003E 8, 9, 10,u003Cbru003E 9, 10, 11,u003Cbru003E u002Fu002FLeftu003Cbru003E 12, 13, 14,u003Cbru003E 13, 14, 15,u003Cbru003E u002Fu002FTopu003Cbru003E 16, 17, 18,u003Cbru003E 17, 18, 19,u003Cbru003E u002Fu002FBottomu003Cbru003E 20, 21, 22,u003Cbru003E 21, 22, 23u003Cbru003E ],u003Cbru003E Texture : [ u002Fu002FThis array is in groups of two, the x and y coordinates (a.k.a U,V) in the textureu003Cbru003E u002Fu002FThe numbers go from 0.0 to 1.0, One pair for each vertexu003Cbru003E u002Fu002FFrontu003Cbru003E 1.0, 1.0,u003Cbru003E 1.0, 0.0,u003Cbru003E 0.0, 1.0,u003Cbru003E 0.0, 0.0,u003Cbru003E u002Fu002FBacku003Cbru003E 0.0, 1.0,u003Cbru003E 0.0, 0.0,u003Cbru003E 1.0, 1.0,u003Cbru003E 1.0, 0.0,u003Cbru003E u002Fu002FRightu003Cbru003E 1.0, 1.0,u003Cbru003E 1.0, 0.0,u003Cbru003E 0.0, 1.0,u003Cbru003E 0.0, 0.0,u003Cbru003E u002Fu002FLeftu003Cbru003E 0.0, 1.0,u003Cbru003E 0.0, 0.0,u003Cbru003E 1.0, 1.0,u003Cbru003E 1.0, 0.0,u003Cbru003E u002Fu002FTopu003Cbru003E 1.0, 0.0,u003Cbru003E 1.0, 1.0,u003Cbru003E 0.0, 0.0,u003Cbru003E 0.0, 1.0,u003Cbru003E u002Fu002FBottomu003Cbru003E 0.0, 0.0,u003Cbru003E 0.0, 1.0,u003Cbru003E 1.0, 0.0,u003Cbru003E 1.0, 1.0u003Cbru003E ]u003Cbru003E};u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E这样一个简单的立方体用到的数据似乎有点过多,不过,在我们教程的第二部分中,我们写一个导入3D模型的脚本,所以你现在不必计较这些。u003Cu002Fpu003Eu003Cpu003E你可能还在想,为什么需要24个顶点 (每一面4个) 呢,实际上只有8个呀? 我这样做是因为,你可以只用为每个顶点指定一个纹理坐标;而如果你用8个顶点,则整个立方体将看起来一样,因为它会将一个纹理值传播到顶点接触的所有面上。 通过我们的方式,每个面都有它独有的点,所以我们可以在每一面上指定不同的纹理区域。u003Cu002Fpu003Eu003Cpu003E现在,我们有了这样一个立方体变量 cube,然后,我们可以准备画它了。 我们还是回到WebGL方法中,并添加一个Draw函数。u003Cu002Fpu003Eu003Cpu003E第三步:Draw函数u003Cu002Fpu003Eu003Cpu003EWebGL中绘制对象的过程有许多步骤;所以最好是将每个步骤写成函数,来简化这个过程的代码。 基本的想法是将三个数组加载到WebGL的缓存中去。 然后,我们将这些缓存连接到着色器中定义的属性,以及变换和透视矩阵。 接下来,我们需要将纹理加载到内存中,并且最后调用draw命令。 那么,我们开始吧。u003Cu002Fpu003Eu003Cpu003E接下来的代码进入到WebGL函数中:u003Cu002Fpu003Eu003Cpreu003Ethis.Draw = function(Object, Texture)u003Cbru003E{u003Cbru003E var VertexBuffer = this.GL.createBuffer(); u002Fu002FCreate a New Bufferu003Cbru003E u002Fu002FBind it as The Current Bufferu003Cbru003E this.GL.bindBuffer(this.GL.ARRAY_BUFFER, VertexBuffer);u003Cbru003E u002Fu002F Fill it With the Datau003Cbru003E this.GL.bufferData(this.GL.ARRAY_BUFFER, new Float32Array(Object.Vertices), this.GL.STATIC_DRAW);u003Cbru003E u002Fu002FConnect Buffer To Shader’s attributeu003Cbru003E this.GL.vertexAttribPointer(this.VertexPosition, 3, this.GL.FLOAT, false, 0, 0);u003Cbru003E u002Fu002FRepeat For The next Twou003Cbru003E var TextureBuffer = this.GL.createBuffer();u003Cbru003E this.GL.bindBuffer(this.GL.ARRAY_BUFFER, TextureBuffer);u003Cbru003E this.GL.bufferData(this.GL.ARRAY_BUFFER, new Float32Array(Object.Texture), this.GL.STATIC_DRAW);u003Cbru003E this.GL.vertexAttribPointer(this.VertexTexture, 2, this.GL.FLOAT, false, 0, 0);u003Cbru003E var TriangleBuffer = this.GL.createBuffer();u003Cbru003E this.GL.bindBuffer(this.GL.ELEMENT_ARRAY_BUFFER, TriangleBuffer);u003Cbru003E u002Fu002FGenerate The Perspective Matrixu003Cbru003E var PerspectiveMatrix = MakePerspective(45, this.AspectRatio, 1, 10000.0);u003Cbru003E var TransformMatrix = MakeTransform(Object);u003Cbru003E u002Fu002FSet slot 0 as the active Textureu003Cbru003E this.GL.activeTexture(this.GL.TEXTURE0);u003Cbru003E u002Fu002FLoad in the Texture To Memoryu003Cbru003E this.GL.bindTexture(this.GL.TEXTURE_2D, Texture);u003Cbru003E u002Fu002FUpdate The Texture Sampler in the fragment shader to use slot 0u003Cbru003E this.GL.uniform1i(this.GL.getUniformLocation(this.ShaderProgram, “uSampler”), 0);u003Cbru003E u002Fu002FSet The Perspective and Transformation Matricesu003Cbru003E var pmatrix = this.GL.getUniformLocation(this.ShaderProgram, “PerspectiveMatrix”);u003Cbru003E this.GL.uniformMatrix4fv(pmatrix, false, new Float32Array(PerspectiveMatrix));u003Cbru003E var tmatrix = this.GL.getUniformLocation(this.ShaderProgram, “TransformationMatrix”);u003Cbru003E this.GL.uniformMatrix4fv(tmatrix, false, new Float32Array(TransformMatrix));u003Cbru003E u002Fu002FDraw The Trianglesu003Cbru003E this.GL.drawElements(this.GL.TRIANGLES, Object.Trinagles.length, this.GL.UNSIGNED_SHORT, 0);u003Cbru003E};u003Cbru003Eu003Cu002Fpreu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002Fc8955a4265e743778f07e1fb4334bb58″ img_width=”600″ img_height=”250″ alt=”「WebGL基础」:第一部分” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E顶点着色器对你的对象进行放置,旋转和缩放时,依据的都是变换和透视矩阵。 在本教程第二部分中,我们会更深入地介绍变换。u003Cu002Fpu003Eu003Cpu003E我已经添加了两个函数:MakePerspective()和MakeTransform()。 它们只不过生成了WebGL所需的4×4矩阵。 MakePerspective()函数接受几个参数:视场竖直高度,宽高比,最近和最远点。 任何比1个单位近或比10000个单位远的对象都不会被显示,但是你可以调整这些值,以得到你所期望的效果。 现在,让我们看一看这两个函数:u003Cu002Fpu003Eu003Cpreu003Efunction MakePerspective(FOV, AspectRatio, Closest, Farest){u003Cbru003E var YLimit = Closest * Math.tan(FOV * Math.PI u002F 360);u003Cbru003E var A = -( Farest + Closest ) u002F ( Farest – Closest );u003Cbru003E var B = -2 * Farest * Closest u002F ( Farest – Closest );u003Cbru003E var C = (2 * Closest) u002F ( (YLimit * AspectRatio) * 2 );u003Cbru003E var D = (2 * Closest) u002F ( YLimit * 2 );u003Cbru003E return [u003Cbru003E C, 0, 0, 0,u003Cbru003E 0, D, 0, 0,u003Cbru003E 0, 0, A, -1,u003Cbru003E 0, 0, B, 0u003Cbru003E ];u003Cbru003E}u003Cbru003Efunction MakeTransform(Object){u003Cbru003E return [u003Cbru003E 1, 0, 0, 0,u003Cbru003E 0, 1, 0, 0,u003Cbru003E 0, 0, 1, 0,u003Cbru003E 0, 0, -6, 1u003Cbru003E ];u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E这些矩阵都会影响到你的对象的最终视觉效果,但透视矩阵影响的是你的“3维世界”,比如视场和可见对象,而变换矩阵影响的是单个对象,比如它们的旋转和位置。 完成这些之后,我们几何可以开始画了,剩下的工作只是将一个图像转变为一个WebGL纹理。u003Cu002Fpu003Eu003Cpu003E第四步:加载纹理u003Cu002Fpu003Eu003Cpu003E加载一个纹理分两步。 首先,我们要用JavaScript的标准做法来加载一幅图像,然后,我们将其转化为一个WebGL纹理。 所以,我们先从第二步开始吧,毕竟我们正在讨论的是JS文件。 将下面的代码加到WebGL函数的底部,恰好在Draw命令之后。u003Cu002Fpu003Eu003Cpreu003Ethis.LoadTexture = function(Img){u003Cbru003E u002Fu002FCreate a new Texture and Assign it as the active oneu003Cbru003E var TempTex = this.GL.createTexture();u003Cbru003E this.GL.bindTexture(this.GL.TEXTURE_2D, TempTex);u003Cbru003E u002Fu002FFlip Positive Y (Optional)u003Cbru003E this.GL.pixelStorei(this.GL.UNPACK_FLIP_Y_WEBGL, true);u003Cbru003E u002Fu002FLoad in The Imageu003Cbru003E this.GL.texImage2D(this.GL.TEXTURE_2D, 0, this.GL.RGBA, this.GL.RGBA, this.GL.UNSIGNED_BYTE, Img);u003Cbru003E u002Fu002FSetup Scaling propertiesu003Cbru003E this.GL.texParameteri(this.GL.TEXTURE_2D, this.GL.TEXTURE_MAG_FILTER, this.GL.LINEAR);u003Cbru003E this.GL.texParameteri(this.GL.TEXTURE_2D, this.GL.TEXTURE_MIN_FILTER, this.GL.LINEAR_MIPMAP_NEAREST);u003Cbru003E this.GL.generateMipmap(this.GL.TEXTURE_2D);u003Cbru003E u002Fu002FUnbind the texture and return it.u003Cbru003E this.GL.bindTexture(this.GL.TEXTURE_2D, null);u003Cbru003E return TempTex;u003Cbru003E};u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E值得一提的是,你的纹理大小必须是偶数字节,否则你会得到错误信息;比如它们可能的维度包括:2×2,4×4,16×16,32×32,等等。 我另加了一行来翻转Y坐标,只是因为我的3D应用的Y坐标是朝后的,但是否这样做完全取决于你。 这是因为一些程序取Y的零点为左上角,而其它则为左下角。 我设置的这些缩放性质只是告诉WebGL,图像应该如何向上采样和向下采样。 你可以使用其它的选项来得到不同的效果,不过我认为这个组合效果最佳。u003Cu002Fpu003Eu003Cpu003E现在,我们完成了JS文件,我们可以回到HTML文件,来完成最后一步了。u003Cu002Fpu003Eu003Cpu003E第五步:合起来u003Cu002Fpu003Eu003Cpu003E如前所述,WebGL是在canvas元素上画画。 因此,在body部分里,我们所需要的就只是一个canvas画布。 在添加canvas元素之后,你的html页面看起来像下面这样:u003Cu002Fpu003Eu003Cpreu003E<html>u003Cbru003E<head>u003Cbru003E <!– Include Our WebGL JS file –>u003Cbru003E <script src=”WebGL.js” type=”textu002Fjavascript”><u002Fscript>u003Cbru003E <script>u003Cbru003E <u002Fscript>u003Cbru003E<u002Fhead>u003Cbru003E<body onload=”Ready()”>u003Cbru003E<canvas id=”GLCanvas” width=”720″ height=”480″>u003Cbru003E Your Browser Doesn’t Support HTML5’s Canvas.u003Cbru003E<u002Fcanvas>u003Cbru003E<!– Your Vertex Shader –>u003Cbru003E<!– Your Fragment Shader –>u003Cbru003E<u002Fbody>u003Cbru003E<u002Fhtml>u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E这个页面相当简单。 在head区域,我链接了JS文件。 现在,让我们实现Ready函数,它在页面加载时调用。u003Cu002Fpu003Eu003Cpreu003Eu002Fu002FThis will hold our WebGL variableu003Cbru003Evar GL;u003Cbru003Eu002Fu002FOur finished textureu003Cbru003Evar Texture;u003Cbru003Eu002Fu002FThis will hold the textures image u003Cbru003Evar TextureImage;u003Cbru003Efunction Ready(){u003Cbru003E GL = new WebGL(“GLCanvas”, “FragmentShader”, “VertexShader”);u003Cbru003E TextureImage = new Image();u003Cbru003E TextureImage.onload = function(){u003Cbru003E Texture = GL.LoadTexture(TextureImage);u003Cbru003E GL.Draw(Cube, Texture);u003Cbru003E };u003Cbru003E TextureImage.src = “Texture.png”;u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E所以,我们创建一个新的WebGL对象,并将canvas和着色器的ID传递进去。 接下来,我们加载纹理图像。 一旦加载完成,我们对立方体Cube和纹理Texture调用Draw()方法。 如果你一路跟下来,你的屏幕上应该有一个覆盖有纹理的静止立方体。u003Cu002Fpu003Eu003Cpu003E虽然我说了下一次再讲变换,但我们不可能只丢给你一个静止矩形,这还不够三维。 让我们回过头去,再添加一个小小的旋转吧。 在HTML文件中,修改onload函数,使之如下面的代码:u003Cu002Fpu003Eu003Cpreu003ETextureImage.onload = function(){u003Cbru003E Texture = GL.LoadTexture(TextureImage);u003Cbru003E setInterval(Update, 33);u003Cbru003E};u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E这会使得每隔33毫秒调用一个称为Update()的函数,因而我们得到约30fps的帧率。 下面是这个更新函数:u003Cu002Fpu003Eu003Cpreu003Efunction Update(){u003Cbru003E GL.GL.clear(16384 | 256);u003Cbru003E GL.Draw(GL.Cube, Texture);u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E这个函数相当简单;它只不过清除屏幕,然后绘制更新后的立方体。 现在,让我们进入JS文件,添加旋转代码。u003Cu002Fpu003Eu003Cpu003E第六步:添加一些旋转u003Cu002Fpu003Eu003Cpu003E我们不会完全实现变换的代码,因为我说了要等到下次现说,这次我们只是加一个绕Y轴的旋转。 要做的第一件事就是在Cube对象中加一个Rotation变量。 它会跟踪当前的角度,并让我们可以递增地保持旋转。 所以你的Cube变量的顶部代码应该如下面这样:u003Cu002Fpu003Eu003Cpreu003Evar Cube = {u003Cbru003E Rotation : 0,u003Cbru003E u002Fu002FThe Other Three Arraysu003Cbru003E};u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E现在,让我们修改MakeTransform()函数,添加旋转功能:u003Cu002Fpu003Eu003Cpreu003Efunction MakeTransform(Object){u003Cbru003E var y = Object.Rotation * (Math.PI u002F 180.0);u003Cbru003E var A = Math.cos(y);u003Cbru003E var B = -1 * Math.sin(y);u003Cbru003E var C = Math.sin(y);u003Cbru003E var D = Math.cos(y);u003Cbru003E Object.Rotation += .3;u003Cbru003E return [u003Cbru003E A, 0, B, 0,u003Cbru003E 0, 1, 0, 0,u003Cbru003E C, 0, D, 0,u003Cbru003E 0, 0, -6, 1u003Cbru003E ];u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp3.pstatp.comu002Flargeu002Fpgc-imageu002F70edd028201c4355bb68ba57d7d27ed0″ img_width=”627″ img_height=”464″ alt=”「WebGL基础」:第一部分” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E更多精彩内容,请微信关注u003Cstrongu003E“前端达人”u003Cu002Fstrongu003E公众号!u003Cu002Fpu003Eu003Cpu003E原文链接:https:u002Fu002Fcode.tutsplus.comu002Fzh-hansu002Farticlesu002Fwebgl-essentials-part-i–net-25856u003Cu002Fpu003Eu003Cpu003E原文作者:Gabriel Manricksu003Cu002Fpu003Eu003Cu002Fdivu003E”

原文始发于:「WebGL基础」:第一部分

主题测试文章,只做测试使用。发布者:杀手梦三刀,转转请注明出处:http://www.cxybcw.com/10780.html

联系我们

13687733322

在线咨询:点击这里给我发消息

邮件:1877088071@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code