WebGL系列教程二(环境搭建及着色器初始化)

news2024/11/25 22:54:21

目录

  • 1 前言
  • 2 新建html页面
  • 3 着色器介绍
    • 3.1 顶点着色器、片元着色器与光栅化的概念
    • 3.2 声明顶点着色器
    • 3.3 声明片元着色器
  • 4 坐标系(右手系)介绍
  • 5 着色器初始化
    • 5.1 给一个画布canvas
    • 5.2 获取WebGL对象
    • 5.3 创建着色器对象
    • 5.4 获取着色器对象的源
    • 5.5 绑定着色器的源
    • 5.6 编译着色器
    • 5.7 创建并关联项目
  • 6 绘制
    • 6.1 声明点的位置、大小和颜色
    • 6.2 绘制
    • 6.3 完整代码
  • 7 总结

1 前言

  上一篇中我们对WebGL进行了简单的介绍,从本篇开始,正式进入实战。那么我们第一步需要做什么呢?当然是环境的搭建,以及Shader的初始化。废话不多说,咱们直接开整。

2 新建html页面

  其实搭建WebGL的环境十分简单,因为WebGL在在浏览里运行的,因此只需要新建一个html页面就行了。

3 着色器介绍

3.1 顶点着色器、片元着色器与光栅化的概念

  那么什么是顶点着色器?什么是片元着色器?什么叫做光栅化?这三个概念对我们学习WebGL还是很重要的,在学习WebGL的过程中,我曾经常困惑于片元、光栅化的概念,现在我们就用一张图来解释下。假设我们要在屏幕上画一个三角形。
在这里插入图片描述
  如图所示,v1 v2 v3 就叫做顶点,三角形内部的一个个红色的点,就叫做片元,也叫片段,其实它的意思就是一个个像素。注意像素应该是密密麻麻占满了整个三角形,这里为了示意只画出来了少部分。屏幕是什么?屏幕是一种光栅设备,因此把任何一种图形,不论是二维三维的,画在屏幕上,就叫做光栅化。光栅化的概念就这么简单。看过很多其他教程,只说光栅化,不说光栅化是什么意思,很令人困惑。

3.2 声明顶点着色器

  声明顶点着色器很简单,只需要写一个script标签,注意type

<script id="vertex-shader" type="x-shader/x-vertex">

</script>

3.3 声明片元着色器

  声明片元着色器也很简单,只需要写一个script标签,同样注意type

<script id="vertex-shader" type="x-shader/x-fragment">

</script>

4 坐标系(右手系)介绍

  现在我们来做一个最简单的例子,画一个点,这个点的坐标分别是x=0.5,y=0.5,z=0。在此之前我们先明确一下WebGL中的坐标系:X轴向右,Y轴向上,Z轴向外。右手握拳,四指从XY转动,大拇指的方向就是Z轴的方向。很明显,WebGL中默认是右手系。因为z=0,因此这个点在xy所形成的平面内。
在这里插入图片描述

5 着色器初始化

  初始化着色也很简单,我们先给出步骤,然后一步步来说明

  1. 创建着色器对象
  2. 获取着色器对象的源代码
  3. 绑定着色器的源
  4. 编译着色器
  5. 创建并关联项目

5.1 给一个画布canvas

<canvas id="canvas" width="1080" height="720"></canvas>

5.2 获取WebGL对象

const canvas = document.getElementById("canvas");
const gl = canvas.getContext("webgl");

5.3 创建着色器对象

//创建着色器对象
let vertexShader = gl.createShader(gl.VERTEX_SHADER);
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);

5.4 获取着色器对象的源

//获取着色器对象的源
let vertexSource = document.getElementById("vertex-shader").innerText;
let fragmentSource = document.getElementById("fragment-shader").innerText;

因为这里我们要用的innerText,也就是script标签里的文本,因此也可以不把文本写在script标签里,而是直接手写字符串,这样的不好处就是没有智能提示,比如:
let vertexSource = “…”
let fragmentSource = “…”

5.5 绑定着色器的源

//绑定着色器的源
gl.shaderSource(vertexShader,vertexSource);
gl.shaderSource(fragmentShader,fragmentSource);

5.6 编译着色器

//编译着色器
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);

5.7 创建并关联项目

//创建并关联项目
let program = gl.createProgram();
gl.attachShader(program,vertexShader);
gl.attachShader(program,fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);

6 绘制

  现在我们的准备工作已经完事了,可以开始绘制了。首先需要补齐script标签的内容

6.1 声明点的位置、大小和颜色

<script id="vertex-shader" type="x-shader/x-vertex">
	//声明一个点,vec2表示2维向量
    attribute vec2 aPos;
    void main(){
    	//点的大小10像素
        gl_PointSize = 10.0;
        //点的位置,将vec2补齐为vec4
        gl_Position = vec4(aPos,0.0,1.0);   
    }
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
    void main(){
    	//点的颜色,rgba形式,红色
        gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }
</script>

6.2 绘制

//绘制
let aPos = gl.getAttribLocation(program,"aPos");
//设置顶点的值,该顶点是用二维坐标表示的,vertexAttrib2f表示vertex中的attribute属性,2个float值
gl.vertexAttrib2f(aPos,0.5,0.5);
//绘制点,从第0个点开始,绘制两个
gl.drawArrays(gl.POINTS,0,2);

在这里插入图片描述
改为x=0,y=0看看效果,点回到了正中间。
在这里插入图片描述

6.3 完整代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #canvas{
            border: 1px solid #ccc;
        }
    </style>
</head>

<body>
    <canvas id="canvas" width="1080" height="720"></canvas>
    <script id="vertex-shader" type="x-shader/x-vertex">
        attribute vec2 aPos;
        void main(){
            gl_PointSize = 10.0;
            gl_Position = vec4(aPos,0.0,1.0);   
            //gl_Position = aPos;   
        }
    </script>
    <script id="fragment-shader" type="x-shader/x-fragment">
        void main(){
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    </script>
    <script>
        const canvas = document.getElementById("canvas");
        const gl = canvas.getContext("webgl");
        //创建着色器对象
        let vertexShader = gl.createShader(gl.VERTEX_SHADER);
        let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        //获取着色器对象的源
        let vertexSource = document.getElementById("vertex-shader").innerText;
        let fragmentSource = document.getElementById("fragment-shader").innerText;
        //绑定着色器的源
        gl.shaderSource(vertexShader,vertexSource);
        gl.shaderSource(fragmentShader,fragmentSource);
        //编译着色器
        gl.compileShader(vertexShader);
        gl.compileShader(fragmentShader);
        console.log(gl.getShaderInfoLog(vertexShader));
        //创建并关联项目
        let program = gl.createProgram();
        gl.attachShader(program,vertexShader);
        gl.attachShader(program,fragmentShader);
        gl.linkProgram(program);
        gl.useProgram(program);
        //绘制
        let aPos = gl.getAttribLocation(program,"aPos");
        //设置顶点的值,该顶点是用二维坐标表示的
        gl.vertexAttrib2f(aPos,0.0,0.0);
        gl.drawArrays(gl.POINTS,0,2);

    </script>
</body>

</html>

7 总结

  本篇博文中我们梳理了WebGL中整个的绘制流程,右手坐标系的指向,顶点着色器、片元着色器、光栅化等概念的含义,并以一个最简单的示例,点绘制来演示Shader的初始化过程,代码并不复杂,希望读者仔细体会,回见~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2128955.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

好看好听的小猪包扩音器,轻巧便携更好用,得胜E10上手

我们以前在学校、景区等地方&#xff0c;都见过教师、讲解员所使用的扩音器&#xff0c;这类设备大多做得笨重粗糙&#xff0c;而且音质一般&#xff0c;声音特别粗糙刺耳&#xff0c;对使用者和旁观者影响都不好。最近我发现了一款得胜E10扩音器&#xff0c;大大提升了这种便携…

HTTPX 与 AIOHTTP 与 Requests:选择哪个?

Python 有三个众所周知的库用于发送 HTTP&#xff08;超文本传输协议&#xff09;请求&#xff1a; HTTPX、AIOHTTP 和 Requests。 所有这些都有其独特的优点和缺点。 通常&#xff0c;您需要对同步 HTTP 请求使用 Requests&#xff0c;在需要同步和异步混合时使用 HTTPX&#…

场景解决方案丨突破成本限制,中小企业如何快速搭建后台管理系统

信息化时代下业务数据量激增&#xff0c;云计算、物联网、人工智能等技术的成本大幅度降低及普及&#xff0c;这些变化推动着市场需求发生改变&#xff0c;使数字化转型成为各行业的共同趋势。在这一背景下&#xff0c;大型企业利用其经济和技术优势巩固市场领导地位&#xff0…

养宠浮毛严重怎么清理?希喂、范罗士、IAM宠物空气净化器真实测评

宠物毛发不等于宠物浮毛&#xff1f;这可真是问到我的知识盲区了。养猫来我已经接受了目光所及之处都是猫毛&#xff0c;可以心平气和的打扫被猫毛占据的屋子。自认为是很勤快的人&#xff0c;家里也一直保持着干净整洁&#xff0c;结果上星期鼻子不舒服去看医生&#xff0c;告…

发现一个有趣的滑动组件样式,并给它实现了

最近在浏览网站的时候看到一个有趣的滑动组件的样式&#xff0c;觉得很有趣。一时有兴趣就去用代码实现了一下&#xff1a; 这里我就不从零开始实现了&#xff0c;借用 Material UI Slider 快速实现&#xff0c;基本上就是重新写样式覆盖。 Material UI 上的 Slider 组件默认样…

面试产品经理,怎样描述过往经历,才能让面试官印象深刻?

金三银四求职季&#xff0c;你是不是也有面试的冲动&#xff01;但面试并不是头脑一热就能取得好结果&#xff0c;在此之前&#xff0c;必须得有周全的准备&#xff0c;才能应对好面试官的“连环问”&#xff01; 所以&#xff0c;给大家分享这篇产品经理面试干货文章&#xf…

【数学建模】相关系数

第一部分&#xff1a;相关系数简介 总体与样本&#xff1a; 总体&#xff1a;指研究对象的全体&#xff0c;比如全国人口普查数据。样本&#xff1a;从总体中抽取的一部分个体&#xff0c;如通过问卷调查收集的学生数据。 皮尔逊相关系数&#xff1a; 总体皮尔逊相关系数&…

GPIO(General Purpose Input/Output)输入/输出

GPIO最简单的功能是输出高低电平&#xff1b;GPIO还可以被设置为输入功能&#xff0c;用于读取按键等输入信号&#xff1b;也可以将GPIO复用成芯片上的其他外设的控制引脚。 STM32F407ZGT6有8组IO。分别为GPIOA~GPIOH&#xff0c;除了GPIOH只有两个IO&#xff0c;其余每组IO有…

cesium.js 入门到精通(5)

现在我们看这个地图是 属于一个平面的 如果我们想把这个弄成 那种真实的高低起伏的 山脉 或者 其他的建筑显示 我们可以使用 添加地形 terrainProvider: new Cesium.CesiumTerrainProvider({url: "./terrains/gz",}), 这是一个参数 配置 地形 整体代码 <templa…

vba发邮件:如何设置自动化发送电子邮件?

vba发邮件的技巧有哪些&#xff1f;VBA如何调用outlook发邮件&#xff1f; VBA发邮件功能是一个非常实用的工具&#xff0c;能够帮助用户自动发送电子邮件&#xff0c;减少手动操作的时间和错误。AokSend将详细介绍如何通过VBA发邮件来实现自动化发送电子邮件的设置。 VBA发邮…

macOS上谷歌浏览器的十大隐藏功能

谷歌浏览器&#xff08;Google Chrome&#xff09;在macOS上拥有一系列强大而隐蔽的特性&#xff0c;这些功能能显著提高您的浏览体验。从多设备同步到提升安全性和效率&#xff0c;这些被低估的功能等待着被发掘。我们将逐步探索这些功能&#xff0c;帮助您最大化利用谷歌浏览…

让人眼前一亮的软件测试简历,收不到面试邀请算我输

不知道大家的简历是不是都写成下面这样 根据需求文档进行需求分析 熟悉业务流程&#xff0c;明确测试点 根据测试点设计测试用例 参与评审测试用例 提交和回归跟踪缺陷&#xff0c;确认修复完成之后关闭Bug 通过使用Fiddler进行抓包分析并定位前后端Bug 使用简单的SQL语…

【北京迅为】《STM32MP157开发板使用手册》- 第二十五章Cortex-M4 GPIO_LED实验

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…

什么是线程池?从底层源码入手,深度解析线程池的工作原理

导航&#xff1a; 【Java笔记踩坑汇总】Java基础JavaWebSSMSpringBootSpringCloud瑞吉外卖/谷粒商城/学成在线设计模式面试题汇总性能调优/架构设计源码解析 目录 一、什么是线程池&#xff1f; 1.1 基本介绍 1.2 创建线程的两种方式 1.2.1 方式1&#xff1a;自定义线程池…

山峰个数【python实现】

思路见此处 def get_mountain_peaks(height):peak_count 0n len(height)if n 0:#如果一个山高都没有&#xff0c;return 0return 0for i in range(1,n-1):if height[i] > height[i-1] and height[i] > height[i1]:peak_count 1if height[0] > height[1] and n &g…

TimedRotatingFileHandler 修改 suffix 后 backupCount 设置失效无法自动删除文件

本文主要分析 TimedRotatingFileHandler 在实际使用中 backupCount 设置未生效的问题。源码分析显示&#xff0c;文件删除依赖于后缀 suffix 的正则匹配&#xff0c;如果自定义了 suffix 格式&#xff0c;必须同步更新 extMatch 的正则表达式&#xff08;保证正则表达式可以正常…

国庆出游季,南卡Runner Pro5骨传导耳机让旅途更完美!

国庆长假将至&#xff0c;无论是计划一场远行还是近郊的户外活动&#xff0c;一款适合的耳机都能让旅途更加愉快。南卡Runner Pro5骨传导耳机以其独特的设计和功能&#xff0c;成为了国庆出行的理想伴侣。 首先&#xff0c;骨传导耳机通过颅骨传递声音&#xff0c;避免了传统耳…

从理论到实战:人才培养基地如何缩短职场适应期?

在当今竞争激烈的职场环境中&#xff0c;从校园到职场的过渡对于许多新人来说充满挑战。而人才培养基地正以其独特的方式&#xff0c;努力缩短这一职场适应期。 人才培养基地首先注重理论与实践的结合。不再是单纯的知识灌输&#xff0c;而是将理论教学与实际操作紧密相连。 实…

JAVA——方法重载

方法的重载&#xff1a;多个方法在同一个类&#xff0c;方法名相同&#xff0c;参数/参数类型/参数数量不同 返回值不能作为重载条件 public class demo9_12_2 {public static void main(String[] args) {//调用&#xff0c;方法的签名getMax();getMax(10);getMax(10.9F);}//…

如何在Word中复制整页内容并保持原有格式不变?

在日常处理工作时&#xff0c;我们经常需要在Word文档中复制和粘贴内容&#xff0c;特别是在处理报告方案等文档时&#xff0c;保持复制内容的格式不变显得尤为重要。本文将详细介绍如何在Word中复制整页内容并保持原有格式不变&#xff0c;确保文档的整洁性和一致性。 方法一&…