WEBGL学习【八】模型视图投影矩阵
- <!--探讨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学习【八】模型视图投影矩阵的更多相关文章
- OpenGL 模型视图投影矩阵 仿射矩阵
矩阵基础知识 要对矩阵进行运算,必须先要了解矩阵的计算公式,这个知识的内容涉及到了线性代数. 我们知道在Cocos2dx中,有关于平移,旋转,缩放等等操作,都必须要进行矩阵的乘法. 只需要一张图就能理 ...
- 【GISER&&Painter】Chapter02:WebGL中的模型视图变换
上一节我们提到了如何在一张画布上画一个简单几何图形,通过创建画布,获取WebGLRendering上下文,创建一个简单的着色器,然后将一些顶点数据绑定到gl的Buffer中,最后通过绑定buffer数 ...
- WEBGL学习【四】模型视图矩阵
<html lang="zh-CN"> <!--服务器运行地址:http://127.0.0.1:8080/webgl/LearnNeHeWebGL/NeHeWe ...
- WebGL或OpenGL关于模型视图投影变换的设置技巧
目录 1. 具体实例 2. 解决方案 1) Cube.html 2) Cube.js 3) 运行结果 3. 详细讲解 1) 模型变换 2) 视图变换 3) 投影变换 4) 模型视图投影矩阵 4. 存在 ...
- 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 ...
- WEBGL学习【十五】利用WEBGL实现三维场景的一般思路总结
实现三维场景载入操作的实现步骤: 主要知识点:着色器,纹理贴图,文件载入 实现思路: 获取canvas,初始化WEBGL上下文信息. 主要是实现WEBGL上下文的获取,设置视的大小,此时gl存储了WE ...
- WEBGL学习【十三】鼠标点击立方体改变颜色的原理与实现
// PickFace.js (c) 2012 matsuda and kanda // Vertex shader program var VSHADER_SOURCE = 'attribute v ...
- WEBGL学习【十】运动模型
<!DOCTYPE HTML> <html lang="en"> <head> <title>LWEBGL6.2, Animated ...
- WEBGL学习【九】立方体贴不同的纹理
<html> <!--开始实现一个三维街景的渲染效果--> <head> <meta http-equiv="Content-Type" ...
随机推荐
- Redis参数
phpredis是php的一个扩展,效率是相当高有链表排序功能,对创建内存级的模块业务关系 很有用;以下是redis官方提供的命令使用技巧: Redis::__construct构造函数$redis ...
- Apache vs. Nginx
精简版 Apache:出名比较早,09年左右是最流行的时期,功能强大,可以根据需求配置为基于进程,基于线程或者基于事件的,但是消耗内存较多,对硬件需求较高,内存是影响服务器性能的最关键因素,在VPS上 ...
- 我要带徒弟学JAVA架构 ( 写架构,非用架构 )
80元,当然我不觉得我带的徒弟比花了1万多在培训班学习的学生差,你努力了.会比他们出色的多.等你学有所成.相同能够成为jeecg核心成员之中的一个.一起构建Java学习平台.你也能够成为非常好的师傅. ...
- Thread和ThreadGroup
Thread和ThreadGroup 学习了:https://www.cnblogs.com/yiwangzhibujian/p/6212104.html 这个里面有Thread的基本内容: htt ...
- OpenCV学习笔记(六十二)——《OpenCV Computer Version with Python》阅读摘要
如今python火啊.每次OpenCV自带的ml模块都让我直呼坑爹,索性准备用python来做OpenCV后期的机器学习算法的处理.于是赶紧拿起这本书读读. 适合OpenCV和python都有一定基础 ...
- JeeCG团队招聘啦!
JeeCG团队招聘啦! 小团队攻坚,创业氛围浓厚.盼望有激情的你增加. 岗位描写叙述: 1,负责Jeecg.jeewx 微信管理系统相关的研发工作.2,高度參与整个产品设计.參与微信相关项目开发.3. ...
- 设计一部iphone手机用面向对象的方法
main.m //编辑字体大小command + < //编译执行快捷键 com + R #import <Foundation/Foundation.h> #import &quo ...
- Spring JDBC数据库开发
针对数据库操作,Spring框架提供了JdbcTemplate类. 1.Spring JDBC的配置 创建配置文件applicationContext.xml,添加如下代码: <!--配置数据源 ...
- cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第0步---知识点总结&效果预览&设计思路
/* 说明: **1.本次游戏实例是<cocos2d-x游戏开发之旅>上的最后一个游戏.这里用3.0重写并做下笔记 **2.我也问过木头本人啦,他说:随便写.第一别全然照搬代码:第二能够说 ...
- 《转》Ceilometer Alarm API 參数具体解释 及 举例说明
Ceilometer Alarm是H版新加入的功能,监控报警是云平台必不可少的部分,Ceilometer已经实现了比較完好的监控体系.报警怎么能缺少呢?用过AWS CloudWatch Alarm的人 ...