WebGL切换着色器 绘制不同物体

1、为何切换着色器

WebGL绘制不同的物体需要使用不同的着色器,每个着色器中可能有非常负责的逻辑以实现各种不同的效果。我们可以准备多个着色器,然后根据需要来切换使用它们。

2、如何实现切换着色器

为了切换着色器,首先创建多个着色器程序对象,然后在绘制之前选择使用的程序对象(使用gl.useProgram()函数来进行切换)。
下面是本次实例程序(实例程序绘制了两个立方体:一个单色立方体,一个纹理立方体)的流程步骤:

1. 准备绘制单色立方体的着色器

2. 准备绘制纹理立方体的着色器

3. 调用createProgram()函数,利用第1步创建出的着色器,创建单色立方体着色器程序对象

4. 调用createProgram()函数,利用第2步创建出的着色器,创建纹理立方体着色器程序对象

5. 调用gl.useProgram()函数,指定使用第3步创建的绘制单色立方体的着色器程序对象。

6. 通过缓冲区对象向着色器中传入attribute变量并开启。

7. 绘制单色立方体。

8. 调用gl.useProgram()函数,指定使用第4步创建的绘制纹理立方体的着色器程序对象。

9. 通过缓冲区对象向着色器传入attribute变量并开启。

10. 绘制纹理立方体。

3、实例程序

效果图:

实例代码:


<!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>
</head>
<body onload="main()">
<canvas id="webgl" width="400" height="400">Please use the browser supporting "canvas"
</canvas><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>// canvas全屏var canvas = document.getElementById('webgl');canvas.width = window.innerWidth;canvas.height = window.innerHeight;// 顶点着色器 绘制单色立方体var SOLID_VSHADER_SOURCE ="attribute vec4 a_Position;\n" +"attribute vec4 a_Normal;\n" + // 法向量"uniform mat4 u_MvpMatrix;\n" +"uniform mat4 u_NormalMatrix;\n" +"varying vec4 v_Color;\n" +"void main(){\n" +"   vec3 lightDirection = vec3(0.0,0.0, 1.0);\n" +//设置灯光的坐标位置(世界坐标下)"   vec4 color = vec4(0.0, 1.0, 1.0, 1.0);\n" + //设置立方体的颜色"   gl_Position = u_MvpMatrix * a_Position;\n" +"   vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));\n" +"   float nDotL = max(dot(normal, lightDirection), 0.0);\n" +"   v_Color = vec4(color.rgb * nDotL, color.a);\n" +"}\n";// 片元着色器 绘制单色立方体var SOLID_FSHADER_SOURCE ="#ifdef GL_ES\n" +"precision mediump float;\n" +"#endif\n" +"varying vec4 v_Color;\n" +"void main(){\n" +"   gl_FragColor = v_Color;\n" +"}\n";// 顶点着色器 绘制纹理立方体var TEXTURE_VSHADER_SOURCE ="attribute vec4 a_Position;\n" +"attribute vec4 a_Normal;\n" +"attribute vec2 a_TexCoord;\n" +"uniform mat4 u_MvpMatrix;\n" +"uniform mat4 u_NormalMatrix;\n" +"varying float v_NdotL;\n" +"varying vec2 v_TexCoord;\n" +"void main(){\n" +"   vec3 lightDirection = vec3(0.0, 0.0, 1.0);\n" +"   gl_Position = u_MvpMatrix * a_Position;\n" +"   vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));\n" +"   v_NdotL = max(dot(normal, lightDirection), 0.0);\n" +"   v_TexCoord = a_TexCoord;\n" +"}\n";// 片元着色器 绘制纹理立方体var TEXTURE_FSHADER_SOURCE ="#ifdef GL_ES\n" +"precision mediump float;\n" +"#endif\n" +"uniform sampler2D u_Sampler;\n" +"varying vec2 v_TexCoord;\n" +"varying float v_NdotL;\n" +"void main(){\n" +"   vec4 color = texture2D(u_Sampler, v_TexCoord);\n" +"   gl_FragColor = vec4(color.rgb * v_NdotL, color.a);\n" +"}\n";// 主函数function main() {// 获取WebGL绘图上下文var gl = getWebGLContext(canvas);if(!gl) {console.log('获取WebGL上下文失败');return;}// 初始化两个程序着色器var solidProgram = createProgram(gl,SOLID_VSHADER_SOURCE, SOLID_FSHADER_SOURCE); // 纯色立方体var textureProgram = createProgram(gl,TEXTURE_VSHADER_SOURCE,TEXTURE_FSHADER_SOURCE); // 纹理立方体if(!solidProgram || !textureProgram) {console.log('创建程序对象失败');return;}// 获取绘制单色立方体着色器的变量位置solidProgram.a_Position = gl.getAttribLocation(solidProgram, "a_Position");solidProgram.a_Normal = gl.getAttribLocation(solidProgram, "a_Normal");solidProgram.u_MvpMatrix = gl.getUniformLocation(solidProgram, "u_MvpMatrix");solidProgram.u_NormalMatrix = gl.getUniformLocation(solidProgram, "u_NormalMatrix");if(solidProgram.a_Position < 0 || solidProgram.a_Normal < 0 || !solidProgram.u_MvpMatrix || !solidProgram.u_NormalMatrix) {console.log('获取单色立方体相关变量存储位置失败');return;}// 获取绘制纹理立方体着色器的变量位置textureProgram.a_Position = gl.getAttribLocation(textureProgram, "a_Position");textureProgram.a_Normal = gl.getAttribLocation(textureProgram, "a_Normal");textureProgram.a_TexCoord = gl.getAttribLocation(textureProgram, "a_TexCoord");textureProgram.u_MvpMatrix = gl.getUniformLocation(textureProgram, "u_MvpMatrix");textureProgram.u_NormalMatrix = gl.getUniformLocation(textureProgram, "u_NormalMatrix");textureProgram.u_Sampler = gl.getUniformLocation(textureProgram, "u_Sampler");if(textureProgram.a_Position < 0 || textureProgram.a_Normal < 0 || textureProgram.a_TexCoord < 0 || !textureProgram.u_MvpMatrix || !textureProgram.u_NormalMatrix || !textureProgram.u_Sampler) {console.log('获取纹理立方体相关变量存储位置失败');return;}// 设置单色立方体顶点信息 存入缓冲区var cube = initVertexBuffers(gl);// 设置纹理立方体的纹理数据 存入缓冲区var texture = initTextures(gl, textureProgram);if(!texture) {console.log('无法获取到纹理');return;}//开启隐藏面消除功能,并设置背景色gl.enable(gl.DEPTH_TEST);gl.clearColor(0.0, 0.0, 0.0, 1.0);// 计算视图投影矩阵var viewProjectMatrix = new Matrix4();viewProjectMatrix.setPerspective(30.0, canvas.width / canvas.height, 1.0, 100.0);viewProjectMatrix.lookAt(0.0, 0.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);// 开始绘制立方体var currentAngle = 0.0; // 当前立方体的角度//设置一个定时绘制的函数var tick = function() {   // Start drawingcurrentAngle = animate(currentAngle); // 更新角度gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);// 绘制单色立方体drawSolidCube(gl, solidProgram, cube, -2.0, currentAngle, viewProjectMatrix);// 绘制纹理立方体drawTexCube(gl, textureProgram, cube, texture, 2.0, currentAngle, viewProjectMatrix);requestAnimationFrame(tick);};tick();}function drawTexCube(gl, program, obj, texture, x, angle, viewProjectMatrix) {gl.useProgram(program);// 分配缓存对象并开启赋值initAttributeVariable(gl, program.a_Position, obj.vertexBuffer); //顶点坐标initAttributeVariable(gl, program.a_Normal, obj.normalBuffer); //法向量initAttributeVariable(gl, program.a_TexCoord, obj.texCoordBuffer); //纹理坐标gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, obj.indexBuffer);//设置好纹理对象,开启使用0号的纹理gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D, texture);//绘制立方体drawCube(gl, program, obj, x, angle, viewProjectMatrix)}function drawSolidCube(gl, program, obj, x, angle, viewProjectMatrix) {gl.useProgram(program);//分配缓冲区对象并启用赋值initAttributeVariable(gl, program.a_Position, obj.vertexBuffer); //顶点坐标initAttributeVariable(gl, program.a_Normal, obj.normalBuffer); //法向量gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, obj.indexBuffer); //绑定索引//绘制立方体drawCube(gl, program, obj, x, angle, viewProjectMatrix);}// 声明绘制需要变换矩阵变量var g_modelMatrix = new Matrix4();var g_mvpMatrix = new Matrix4();var g_normalMatrix = new Matrix4();function drawCube(gl, program, obj, x, angle, viewProjectMatrix) {// 计算模型矩阵g_modelMatrix.setTranslate(x, 0.0, 0.0);g_modelMatrix.rotate(20.0, 1.0, 0.0, 0.0);g_modelMatrix.rotate(angle, 0.0, 1.0, 0.0);// 计算出法向量的方向 并赋值g_normalMatrix.setInverseOf(g_modelMatrix);g_normalMatrix.transpose();gl.uniformMatrix4fv(program.u_NormalMatrix, false, g_normalMatrix.elements);// 计算视图模型投影矩阵g_mvpMatrix.set(viewProjectMatrix);g_mvpMatrix.multiply(g_modelMatrix);gl.uniformMatrix4fv(program.u_MvpMatrix, false, g_mvpMatrix.elements);gl.drawElements(gl.TRIANGLES, obj.numIndices, obj.indexBuffer.type, 0);}function initAttributeVariable(gl, a_attribute, buffer) {gl.bindBuffer(gl.ARRAY_BUFFER, buffer);gl.vertexAttribPointer(a_attribute, buffer.num, buffer.type, false, 0, 0);gl.enableVertexAttribArray(a_attribute);}var angle_step = 30; // 每秒旋转角度var last = +new Date(); // 保存上次调用animate函数的时间function animate(angle) {var now = +new Date();var elapsed = now - last;last = now;var newAngle = angle + (angle_step * elapsed) / 1000.0;return newAngle % 360.0;}function initTextures(gl,program) {var texture = gl.createTexture();if(!texture) {console.log('无法创建纹理缓冲区');return null;}var img = new Image();img.onload = function() {// 将图形数据存入纹理对象gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D, texture);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);// 将纹理存入到第一个纹理缓冲区gl.useProgram(program);gl.uniform1i(program.u_Sampler, 0);gl.bindTexture(gl.TEXTURE_2D, null); // 解绑当前}img.src = '../images/wallpaper.jpg';return texture;}function initVertexBuffers(gl) {var vertices = new Float32Array([1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0,    // v0-v1-v2-v3 front1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0,    // v0-v3-v4-v5 right1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0,    // v0-v5-v6-v1 up-1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0,    // v1-v6-v7-v2 left-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0,    // v7-v4-v3-v2 down1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0     // v4-v7-v6-v5 back]);var normals = new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,     // v0-v1-v2-v3 front1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,     // v0-v3-v4-v5 right0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,     // v0-v5-v6-v1 up-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0,     // v1-v6-v7-v2 left0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0,     // v7-v4-v3-v2 down0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0      // v4-v7-v6-v5 back]);var texCoords = new Float32Array([1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,    // v0-v1-v2-v3 front0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0,    // v0-v3-v4-v5 right1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,    // v0-v5-v6-v1 up1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,    // v1-v6-v7-v2 left0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,    // v7-v4-v3-v2 down0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0     // v4-v7-v6-v5 back]);var indices = new Uint8Array([0, 1, 2, 0, 2, 3,    // front4, 5, 6, 4, 6, 7,    // right8, 9, 10, 8, 10, 11,    // up12, 13, 14, 12, 14, 15,    // left16, 17, 18, 16, 18, 19,    // down20, 21, 22, 20, 22, 23     // back]);var obj = {}; // 使用对象返回多个缓冲区对象// 将顶点信息写入缓冲区obj.vertexBuffer = initArrayBufferForLaterUse(gl, vertices, 3, gl.FLOAT);obj.normalBuffer = initArrayBufferForLaterUse(gl, normals, 3, gl.FLOAT);obj.texCoordBuffer = initArrayBufferForLaterUse(gl, texCoords, 2, gl.FLOAT);obj.indexBuffer = initElementArrayBufferForLaterUse(gl, indices, gl.UNSIGNED_BYTE);if(!obj.vertexBuffer || !obj.normalBuffer || !obj.texCoordBuffer || !obj.indexBuffer){return null;}obj.numIndices = indices.length;//取消绑定焦点的数据gl.bindBuffer(gl.ARRAY_BUFFER, null);gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);return obj;}function initElementArrayBufferForLaterUse(gl, data, type) {var buffer = gl.createBuffer();if(!buffer) {console.log('无法创建缓冲区对象');return;}// 将数据写入缓冲区gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW);buffer.type = type;return buffer;}function initArrayBufferForLaterUse(gl, data, num, type) {var buffer = gl.createBuffer();if(!buffer) {console.log('无法创建缓冲区对象');return;}// 将数据写入缓冲区对象gl.bindBuffer(gl.ARRAY_BUFFER, buffer);gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);// 保留信息buffer.num = num;buffer.type = type;return buffer;}</script>
</body>
</html>

WebGL切换着色器 绘制不同物体相关推荐

  1. WebGL切换着色器方法与错误

    WebGL一种着色器,是无法满足渲染需求的,需要使用不同的渲染器,这次测试了 一下渲染器的切换.切换渲染器的时候,上一个着色器的东西肯定是要清除的. gl.deleteShader(FSShader) ...

  2. 网页高性能图形编程(四)-WebGL颜色-使用着色器绘制多顶点颜色的三角图形 操作部骤-顶点着色器和片段着色器 着色器编译羽图像绘制-vertexAttribPointer 方法

    第5章-WebGL颜色 01-操作步骤介绍 颜色添加步骤 在顶点着色器中定义一个接收外部传入颜色值的属性变量a_Color和用于传输获取到的颜色值变量v_Color 在片段着色器中定义一个同一类型和名 ...

  3. webgl入门(2)-初识webgl和着色器

    前言 原书中第2章非常长,如果整理成一个文档的话,得看好多天.为了浏览方便,我将其拆分成若干小节,方便大家学习. webgl采用HTML5中引入的canvas元素来定义页面的绘图区域.如果没有WegG ...

  4. webgl——使用着色器给图形给点颜色看看(二)

    文章目录 前言 绘制一个点 初始化着色器 存储限定符 向 webgl 系统传递变量 前言 接前面文章,我们实现了一个最简单的 webgl 程序,但是只是程序运行起来只是漆黑一片,我们想要通过 webg ...

  5. WebGL基础:着色器基础知识

    今天由字节跳动的"yancy"童鞋给大家重磅推出一篇WebGL的干货接下来让我们开启奇幻旅程,进入 3D 的世界. 本文作者:yancy 1. 认识3D 首先我们要介绍的是几个概念 ...

  6. WebGL入门(四)-在JavaScript程序通过uniform变量向片元着色器传值

    在JavaScript程序通过uniform变量向片元着色器传值 1.demo效果 2.相关知识点 2.1 片元着色器中的uniform变量 2.2 gl.getUniformLocation()方法 ...

  7. WebGL编程指南03-在javaScript程序通过uniform变量向片元着色器传值

    1.demo效果 如上图,这个demo实现在黑色区域内点用鼠标点击,会在不同的区域画出不同颜色的小方块,第一象限的画红色方块,第三象限画绿色方块,第二.四象限画蓝色方块. 2 片元着色器的unifor ...

  8. 《Qt-OpenGL系列编程》课程学习记录(1):相关概念、VAO、VBO、绘制三角形、使用OpenGL原生方式编译链接着色器程序

    大家可以去B站看课程的视频支持一下作者哈: OpenGL,Qt实现:1入门篇(已更完)_哔哩哔哩_bilibili课程相关源码.PPT.安装包,完整课程合集(1:入门篇:2:基础光照:3:模型加载:4 ...

  9. 多个着色器与多个VAO,VBO绘制三角形

    多个着色器与多个VAO,VBO绘制三角形 设置不同片段着色器绘制两个三角形 设置多个不同片段着色器绘制三个三角形 写在最前面: 如果对一个三角形的绘制过程还不明白建议先去看看

  10. three.js的着色器(巨详细 初学者 大白话)

    three.js就不过多介绍了 可以看另一篇文章 总结就是场景  相机  和 渲染器 学起来 也比较轻松 后来看到了着色器 给我整懵乐了  一会一个API  一会一个API 都没见过 然后就一点点去学 ...

最新文章

  1. 领域驱动设计学习之路—DDD的原则与实践
  2. Java SecurityManager checkListen()方法与示例
  3. Go error 处理实践
  4. liblfds 测试
  5. oracle rac 高并发性能_Tomcat 高并发之道原理拆解与性能调优
  6. Android 4.4环境搭建——Android SDK下载与安装
  7. Android知识点汇总以及常见面试题
  8. ini文件中文乱码 python_用心盘Python:中文文件处理早晚会用到的将中文转成拼音...
  9. 在window10上安装miniconda
  10. paip.提升用户体验---c++ 右键菜单以及socket接口
  11. 【log4cpp_学习】2_log4cpp配置文件的使用
  12. Windows游戏编程 - 简单的弹球窗口
  13. 74CMS 3.0 SQL注入漏洞前台
  14. ArcGIS中ERROR 999999报错Configuration RasterCommander ImageServer can not be started解决
  15. 嵌入式开发Linux入门
  16. mutiget FlashGot
  17. 亲测好用的PS图片无损放大插件:Blow Up 3 for Mac
  18. KOL营销抢跑新消费品牌
  19. PTE学术英语考试受全球广泛认可,2018中国考量快速增长
  20. 我在华为的一次面试经历

热门文章

  1. jeeplus框架简介
  2. 在 VMware 虚拟机中 安装 Windows7 精简版系统
  3. chronodex怎么用_滴答清单使用全攻略:如何把手帐搬到滴答清单上,提升效率?...
  4. selenium之键盘操作
  5. selenium键盘操作
  6. 晚上睡觉手机放床头对大脑会有伤害吗
  7. 读书笔记:学习C语言必须读的第二本书
  8. 计算机网络计算1g等于多少MB,1g是多少mb(1g等于多少兆)
  9. java cmyk转rgb_Java实现把cmyk格式图片转换为RGB格式图片
  10. mac pdf去水印_Acrobat XI PRO/DC 2019 PDF编辑转换器去水印 WIN/MAC