<!--探讨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. CvsHelper 使用指南

    用于读取和写入CSV文件的.NET库. 非常快速,灵活和易于使用. 支持读写自定义类对象. 入门 要安装CsvHelper,请从包管理器控制台运行以下操作. Install-Package CsvHe ...

  2. 奇妙的go语言(基本的语法)

    [ 声明:版权全部,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 学习一门新的语言无非就是从主要的语法開始的.通过语法书来学习语言毕竟是很枯燥的,所以我们最好还 ...

  3. structs实现三种action的方法

    第一种:一般类,带有public String execute()方法. 另外一种:继承LoginActionInterface implements Action接口的类. 第三种:继承LoginA ...

  4. Cloud Card是否能干掉App

    算下来有一年没写blog了.这一年算是潜心做一件事情,随着云OS 3.0已公布.总算能够向外界表达了我们想做个啥,非常多人也開始质疑,Cloud Card究竟是个啥?云OS 3.0算不算自主研发的OS ...

  5. Qt 3D的研究(十):描边渲染(轮廓渲染)以及Silhouette Shader

    Qt 3D的研究(十):描边渲染(轮廓渲染)以及Silhouette Shader 之前写了两篇文章,介绍了我在边缘检測上面的研究.实际上.使用GPU对渲染图像进行边缘检測.前提是须要进行两遍渲染.前 ...

  6. Red Hat Linux分辨率调整

    在/etc/X11下手动产生xorg.conf文件, # vi /etc/X11/xorg.conf 文件中内容如下: ##Add the following codes: Section " ...

  7. 【待解决】An internal error occurred during: "Launching baiduTest1". java.lang.NullPointerException

    编写的一个Java类,以junit运行可以正常执行,以testNG执行就报如下错误 解决方法:

  8. 数据结构(三)——栈Stack

    栈是一种特殊的线性表,插入和删除操作均在栈顶进行,插入操作称为入栈,删除操作称为出栈. 一.顺序栈 利用顺序存储方式实现的栈称为顺序栈,下面是它的一些基本操作实现算法,需要理解和记忆. 1.顺序栈的类 ...

  9. element-UI中table表格的@row-click事件和@selection-change耦合了

    <el-table ref="multipleTable" :data="tableData" tooltip-effect="dark&quo ...

  10. java怎么学

    java怎么学 给你推荐一个写得非常用心的Java基础教程:Java入门基础教程 | 天码营 这个教程将Java的入门基础知识贯穿在一个实例中,逐步深入,可以帮助你快速进入Java编程的世界.万事开头 ...