WebGL 纹理完整教程:原理、场景 + 可直接运行 Demo一、WebGL 纹理核心概念1. 纹理是什么纹理就是一张图片,把像素数据贴到几何体表面(类似贴纸),WebGL 通过纹理单元、纹理对
WebGL 纹理完整教程原理、场景 可直接运行 Demo一、WebGL 纹理核心概念1. 纹理是什么纹理就是一张图片把像素数据贴到几何体表面类似贴纸WebGL 通过纹理单元、纹理对象、采样器、UV 坐标配合使用。 核心四要素纹理对象 (Texture)存储图片像素缓存纹理单元 (Texture Unit)GPU 并行纹理槽位默认至少 16 个gl.TEXTURE0 ~ gl.TEXTURE15UV 坐标贴图坐标范围[0,1](0,0) 图片左上角(1,1) 右下角纹理参数缩放过滤、环绕模式2. 关键纹理参数环绕模式图片超出 UV 0~1 时gl.REPEAT重复平铺默认gl.CLAMP_TO_EDGE拉伸边缘像素gl.MIRRORED_REPEAT镜像重复过滤模式缩放贴图时放大TEXTURE_MAG_FILTERgl.LINEAR线性模糊平滑gl.NEAREST像素块马赛克缩小TEXTURE_MIN_FILTER多配合 Mipmapgl.LINEAR_MIPMAP_LINEAR三线性画质最好gl.NEAREST硬像素二、纹理常见应用场景2D/3D 模型贴图人物皮肤、墙体、地板、道具外观UI 界面游戏按钮、图标、背景面板帧缓冲 FBO 渲染纹理离屏渲染、镜面反射、阴影贴图、后期滤镜模糊 / 调色数据纹理把数组数据存纹理GPU 并行计算GPGPU视频纹理播放视频贴到模型播放器、虚拟大屏文字纹理字体图集贴图渲染文字环境贴图天空盒、反射球环境光三、完整可运行 Demo贴图矩形 本地图片纹理功能绘制一个带图片纹理的全屏矩形包含完整纹理创建、图片异步加载、着色器 UV 采样逻辑 复制全部代码保存为.html直接浏览器打开即可。html预览!DOCTYPE html html langzh-CN head meta charsetUTF-8 titleWebGL Texture Demo/title style canvas { border: 1px solid #000; } /style /head body canvas idwebglCanvas width600 height400/canvas script // 1. 获取Canvas与WebGL上下文 const canvas document.getElementById(webglCanvas); const gl canvas.getContext(webgl) || canvas.getContext(experimental-webgl); if (!gl) alert(浏览器不支持WebGL); // 着色器代码 // 顶点着色器传递顶点坐标 UV贴图坐标 const vertexShaderSource attribute vec2 a_Position; attribute vec2 a_Uv; varying vec2 v_Uv; void main() { gl_Position vec4(a_Position, 0.0, 1.0); v_Uv a_Uv; } ; // 片元着色器纹理采样sampler2D读取纹理 const fragmentShaderSource precision mediump float; uniform sampler2D u_Texture; varying vec2 v_Uv; void main() { // 根据UV从纹理采样像素颜色 gl_FragColor texture2D(u_Texture, v_Uv); } ; // 工具函数编译着色器、链接程序 function createShader(gl, type, source) { const shader gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { console.error(着色器编译失败, gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return null; } return shader; } function createProgram(gl, vsSource, fsSource) { const vs createShader(gl, gl.VERTEX_SHADER, vsSource); const fs createShader(gl, gl.FRAGMENT_SHADER, fsSource); const program gl.createProgram(); gl.attachShader(program, vs); gl.attachShader(program, fs); gl.linkProgram(program); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { console.error(程序链接失败, gl.getProgramInfoLog(program)); return null; } gl.useProgram(program); return program; } // 初始化着色器程序 const program createProgram(gl, vertexShaderSource, fragmentShaderSource); // 顶点数据矩形 UV坐标 // 格式[x,y, u,v] 四个顶点两个三角组成矩形 const vertices new Float32Array([ -1.0, 1.0, 0.0, 0.0, // 左上 -1.0, -1.0, 0.0, 1.0, // 左下 1.0, 1.0, 1.0, 0.0, // 右上 1.0, -1.0, 1.0, 1.0 // 右下 ]); const buffer gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); // 绑定顶点属性 const a_Position gl.getAttribLocation(program, a_Position); const a_Uv gl.getAttribLocation(program, a_Uv); const stride 4 * Float32Array.BYTES_PER_ELEMENT; // 一组4个浮点数 // 位置每组前2个 gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, stride, 0); gl.enableVertexAttribArray(a_Position); // UV每组后2个偏移2个浮点数 gl.vertexAttribPointer(a_Uv, 2, gl.FLOAT, false, stride, 2 * Float32Array.BYTES_PER_ELEMENT); gl.enableVertexAttribArray(a_Uv); // 创建纹理对象核心逻辑 function createTexture(gl) { const texture gl.createTexture(); // 绑定到当前激活纹理单元 TEXTURE0 gl.bindTexture(gl.TEXTURE_2D, texture); // 设置纹理环绕模式 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); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); // 临时填充1x1白色像素避免图片未加载时黑屏报错 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255,255,255,255])); return texture; } // 加载图片到纹理 function loadTexture(gl, texture, imgUrl) { const img new Image(); img.crossOrigin anonymous; // 解决跨域图片报错 img.onload () { gl.bindTexture(gl.TEXTURE_2D, texture); // 上传图片像素到GPU纹理 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img); render(); // 图片加载完成重绘 }; img.src imgUrl; } // 渲染函数 function render() { gl.clearColor(0.2, 0.2, 0.2, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); // 激活0号纹理单元 gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, texture); // 把采样器u_Texture绑定到0号纹理单元 gl.uniform1i(gl.getUniformLocation(program, u_Texture), 0); // 绘制两个三角形共4顶点 gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); } // 启动流程 const texture createTexture(gl); // 替换成你自己的图片链接本地图片直接放同目录 loadTexture(gl, texture, https://picsum.photos/id/237/400/300); render(); /script /body /html四、关键 API 分步解析1. 创建纹理js运行const texture gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); // 绑定2D纹理目标2. 设置纹理参数必写否则缩放会黑块js运行// S水平方向T垂直方向环绕 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); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);3. 上传图片数据到 GPUjs运行gl.texImage2D( gl.TEXTURE_2D, 0, // mip层级 gl.RGBA, // GPU内部存储格式 gl.RGBA, // 图片像素格式 gl.UNSIGNED_BYTE, // 像素数据类型 img // Image/Video/Canvas数据源 );4. 激活纹理单元 传入着色器js运行// 激活第0个纹理槽 gl.activeTexture(gl.TEXTURE0); // 绑定纹理对象到当前激活单元 gl.bindTexture(gl.TEXTURE_2D, texture); // 片元着色器sampler2D变量 纹理单元编号0 gl.uniform1i(u_TextureLoc, 0);5. 着色器采样glsluniform sampler2D u_Texture; // 纹理采样器 varying vec2 v_Uv; // 插值UV坐标 // 采样获取像素颜色 vec4 color texture2D(u_Texture, v_Uv);五、拓展常用纹理拓展用法1. Mipmap 优化远距离贴图图片尺寸是 2 的幂512/1024/2048时开启js运行gl.generateMipmap(gl.TEXTURE_2D); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);2. 多纹理叠加双纹理单元js运行// 纹理1绑定TEXTURE0 gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, tex1); gl.uniform1i(texLoc1, 0); // 纹理2绑定TEXTURE1 gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D, tex2); gl.uniform1i(texLoc2, 1);片元着色器混合两张贴图glslvec4 col1 texture2D(u_Tex1, v_Uv); vec4 col2 texture2D(u_Tex2, v_Uv); gl_FragColor mix(col1, col2, 0.5);3. Video 视频纹理直接传入video标签到texImage2D渲染循环每帧更新纹理。4. FBO 渲染纹理离屏渲染创建纹理绑定帧缓冲把 3D 场景渲染到纹理再贴到模型实现镜面、特效。六、常见踩坑点图片跨域黑屏设置img.crossOrigin anonymous图片服务器允许跨域UV 超出范围拉伸异常修改TEXTURE_WRAP_S/T为CLAMP_TO_EDGE缩小贴图出现黑块没设置TEXTURE_MIN_FILTER过滤参数Mipmap 报错图片宽高必须是 2 的整数次幂图片加载前黑屏先填充 1x1 临时像素纹理

相关新闻

UE5模板序列:跨关卡复用动画与逻辑的高效解决方案

UE5模板序列:跨关卡复用动画与逻辑的高效解决方案

1. 项目概述:为什么跨关卡复用模板序列是UE开发者的必修课在虚幻引擎(UE5/UE4)的项目开发中,尤其是涉及到大型开放世界、多章节叙事或者重复性玩法机制时,我们经常会遇到一个头疼的问题:辛辛苦苦在某个关卡…

2026/10/27 14:41:56 阅读更多 →
AI图书出版系统实战:从架构设计到生产部署完整指南

AI图书出版系统实战:从架构设计到生产部署完整指南

如果你正在探索如何将AI技术真正落地到内容创作领域,特别是想了解从零搭建一个AI驱动的图书出版系统会遇到哪些实际挑战,那么这篇文章正是为你准备的。过去一年,AI内容生成技术看似成熟,但真正将其应用到严肃出版领域时&#xff0…

2026/10/25 2:48:43 阅读更多 →
智能视频创作技术:从生成式AI到神经渲染的实践

智能视频创作技术:从生成式AI到神经渲染的实践

1. 智能视频创作的技术演进脉络2026年视频创作领域正在经历一场由底层技术驱动的范式转移。过去三年间,三个关键技术突破彻底改变了行业格局:首先是神经渲染技术从实验室走向工业化,使得实时生成影视级画质成为可能;其次是多模态大…

2026/10/25 18:50:54 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/27 17:33:32 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/27 4:06:49 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/27 7:21:53 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/27 18:20:50 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/27 6:20:47 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/27 4:06:50 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 13:55:19 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 7:21:50 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 19:19:37 阅读更多 →