<!--探讨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. JAVA反映机制A

    以下这个URL讲得不错,可以把概念和用途结合起来, 练练手: http://blog.csdn.net/xiaohai798/article/details/11640427 import java. ...

  2. POJ 3225

    基本参考http://blog.csdn.net/metalseed/article/details/8039326 总的来说,敲完一遍理解会更加好一点,标记下传法. U:把区间[l,r]覆盖成1I: ...

  3. 关于IFeatureSelection的SelectFeatures方法

    近期做项目时用到IFeatureLayer as IFeatureSelection,然后使用IFeatureSelection.SelectFeatures方法.可是得到的IFeatureSelec ...

  4. org.openqa.selenium.NoSuchElementException:

    http://www.blogjava.net/qileilove/archive/2014/12/11/421309.html selenium webdriver定位不到元素的五种原因及解决办法 ...

  5. Fitnesse FIT的使用

    FIT是fitnesse使用的默认的引擎(SLIM的使用在上一篇文章中说明),不需要特别声明即可使用执行表格测试,所有编写的fixture都需要继承Fit的Fitxture 编写测试用例前需要先声明c ...

  6. HDOJ GCD 2588【欧拉函数】

    GCD Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis ...

  7. 深度学习实战篇-基于RNN的中文分词探索

    深度学习实战篇-基于RNN的中文分词探索 近年来,深度学习在人工智能的多个领域取得了显著成绩.微软使用的152层深度神经网络在ImageNet的比赛上斩获多项第一,同时在图像识别中超过了人类的识别水平 ...

  8. js分享代码

    <<!DOCTYPE html><html><head> <title></title></head> <body& ...

  9. php简单测试slim框架的功能

    php简单测试slim框架的功能 监听主路径/ $app->get( '/', function () { $template = <<<EOT<!DOCTYPE htm ...

  10. Python基本数据类型之字符串str

    字符串 定义:它是一个有序的字符的集合,用于存储和表示基本的文本信息,‘’或“”或‘’‘ ’‘’中间包含的内容称之为字符串 字符串的结构类型为'...' "..." "' ...