<!--探讨WEBGL中不同图形的绘制方法:[待测试2017.11.6]-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>WEBGL高级编程----绘制三维场景(变换矩阵)</title>
<meta charset="utf-8">
<!--顶点着色器-->
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor; uniform mat4 uMVMatrix;
uniform mat4 uPMatrix; varying vec4 vColor; void main() {
vColor = aVertexColor;
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
} </script> <!--片元着色器-->
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float; varying vec4 vColor;
void main() {
gl_FragColor = vColor;
} </script> <!--引入我的库文件-->
<script src="./lib/webgl-debug.js"></script> <script type="text/javascript">
var gl;
var canvas;
var shaderProgram; //绘制桌子的场景模型
//地板的顶点位置和索引
var floorVertexPositionBuffer;
var floorVertexIndexBuffer; //立方体的顶点位置和索引
var cubeVertexPositionBuffer;
var cubeVertexIndexBuffer; //我的模型 视图 投影矩阵
var modelViewMatrix;
var projectionMatrix; //模型视图的矩阵栈
var modelViewMatrixStack; //创建我的上下文句柄
function createGLContext(canvas) {
var names = ["webgl", "experimental-webgl"];
var context = null;
for (var i = 0; i < names.length; i++) {
try {
context = canvas.getContext(names[i]);
} catch (e) {
}
if (context) {
break;
}
}
if (context) {
context.viewportWidth = canvas.width;
context.viewportHeight = canvas.height;
} else {
alert("Failed to create WebGL context!");
}
return context;
} //从JavaScript代码中通过DOM加载着色器
function loadShaderFromDOM(id) {
var shaderScript = document.getElementById(id); // If we don't find an element with the specified id
// we do an early exit
if (!shaderScript) {
return null;
} // Loop through the children for the found DOM element and
// build up the shader source code as a string
var shaderSource = "";
var currentChild = shaderScript.firstChild;
while (currentChild) {
if (currentChild.nodeType == 3) { // 3 corresponds to TEXT_NODE
shaderSource += currentChild.textContent;
}
currentChild = currentChild.nextSibling;
} var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
} gl.shaderSource(shader, shaderSource);
gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
} //设置我的着色器(完成着色器的部分初始化操作)
function setupShaders() {
var vertexShader = loadShaderFromDOM("shader-vs");
var fragmentShader = loadShaderFromDOM("shader-fs"); shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram); if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Failed to setup shaders");
} gl.useProgram(shaderProgram); //获取顶点的位置和颜色的存储地址
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor"); //回去模型视图矩阵的存储地址
shaderProgram.uniformMVMatrix = gl.getUniformLocation(shaderProgram, "uMVMatrix");
shaderProgram.uniformProjMatrix = gl.getUniformLocation(shaderProgram, "uPMatrix"); gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); //开始创建我的模型视图矩阵
modelViewMatrix = mat4.create();
projectionMatrix = mat4.create();
modelViewMatrixStack = [];
} //定义两个辅助函数(矩阵的入栈和出栈操作)
function pushModelViewMatrix() {
//把当前的模型视图矩阵存储在一个JavaScript数组中去
var copyToPush = mat4.create(modelViewMatrix);
modelViewMatrixStack.push(copyToPush);
} function popModelViewMatrix() {
if (modelViewMatrixStack.length == 0) {
throw "Error popModelViewMatrix() - Stack was empty";
}
//把我自己保存的模型视图矩阵弹出去
modelViewMatrix = modelViewMatrixStack.pop();
} //处理物体运动的一些基本参数
var xRot = 0;
var xSpeed = 3; var yRot = 0;
var ySpeed = -3; var z = -5.0; //可以处理多个按键同时按下的情形
var currentlyPressedKeys = {}; function handleKeyDown(event) {
currentlyPressedKeys[event.keyCode] = true;
} function handleKeyUp(event) {
currentlyPressedKeys[event.keyCode] = false;
} //根据不同的按键做出不同的反应
function handleKeys() {
if (currentlyPressedKeys[33]) {
// Page Up
z -= 0.05;
}
if (currentlyPressedKeys[34]) {
// Page Down
z += 0.05;
}
if (currentlyPressedKeys[37]) {
// Left cursor key
ySpeed -= 1;
}
if (currentlyPressedKeys[39]) {
// Right cursor key
ySpeed += 1;
}
if (currentlyPressedKeys[38]) {
// Up cursor key
xSpeed -= 1;
}
if (currentlyPressedKeys[40]) {
// Down cursor key
xSpeed += 1;
}
} //地板的顶点位置参数
function setupFloorBuffers() {
/****第一步****/
//1.创建地板顶点缓冲区
floorVertexPositionBuffer = gl.createBuffer();
//2.绑定缓冲区到目标对象
gl.bindBuffer(gl.ARRAY_BUFFER, floorVertexPositionBuffer);
var floorVertexPosition = [
// Plane in y=0
5.0, 0.0, 5.0, //v0
5.0, 0.0, -5.0, //v1
-5.0, 0.0, -5.0, //v2
-5.0, 0.0, 5.0 //v3
];
//3.向缓冲区对象中写入数据
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(floorVertexPosition), gl.STATIC_DRAW); floorVertexPositionBuffer.itemSize = 3;
floorVertexPositionBuffer.numberOfItems = 4; /****第二步***/
//1.创建地板顶点索引缓冲区.
floorVertexIndexBuffer = gl.createBuffer();
//2.绑定缓冲区到目标对象
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, floorVertexIndexBuffer);
var floorVertexIndices = [
0, 1, 2, 3
];
//3.向缓冲区对象中写入数据(16为无符号整型数字)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(floorVertexIndices), gl.STATIC_DRAW); floorVertexIndexBuffer.itemSize = 1;
floorVertexIndexBuffer.numberOfItems = 4; } //立方体的顶点位置参数
function setupCubeBuffers() {
/*****立方体的顶点位置*****/
//1.创建立方体的顶点缓冲区
cubeVertexPositionBuffer = gl.createBuffer();
//2.绑定缓冲区到目标对象
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
var cubeVertexPosition = [
// Front face
1.0, 1.0, 1.0, //v0
-1.0, 1.0, 1.0, //v1
-1.0, -1.0, 1.0, //v2
1.0, -1.0, 1.0, //v3 // Back face
1.0, 1.0, -1.0, //v4
-1.0, 1.0, -1.0, //v5
-1.0, -1.0, -1.0, //v6
1.0, -1.0, -1.0, //v7 // Left face
-1.0, 1.0, 1.0, //v8
-1.0, 1.0, -1.0, //v9
-1.0, -1.0, -1.0, //v10
-1.0, -1.0, 1.0, //v11 // Right face
1.0, 1.0, 1.0, //12
1.0, -1.0, 1.0, //13
1.0, -1.0, -1.0, //14
1.0, 1.0, -1.0, //15 // Top face
1.0, 1.0, 1.0, //v16
1.0, 1.0, -1.0, //v17
-1.0, 1.0, -1.0, //v18
-1.0, 1.0, 1.0, //v19 // Bottom face
1.0, -1.0, 1.0, //v20
1.0, -1.0, -1.0, //v21
-1.0, -1.0, -1.0, //v22
-1.0, -1.0, 1.0, //v23
];
//3.向缓冲区对象中写入数据
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubeVertexPosition), gl.STATIC_DRAW); //错误提示:Uncaught TypeError: Cannot read property 'toString' of undefined!
/*cubeVertexPosition.itemSize = 3;
cubeVertexPosition.numberOfItems = 24;*/
/*
* 【经验话语】:如果控制台提示toString()类型的错误,多半原因是由于调用该函数的语句中的某一个变量没有正确定义,或者没有正确初始化操作
* 【解决方案】:通常检查出错语句中的变量,是否正确赋值!
* */
cubeVertexPositionBuffer.itemSize = 3;
cubeVertexPositionBuffer.numberOfItems = 24; /*****立方体的顶点位置索引信息****/
//1.创建立方体顶点位置索引缓冲区
cubeVertexIndexBuffer = gl.createBuffer();
//2.绑定缓冲区到目标对象
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
var cubeVertexIndices = [
0, 1, 2, 0, 2, 3, // Front face
4, 6, 5, 4, 7, 6, // Back face
8, 9, 10, 8, 10, 11, // Left face
12, 13, 14, 12, 14, 15, // Right face
16, 17, 18, 16, 18, 19, // Top face
20, 22, 21, 20, 23, 22 // Bottom face
];
//3.向缓冲区对象中写入数据
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW); //索引之间互相独立, 共计有36个索引点的信息
cubeVertexIndexBuffer.itemSize = 1;
cubeVertexIndexBuffer.numberOfItems = 36;
} //设置我的缓冲区
function setupBuffers() {
//设置缓冲区分解为两个部分
//1.设置地板的顶点缓冲区
setupFloorBuffers();
//2.设置立方体的顶点缓冲区
setupCubeBuffers();
} //把我的模型视图矩阵传给顶点着色器
function uploadModelViewMatrixToShader() {
gl.uniformMatrix4fv(shaderProgram.uniformMVMatrix, false, modelViewMatrix);
}
//把我的投影矩阵传给顶点着色器
function uploadProjectionMatrixToShader() {
gl.uniformMatrix4fv(shaderProgram.uniformProjMatrix, false, projectionMatrix);
} //绘制地板
function drawFloor(r, g, b, a) {
//指定一个常量颜色
gl.disableVertexAttribArray(shaderProgram.vertexColorAttribute);
gl.vertexAttrib4f(shaderProgram.vertexColorAttribute, r, g, b, a); //开始绘制(先把地板顶点位置信息传给顶点着色器)
gl.bindBuffer(gl.ARRAY_BUFFER, floorVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,
floorVertexPositionBuffer.itemSize,
gl.FLOAT, false, 0, 0);
//利用顶点索引信息开始绘图
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, floorVertexIndexBuffer);
gl.drawElements(gl.TRIANGLE_FAN, floorVertexIndexBuffer.numberOfItems, gl.UNSIGNED_SHORT, 0); } //绘制立方体
function drawCube(r, g, b, a) {
//设置指定的颜色
gl.disableVertexAttribArray(shaderProgram.vertexColorAttribute);
gl.vertexAttrib4f(shaderProgram.vertexColorAttribute, r, g, b, a); //开始绘制
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0); //开始利用索引坐标绘制立方体
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numberOfItems,
gl.UNSIGNED_SHORT, 0); } //绘制卓子
function drawTable() {
//绘制之前先保存当前的模型视图矩阵
pushModelViewMatrix();//最初的模型视图矩阵
//alert(modelViewMatrixStack.length); 此时这里面存放了两个模型视图矩阵
//向上移动1个单位
mat4.translate(modelViewMatrix, [0.0, 1.0, 0.0], modelViewMatrix);
//开始缩放
mat4.scale(modelViewMatrix, [2.0, 0.1, 2.0], modelViewMatrix);
//把平移并且缩放后的矩阵(此时的模型视图矩阵)传到顶点着色器
uploadModelViewMatrixToShader(); //开始绘制立方体(主要是把立方体的顶点位置传给顶点着色器,然后顶点着色器就会对这个顶点位置向量进行矩阵变换)
drawCube(0.72, 0.53, 0.04, 1.0);
popModelViewMatrix(); //绘制桌子腿
for (var i=-1; i<=1; i+=2) {
for (var j= -1; j<=1; j+=2) {
pushModelViewMatrix();
mat4.translate(modelViewMatrix, [i*1.9, -0.1, j*1.9], modelViewMatrix);
mat4.scale(modelViewMatrix, [0.1, 1.0, 0.1], modelViewMatrix);
uploadModelViewMatrixToShader();
//绘制立方体(会把立方体的顶点坐标,进行矩阵变换)
drawCube(0.72, 0.53, 0.04, 1.0); // argument sets brown color
popModelViewMatrix();
}
}
} //绘图函数
function draw() {
//设置视口,清空深度缓存(左下角坐标, 宽度, 高度)
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT); //设置我的透视投影矩阵
mat4.perspective(60, gl.viewportWidth/gl.viewportHeight, 0.1, 100, projectionMatrix);
//重置模型视图矩阵
mat4.identity(modelViewMatrix);
mat4.lookAt([8, 5, -10], [0, 0, 0], [0, 1, 0], modelViewMatrix); //在这里设置转动整个场景
mat4.translate(modelViewMatrix, [0, 0, z], modelViewMatrix);
mat4.rotateY(modelViewMatrix, yRot, modelViewMatrix); //把当前的模型视图投影矩阵传递给顶点着色器(到这里顶点的坐标已经转换为了裁剪坐标系)
uploadModelViewMatrixToShader();
uploadProjectionMatrixToShader(); //开始绘制地板
drawFloor(1.0, 0.0, 0.0, 1.0); //绘制桌子
//绘制之前先把我当前的WEBGL坐标系统的矩阵保存起来【相当于是桌子腿的最下面位置】
pushModelViewMatrix();
//此时物体的坐标系到达桌子的最上表面(注意物体自身的坐标系和WEBGL坐标系的区别)
//这里实际上是把WEBGL坐标系移动到物体坐标系的原点位置
mat4.translate(modelViewMatrix, [0.0, 1.1, 0.0], modelViewMatrix);
uploadModelViewMatrixToShader();
drawTable();
popModelViewMatrix(); //开始绘制桌子上面的一个物体
pushModelViewMatrix();
mat4.translate(modelViewMatrix, [0.0, 2.7, 0.0], modelViewMatrix);
//把原来的立方体2*2*2变换为1*1*1的立方体,相当于把长宽高都缩减为原来的一半
mat4.scale(modelViewMatrix, [0.5, 0.5, 0.5], modelViewMatrix);
uploadModelViewMatrixToShader();
drawCube(0.0, 0.0, 1.0, 1.0);
popModelViewMatrix(); //在绘制一个图形
pushModelViewMatrix();
mat4.translate(modelViewMatrix, [0.0, 3.7, 0.0], modelViewMatrix);
mat4.scale(modelViewMatrix, [0.5, 0.5, 0.5], modelViewMatrix);
uploadModelViewMatrixToShader();
drawCube(0.0, 1.0, 0.0, 1.0);
popModelViewMatrix(); pushModelViewMatrix();
mat4.translate(modelViewMatrix, [0.0, 4.7, 0.0], modelViewMatrix);
mat4.scale(modelViewMatrix, [0.5, 0.5, 0.5], modelViewMatrix);
//mat4.rotateY(modelViewMatrix, yRot, modelViewMatrix);
uploadModelViewMatrixToShader();
drawCube(1.0, 1.0, 0.0, 1.0);
popModelViewMatrix(); //开始转动场景
/*mat4.rotate(modelViewMatrix, xRot, [1, 0, 0], modelViewMatrix);
mat4.rotateY(modelViewMatrix, yRot, modelViewMatrix);
uploadModelViewMatrixToShader();
uploadProjectionMatrixToShader();*/ } var lastTime = 0;
//实时更新旋转角度
function animate() {
var timeNow = new Date().getTime();
if (lastTime != 0) {
var elapsed = timeNow - lastTime; xRot += (xSpeed * elapsed) / 1000.0;
yRot += (ySpeed * elapsed) / 1000.0;
}
lastTime = timeNow;
} //不断重绘场景
function tick() {
requestAnimationFrame(tick);
handleKeys();
draw();
animate();
} function startup() {
canvas = document.getElementById("myGLCanvas");
gl = WebGLDebugUtils.makeDebugContext(createGLContext(canvas));
setupShaders();
setupBuffers();
gl.clearColor(1.0, 1.0, 1.0, 1.0); //逆时针方向是前面
gl.frontFace(gl.CW);
//激活背面剔除功能
gl.enable(gl.CULL_FACE);
//WEBGL剔除背面三角形
gl.cullFace(gl.FRONT); //draw(); document.onkeydown = handleKeyDown;
document.onkeyup = handleKeyUp; tick();
}
</script>
<script src="./lib/glMatrix.js"></script> </head> <body onload="startup();">
<canvas id="myGLCanvas" width="500" height="500" style="border: 2px solid springgreen;"></canvas>
</body> </html>
												

WEBGL学习【八】模型视图投影矩阵的更多相关文章

  1. OpenGL 模型视图投影矩阵 仿射矩阵

    矩阵基础知识 要对矩阵进行运算,必须先要了解矩阵的计算公式,这个知识的内容涉及到了线性代数. 我们知道在Cocos2dx中,有关于平移,旋转,缩放等等操作,都必须要进行矩阵的乘法. 只需要一张图就能理 ...

  2. 【GISER&&Painter】Chapter02:WebGL中的模型视图变换

    上一节我们提到了如何在一张画布上画一个简单几何图形,通过创建画布,获取WebGLRendering上下文,创建一个简单的着色器,然后将一些顶点数据绑定到gl的Buffer中,最后通过绑定buffer数 ...

  3. WEBGL学习【四】模型视图矩阵

    <html lang="zh-CN"> <!--服务器运行地址:http://127.0.0.1:8080/webgl/LearnNeHeWebGL/NeHeWe ...

  4. WebGL或OpenGL关于模型视图投影变换的设置技巧

    目录 1. 具体实例 2. 解决方案 1) Cube.html 2) Cube.js 3) 运行结果 3. 详细讲解 1) 模型变换 2) 视图变换 3) 投影变换 4) 模型视图投影矩阵 4. 存在 ...

  5. three.js中的矩阵变换(模型视图投影变换)

    目录 1. 概述 2. 基本变换 2.1. 矩阵运算 2.2. 模型变换矩阵 2.2.1. 平移矩阵 2.2.2. 旋转矩阵 2.2.2.1. 绕X轴旋转矩阵 2.2.2.2. 绕Y轴旋转矩阵 2.2 ...

  6. WEBGL学习【十五】利用WEBGL实现三维场景的一般思路总结

    实现三维场景载入操作的实现步骤: 主要知识点:着色器,纹理贴图,文件载入 实现思路: 获取canvas,初始化WEBGL上下文信息. 主要是实现WEBGL上下文的获取,设置视的大小,此时gl存储了WE ...

  7. WEBGL学习【十三】鼠标点击立方体改变颜色的原理与实现

    // PickFace.js (c) 2012 matsuda and kanda // Vertex shader program var VSHADER_SOURCE = 'attribute v ...

  8. WEBGL学习【十】运动模型

    <!DOCTYPE HTML> <html lang="en"> <head> <title>LWEBGL6.2, Animated ...

  9. WEBGL学习【九】立方体贴不同的纹理

    <html> <!--开始实现一个三维街景的渲染效果--> <head> <meta http-equiv="Content-Type" ...

随机推荐

  1. ACDream - k-GCD

    先上题目: B - k-GCD Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) Sub ...

  2. 洛谷——P1910 L国的战斗之间谍

    https://www.luogu.org/problem/show?pid=1910#sub 题目背景 L国即将与I国发动战争!! 题目描述 俗话说的好:“知己知彼,百战不殆”.L国的指挥官想派出间 ...

  3. 关于double类型数字相加位数发生变化的问题

     因为计算机内部存贮本身的缺陷,导致double类型的数字相加.得到的结果有非常多位,比方 774.23 750.0 2638.66 4162.889999999999 看到这个是不是非常晕 当然 ...

  4. 搭建单机CDH环境,并更新spark环境

    搭建单机CDH环境,并更新spark环境 1,安装VMWare Player,http://dlsw.baidu.com/sw-search-sp/soft/90/13927/VMware_playe ...

  5. GitLab 7.5.3 CentOS7安装和SMTP配置

    CentOS 7安装GitLab还是比較简单的,依照官方文档的提示一步一步操作下来.就一个地方须要改动. 參考:GitLab安装说明 在安装好以后,执行 gitlab-ctl reconfigure ...

  6. 剖析Mysql的InnoDB索引

    摘要: 本篇介绍下Mysql的InnoDB索引相关知识,从各种树到索引原理到存储的细节. InnoDB是Mysql的默认存储引擎(Mysql5.5.5之前是MyISAM,文档).本着高效学习的目的,本 ...

  7. Tomcat容器 web.xml具体解释

    <init-param> <param-name>debug</param-name> <param-value>0</param-value&g ...

  8. Python去除多余空格

    今天做爬虫时.发现结果中好多多余的空格.然后有强迫症的我当然不会放过 " xyz ".strip() # returns "xyz" " xyz &q ...

  9. 【java项目实战】ThreadLocal封装Connection,实现同一线程共享资源

    线程安全一直是程序员们关注的焦点.多线程也一直是比較让人头疼的话题,想必大家以前也遇到过各种各种的问题.我就不再累述了.当然,解决方案也有非常多,这篇博文给大家提供一种非常好的解决线程安全问题的思路. ...

  10. docker overlay网络实现

    DOCKER的内置OVERLAY网络 内置跨主机的网络通信一直是Docker备受期待的功能,在1.9版本之前,社区中就已经有许多第三方的工具或方法尝试解决这个问题,例如Macvlan.Pipework ...