8

图形学之WebGL实现3D效果/ 纹理的使用

 3 years ago
source link: https://segmentfault.com/a/1190000040364334
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本篇收录于《前端读书会》专栏

上文介绍了纹理相关的内容,并使用WebGL进行了2d的实现,今天延续上节课的内容对于纹理的3D实现 也算是吸取了MDN-Tutorial的模式,感觉这样的学习轨道 也算是初衷(每次长篇大论的讲图形学的理论我怕我和你都坚持不下去)目前来说最好的方式了,对于WebGL的学习还是图形学的学习都能有一个认识。话不多说开始今天的内容(大部分是code的讲解 尽可能快速过完一些基础的API...第一步成为一个API工程师)

上文介绍了纹理相关的内容,有需要可以参考上文

  1. 2D与3D的区别?绘制思路?
  2. coding (WebGL中简单使用纹理)

coding部分引入webgl-utils(方面一些useprogram,linkProgram的简写 无太大魔力)&martix(矩阵的一些生成/计算..)工具类库

1.2d与3d的区别

首先我们都知道2D只是一个平面 3D可以理解为是6个平面,那么本篇文章最主要解决如何给添加5个平面就好(当然添加会伴随着一些问题,没关系 一步步的来)

本篇会对于上文的一些反馈进行改正 例如code 注释太少。。ok 我尽量多写点

WebGl coding 首先回顾一下步骤

  1. shader
  2. 创建program
  3. 处理坐标还有纹理相关
  4. 获取并绑定坐标信息
  5. 绘制draw

看着是如此简单 那么接下来我们一起来写一下

coding

coding开始之前先看看效果

缺一个gif图 明天找个有电脑的地方补充一下。

image.png

image.png

1. shader

有朋友反馈shader部分要照顾新手, 那么我逐行加下注释介绍下。当然更多细节信息还是得去看看相关资料呢。 我讲的不好(-- 主要是懒癌患者)

// vertex shader  
// attribute变量 只能作用于顶点着色器 vec4 是矢量 a_position 一个变量名
attribute vec4 a_position;
// attribute变量 只能作用于顶点着色器 vec4 是矢量 a_position 一个变量名
attribute vec2 a_texcoord;
// uniform变量(全局) 可以在顶点和片元使用(如果俩个着色命名同名 可进行共享) mat4 是矩阵 u_matrix变量名
uniform mat4 u_matrix;
// varying变量(全局) 目的就是为了给片元传输数据 vec2 矢量 v_texcoord变量名
varying vec2 v_texcoord;
// main类似主执行函数 但是是必须的 C/C++用法类似
void main() {
    // gl_Position 顶点坐标
   gl_Position = u_matrix * a_position;
   // 将纹理坐标传给片断着色器
   v_texcoord = a_texcoord;
}

// fragment shader 
// 精度限定  mediump中度精度 float数据类型 对了SL语言中是区分整型和浮点型的哦~
precision mediump float;
// varying变量(全局) 接收传输过来的数据 vec2 矢量 v_texcoord变量名
varying vec2 v_texcoord;
// uniform变量(只读 全局)  sampler2D纹理 u_texture变量名
uniform sampler2D u_texture;
// 主执行函数
void main() {
   // gl_FragColor 颜色信息  此处是纹理  texture2D是取样器纹理 v_texcoord纹理坐标 看js代码穿插理解
   gl_FragColor = texture2D(u_texture, v_texcoord);
}

我这个注释写的 我都佩服。哈哈 不懂记得留言。我都让你们问,你们也不问。要知道不会就问没什么不好意思的 学会了那是自己的 强大自己升职加薪 加油

2. 创建program

// 用到了webgl-Utils 其实就是useVertex 和useFragment 然后linkProgram...
var program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-3d", "fragment-shader-3d"]);

3. 处理坐标还有纹理相关

// 顶点坐标 发生了变换 6个面 
var positions = new Float32Array(
    [
    -0.5, -0.5,  -0.5,
    -0.5,  0.5,  -0.5,
     0.5, -0.5,  -0.5,
    -0.5,  0.5,  -0.5,
     0.5,  0.5,  -0.5,
     0.5, -0.5,  -0.5,

    -0.5, -0.5,   0.5,
     0.5, -0.5,   0.5,
    -0.5,  0.5,   0.5,
    -0.5,  0.5,   0.5,
     0.5, -0.5,   0.5,
     0.5,  0.5,   0.5,

    -0.5,   0.5, -0.5,
    -0.5,   0.5,  0.5,
     0.5,   0.5, -0.5,
    -0.5,   0.5,  0.5,
     0.5,   0.5,  0.5,
     0.5,   0.5, -0.5,

    -0.5,  -0.5, -0.5,
     0.5,  -0.5, -0.5,
    -0.5,  -0.5,  0.5,
    -0.5,  -0.5,  0.5,
     0.5,  -0.5, -0.5,
     0.5,  -0.5,  0.5,

    -0.5,  -0.5, -0.5,
    -0.5,  -0.5,  0.5,
    -0.5,   0.5, -0.5,
    -0.5,  -0.5,  0.5,
    -0.5,   0.5,  0.5,
    -0.5,   0.5, -0.5,

     0.5,  -0.5, -0.5,
     0.5,   0.5, -0.5,
     0.5,  -0.5,  0.5,
     0.5,  -0.5,  0.5,
     0.5,   0.5, -0.5,
     0.5,   0.5,  0.5,

    ]);
// 解决图片跨域问题  当然方式很多你也可以绘制canvas2d 然后创建纹理 canvas在标准上支持了图片跨域 有兴趣可以查查
function requestCORSIfNotSameOrigin(img, url) {
    if ((new URL(url, window.location.href)).origin !== window.location.origin) {
      img.crossOrigin = "";
    }
}
// 加载图片 并在load完成绑定纹理
function loadImageAndCreateTextureInfo(url) {
    var tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, tex);
   
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
                  new Uint8Array([0, 0, 255, 255]));

    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

    var textureInfo = {
      width: 1,  
      height: 1,
      texture: tex,
    };
    var img = new Image();
    img.addEventListener('load', function() {
      textureInfo.width = img.width;
      textureInfo.height = img.height;

      gl.bindTexture(gl.TEXTURE_2D, textureInfo.texture);
      // 调用 texImage2D() 把已经加载的图片图形数据写到纹理
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
    });
    requestCORSIfNotSameOrigin(img, url);
    img.src = url;

    return textureInfo;
  }
  var texInfo = loadImageAndCreateTextureInfo('https://webglfundamentals.org/webgl/resources/leaves.jpg');

4. 获取并绑定坐标信息

  var positionLocation = gl.getAttribLocation(program, "a_position");
  var texcoordLocation = gl.getAttribLocation(program, "a_texcoord");

  var matrixLocation = gl.getUniformLocation(program, "u_matrix");
  var textureLocation = gl.getUniformLocation(program, "u_texture");

  var positionBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  setGeometry(gl);

  var texcoordBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
  setTexcoords(gl);

  var texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texture);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
                new Uint8Array([0, 0, 255, 255]));

5. 使用program并提供buffer取数据 然后绘制

gl.vertexAttribPointer(
    positionLocation, size, type, normalize, stride, offset);

// 启用texcoord属性
gl.enableVertexAttribArray(texcoordLocation);

// 绑定texcoord buffer.
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);

....
gl.drawArrays(gl.TRIANGLES, 0, 6 * 6);

ok, 效果就这样实现了.为了大家的练习, 说明一下需要注意的地方是上面的代码 纹理是采用了一个纹理 如果要改多个图片可以采取多个纹理。也可以合并成一个纹理 通过坐标信息进行调节。

全部代码请去github下载并使用

最后强烈希望大家学习相关理论知识;理论可能日常用到的地方很少,但是它能决定你走多远。(有的人问难怎么办,勤于练习吧),写作速度呢 该专栏我加速(一周1-2篇) 其他专栏(1篇) 计算机图形学相关的基础知识都会带一遍。然后后续主要写数据可视化方向。

下一篇写点什么呢? 个人准备把MDN-Tutorial部分的内容结个尾。然后开始正式的可视化环节(可以介绍几个大家常用的库 2D 3D的都可以,大家看看有什么好用的库需要我一起过一下的呢)。或者大家提提意见!


Recommend

  • 51

    全球领先的信息与通信解决方案供应商华为,为应对云领域专业人才培养的挑战,加速云人才培养,助力行业数字化转型,博赛携手华为2018年华为生态大学之“耕云计划“”华为云计算认证全国行 ,推广华为云系列认证,包含云计算、云服务、大数...

  • 52

    如果未来可以预见,你是否会来相约... 未来的云机房是这酱紫的... 面向未来,华为希望携手广大客户和伙伴,一同预见云时代的未来...

  • 49

    全球领先的信息与通信解决方案供应商华为,为应对云领域专业人才培养的挑战,加速云人才培养,助力行业数字化转型,博赛携手华为2018年华为生态大学之“耕云计划“”华为云计算认证全国行 ,推广华为云系列认证,包含云计算、云服务、大数...

  • 51
    • 微信 mp.weixin.qq.com 6 years ago
    • Cache

    走进科学之揭开神秘的"零拷贝"

  • 51
    • dopro.io 5 years ago
    • Cache

    webgl实现火焰效果

    此篇文章我们要实现一个燃烧的火焰效果,其中会包含产生燃烧效果的相关算法,如果不是很理解的话,可以自己动手调节相关参数来进一步理解,先看一下实现的效果。 ...

  • 15
    • gameinstitute.qq.com 4 years ago
    • Cache

    图形硬件上基于图块的纹理映射

    图形硬件上基于图块的纹理映射 发表于2020-10-26 评论0 1.1k浏览 想免费获取内部独家PPT资料...

  • 12

    目前工作中有不少涉及到地图的项目,我参加了几次技术评审,前端伙伴们在 WebGIS 方面的知识储备稍有不足,这次分享的主要目的是科普一些在前端领域比较常用的 WebGIS 知识。另外,我之前的工作中积攒了一些从零开始搭建 WebGL 地图引擎的微薄经验,虽然最终遗...

  • 4

    图形学之纹理后续/WebGL多纹理处理本篇收录于

  • 8

    图形编程中的纹理,是一个很大的话题,涉及到的知识面非常多,有硬件的,也有软件的,有实时渲染技术,也有标准的实现等非常多可以讨论的。 受制于个人学识浅薄,本文只能浅表性地列举 WebGL 和 WebGPU 中它们创建、数据传递和着色器...

  • 8
    • hx-w.github.io 2 years ago
    • Cache

    计算机图形学-纹理

    纹理映射是着色部分的内容,包括了抗混叠等技术。 重心坐标 Barycentric Coordinates 重心坐标是定义在三角形上的,表示为(α,β,γ)(α,β,γ),满足: (x,y)=αA+βB+γCα+β+γ=1(x,y)=αA+βB+γCα+β+γ=1 当点在三角形内时,满足: ...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK