WebGL 添加背景图

1. 纹理坐标(st坐标)简介

ST纹理坐标(也称为UV坐标)是一种二维坐标系统,用于在三维模型的表面上精确地定位二维纹理图像。这种坐标系统通常将纹理的左下角映射到(0,0),而右上角映射到(1,1)。

  • S坐标(U坐标):通常对应纹理图像的水平方向,即纹理的宽度。
  • T坐标(V坐标):通常对应纹理图像的垂直方向,即纹理的高度。

1.1 纹理坐标的工作原理

  • 纹理坐标的范围通常是从0.0到1.0,其中(0.0, 0.0)代表纹理的左下角,而(1.0, 1.0)代表右上角。
  • 在WebGL中,纹理坐标系统的t轴(垂直轴)与传统图像文件的y轴方向相反,这意味着当你在WebGL中使用纹理时,通常需要翻转图像的Y轴以确保正确的映射。
  • 这可以通过设置gl.UNPACK_FLIP_Y_WEBGL为1来实现。

2. 基本步骤

​​​​2.1 创建纹理对象

  • 使用gl.createTexture()创建一个新的纹理对象。
  • 可以通过 gl.deleteTexture(textrue)来删除纹理对象。
 const texture = gl.createTexture();

2.2 翻转图片Y轴

gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); 

2.3 开启纹理单元

gl.activeTexture(gl.TEXTURE0)

2.4绑定纹理对象

使用gl.bindTexture(type, texture)将纹理对象绑定到纹理单元上。type 参数有以下两种:

  • gI.TEXTURE_2D:二维纹理
  • gI.TEXTURE_CUBE_MAP:立方体纹理
gl.bindTexture(gl.TEXTURE_2D, texture);

2.5 配置纹理参数

设置纹理的过滤方式(gl.TEXTURE_MIN_FILTER和gl.TEXTURE_MAG_FILTER)、包裹方式(gl.TEXTURE_WRAP_S和gl.TEXTURE_WRAP_T)等参数。

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
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);

2.6 上传纹理图像数据

使用gl.texImage2D(type, level,internalformat, format,dataType, image)将图像数据上传到纹理对象中。

2.6.1 type参数:
  • gI.TEXTURE_2D:二维纹理
  • gI.TEXTURE_CUBE_MAP:立方体纹理
2.6.2 level参数:
  • 默认为0
2.6.3 internalformat参数
  • gI.RGB
  • gI.RGBA
  • gI.ALPHA
  • gI.LUMINANCE 使用物体表面的红绿蓝 分量的加权平均值来计算
  • gI.LUMINANCE ALPHA
2.6.4 format参数
  • format 纹理的内部格式,必须和internalformat 相同
2.6.5 dataType参数
  • 9I.UNSIGNED_BYTE
  • gI.UNSIGNED_SHORT_5_6_5
  • gI.UNSIGNED_SHORT_4_4_4_4
  • gI.UNSIGNED_SHORT_5_5_5_1
 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);

3. 实例代码

以下是一个简单的WebGL示例,展示了如何给一个简单的四边形添加背景图:

/** @type {HTMLCanvasElement} */
        const ctx = document.getElementById('canvas')
        const gl = ctx.getContext('webgl')
        // 顶点着色器源码
        const vertexShaderSource = `
            attribute vec4 aPosition;
            attribute vec4 aTex;
            varying vec2 vTex;

            void main() {
                gl_Position = aPosition;
                vTex = vec2(aTex.x, aTex.y);
            }`

        // 片源着色器源码
        const fragmentShaderSource = `
            precision lowp float;
            uniform sampler2D uSampler;
            varying vec2 vTex;

            void main() {
                gl_FragColor = texture2D(uSampler, vTex);
            }`
        const program = initShader(gl, vertexShaderSource, fragmentShaderSource);
        const aPosition = gl.getAttribLocation(program, 'aPosition');
        const aTex = gl.getAttribLocation(program, 'aTex');
        const uSampler = gl.getUniformLocation(program, 'uSampler');//赋值

        const points = 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,
        ])
        const buffer = gl.createBuffer();
        const BYTES = points.BYTES_PER_ELEMENT; // 偏移字节
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
        gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, BYTES * 4, 0);
        gl.enableVertexAttribArray(aPosition);
        gl.vertexAttribPointer(aTex, 2, gl.FLOAT, false, BYTES * 4, BYTES * 2);
        gl.enableVertexAttribArray(aTex);

        const img = new Image();
        img.onload = function () {
            // 创建纹理对象并加载图片
            const texture = gl.createTexture();
            // 翻转图片Y轴
            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
            // 开启一个单元纹理
            gl.activeTexture(gl.TEXTURE0)
            // 绑定纹理对象
            gl.bindTexture(gl.TEXTURE_2D, texture);
            // 配置纹理参数
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
            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.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, img);
            gl.uniform1i(uSampler, 0);
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
        }
        img.src = './images/img2.png';

4.效果如下

 

5. 添加多张背景图 

  • 添加几张图,就定义几个sampler2D 
// 片源着色器源码
const fragmentShaderSource = `
    precision lowp float;
    uniform sampler2D uSampler;
    uniform sampler2D uSampler1;
    varying vec2 vTex;

    void main() {
    vec4 c1 = texture2D(uSampler, vTex);
    vec4 c2 = texture2D(uSampler1, vTex);
    texture2D(uSampler1, vTex);
        gl_FragColor = c1 * c2;
    }`
  • 将创建纹理的过程封装方法
// 封装函数
        function getImage(location, url, index) {
            // Promise
            return new Promise(resolve => {
                const img = new Image();
                img.onload = function () {
                    // 创建纹理对象并加载图片
                    const texture = gl.createTexture();
                    // 翻转图片Y轴
                    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
                    // 开启一个单元纹理
                    gl.activeTexture(gl[`TEXTURE${index}`])
                    // 绑定纹理对象
                    gl.bindTexture(gl.TEXTURE_2D, texture);
                    // 配置纹理参数
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
                    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.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, img);
                    gl.uniform1i(location, index);

                    resolve();
                }
                img.src = url;
            });
        }
        Promise.all([getImage(uSampler, "./images/img.png", 0), getImage(uSampler1, "./images/img2.png", 1)]).then(() => {
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
        })

效果如下 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

leetcode_128:最长连续序列

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1: 输入:nums [100,4,200,1,3,2] 输出:4 解…

CSS揭秘:7. 伪随机背景

前置知识:CSS 渐变,5. 条纹背景,6. 复杂的背景图案 前言 本篇主要内容依然是关于背景的,无限平铺的背景会显得整齐美观,但又有些呆板,如何实现背景的多样性和随机性,是本篇的核心。 一、四种颜…

AI周报(10.20-10.26)

AI应用-牙科AI产品Pearl Pearl是一家致力于改善牙科患者护理的人工智能驱动型公司,推出了首款获得美国食品药品监督管理局(FDA)批准的人工智能,能够读取牙科X光片并即时识别疾病。今年7月获得5800万美元的B轮融资,以加…

GESP一级真题分析-202303-选择题1-输入输出设备、存储单位、默认数据类型、标识符命名

PDF文档回复:20241026 1 相关知识点 1) 输入输出设备 输入设备 是外界向计算机传送信息的装置。在微型计算机系统中,最常用的输入设备是键盘和鼠标。 此外还有电子光笔、数字化仪、图形扫描仪、触摸屏、麦克风、视频输入设备、条形码扫描等 输出设备 作用是将计…

Java-图书管理系统

我的个人主页 欢迎来到我的Java图书管理系统,接下来让我们一同探索如何书写图书管理系统吧! 1管理端和用户端 2建立相关的三个包(book、operation、user) 3建立程序入口Main类 4程序运行 1.首先图书馆管理系统分为管理员端和…

6.stm32 OLED显示屏

调试方式 串口调试:通过串口通信,将调试信息发送到电脑端,电脑使用串口助手显示调试信息 显示屏调试:直接将显示屏连接到单片机,将调试信息打印在显示屏上 Keil调试模式:借助Keil软件的调试模式&#…

【阅读笔记】Instruction-based Hypergraph Pretraining

Abstract中可以提炼的信息: 背景:预训练的作用是为了增强图学习模型将知识从大数据集转移到下游任务的适应性。 想解决的问题:训练目标的不同与数据分布的不同会阻碍预训练知识的迁移。 文章受到基于指令的提示词在语言模型训练广泛应用的启发…

Vue学习笔记(四)

事件处理 我们可以使用 v-on 指令 (通常缩写为 符号) 来监听 DOM 事件,并在触发事件时执行一些 JavaScript。用法为 v-on:click"methodName" 或使用快捷方式 click"methodName" 事件处理器的值可以是: 内联事件处理器&#xff1…

鹅厂面试官:Transformer 为何需要位置编码?

最近这一两周看到不少互联网公司都已经开始秋招发放Offer。 不同以往的是,当前职场环境已不再是那个双向奔赴时代了。求职者在变多,HC 在变少,岗位要求还更高了。 最近,我们又陆续整理了很多大厂的面试题,帮助一些球…

前端零基础入门到上班:【Day2】开发环境VSCode安装

VSCode 安装教程:图文保姆教程 引言 在前端开发中,选择合适的代码编辑器是提高工作效率的重要一步。Visual Studio Code(简称 VSCode)作为一款强大的开源编辑器,因其简洁易用、功能强大、扩展性好而广受开发者喜爱。…

【智能大数据分析 | 实验四】Spark实验:Spark Streaming

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈智能大数据分析 ⌋ ⌋ ⌋ 智能大数据分析是指利用先进的技术和算法对大规模数据进行深入分析和挖掘,以提取有价值的信息和洞察。它结合了大数据技术、人工智能(AI)、机器学习(ML&a…

Postman常见问题及解决方(全)

🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 1、网络连接问题 如果Postman无法发送请求或接收响应,可以尝试以下操作: 检查网络连接是否正常,包括检查网络设置、代理设置…

前端零基础入门到上班:【Day3】从零开始构建网页骨架HTML

HTML 基础入门&#xff1a;从零开始构建网页骨架 目录 1. 什么是 HTML&#xff1f;HTML 的核心作用 2. HTML 基本结构2.1 DOCTYPE 声明2.2 <html> 标签2.3 <head> 标签2.4 <body> 标签 3. HTML 常用标签详解3.1 标题标签3.2 段落和文本标签3.3 链接标签3.4 图…

市面上热门的四款PDF转换器解析!!

在互联网普及的今天&#xff0c;PDF和Excel已经成为我们工作中不可或缺的两种文件格式。PDF常用于文档的阅读、打印和分享&#xff0c;而Excel则适用于数据的分析和处理。但是&#xff0c;有时候我们需要在两者之间进行转换&#xff0c;例如将PDF中的数据导入到Excel中进行进一…

物联网数据采集网关详细介绍-天拓四方

一、物联网数据采集网关的概述 物联网数据采集网关&#xff0c;简称数据采集网关&#xff0c;是物联网系统中的重要组成部分&#xff0c;位于物联网设备和云端平台之间。其主要职责是实现数据的采集、汇聚、转换、传输等功能&#xff0c;确保来自不同物联网设备的数据能够统一…

Hadoop 踩坑汇总

文章目录 一、完整教程二、解决问题问题①&#xff1a; DataNode 没有问题②&#xff1a; 网页打不开 三、大功告成&#xff01;&#xff01; 一、完整教程 这个教程比较详细&#xff0c;博主是按照这个来执行的 https://blog.csdn.net/qq_47831505/article/details/123806514…

VsCode插件:前端每日一题

Javascript本地存储的方式有哪些&#xff1f; 区别及应用场景? 1. Cookie Cookie 是网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据。Cookie 通常包含了用户的一些个人信息&#xff0c;如用户名、密码、浏览记录、偏好设置等。Cookie 一般在用户访问网站…

Excel:vba实现生成随机数

Sub 生成随机数字()Dim randomNumber As IntegerDim minValue As IntegerDim maxValue As Integer 设置随机数的范围(假入班级里面有43个学生&#xff0c;学号是从1→43)minValue 1maxValue 43 生成随机数(在1到43之间生成随机数)randomNumber Application.WorksheetFunctio…

智联招聘×Milvus:向量召回技术提升招聘匹配效率

01. 业务背景 在智联招聘平台&#xff0c;求职者和招聘者之间的高效匹配至关重要。招聘者可以发布职位寻找合适的人才&#xff0c;求职者则通过上传简历寻找合适的工作。在这种复杂的场景中&#xff0c;我们的核心目标是为双方提供精准的匹配结果。在搜索推荐场景下&#xff0c…

深入理解gPTP时间同步过程

泛化精确时间协议(gPTP)是一个用于实现精确时间同步的协议,特别适用于分布式系统中需要高度协调的操作,比如汽车电子、工业自动化等。 gPTP通过同步主节点(Time Master)和从节点(Time Slave)的时钟,实现全局一致的时间参考。 以下是gPTP实现主从时间同步的详细过程:…