<!--探讨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. HDU 1515

    简单题,直接用STACK模拟整个过程. 模拟出栈时,应注意保护现场,等到递归完成后返回. #include <iostream> #include <string.h> #in ...

  2. HDU 1466

    经典DP,这样的递推确实有点难. 把所有直线分成两组,可以知道 m条直线的交点方案数 =(m-r)条平行线与r条直线交叉的交点数  + r条直线本身的交点方案 亦就是  =(m-r)*r+r条之间本身 ...

  3. Keil5.15使用GCC编译器链接.a库文件

    我们知道,当使用第三方的代码时,人家有可能会扔个Lib文件给你.这时候,别人仅仅要提供header文件给你,则你就能够通过Lib文件及header的函数声明,对Lib中的函数进行调用.在Keil中假设 ...

  4. dlopen failed: empty/missing DT_HASH in &quot;libx.so&quot; (built with --hash-style=gnu?)

    崩溃日志内容: java.lang.UnsatisfiedLinkError: dlopen failed: empty/missing DT_HASH in "libxxxx.so&quo ...

  5. PbootCMS V1.1.4 正式发布

    PbootCMS V1.1.4 正式发布 PbootCMS V1.1.4 build 2018-06-251.修复自定义表单表名重复仍然添加成功问题:2.修复分享到微信导致页面错误的问题:3.修复静态 ...

  6. POJ1179 Polygon 区间DP

    题目大意: 多边形游戏,有N个顶点的多边形,3 <= N <= 50 ,多边形有N条边,每个顶点中有一个数字(可正可负),每条边上或者是“+”号,或者是“*”号.边从1到N编号,首先选择一 ...

  7. POJ1837 Balance 背包

    题目大意: 有一个天平,天平左右两边各有若干个钩子,总共有C个钩子(每个钩子有相对于中心的距离,左负右正),有G个钩码,求将钩码全部挂到钩子上使天平平衡的方法的总数. 将每个砝码看作一组,组内各个物品 ...

  8. 关于ShapeDrawable应用的一些介绍(下)

    我们今天接着来看一下Shape中的stroke属性,stroke其实就是边缘的意思,当我们在定义画笔的时候,有很多时候会用到 FILL 和 STROKE,前者能够画出一个实心的形状,而后者就画出一个空 ...

  9. Queue 与List、LinkedList与 ArrayList 区别

    List 是一个接口,不能实例化,通过实例化ArrayList 或者LinkedList来调用:List list = new ArrayList(); |--List: 元素是有序的(怎么存的就怎么 ...

  10. 【media-queries】媒体查询,为了响应式设计而生

    目录 简介 语法 常用尺寸 一 简介 针对现在纷杂的设备,css3中加入,可以查询你的浏览类型(screen彩色屏幕, print, all)和css属性判断. 最常用的就是查询屏幕大小,给予适合的展 ...