关闭

WebGL之旅(三)VBO和多种图形绘制

标签: webgl图形
325人阅读 评论(0) 收藏 举报
分类:

通过gl.vertexAttribXX和gl.uniformXX函数,一次只能向shader中传递一个变量,要一次性向shader中传递多个数据就要用到顶点缓冲区对象(VBO)。

一 VBO

VBO使用步骤:

  1. 创建缓冲区对象(gl.createBuffer());
  2. 绑定缓冲区对象(gl.bindBuffer());
  3. 将数据写入缓冲区(gl.bufferData());
  4. 将缓冲区对象分配给一个attribute变量(gl.vetextAttribPointer());
  5. 开启attribute变量(gl。enableVetextAttribArray())。

示例:

/**
 * VBO
 * xu.lidong@qq.com
 * */

// 顶点着色器源码
var vertexShaderSrc = `
attribute vec4 a_Position;// 接收传入位置坐标,必须声明为全局
attribute float a_PointSize;// 接收传入位置坐标,必须声明为全局
void main(){
    gl_Position = a_Position;// gl_Position 内置变量,表示点的位置,必须赋值
    gl_PointSize = a_PointSize;// gl_PointSize 内置变量,表示点的大小(单位像素),可以不赋值,默认为1.0
}`;

// 片段着色器源码
var fragmentShaderSrc = `
void main(){
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);// gl_FragColor 内置变量,表示片元颜色,必须赋值
}`;

// 初始化使用的shader
function initShader(gl) {
    var vertexShader = gl.createShader(gl.VERTEX_SHADER);// 创建顶点着色器
    gl.shaderSource(vertexShader, vertexShaderSrc);// 绑定顶点着色器源码
    gl.compileShader(vertexShader);// 编译定点着色器

    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);// 创建片段着色器
    gl.shaderSource(fragmentShader, fragmentShaderSrc);// 绑定片段着色器源码
    gl.compileShader(fragmentShader);// 编译片段着色器

    var shaderProgram = gl.createProgram();// 创建着色器程序
    gl.attachShader(shaderProgram, vertexShader);// 指定顶点着色器
    gl.attachShader(shaderProgram, fragmentShader);// 指定片段着色色器
    gl.linkProgram(shaderProgram);// 链接程序
    gl.useProgram(shaderProgram);//使用着色器

    gl.program = shaderProgram;
}

function main() {
    var canvas = document.getElementById("container");
    var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
    initShader(gl);// 初始化着色器
    var n = initVertexBuffers(gl);// 初始化顶点

    var a_PointSize = gl.getAttribLocation(gl.program, "a_PointSize");// 获取shader中的a_PointSize变量
    gl.vertexAttrib1f(a_PointSize, 10.0);// 给a_PointSize赋值

    gl.clearColor(0.0, 0.0, 0.0, 1.0);// 指定清空canvas的颜色
    gl.clear(gl.COLOR_BUFFER_BIT);// 清空canvas
    gl.drawArrays(gl.POINTS, 0, n);
}

function initVertexBuffers(gl) {
    var vertices = new Float32Array([
        0.0, 0.5,
        -0.5, -0.5,
        0.5, -0.5
    ]);

    var vertexBuffer = gl.createBuffer();// 创建缓冲区对象
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);// 将缓冲区对象绑定到目标
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);// 向缓冲区中写入数据

    var a_Position = gl.getAttribLocation(gl.program, "a_Position");// 获取a_Position变量
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);// 将缓冲区对象分配给a_Position
    gl.enableVertexAttribArray(a_Position);// 链接a_Position与分配给他的缓冲区对象

    return vertices.length / 2;
}

如图:

这里写图片描述

通过initVertexBuffers函数,一次性向缓冲区写入了三个顶点,绘制每个顶点时,都会执行一次顶点着色器程序。

另外,需要注意的时,通过vertexAttribPointer函数,我们只给a_Position传递了两个值,另外两个值将被自动填充为0.0和1.0f。

多种图形的绘图

前面我们通过gl.drawArrays(gl.POINTS, 0, 3);绘制了三个点,将分别修改为:

  1. gl.drawArrays(gl.POINTS, 0, 2); 绘制2个点
  2. gl.drawArrays(gl.POINTS, 0, 1); 绘制1个点

可以看到,可以通过修改第三个参数来控制绘制点的个数。

修改第一个参数呢?将代码做个小得调整:

  1. 删掉gl_PointSize相关代码,gl_PointSize只在绘制点时生效
  2. gl.POINTS修改为gl.TRANGLES

如下:

/**
 * 绘制多种图形
 * xu.lidong@qq.com
 * */

// 顶点着色器源码
var vertexShaderSrc = `
attribute vec4 a_Position;// 接收传入位置坐标,必须声明为全局
void main(){
    gl_Position = a_Position;// gl_Position 内置变量,表示点的位置,必须赋值
}`;

// 片段着色器源码
var fragmentShaderSrc = `
void main(){
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);// gl_FragColor 内置变量,表示片元颜色,必须赋值
}`;

// 初始化使用的shader
function initShader(gl) {
    var vertexShader = gl.createShader(gl.VERTEX_SHADER);// 创建顶点着色器
    gl.shaderSource(vertexShader, vertexShaderSrc);// 绑定顶点着色器源码
    gl.compileShader(vertexShader);// 编译定点着色器

    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);// 创建片段着色器
    gl.shaderSource(fragmentShader, fragmentShaderSrc);// 绑定片段着色器源码
    gl.compileShader(fragmentShader);// 编译片段着色器

    var shaderProgram = gl.createProgram();// 创建着色器程序
    gl.attachShader(shaderProgram, vertexShader);// 指定顶点着色器
    gl.attachShader(shaderProgram, fragmentShader);// 指定片段着色色器
    gl.linkProgram(shaderProgram);// 链接程序
    gl.useProgram(shaderProgram);//使用着色器

    gl.program = shaderProgram;
}

function main() {
    var canvas = document.getElementById("container");
    var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
    initShader(gl);// 初始化着色器
    var n = initVertexBuffers(gl);// 初始化顶点

    gl.clearColor(0.0, 0.0, 0.0, 1.0);// 指定清空canvas的颜色
    gl.clear(gl.COLOR_BUFFER_BIT);// 清空canvas
    gl.drawArrays(gl.TRIANGLES, 0, 3);
}

function initVertexBuffers(gl) {
    var vertices = new Float32Array([
        0.0, 0.5,
        -0.5, -0.5,
        0.5, -0.5
    ]);

    var vertexBuffer = gl.createBuffer();// 创建缓冲区对象
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);// 将缓冲区对象绑定到目标
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);// 向缓冲区中写入数据

    var a_Position = gl.getAttribLocation(gl.program, "a_Position");// 获取a_Position变量
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);// 将缓冲区对象分配给a_Position
    gl.enableVertexAttribArray(a_Position);// 链接a_Position与分配给他的缓冲区对象

    return vertices.length / 2;
}

如图:

这里写图片描述

参数说明:

  • POINTS:绘制一个个点单;
  • LINES:在V0-V1,V2-V3,…之间划线,奇数个点最后一个会被忽略;
  • LINE_STRIP: 依次收尾链接v0-v1-v2-v3…;
  • LINE_LOOP:在所有点之间两两连线;
  • TRIANGLES: 绘制三角形v0-v1-v2, v3-v4-v5,…;
  • TRIANGLE_STRIP:任意连续三个点之间绘制三角形;
  • TRIANGLE_FAN:复用上一个三角形的一边与下一个点,绘制一个三角形。

为了测试这些类型,将定点数扩展到4个。修改vertices的值为:

    var vertices = new Float32Array([
        -0.5, 0.5,
        -0.5, -0.5,
        0.5, 0.5,
        0.5, -0.5
    ]);

然后修改参数的值,就可以看到绘制出不同的图形, 如下:

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

0
0
查看评论

[WebGL入门]九,顶点缓存的基础

顶点里添加怎样的情报,程序员是可以自由决定的,DirectX中有一种叫做[灵活顶点格式]的机制,WebGL中顶点格式是没有的,程序员必须自己处理所有的顶点情报。 只需要添加你想要添加的顶点信息的VBO就行了,VBO的生成方法以及怎样把数组信息传递给VBO等等,以后的文章中会详细的介绍。首先,把大概的...
  • lufy_Legend
  • lufy_Legend
  • 2014-08-03 09:30
  • 8350

VA、VAO和VBO API备忘

缘起 接触OpenGL有一段时间了,
  • csxiaoshui
  • csxiaoshui
  • 2014-04-18 14:38
  • 4429

[WebGL入门]十四,绘制多边形

其实这次的代码绘制的只是一个简单的三角形。只是这样,却写了这么长的代码,所以才说3D开发是比较难的。 但是,个人认为,即使这样,和DirectX相比较的话,已经相当简单,简练了。 单从开发环境上来说,不需要特别的开发环境,WebGL这一点已经很轻松了吧。理解了本次的内容的话,只需要稍微慢慢的调整一下...
  • lufy_Legend
  • lufy_Legend
  • 2014-08-08 23:10
  • 11856

我的shiro之旅: 一 shiro简介

一 什么是shiro Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理功能,可为任何应用提供安全保障. 二 shiro的几个特性 易于使用 - 易用性是这个项目的最终目标。应用安全有可能会非常让人糊涂,令人沮丧,并被认为是“必要之恶”。若是能让它简化到新...
  • LHacker
  • LHacker
  • 2013-08-28 13:54
  • 3509

八大疯狂的HTML5 Canvas及WebGL动画效果

处理器的性能越来越高。我们的电脑已经有足够的强大的能力去渲染最为复杂的动画效果。现在浏览器和web技术的不断发展。浏览器如Firefox、Chrome、Safari和IE10,web技术如Canvas、SVG和WebGL。网速越来越快。一些体验需要实时数据流和预加载资源,更好的网络状况能有更好的体验...
  • cuo9958
  • cuo9958
  • 2013-12-26 10:30
  • 2994

WebGL之旅(十六) 层级模型

层次模型是指用一颗“有向树”的数据结构来表示表示各类实体以及实体间的联系,树中每一个节点代表一个记录类型,树状结构表示实体型之间的联系。——百度百科 在变换时,父节点的变换会待着子节点一起,而子节点的变换则不会影响父节点。例如手臂的运动会带动手肘的运动,而手肘的运动不影响手臂的运动。即: 子节点的模...
  • xufeng0991
  • xufeng0991
  • 2017-07-30 22:51
  • 319

opengl VAO and VBO

VBO用于存储顶点数据,包括顶点颜色、坐标、法线,以及顶点的indices。 VAO则用于存储图形处理器将怎么使用VBO里面的数据,及顶点数据中哪些是坐标、哪些是颜色、哪些是法线等信息。 之前对于这些总是不是太明白,因此我猜测也有一部分跟我一样不明白,所以我准备通过Cocos2d-x的rende...
  • sydnash
  • sydnash
  • 2015-08-08 09:29
  • 3916

VAO与VBO

VAO 1.创建代码
  • qweewqpkn
  • qweewqpkn
  • 2014-09-12 15:56
  • 2127

OpenGL学习:VAO和VBO以及几种顶点绘图方式比较

一.为什么要有opengl缓冲区对象 在给shader传递顶点数据的时候,如果每次都要向GPU发送一大块数据,而这数据其实并没有修改过,那么这传输就是冗余的。所以这里添加了缓冲区对象,将顶点数组存储在服务器端的缓冲区对象中。 二.如何创建和使用缓冲区对象   1.创建缓冲区对...
  • arag2009
  • arag2009
  • 2016-10-28 11:50
  • 1142

VBO与VAO

VBO与VAO (2012-07-09 17:57:36) 转载▼ 标签: 杂谈 分类:OpenGL 我想大家都已经熟悉VBO了吧。在GL3.0时代的VBO大体还是处于最重要的地位,但是与此同时也出现了不少新的用法和辅助役,其中一个就是VAO。...
  • wanglang3081
  • wanglang3081
  • 2013-04-02 10:55
  • 5976
    个人资料
    • 访问:561943次
    • 积分:8923
    • 等级:
    • 排名:第2542名
    • 原创:349篇
    • 转载:13篇
    • 译文:0篇
    • 评论:85条
    关于我
    编程是一门艺术,态度决定高度,细节决定成败。