惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Hackread – Cybersecurity News, Data Breaches, AI and More
W
WeLiveSecurity
C
Check Point Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Vulnerabilities – Threatpost
GbyAI
GbyAI
A
Arctic Wolf
NISL@THU
NISL@THU
N
Netflix TechBlog - Medium
The Register - Security
The Register - Security
M
MIT News - Artificial intelligence
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Microsoft Security Blog
Microsoft Security Blog
Cyberwarzone
Cyberwarzone
C
CERT Recently Published Vulnerability Notes
T
Tenable Blog
G
GRAHAM CLULEY
O
OpenAI News
S
Schneier on Security
Google Online Security Blog
Google Online Security Blog
Vercel News
Vercel News
宝玉的分享
宝玉的分享
Attack and Defense Labs
Attack and Defense Labs
T
The Blog of Author Tim Ferriss
量子位
aimingoo的专栏
aimingoo的专栏
The Cloudflare Blog
P
Privacy & Cybersecurity Law Blog
S
SegmentFault 最新的问题
MongoDB | Blog
MongoDB | Blog
Apple Machine Learning Research
Apple Machine Learning Research
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
LINUX DO - 热门话题
博客园_首页
F
Full Disclosure
Recent Commits to openclaw:main
Recent Commits to openclaw:main
D
Docker
U
Unit 42
A
About on SuperTechFans
博客园 - 司徒正美
Hacker News - Newest:
Hacker News - Newest: "LLM"
人人都是产品经理
人人都是产品经理
Application and Cybersecurity Blog
Application and Cybersecurity Blog
G
Google Developers Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
J
Java Code Geeks
云风的 BLOG
云风的 BLOG
Scott Helme
Scott Helme
TaoSecurity Blog
TaoSecurity Blog

机核

游戏性能旗舰最强之选,一加 Ace 6 至尊版国补到手价2999元起 6元钱自己更换电动车刹车线 《生化危机9:安魂曲》编剧Haris Orkin专访 摸金游戏?音乐游戏!暗区新赛季这把能弹的琴有何来历? 好评国产武侠SRPG《息风谷战略》免费DLC现已推出 | 机核 GCORES 碎片 《生化危机:安魂曲》将于5月实装首个免费更新内容 | 机核 GCORES 新锐东方游戏,谱写世界新章! 沉浸式恋爱视觉小说游戏《心象演算》免费试玩版现已正式上线 | 机核 GCORES 互动影游《代号三国:龙起》上线!穿越三国与曹操并肩、与佳人同行、与权谋博弈! 《老头收集梦想生活》,游戏酒桌会6,录音笔VOL.689 | 机核 GCORES 破界·共生——《白日梦:无限世界》五大核心游戏特点解析 价格已到史低,锐龙5 9600X/锐龙7 9700X正适合抄底 时间循环之旅即刻启程!《归环》一周目测试今日开启 热门在线韩游变魂游,洛奇衍生作能否打破“花瓶”魔咒? LG UltraGear evo 全新高端显示器系列:当“5K”遇见“AI”,不止强大,更懂热爱 反套路三国互动影游《代号三国:龙起》今日上线! 愿望单登记人数突破10万!备受瞩目的“女儿养成游戏” 《梦幻魔法公主》今日于Steam平台上线!限时八折优惠中 《黑神话:悟空》全球音乐会2026巡演将于4月29日12时开票 | 机核 GCORES “Snowguelike”生存肉鸽挖矿新作《蛙穿雪境》公布发售日期,5月7日正式上线 | 机核 GCORES 重塑移动办公、AI创作新境!全新华硕灵耀Air系列、ProArt 骁龙版震撼首发,创芯未来 均分88:《Saros》媒体评分汇总 | 机核 GCORES 上海烛龙公布合作遗迹探险游戏《吉时已到》首支预告片 | 机核 GCORES 首个独立游戏《萝薇日记》已上线Steam! 烛龙新IP《吉时已到》首曝,打造国内首款中式合作遗迹探险游戏 喜加一:《暗黑破坏神Ⅳ》国服现已开启限时免费领取本体活动 | 机核 GCORES 新版《生化危机》电影定于9月18日上映,官方网站现已上线 | 机核 GCORES 《冲就完事模拟器2》“星球大战”联动DLC正式宣布 | 机核 GCORES SteamController将于5月4日发售,售价99美元 | 机核 GCORES 事已至此,内存这么用也算省钱了,“2+1”非对称双通道应用实测 505游戏母公司现已收购《明末:渊虚之羽》IP | 机核 GCORES 基石 手动杂谈12|格斗游戏也能讲好故事 | 机核 GCORES I Love You Mr Snowball 我的向日葵小姐 会比GTA6先发售吗?最硬核的生存游戏《DAYZ》要推新DLC了 周记02:在2026遇到新怪谈 什么硬件,能让游戏Loading界面快速消失? | 机核 GCORES GadioSpec《百年风云世界杯》免费试听集 | 机核 GCORES 百年风云世界杯Vol.1丨足球崛起 | 机核 GCORES 100年前,一群人提前替我们经历了AI恐惧 | 机核 GCORES 《呼啸山庄》2026 ——一辆当代艺术的大卡车冲撞了我的大脑 手游《天穗之咲稻姬:日之香巡灵传》宣布将于7月27日停服 | 机核 GCORES 集结梦之队,征战世界杯,《最佳球会ONLINE》上线Steam 山水绝景随心拼 休闲建造游戏《千里山河录》Steam商店页公开 巫师帽、法袍、魔杖,为什么它们是影视、游戏里的法师必备三件套? 《无鞘信使》-第一章 复古风自动战斗肉鸽《终结之终结》Steam商店页面现已上线 电脑里有一款不破不立的MMO,录音笔VOL.688 | 机核 GCORES 《生化危机》30周年纪念周边发售,这次是真的“保护伞” 可靠耐用+AI全能,惠普战66 2025锐龙版深度体验 《时之书:无尽终章》关卡“大航海时代”全球首次公开 经典名作《乌龙派出所》改编经营模拟游戏《乌龙派出所~阿两的商店街物语~》正式宣布支持简体中文 明日开冲,解锁反套路三国互动影游《代号三国:龙起》即将上线 独立游戏《这是我的宝藏!》已发售~ 降低难度不是唯一解,无压力死亡也是好体验 Netflix官宣新片《普通人》:讲述韩国现代史上的权力风暴 《生化危机:安魂曲》全球销量现已突破700万份 《绝地鸭卫》PC版5月15日正式发售 亡妻回忆录?女性向情感叙事游戏《S-mail》现已正式发售 全新酷黑风格,酷睿Ultra 200S PLUS的高性价比搭档!七彩虹BATTLE-AX B860M-PLUS S WIFI7 V20 超级黑刃主板测评 胖狗 索尼发布了港台地区PS5产品价格调整公告,将于5月1日起实施 二次元怪猎+性感美女!《碧蓝幻想:无尽黄昏》开启Beta公测 这款怪谈类型中式恐怖游戏居然更新了?! 《百日战纪 -最终防卫学园-》改编漫画将于今年冬季开启连载 《如被附身,请致电我们》:匈牙利黑色幽默恐怖小说 《竹屿山房杂部卷五》(译文) 大树 超越引擎 摄影分享丨四月 碎片杂记vol.72 当老式FPS与老式动画技术碰撞出新时代的火花—《神探杰克鼠》 想做独游,如何避免首个项目就褒姒? 在线多人动作游戏《OCTOPinbs》将于5月12日上线Steam! 《酒鬼女神的酒诡》确定将于2026年登陆Steam 《CRYMELIGHT》将于11月5日(周四)正式发售!4月25日开始预购! 钢铁国度MKI部落Evolution,蛮兵部分 【钢铁国度】部落-Primal MK I,蛮兵部分 这是一个高中生用ai跑出来的作品,我自称他为物理神话 钢铁国度MKI部落Metamorphosis,蛮兵部分上 钢铁国度MKI部落Metamorphosis,蛮兵部分下 INDIE Live Expo于4月25日举办:首发9款新作,超200款独立游戏亮相 暗黑卡牌策略新作《魔忌:穷鼠啮狸》发布全新中文试玩版和发售预告片,4月30日正式上线在即 战锤40K长篇小说:变节者・苦难主宰(三)(全书完) 战锤40K长篇小说:变节者・苦难主宰(二) 战锤40K长篇小说:变节者・苦难主宰(一) 英语语言学习丨短语专题1:短语的特点 唯一的EVE战争 【少前同人】【M200】战术人形会梦见音乐会吗 【昏迷3】即将发售,前作主角悉数到场!“恶灵”宋老师化身可操控角色 业内人士:游戏公司“十有八九”使用生成式AI,包括卡普空 欢庆一周年:《光与影:33号远征队》全新纪念艺术图、超值折扣与免费更新同步上线 才刚刚开始呢 【抽奖】《星际卡车司机》推出免费大型更新,四折平史低折扣进行中 四人合作FPS游戏《佣兵猎手》抢先体验重大更新 1 现已上线 Raw Fury新作《深馅地牢 Deep Dish Dungeon》将于今秋加入 XGP 塔防幸存者游戏《魔怪来袭》推出首个 DLC 《饿狼传说:群狼之城》1周年纪念!新DLC“沃尔夫冈·克劳萨”今日参战 猫狗相伴 欢乐闯关 双人合作平台跳跃游戏《猫狗同行》上线Steam商店页 《同行:月球逃脱》(Together: Moon Escape)上线将于明日上线Steam
实现类《笼中窥梦》效果的三种方法
温吞吞吞吞 · 2026-02-06 · via 机核

俗话说条条大路通罗马,效果的实现也不一定有唯一的答案,今天就来分享下我想到的几种《笼中窥梦》游戏中 portal 效果的实现方法,并附带我在 Godot 引擎中的实现。

1 / 2

《笼中窥梦》(Moncage)是一款由两人工作室 Optillusion 开发、高度纯粹的视错觉解谜游戏。它在 Steam 平台 上获得了“特别好评”,并因其独特的创意被视为《画中世界》(Gorogoa)后的又一艺术精品。 右图为笔者模仿的 portal 效果。

方法一:非对称视锥体投影

原理

在标准的透视投影中,摄像机就像人的眼睛,正对着屏幕中心,其视锥体(由六个平面包围的可见区域)是对称的。

非对称就是让摄像机不再位于视锥体的中心轴线上(右一),在这种投影中,依然是位于近远平面间的物体被投影在近平面上,只是近平面不在摄影机朝向的中心处。为什么这种方式可以实现效果呢?其实使用这种方式“恰好”从光路上模拟了这个效果在现实世界中的样子。 想象你站在一栋房子前,房子有一扇窗户,那么你透过窗子能看到哪些东西呢?

没错!相信你也发现了,你能看到的部分就相当于以窗户为近平面,房子的对侧为远平面,摄像机垂直于窗户所在的墙壁,把房子内的物体投影在窗户上。有很多街头视错觉艺术也是类似的原理,只要你看到的角度和投影的角度重合,看起来就像是真存在一个物体。

而在我们主相机的运动中,实时计算“窗户”投影的的摄像机的位置,将绘制出的窗内画面贴在对应的 quad 或者 Box 上,就可以得到逼真的 portal 效果。

投影公式

非对称视锥体投影依然是将一个平截头体转换到标准设备坐标系(NDC),只不过是任意形状的平截头体(Frustum)。设定视锥体在近裁剪面(z=−n)处的六个边界参数:

  • l,r: 近平面在 x 轴的左、右边界;

  • b,t: 近平面在 y 轴的下、上边界;

  • n,f: 相机到近、远平面的距离。

关于为什么齐次坐标映射要除以 -z,涉及到使用四维的线性变换来模拟透视除法的问题;为什么只能由常数和 z 组成分子,也涉及到 z 分量运算时不应该由 x、y 影响 z 计算的问题;与本文无关,有机会再讲 orz

根据变换后的向量,一顿运算,最后可以得到投影矩阵P为:

该矩阵与普通透视矩阵唯一的区别在于第三列的前两个分量。当 r=−l 且 t=−b 时(对称情况),第三列前两项变为 0,矩阵退化为普通的透视矩阵。(累死我了……终于敲完了这一大堆……机核编辑器不支持公式,只能贴图了)

Godot实现示例

在 Godot 中,其实没这么麻烦,已经有这种相机了,可以通过设置 projectionPROJECTION_FRUSTUM 并控制 frustum_offset 来实现。

# 计算相机到 Quad 平面的距离 (Z 轴) var d = abs(local_eye.z) if d < 0.01: d = 0.01 # 防止除以 0 ​ # 设置相机的近平面为到平面的距离 near = d # 设置远平面为深度 10 (相对于近平面) far = d + 10.0 # 计算非对称平截头体的边界 # 因为 near = d,所以 scale = 1 var scale = 1.0 var left = (-width / 2.0 - local_eye.x) * scale var right = (width / 2.0 - local_eye.x) * scale var bottom = (-height / 2.0 - local_eye.y) * scale var top = (height / 2.0 - local_eye.y) * scale # 应用到相机属性 projection = PROJECTION_FRUSTUM frustum_offset = Vector2((left + right) / 2.0, (top + bottom) / 2.0) size = top - bottom ​ # 将相机的旋转设置为与 Quad 一致,这样相机的视平面就与 Quad 平行 global_transform.basis = quad_tf.basis

shader就特别简单了,直接贴就行,另外别忘了这个相机的世界位置和普通相机要保持一致,这样投影才能和主相机这双“眼睛”对齐。

不过这种做法也有缺陷,贴在 quad 表面的分辨率是由单独的 Viewport 控制的,如下图所示,当 SubViewport 分辨率不高时,Quad 表面的贴图会比较模糊。不过这也不全是坏处,远处的物体可以采用分辨率较低的 RenderTexture, 不必和方法二一样多出一个屏幕分辨率的 Texture,降低 GPU 和内存压力。

而且这张图可以很方便地被传递给一些 2D 渲染管线,例如和网页内容融合,实现类似 Apple Vision Pro 中把 3D 物体内嵌的效果,同时可以支持网页内容和 3D canvas 的合成(CSS filter 等效果)

方法二:投影纹理映射

原理

这种方法的核心思想非常直观:想象我们在“里世界”放置了一个投影仪(也就是摄像机),它把拍摄到的画面投射到了“表世界”的窗口上。

我们在渲染窗口的每一个像素时,都去反问一下里世界的摄像机:“在你的视角里,这个位置对应的是哪个点?”然后直接把那个点的颜色拿过来涂上。

这就不需要窗口是什么规则形状,也不需要摄像机有什么特殊的变形,只要我们能把表世界的坐标转换到里世界摄像机的屏幕坐标系下,一切就搞定了。这被称为“投影纹理映射”。

关键在于如何正确地采样这张纹理。我们不能使用几何体自带的 UV,而是需要根据当前像素在“里世界”摄像机视角下的屏幕坐标(Screen Space / NDC)来计算 UV。

相关公式

Shader 伪代码:

uniform mat4 target_view_proj; // 里世界相机的 VP 矩阵 ​ void vertex() { // 计算 Clip Space 坐标 v_clip_pos = target_view_proj * world_pos; } ​ void fragment() { // 透视除法 vec3 ndc = v_clip_pos.xyz / v_clip_pos.w; // 检查是否在视野内 if (v_clip_pos.w < 0 || abs(ndc.x) > 1 || abs(ndc.y) > 1) { return float4(0, 0, 0, 1); // 裁剪掉视野外部分 } // 采样 vec2 uv = ndc.xy * 0.5 + 0.5; color = texture(input_texture, uv); }

Godot 实现示例

计算并传递 view_proj 矩阵。

# 获取相机的 View Matrix (World -> Camera) var cam_transform := target_camera.global_transform.inverse() var cam_view_proj := Projection(cam_transform) # 获取相机的 Projection Matrix var cam_projection := target_camera.get_camera_projection() # 组合 View-Projection Matrix var view_proj := cam_projection * cam_view_proj # 传递给 Shader # Projection 类型可以直接作为 mat4 传递给 shader parameter mat.set_shader_parameter("target_view_proj", view_proj)

在 Shader 中执行投影计算(和上面的伪代码基本一样,就是多一些 Godot 坐标的细节)。

1 / 2

这种方法非常直观好懂,而且可以适用于各种形状的物体,不一定是 Quad,这点就比方法一灵活得多,同时可以保证输出的清晰度 一定和主窗口分辨率一致。只是性能上确实差一些,因为要独立渲染一遍整个场景。

这种方法当然也可以实现 3D 物体内嵌的效果,只是把里世界的屏幕纹理做透视矫正再贴回到网页中是比较费力的事情,2D 渲染引擎不一定可以支持这种矫正,如果支持(比如skia)或者自己实现也能做到,就是相比第一种方法没那么直观了。

// skia 中的透视矫正 void draw(SkCanvas* canvas, sk_sp<SkImage> image) { // quad 四角在纹理中的坐标,需要预先使用 MVP 矩阵计算投影后的 NDC,再乘纹理宽高得到 SkPoint srcPoints[] = {{383, 824}, {1184, 1006}, {1179, 1588}, {402, 1857}}; // 还原的矩形 float targetW = 400.0f; float targetH = 300.0f; SkPoint dstPoints[] = {{0, 0},{targetW, 0},{targetW, targetH},{0, targetH}}; // 计算变换矩阵这个矩阵会把 srcPoints 围成的区域“拉伸且矫正”到 dstPoints SkMatrix matrix; if (!matrix.setPolyToPoly(srcPoints, dstPoints, 4)) { return; } // 应用矫正矩阵 canvas->concat(matrix); // 绘制并矫正纹理 canvas->drawImage(image, 0, 0, nullptr, nullptr); }

方法三:模版缓冲 (Stencil Buffer)

原理

这种方法也是《笼中窥梦》制作组选择的实现方式。如果说前两种方式是在平面上画出另一个世界,那么模版缓冲就像是在空间中挖了一个洞。

它的原理利用了 GPU 的模版测试(Stencil Test)功能。想象你有一张带孔的遮罩纸(模版),你先把这张纸盖在屏幕上,把窗口的位置挖空(写入模版值)。然后,当你绘制里世界的物体时,GPU 会只允许画在挖空的地方。

这样,里世界的物体就真的“嵌”在了表世界的窗口里,而且因为是直接渲染几何体而不是纹理,清晰度极高,还没有 RenderTexture 的分辨率限制。这种方式的优点是性能极高(没有 Render Texture 的开销),且天然支持递归(镜中镜)。

实现

伪代码

// Pass 1: 绘制窗口蒙版(挖洞) Stencil { Ref 1 // 设置模版值为 1 Comp Always // 总是通过测试 Pass Replace // 写入模版值 } Draw(WindowMesh); ​ // Pass 2: 绘制里世界(填洞) Stencil { Ref 1 Comp Equal // 只有模版值为 1 的地方才绘制 } Clear(DepthBuffer); // 清空深度,防止被表世界遮挡 Draw(InnerWorldObjects);

这种暂时就没办法在 Godot 中实现了,我用的是 Godot 4.4,Godot Shader 和材质系统没有暴露完整的 Stencil Op,在 Unity 中倒是很好实现,也有大把教程。

这种方法是直接把内容绘制到同一个目标上,就没办法做 2D 相关的处理了,不过对于传统的传送门类型游戏,这是一种非常好用且非常常见的实现方法(也是教程最多的hhh)。

后记

当然笼中窥梦这个游戏中还有很多有趣效果的细节,比如如何判断两个场景物体的吻合、怎么在资产制作的过程中保证近大远小的物体可以顺利接在一起、对接后生成的物体如何顺利自然地呈现出动画。

本文只是对 portal 这类效果的一个小实践,让游戏真正好玩的永远是游戏设计师们在某个小巧思后脚踏实地衍生出的繁华世界,也再次推荐《笼中窥梦》这部优秀的国产独立游戏,感受视错觉与解密的独特魅力~

《笼中窥梦》制作人 monokura 对游戏设计思路的介绍 https://www.zhihu.com/question/499287700/answer/2230626908