当前位置: 首页 > news >正文

WebGL 同时使用多幅纹理

目录

前言

​编辑

示例代码

颜色矢量的分量乘法来计算两个纹素最终的片元颜色

注册事件响应函数:loadTexture(),最后一个参数是纹理单元编号。

请求浏览器加载图像:

配置纹理:loadTexture()函数。该函数的核心部分代码如下所示: 

需要注意的是


前言

WebGL可以同时处理多幅纹理,纹理单元就是为了这个目的而设计的。本例程序在矩形上重叠粘贴两幅纹理图像。下图显示了本例运行效果,两张纹理图像在矩形上的混合效果如下。

下图中的两幅图分别显示了示例程序用到的两幅纹理图像。为了说明WebGL具有处理不同纹理图像格式的能力,本例故意使用了两种不同格式的图像(左侧jpg,右侧gif)。 

示例代码

// 顶点着色器
var VSHADER_SOURCE ='attribute vec4 a_Position;\n' +'attribute vec2 a_TexCoord;\n' +'varying vec2 v_TexCoord;\n' +'void main() {\n' +'  gl_Position = a_Position;\n' +'  v_TexCoord = a_TexCoord;\n' +'}\n';// 片元着色器
var FSHADER_SOURCE ='#ifdef GL_ES\n' +'precision mediump float;\n' +'#endif\n' +'uniform sampler2D u_Sampler0;\n' +'uniform sampler2D u_Sampler1;\n' +'varying vec2 v_TexCoord;\n' +'void main() {\n' +'  vec4 color0 = texture2D(u_Sampler0, v_TexCoord);\n' +'  vec4 color1 = texture2D(u_Sampler1, v_TexCoord);\n' +'  gl_FragColor = color0 * color1;\n' +'}\n';function main() {var canvas = document.getElementById('webgl');var gl = getWebGLContext(canvas);if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {console.log('Failed to intialize shaders.');return;}var n = initVertexBuffers(gl);gl.clearColor(0.0, 0.0, 0.0, 1.0);// 配置纹理if (!initTextures(gl, n)) {console.log('Failed to intialize the texture.');return;}
}function initVertexBuffers(gl) {var verticesTexCoords = new Float32Array([// 顶点坐标和纹理坐标-0.5,  0.5,   0.0, 1.0,-0.5, -0.5,   0.0, 0.0,0.5,  0.5,   1.0, 1.0,0.5, -0.5,   1.0, 0.0,]);var n = 4; // 顶点数量var vertexTexCoordBuffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;var a_Position = gl.getAttribLocation(gl.program, 'a_Position');gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);gl.enableVertexAttribArray(a_Position);  // Enable the assignment of the buffer objectvar a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord');gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);gl.enableVertexAttribArray(a_TexCoord);  // Enable the buffer assignmentreturn n;
}function initTextures(gl, n) {// 创建纹理缓冲区对象var texture0 = gl.createTexture(); var texture1 = gl.createTexture();// 获取u_Sampler1和u_Sampler2的存储位置var u_Sampler0 = gl.getUniformLocation(gl.program, 'u_Sampler0');var u_Sampler1 = gl.getUniformLocation(gl.program, 'u_Sampler1');var image0 = new Image();var image1 = new Image();// 注册事件响应函数,在图像加载完成后调用image0.onload = function(){ loadTexture(gl, n, texture0, u_Sampler0, image0, 0); };image1.onload = function(){ loadTexture(gl, n, texture1, u_Sampler1, image1, 1); };// 告诉浏览器开始加载图像image0.src = '../resources/sky.jpg';image1.src = '../resources/circle.gif';return true;
}
// 标记纹理单元是否已经就绪
var g_texUnit0 = false, g_texUnit1 = false; 
function loadTexture(gl, n, texture, u_Sampler, image, texUnit) {gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);// 沿反转图像// 激活纹理单元if (texUnit == 0) {gl.activeTexture(gl.TEXTURE0);g_texUnit0 = true;} else {gl.activeTexture(gl.TEXTURE1);g_texUnit1 = true;}// 绑定纹理对象到目标上(先绑定到纹理单元后指定纹理类型绑定到目标上)gl.bindTexture(gl.TEXTURE_2D, texture);   // 配置纹理参数gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);// 设置纹理图像gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);// 将纹理单元编号传递给取样器gl.uniform1i(u_Sampler, texUnit);   gl.clear(gl.COLOR_BUFFER_BIT);// 图像加载是异步的,我们无法预测哪一张纹理被加载完成,只有两幅都加载好,程序才开始绘制if (g_texUnit0 && g_texUnit1) {gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);  }
}

首先,让我们来看一下片元着色器,本例用到了两幅纹理,那么就需要两个定义uniform变量

然后,在片元着色器的main()函数中,我们从两个纹理中取出颜色,分别存储在变量color0和color1中

颜色矢量的分量乘法来计算两个纹素最终的片元颜色

使用两个纹素来计算最终的片元颜色(gl_FragColor)有多种可能的方法。示例程序使用的是颜色矢量的分量乘法——两个矢量中对应的分量相乘作为新矢量的分量,如下图所示。这很好理解。在GLSL ES中,只需要将两个vec4变量简单相乘一下就可以达到目的。 

第55、56行创建了两个纹理缓冲区对象,变量名的后缀(texture0中的 “0” 和 texture1中的 “1”)对应对应着纹理单元的编号(纹理单元0和纹理单元1),此外uniform变量(第68,69行)与image对象(第70,71行)也采用了类似的命名方式

注册事件响应函数:loadTexture(),最后一个参数是纹理单元编号。

请求浏览器加载图像:

配置纹理:loadTexture()函数。该函数的核心部分代码如下所示: 

需要注意的是

在loadTexture()函数中,我们无法预测哪一幅纹理图像先被加载完成,因为加载的过程是异步进行的。只有当两幅纹理图像都完成加载时,程序才会开始绘图。为此,我们定义了两个全局变量g_texUnit0和g_texUnit1来指示对应的纹理是否加载完成(第81行)。 

这些变量都被初始化为false(第81行)。当任意一幅纹理加载完成时,就触发onload事件并调用响应函数loadTexture()。该函数首先根据纹理单元编号0或1来将g_texUnit0或g_texUnit1赋值为true(第85行)。换句话说,如果触发本次onload事件的纹理的编号是0,那么0号纹理单元就被激活了,并将g_texUnit0设置为true;如果是1,那么1号纹理单元被激活了,并将g_texUnit0设置为ture

接着,纹理单元编号texUnit被赋给了uniform变量(第99行)。注意texUnit是通过gl.uniform1i()方法传入着色器的。在两幅纹理图像都完成加载后,WebGL系统内部的状态就如下图所示。

loadTexture()函数的最后通过检查g_texUnit0和g_texUnit1变量来判断两幅图像是否全部完成加载了(第103行)。如果是,就开始执行顶点着色器,在图形上重叠着绘制出两层纹理,如本文第一张图所示。 

相关文章:

WebGL 同时使用多幅纹理

目录 前言 ​编辑 示例代码 颜色矢量的分量乘法来计算两个纹素最终的片元颜色 注册事件响应函数:loadTexture(),最后一个参数是纹理单元编号。 请求浏览器加载图像: 配置纹理:loadTexture&#xff0…...

探索云计算和大数据分析的崛起:API行业的机遇与挑战【电商大数据与电商API接入】

I. 引言 随着云计算和大数据分析技术的快速发展,企业和个人对数据分析和处理的需求不断增加。在这个信息爆炸的时代,数据已成为企业决策和战略规划的重要基础。云计算提供了强大的计算和存储能力,使得大规模数据的处理和分析变得更加容易和高…...

android studio通过wifi、无线连接设备

AndroidStudio无线wifi调试设备_android studio wifi_zwylovemzj的博客-CSDN博客 使用​​adbWireless​​工具,其能够让手机用无线来取代USB连接而使用ADB工具 1. 手机需要与电脑在同一局域网内 2. 把adbWireless安装到手机上,并开启,上面…...

kafka 3.5 主题分区ISR伸缩源码

ISR(In-sync Replicas):保持同步的副本 OSR(Outof-sync Replicas):不同步的副本。最开始所有的副本都在ISR中,在kafka工作的过程中,如果某个副本同步速度慢于replica.lag.time.max.ms指定的阈值,则被踢出ISR存入OSR&am…...

1-centOS7搭建伪分布式

前言:虚拟机快照的使用 VMware Workstation 软件可以用快照进行迅速的虚拟机状态的切换 ※. 类似于虚拟机备份, 可以使用备份进行快速恢复。 比如没安装jdk之前拍摄快照来备份 ※. 若jdk没安装好或者jdk环境变量配置的有问题, 可以用安装之…...

对开源自动化测试平台MeterSphere的使用感触

1:该平台可以通过接口,参数,配置的维护,然后继续接口自动化“一键测试”,功能还是挺强大的,具体的使用需要研究 MeterSphere的官网:MeterSphere - 专业测试云 2:一键测试在生产环境…...

Spring boot 第一个程序

新建工程 选择spring-boot版本 右键创建类TestController: 代码如下: package com.example.demo; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springf…...

【SpringMVC】实现增删改查(附源码)

目录 引言 一、前期准备 1.1.搭建Maven环境 1.2.导入pom.xml依赖 1.3.导入配置文件 ①jdbc.properties ②generatorConfig.xml ③log4j2.xml ④spring-mybatis.xml ⑤spring-context.xml ⑥spring-mvc.xml ⑦修改web.xml文件 二、逆向生成增删改查 2.1.导入相关u…...

理财是什么?怎样学习理财?

大家好,我是财富智星,今天跟大家分享一下理财是什么?怎样学习理财的方法。 一、理财的基本原则 1、理财应注重投资而不是投机,要与时间为友。 让我们先考虑以下问题:什么样的回报才算是真正的高回报?假设有…...

华为云云耀云服务器L实例评测 | 开启OPC UA之旅

OPC Unified Architecture (OPC UA)是一种用于工业自动化的M2M协议(Machine-to-machine),具有平台独立性,在Windows和Linux上都可以运行。随着云服务在工业现场的不断普及,OPCUA服务也开始大量部署在云端。 本文以华为云云耀云服务器L为基础…...

帝国CMS灵动标签如何调用$ecms_hashur[‘ehref‘]函数

我们在二次开发时,后台调用链接就需要加上帝国CMS的$ecms_hashur[ehref]函数,这是帝国CMS后台的安全函数,防止外部直接访问后台页面,直接强制访问后台链接就会提示“非法来源”。 我的站长站分享下制作自定义php页面,用帝国CMS灵动标签如何调用$ecms_hashur[ehref]函数方…...

ES6 拓展(下)

一、函数的拓展 1.1、默认参数 在ES5中设置默认参数: function func(words, name) {name name || "闷墩儿";console.log(words, name); } func("大家好!我是"); func("大家好!我是", "憨憨");func(…...

TouchGFX之自定义触发条件和操作

通过TouchGFX Designer,您可以自己定义具有触发条件和操作的交互组件。 自定义容器创建自定义触发条件:通过自定义容器的属性选项卡添加自定义触发条件 使用交互系统发送自定义触发条件: 通过自定义容器的“交互”选项卡,创建新的…...

Linux防火墙(iptables)

一、linux的防火墙组成 linux的防火墙由netfilter和iptables组成。用户空间的iptables制定防火墙规则,内核空间的netfilter实现防火墙功能。 netfilter(内核空间)位于Linux内核中的包过滤防火墙功能体系,称为Linux防火墙的“内核…...

zookeeper教程

zookeeper教程 zookeeper简介zookeeper的特点及数据模型zookeeper下载安装zookeeper客户端命令zookeeper配置文件zookeeper服务器常用命令zookeeper可视化管理工具zkuizookeeper集群环境搭建zookeeper选举机制使用Java原生api操作zookeeper使用java zkclient库操作zookeeper使用…...

杭州快递物流展-2024长三角快递物流供应链与技术装备展览会(杭州)

2024快递物流创新高质量发展论坛暨 2024长三角快递物流供应链与技术装备展览会(杭州) 时间:2024年4月12-14 日 地点:杭州国际博览中心 ESYE长三角快递物流展是亚洲范围内超大规模的快递物流业展示平台,由于展会的需求 及扩大市场的影响力…...

CSP 202203-1 未初始化警告

答题 要注意是xi和yi的范围&#xff0c;yi可以是0为常数。 #include<iostream> using namespace std;int main() {int n,k;cin>>n>>k;bool*initializenew bool[n]{false};int result0,x,y;while(k--){cin>>x>>y;if(y&&!initialize[y-1…...

开发指导—利用组件插值器动画实现 HarmonyOS 动效

一. 组件动画 在组件上创建和运行动画的快捷方式。具体用法请参考通用方法。 获取动画对象 通过调用 animate 方法获得 animation 对象&#xff0c;animation 对象支持动画属性、动画方法和动画事件。 <!-- xxx.hml --><div class"container"> <di…...

树莓派入门

目录 前言系统烧录使用官方烧录工具选择操作系统选择存储卡配置 Win32DiskImager 有屏幕树莓派开机树莓派关机无屏幕树莓派开机获取树莓派IP地址通过路由器获取共享网络方式获取给树莓派配置静态IP地址查找默认网关分盘给树莓派的IP地址修改树莓派DHCP配置文件 ssh登录 让树莓派…...

算法模型嵌入式 Mendix应用的开发示例

一、前言 根据埃森哲最新一项调查&#xff0c;2023年67%的企业持续加大在技术方面的投入&#xff0c;其中数据和AI应用是重中之重。AI在企业内部应用这个话题已经保持了十多年的热度&#xff0c;随着ChatGPT为代表的生成式AI技术的出现&#xff0c;这一话题迎来又一波的高潮。…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

Linux nano命令的基本使用

参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时&#xff0c;显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...