SpriteJS 3D 渲染对象(RenderTarget)实战:FrameBuffer 离屏渲染、纹理回读与双缓冲复用
图形学3D渲染【免费下载链接】spritejsA cross platform high-performance graphics system.项目地址https://gitcode.com/gh_mirrors/sp/spritejs点击查看免费下载导读在 SpriteJS 3D 扩展中RenderTarget是一块可绘制的 FrameBuffer用于把 3D 场景先渲染到离屏缓冲再以纹理的形式贴回屏幕从而支撑「渲染结果作为输入再次渲染」这类多次渲染需求。本文以 docs/zh-cn/ext3d/render-target.md 为核心结合仓库内可运行的 demo 与 API 文档系统讲解 RenderTarget 的构造参数、layer.renderTarget调用方式、多 Target 叠加、双缓冲复用以及autoClear控制缓冲区保留等完整实战方案。为什么需要渲染对象RenderTarget在普通的 3D 绘制流程里场景内容直接被渲染到屏幕上。但有些时候我们需要多次渲染例如先把一些内容渲染到 FrameBuffer 中然后作为纹理输出到屏幕将前一步的渲染结果当作下一步的输入形成链式/迭代处理如后期处理、GPGPU 流体模拟。在 SpriteJS 的 3D 扩展sprite-extend-3d中这个需求由RenderTarget对象解决——它定义了一个用于将元素绘制到 FrameBuffer 的对象见 docs/zh-cn/api/ext3d/render-target.md。RenderTarget 继承自Group3d因此它本身就是一个 3D 分组节点可以像普通 Group 一样append子元素、拥有自己的相机。使用前请确保已按 docs/zh-cn/ext3d/index.md 的说明加载sprite-extend-3d在spritejs之后引入即可随后通过spritejs.ext3d.RenderTarget访问该 API。快速上手把场景渲染到 FrameBuffer 再贴回屏幕下面这段完整示例与 demos/3d/render_target/index.js 一致展示了 RenderTarget 最核心的用法一个立方体mesh被渲染到target的 FrameBuffer 上然后target.texture作为另一个立方体mesh2的 Program 纹理最终mesh2输出到屏幕。const vertex /* glsl */ precision highp float; precision highp int; attribute vec3 position; attribute vec3 normal; attribute vec2 uv; uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; uniform mat3 normalMatrix; varying vec2 vUv; varying vec3 vNormal; void main() { vUv uv; vNormal normalize(normalMatrix * normal); gl_Position projectionMatrix * modelViewMatrix * vec4(position, 1.0); } ; const fragment /* glsl */ precision highp float; precision highp int; uniform sampler2D tMap; varying vec2 vUv; varying vec3 vNormal; void main() { vec3 normal normalize(vNormal); float lighting 0.2 * dot(normal, normalize(vec3(-0.3, 0.8, 0.6))); vec3 tex texture2D(tMap, vUv).rgb; gl_FragColor.rgb tex lighting vec3(vUv - 0.5, 0.0) * 0.1; gl_FragColor.a 1.0; } ; const {Scene} spritejs; const {Cube, RenderTarget} spritejs.ext3d; const container document.getElementById(container); const scene new Scene({ container, displayRatio: 2, }); const layer scene.layer3d(fglayer, { camera: { fov: 35, }, }); layer.camera.attributes.pos [0, 1, 5]; layer.camera.lookAt([0, 0, 0]); const texture layer.createTexture({ image: new Uint8Array([ 191, 25, 54, 255, 96, 18, 54, 255, 96, 18, 54, 255, 37, 13, 53, 255, ]), width: 2, height: 2, magFilter: layer.gl.NEAREST, }); const program layer.createProgram({ vertex, fragment, texture, }); const target new RenderTarget(layer.gl, { width: 512, height: 512, camera: { fov: 35, }, }); target.camera.attributes.pos [0, 1, 5]; target.camera.lookAt([0, 0, 0]); const mesh new Cube(program); target.append(mesh); const targetProgram layer.createProgram({ vertex, fragment, texture: target.texture, }); target.addEventListener(beforerender, (e) { layer.gl.clearColor(0.15, 0.05, 0.2, 1); }); target.addEventListener(afterrender, (e) { layer.gl.clearColor(1, 1, 1, 0); }); const mesh2 new Cube(targetProgram); layer.append(mesh2); layer.tick(() { layer.renderTarget(target); mesh.attributes.rotateY - 1.5; mesh2.attributes.rotateY - 0.9; mesh2.attributes.rotateX - 1; });拆解这段代码的完整流程定义着色器顶点着色器做常规的modelViewMatrix/projectionMatrix/normalMatrix变换片元着色器通过uniform sampler2D tMap采样纹理并叠加一个简单的方向光计算。创建 3D 层与相机scene.layer3d(fglayer, {camera: {fov: 35}})创建一个带透视相机的 3D 层layer.camera与target.camera分别设置位置[0, 1, 5]并lookAt([0, 0, 0])——RenderTarget 拥有独立的相机可以看作一个迷你 3D 场景。创建 RenderTargetnew RenderTarget(layer.gl, {width: 512, height: 512, camera: {fov: 35}})在离屏开辟一块 512×512 的 FrameBuffer。把元素挂到 target 上target.append(mesh)这与把元素append到 layer 上的方式完全一致。回读纹理通过target.texture只读属性返回渲染后的纹理数据创建第二个 ProgramtargetProgram用它再生成一个立方体mesh2并layer.append(mesh2)。渲染到离屏缓冲在layer.tick中调用layer.renderTarget(target)先执行 target 上元素的渲染beforerender/afterrender事件用来在渲染前后修改clearColor如渲染时清为深紫色(0.15, 0.05, 0.2)渲染结束后恢复为白色透明(1, 1, 1, 0)。驱动动画每帧分别旋转两个立方体即可看到mesh2表面显示的是mesh渲染到 FrameBuffer 中的画面。RenderTarget 构造参数详解根据 docs/zh-cn/api/ext3d/render-target.mdnew RenderTarget(gl, attrs)支持的配置项及默认值如下配置项默认值说明widthgl.canvas.width离屏缓冲宽度像素heightgl.canvas.height离屏缓冲高度像素targetgl.FRAMEBUFFER绑定的帧缓冲类型color1颜色附件的数量depthtrue是否启用深度缓冲stencilfalse是否启用模板缓冲depthTexturefalse是否使用深度纹理注意开启后与 stencil 不兼容即「stencil breaks」wrapSgl.CLAMP_TO_EDGE水平方向纹理环绕方式wrapTgl.CLAMP_TO_EDGE垂直方向纹理环绕方式minFiltergl.LINEAR纹理缩小过滤方式magFilterminFilter纹理放大过滤方式默认跟随 minFiltertypegl.UNSIGNED_BYTE纹理数据类型formatgl.RGBA纹理格式internalFormatformat内部存储格式默认跟随 formatunpackAlignment—像素数据行对齐方式premultiplyAlpha—是否预乘 AlphacameracameraOptions该 RenderTarget 使用的相机配置bufferfalse是否启用双缓冲true时可用swap()交换缓冲实用建议需要精确纹理采样时可像示例一样指定magFilter: layer.gl.NEAREST避免放大时的线性插值模糊涉及深度测试的 3D 内容要保持depth: true只做 2D 后处理或 GPGPU 计算时可设depth: false以节省开销高精度浮点模拟如流体可将type设为半浮点WebGL2 下为gl.HALF_FLOAT并显式指定format/internalFormat参见下文「源码佐证」一节的demos/3d/post/index.js。作为Group3d的子类RenderTarget 同样继承Node3d的位置/旋转/缩放属性pos、rotate、scale等与 Group 的子元素管理能力也拥有readonly texture属性。核心方法包括renderBy(layer, {root this, ...options} {})让 RenderTarget 实例被 layer 渲染swap()当构造时设置了buffer后交换当前缓冲与目标缓冲。layer.renderTarget把内容绘制到目标缓冲区layer.renderTarget(target, options)是Layer3d提供的方法用于渲染指定的 RenderTarget 对象参见 docs/zh-cn/api/ext3d/layer3d.md。与bindTarget的「持续绑定」不同renderTarget通常配合tick在每帧显式调用用于一次性绘制某个目标。它支持传入渲染选项在 demos/3d/post/index.js 的流体模拟中可以看到实际用法layer.renderTarget(velocity, { root: splatProgram, sort: false, update: false, });其中root本次渲染的根节点缺省时渲染 RenderTarget 自身挂载的子元素。传入外部节点即可实现「不把 root 添加到 renderTarget 上针对不同 renderTarget 复用同一个 root」sort是否对网格排序计算类渲染如后处理可设为false跳过排序update是否更新网格数据固定几何如全屏三角形可设为false跳过更新以提升性能。底层上这些选项与Layer3d.setRenderOptions(opts)的配置update true、sort true、frustumCull true、clear对应均来自 docs/zh-cn/api/ext3d/layer3d.md。多次渲染的三种实现方案「渲染结果作为纹理继续参与渲染」是 RenderTarget 最常见的进阶场景。官方文档给出了三种逐步递进的方案。方案一创建多个 RenderTarget 叠加当需要多道处理时最直接的做法是创建多个 RenderTarget把同一个 root 复用到不同目标上再读取各自的textureconst target1 new RenderTarget(layer.gl, { width: 512, height: 512, camera: { fov: 35, }, }); const target2 new RenderTarget(layer.gl, { width: 512, height: 512, camera: { fov: 35, }, }); const target3 new RenderTarget(layer.gl, { width: 512, height: 512, camera: { fov: 35, }, }); ... const root new Mesh3d(...); layer.tick(() { // 我们可以不将root添加到renderTarget上这样就可以针对不同的renderTarget复用root layer.renderTarget(target1, {root}); root.program.uniforms.tMap.value target1.texture; layer.renderTarget(target2, {root}); root.program.uniforms.tMap.value target2.texture; layer.renderTarget(target3, {root}); root.program.uniforms.tMap.value target2.texture; ... });注意两个关键点root 不挂载到 RenderTarget 上而是通过layer.renderTarget(target, {root})临时指定这样同一个root可以在不同 target 之间复用纹理通过 uniform 切换每轮渲染前把root.program.uniforms.tMap.value指向上一个 target 的texture实现结果链式传递。这种方案的缺点是处理 N 次就要创建 N 个 RenderTargetFrameBuffer 与纹理都占用显存比较消耗内存。方案二两个 target 依次交换如果处理是反复迭代的其实只需要两个target依次交换使用即可const root new Mesh3d(...); layer.tick(() { // 我们可以不将root添加到renderTarget上这样就可以针对不同的renderTarget复用root layer.renderTarget(target1, {root}); root.program.uniforms.tMap.value target1.texture; layer.renderTarget(target2, {root}); root.program.uniforms.tMap.value target2.texture; layer.renderTarget(target1, {root}); ... });target1 → target2 → target1 → ...交替渲染每次读取的是上一轮写出的结果从而把内存占用从 N 个 target 降到 2 个。方案三双缓冲 buffer: true swap()更简洁的做法是创建 RenderTarget 时传入配置项buffer: true启用双缓冲这样连第二个 target 都不需要代码简化为const root new Mesh3d(...); layer.tick(() { // 我们可以不将root添加到renderTarget上这样就可以针对不同的renderTarget复用root layer.renderTarget(target, {root}); root.program.uniforms.tMap.value target.texture; target.swap(); layer.renderTarget(target, {root}); root.program.uniforms.tMap.value target.texture; target.swap(); layer.renderTarget(target, {root}); ... });target.swap()交换缓冲与目标渲染时写入「背面缓冲」swap后再读到的target.texture就是刚渲染完的那一帧天然规避了「一边读一边写同一块缓冲」的冲突。保留缓冲区内容layer.autoClear默认情况下每次执行layer.renderTarget都会清空之前缓冲区中的内容clearColor默认由beforerender事件控制。如果不希望清空可以把layer.autoClear设为false这样每次渲染会保留缓冲区中已有的内容新内容直接叠加其上layer.autoClear false; // 执行多次 renderTarget缓冲区内容不丢失 layer.renderTarget(target, {root}); ... layer.autoClear true; // 记得恢复Layer3d的autoClear属性默认true含义即「绘制前是否自动清除 layer 或 FrameBuffer」见 docs/zh-cn/api/ext3d/layer3d.md。在迭代式渲染中关闭它还能省去大量gl.clear调用提升性能。源码佐证流体模拟中的 RenderTarget 链式用法仓库内的 demos/3d/post/index.js对应文档 docs/zh-cn/ext3d/post.md是一个把 RenderTarget 用到极致的 GPGPU 流体模拟示例与本文主题高度相关可以作为进阶参考多个 RenderTarget 分工分别创建density染料密度、velocity速度场、pressure压强、divergence散度、curl旋度等模拟场尺寸和格式各不相同如RGBA16F、RG16F、R16F并通过supportRenderTextureFormat检测设备对渲染纹理格式的支持情况半浮点纹理在 WebGL2 下使用gl.HALF_FLOAT与浮点内部格式模拟场因此拥有比 8bit 更高的数值精度buffer swap 迭代velocity、density、pressure均配置buffer: true每完成一步模拟就swap()一次将上一步结果作为下一步输入splat、advection、divergence、pressure、gradient subtract 等多道 Pass 依次执行关闭自动清屏layer.autoClear false让模拟过程不再清除缓冲区每帧结束时再恢复为true全屏三角形复用所有模拟 Pass 共用一个由Geometry构造的全屏三角形网格配合sort: false, update: false提升渲染效率。这套写法正是「多个 RenderTarget 双缓冲 swap autoClear 控制」三种方案在生产级场景中的综合应用也印证了本文上述各节所述机制。小结与延伸阅读RenderTarget 让 SpriteJS 3D 扩展具备了完整的离屏渲染能力离屏绘制new RenderTarget(gl, attrs)创建 FrameBuffer元素照常append用layer.renderTarget(target)触发渲染结果回读target.texture作为 Program 的 texture 参与下一次渲染多次处理优先考虑buffer: trueswap()的双缓冲方案其次是两个 target 交换最后才用多 target 叠加内容保留layer.autoClear false控制渲染前是否清空缓冲区。如需进一步深入可在仓库中继续查阅RenderTarget 完整 API 参考构造参数、属性、方法全表Layer3d API 参考renderTarget、bindTarget、autoClear、setRenderOptions等3D 扩展总览与安装方式后期处理通道指南layer.post与 RenderTarget 的关系官方指出后期处理本质上就是通过多个 RenderTarget 实现可运行示例demos/3d/render_target/index.js 与 demos/3d/post/index.js赞分享图形学3D渲染【免费下载链接】spritejsA cross platform high-performance graphics system.项目地址https://gitcode.com/gh_mirrors/sp/spritejs点击查看免费下载相关推荐Node Editor Framework核心组件解析Node、Canvas、ConnectionPort深度剖析Node Editor Framework核心组件解析Node、Canvas、ConnectionPort深度剖析 Node Editor Framework如何快速上手 CrossPoint Reader从刷机到阅读的完整教程如何快速上手 CrossPoint Reader从刷机到阅读的完整教程 想要为你的 Xteink X3/X4 电纸书刷入开源固件 CrossPoint Rea如何使用WaybackProxy在5分钟内访问历史网页简单教程与配置指南如何使用WaybackProxy在5分钟内访问历史网页简单教程与配置指南 WaybackProxy是一款强大的HTTP代理工具能够通过互联网档案馆Wayba上一篇如何快速掌握Pyfa5个提升EVE Online舰船配置效率的终极技巧下一篇AutoActions 开源项目教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

用Cucumber让自动化测试成为团队通用语言:从BDD到工程落地

用Cucumber让自动化测试成为团队通用语言:从BDD到工程落地

你们有没有经历过这种尴尬:自动化测试代码写完了,用例也跑起来了,结果一到评审会,业务方盯着满屏的assertEquals和元素定位表达式,问了一句“这到底验证的是什么业务规则?”整个会议室瞬间安静。这不是我编…

2026/10/13 1:43:13 阅读更多 →
TaskingAI Record 删除指南:用 Python SDK 永久删除 Collection 中的记录及其 Chunks

TaskingAI Record 删除指南:用 Python SDK 永久删除 Collection 中的记录及其 Chunks

人工智能大模型AI AgentRAG后端前端 【免费下载链接】TaskingAI The open source platform for AI-native application development. 项目地址: https://gitcode.com/gh_mirrors/ta/TaskingAI 点击查看 免费下载 本指南围绕 TaskingAI 检索(Retrieval&a…

2026/10/13 1:43:13 阅读更多 →
多模型调度网关实战:成本、延迟、质量三透明架构设计与落地

多模型调度网关实战:成本、延迟、质量三透明架构设计与落地

1. 从单模型硬扛到多模型调度:我为什么要折腾这套网关去年下半年开始,我手上同时跑着好几个AI应用:一个面向内部知识库的问答助手、一个给运营团队用的文案生成工具、还有一个做结构化信息抽取的小服务。最开始图省事,所有请求都往…

2026/10/13 1:43:13 阅读更多 →

最新新闻

webpack-bundle-analyzer三视图详解:Stat、Parsed、Gzipped体积口径与优化实践

webpack-bundle-analyzer三视图详解:Stat、Parsed、Gzipped体积口径与优化实践

做前端构建优化时,webpack-bundle-analyzer 几乎是标配。打开这个插件的报告,第一眼看到的是右下角那块密密麻麻的矩形树图,再往右上角看,会发现可以切换 Stat、Parsed、Gzipped 三种视图。很多同学折腾半天也没弄明白这三者究竟差…

2026/10/13 2:24:29 阅读更多 →
es查询相关问题

es查询相关问题

如果没有kibana管理台页面工具,还可以用postman!!!_search不带条件查询curl --location --request GET http://ip:9200/xxx-gift_pack_record202409/_search \ --header Authorization: Basic ZWxhc3RpYzpIaWhvbm9yQG1hcmtldDFuZw…

2026/10/13 2:24:29 阅读更多 →
SpriteJS 渲染引擎选择、自动降级与内存控制(bufferSize)实践指南

SpriteJS 渲染引擎选择、自动降级与内存控制(bufferSize)实践指南

图形学3D渲染 【免费下载链接】spritejs A cross platform high-performance graphics system. 项目地址: https://gitcode.com/gh_mirrors/sp/spritejs 点击查看 免费下载 本文围绕 SpriteJS 的渲染引擎体系展开,讲解其多引擎架构下的默认选择策略、we…

2026/10/13 2:24:28 阅读更多 →
darktable 教程:免费开源 RAW 照片处理从安装到出片的完整指南

darktable 教程:免费开源 RAW 照片处理从安装到出片的完整指南

darktable 教程:免费开源 RAW 照片处理从安装到出片的完整指南 【免费下载链接】darktable darktable is an open source photography workflow application and raw developer 项目地址: https://gitcode.com/GitHub_Trending/da/darktable 给拍 RAW、又不想…

2026/10/13 2:24:28 阅读更多 →
深度解析 LLM Agent ReAct 架构:基于 Function Calling 的代码重构实践

深度解析 LLM Agent ReAct 架构:基于 Function Calling 的代码重构实践

1. 背景:为什么我们需要 Agent?痛点:传统编程中,简单的重复性工作(如加注释、改格式)浪费了开发者大量时间。思路:既然 LLM(大模型)懂代码,能不能让它自己读取…

2026/10/13 2:24:28 阅读更多 →
Pyre Code扩散模型专题:Noise Schedule、DDIM、Flow Matching与adaLN-Zero从零实现指南

Pyre Code扩散模型专题:Noise Schedule、DDIM、Flow Matching与adaLN-Zero从零实现指南

教育人工智能深度学习 【免费下载链接】pyre-code A self-hosted ML coding practice platform. 68 problems from ReLU to flow matching — attention, training, RLHF, diffusion, and more. Instant feedback in the browser. 项目地址: https://gitcode.com/gh…

2026/10/13 2:23:28 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 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/12 21:05:09 阅读更多 →
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/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练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/12 18:11:17 阅读更多 →