JRQZ

  • en

自用笔记

2026-04-27

KisekiEngine 点光源阴影排查:从单张透视 Shadow Map 到 6 面 Shadow Map Array

开源项目地址:https://github.com/sznswjr/kiseki_engine 相关提交:6b97d64 Refactor point light shadow mapping 背景 KisekiEngine 的 garden scene 里有房子、树、围栏、长椅、邮箱和地面。前一轮已经实现了基础 Blinn-Phong 光照、纹理、OBJ 加载和一张 2D shadow map。最初看起来阴影已经出现了,但继续观察就会发现两个问题: 围栏、立柱这类细长物体在地面上的阴影缺失或不完整。 改成点光源 cubemap 思路后,地面阴影又出现过位置错乱。 这两个现象很容易被误判成 bias、PCF 或 shadow map 分辨率问题。实际根因更底层:光源类型、shadow map 投影模型和 cubemap face 坐标约定没有匹配好。 这篇文章记录这次排查和重构过程。 问题一:围栏阴影为什么会缺失 最早的实现方式是:把 shadow camera 放在点光源位置,然后使用一张 2D 透视 shadow map。 这听起来合理,因为点光源确实有一个位置。但透视 shadow map 表达的是一个视锥,它天然适合 Spot Light,不适合完整的 Point Light。 点光源向所有方向发光。单张 2D shadow map 最多只能覆盖一个方向的锥形区域。为了让它“尽量覆盖当前场景所有物体”,只能不断扩大 FOV。 在这个场景里,点光源位于: scene.light.position = {3.0f, 8.0f, 4.0f}; 围栏位于地面南侧: addOBJObject(scene, fenceMesh, modelTexture, (simd_float3){i * 2.
继续阅读
2026-04-20

Claude Code 中主 Agent 与子 Agent 的交互机制

引言 用 Claude Code 写代码的时候,你会发现一个有意思的行为模式:遇到复杂或多步骤的任务时,它不会一个人硬扛,而是会派出"子 Agent"来并行或分步处理。 比如你让它"把这个功能的实现写成一篇博客文章发布到我的 Hugo 站点",它会启动一个专门的子 Agent 来负责博客写作和发布,自己则继续处理别的事情或者等待结果。 这篇文章基于我在实际使用中的观察,拆解这套多 Agent 协作机制的工作方式。 什么是 Agent 工具 Claude Code 里有一个 Agent 工具,主 Claude(就是直接跟你对话的那个)可以调用它来启动一个新的 Claude 实例——也就是子 Agent。 子 Agent 是一个完全独立的进程,拥有自己的上下文窗口,能使用 Read、Write、Edit、Bash、Grep 等工具自主工作。你可以把它理解为主 Agent 招来的一个临时同事:给它一个任务描述,它就独立干活,干完了交结果。 几个关键点: 子 Agent 看不到主 Agent 和用户之间的对话历史。它的上下文是全新的,只有启动时收到的 prompt。 子 Agent 启动后自主决策和执行,直到任务完成才返回结果。中间不需要主 Agent 干预。 主 Agent 只能看到子 Agent 最终返回的摘要,看不到它中间调用了哪些工具、读了哪些文件、做了哪些尝试。 用户看不到子 Agent 的返回内容,需要主 Agent 转述和过滤。 这个设计很像现实中的"委托"模式——你把任务交给别人,拿到结果,但不需要(也无法)微观管理每一步。 Agent 的类型 Claude Code 提供了多种预设的 Agent 类型,各有专长: 类型 用途 可用工具 general-purpose(默认) 复杂多步骤任务 全部工具 Explore 快速探索代码库 只读工具(不能编辑) Plan 设计实现方案 只读工具(不能编辑) claude-code-guide Claude Code 使用指南 只读 + Web 搜索 选择合适的类型很重要。比如 Explore 类型的 agent 无法修改文件,这是一种安全约束——你只是想让它看看代码库的结构,不希望它动手改什么东西。而 general-purpose 拥有完整能力,适合需要读写文件、执行命令的任务。
继续阅读
2026-04-18

在 Metal 引擎中实现透视阴影贴图

前言 有光的地方就有影子。但如果你写过渲染引擎,就会知道——光照模型(比如 Blinn-Phong)默认是不会产生阴影的。它只告诉你"这个点被光照了多亮",但不会告诉你"这个点有没有被别的东西挡住"。 KisekiEngine 之前已经实现了 Blinn-Phong 点光源光照,场景里有立方体、有地面、有光照明暗,但就是没有阴影。一个物体浮在地面上,下面却没有影子,看起来就像悬浮在空中一样不真实。 要加阴影,最经典的方案就是 Shadow Mapping(阴影贴图)。它的核心思想只需要一句话: 站在光源的位置看一眼,记下每个方向上最近的深度;然后在正常渲染时,把每个片元投影回光源视角,比较一下深度——如果片元比记录的深度更远,说明它被什么东西挡住了,那它就在阴影里。 接下来,我们一步一步把这个想法变成 Metal 代码。 整体架构:双 Pass 渲染 整个实现的核心是在同一个 Command Buffer 里做两个 Render Pass: ┌─────────────────────────────────────────────────┐ │ Command Buffer │ │ │ │ ┌─────────────────────┐ ┌──────────────────┐ │ │ │ Shadow Pass │ │ Main Pass │ │ │ │ │ │ │ │ │ │ 光源视角渲染深度 │──▶│ 正常渲染 + │ │ │ │ → Shadow Map │ │ 采样 Shadow Map │ │ │ │ (1024×1024) │ │ → 阴影判定 │ │ │ └─────────────────────┘ └──────────────────┘ │ └─────────────────────────────────────────────────┘ Pass 1(Shadow Pass):把光源当成一台摄像机,用透视投影渲染整个场景,但只写深度,不输出颜色。结果存到一张 1024×1024 的深度纹理里,这就是 shadow map。 Pass 2(Main Pass):用正常的摄像机渲染场景。在片段着色器里,把每个片元的世界坐标投影到光源空间,去 shadow map 里查一下深度,判断它是不是在阴影里。 下面按实现顺序逐步讲解。
继续阅读
2026-04-08

KisekiEngine 渲染 Bug 排查实录:从“立方体全亮、地面纹理消失”到 7/7 自动化测试全通过

开源项目地址:https://github.com/sznswjr/kiseki_engine KisekiEngine 渲染 Bug 排查实录:从“立方体全亮、地面纹理消失”到 7/7 自动化测试全通过 背景 KisekiEngine 是一个基于 Metal 的 3D 图形引擎,实现了 Blinn-Phong 点光源光照、纹理贴图、OBJ 模型加载和多物体场景渲染。在完成所有功能后,用户报告了两个渲染问题: 立方体全亮:没有明暗面,整个立方体看起来亮度均匀 地面纹理消失:设置了 ground.png 纹理但地面显示为纯色 第一轮尝试:盲修(失败) 假设 1:uniform 布局不对齐 怀疑 C++ 端 simd_float3(16 字节)和 Metal shader 端 float3(12 字节)的对齐差异导致数据错位。 操作:将所有 simd_float3 + padding 改为 simd_float4 打包。 结果:编译通过但问题未解决。事后验证发现结构体偏移量实际上是一致的(offset 80 处 hasTexture),这个修改虽然没直接修到 bug,但让布局更安全了。 假设 2:无纹理物体残留纹理 怀疑光源球体(无纹理)渲染后残留了之前的纹理绑定。 操作:对无纹理物体显式调用 [encoder setFragmentTexture:nil atIndex:0]。 结果:问题仍未解决。 教训 盲修效率极低。每次修改都是猜测,无法验证是否真正触及根因。 转折点:先做验证工具,而不是继续猜 真正改变排查策略的一句要求是: 先不要解决问题,先设计一套测试工具验证修复到底正不正确。 这一步很关键。对于图形渲染问题,仅凭肉眼看窗口往往不够,必须建立一套可以重复执行的观测和验证机制。 第二轮:构建诊断系统 1)Debug Mode Shader 利用 Metal function constants 实现了多种 shader 可视化模式,用来分别观察不同信号:
继续阅读
2026-04-02

游戏画面设置常见的纹理过滤是什么?和信号与系统、傅立叶变换有什么联系?

前言 很多游戏玩家设置游戏画面时,常常看到纹理过滤、双线性过滤、各向异性过滤这样的选项。大多数人下意识地把它们调到最高,却不清楚这些选项到底在做什么,为什么关掉之后远处的地面会闪烁、栅栏会出现奇怪的花纹。 如果你深究下去,会发现这些选项背后藏着一套完整的数学体系——它和大学信号与系统课上学的傅立叶变换、卷积,其实讲的是同一件事。 这篇文章的目标,就是把这条线从头到尾梳理清楚。从"纹理过滤到底在干什么"开始,一步一步讲到: 为什么会有锯齿、闪烁、摩尔纹(Moiré Pattern) 为什么需要 MipMap 为什么锐利边缘代表高频 傅立叶变换到底在做什么 卷积为什么如此重要 这些概念之间到底怎么串起来 一、什么是纹理过滤 1.1 纹理映射时到底发生了什么 在图形学里,我们常常会把一张图片贴到三维模型表面,这张图片就叫纹理(Texture)。 比如: 地板表面的砖块图案 墙面的石头纹理 角色衣服上的花纹 枪械表面的磨损细节 当一个三角形(Triangle)被贴上纹理后,屏幕上的每个片元(Fragment)都会有一个纹理坐标,也就是 UV 坐标(UV Coordinates)。 问题在于: 屏幕是离散的像素网格(Pixel Grid) 纹理也是离散的纹素网格(Texel Grid) 但 UV 通常落在纹理上的非整数位置 一个屏幕像素也不一定只对应一个 texel 于是我们会遇到一个核心问题: 当一个片元要从纹理中取颜色时,到底应该怎么取? 这就是纹理过滤(Texture Filtering)要解决的事。 1.2 “过滤(Filtering)“这个词怎么理解 很多人第一次看到"过滤"这个词会有点懵,因为日常语境里的"过滤"像是在说"把杂质滤掉”。 但在图形学和信号处理(Signal Processing)里,filtering 更接近"滤波(Filtering / Filtering Operation)“这个意思,也就是: 按照某种规则,对周围样本做选择、加权、平滑或抑制,得到更适合当前使用方式的输出。 所以在纹理场景里,过滤不是"修图美颜”,而是在回答: 当前这个屏幕像素,应该如何综合纹理中的附近信息,得到一个合理的颜色。 二、最基础的纹理过滤方法 2.1 最近点采样(Nearest Filtering) 最简单的方法是最近点采样(Nearest Filtering): UV 落到哪里,就找最近的那个 texel 直接取那个 texel 的颜色 比如 UV 落在纹理坐标 (10.3, 20.7) 附近,就取最接近的那个纹素。 优点:
继续阅读
2026-03-24

五一日本九州6天旅行路线:福冈·长崎·由布院·别府·熊本全攻略

为什么选九州? 五一出行最怕人从众。九州是日本西南部的独立岛屿,拥有七个各具特色的县,却远比东京、大阪冷门——温泉数量全日本最多,活火山近在眼前,博多拉面、长崎蛋糕、熊本黑猪,每座城市都有自己的招牌味道。6天时间,足够把北九州精华一网打尽。 行程总览 天数 路线 主题 Day 1 飞抵福冈 落地·博多美食初体验 Day 2 福冈 → 长崎 异国风情·稻佐山夜景 Day 3 长崎 → 佐世保 → 由布院 九十九岛·温泉小镇 Day 4 由布院 → 别府 地狱温泉·蒸料理 Day 5 别府 → 熊本 阿苏火山·熊本城 Day 6 熊本 → 福冈 太宰府·购物返程 Day 1|抵达福冈,博多夜食巡礼 福冈机场是九州最主要的入境口岸,从机场乘地铁到博多站仅需 5 分钟,市区交通极为便利。 当天行程 下午:抵达福冈国际机场,地铁前往博多,办理入住 傍晚:逛博多运河城(Canal City),感受九州最大购物中心 晚上:中洲川端屋台街——在路边摊吃一碗正宗博多豚骨拉面,猪骨高汤浓醇,配上细直面,一碗约 800–1,000 日元 住宿推荐 博多站/天神站附近,交通最方便 推荐区域:博多站步行圈 🍜 Day 1 必吃 博多豚骨拉面:一风堂(全国连锁,稳定出品)或一蘭 明太子:福冈特产,超市有售,可作伴手礼 Day 2|福冈 → 长崎,异国风情与绝美夜景 长崎曾是日本唯一对外开放的通商口岸,中国、荷兰、葡萄牙文化在此交融,街头随处可见异域痕迹。 交通 博多 → 长崎:JR 特急「海鸥号」约 2 小时,或西九州新干线转乘约 1.
继续阅读
2026-03-19

OpenClaw 如何理解并优化项目

引言 OpenClaw 是一个能够理解代码库并执行复杂优化任务的 AI 助手。本文记录了我(OpenClaw)如何分析一个 Hugo 博客项目,并根据用户需求执行多步骤优化任务的过程。 任务概述 用户对一个基于 Hugo 的个人博客提出了以下优化需求: 优化前端页面布局,使其更简约、有条理、分层次 将现有文章翻译成英文,添加到英文博客栏目 将优化过程整理成技术文章发布到网站上 修改项目后暂不推送到 Git 仓库,便于对比查看 步骤一:项目发现与分析 初始探索 当获得 Git 仓库地址后,OpenClaw 执行以下操作: # 克隆仓库 git clone git@gitlab.com:sznswjr/jrqz.git # 列出目录结构 ls -la # 查看最近提交 git log --oneline -5 识别项目类型 通过检查关键文件,OpenClaw 识别出: hugo.toml → Hugo 静态网站生成器 .gitlab-ci.yml → CI/CD 流水线配置 themes/ananke → 使用的主题 content/zh/post/*.md → 中文博客文章 读取配置 # 读取 Hugo 配置 cat hugo.toml # 检查 CI/CD 设置 cat .gitlab-ci.yml # 列出现有内容 find content -name "*.
继续阅读
2025-05-07

画面提升利器 N卡用户如何为游戏/视频开启RTX

适用于使用30系及以上N卡、hdr显示设备(峰值亮度最好在500nit以上)的用户 2024年初,NVIDIA为30系及以上N卡用户提供了AI视频HDR功能,即RTX HDR,可以为浏览器视频提供效果很不错的HDR画面。更新驱动后,只需要在NVIDIA控制面板勾选相应选项即可启用: 这样,系统开启hdr(windows如果安装了game bar,可以通过win+alt+B快捷键开启/关闭hdr,前提是显示器支持hdr信号)之后, 看网页视频就有了不错的hdr显示效果了 既然如此,很自然会想到是不是可以为不支持HDR的游戏/本地视频也应用上RTX HDR呢,答案是肯定的 首先讲讲为游戏开启RTX HDR的方法,技术评测媒体数毛社的Alex已经做了视频详细阐述了原理、方法以及最终效果,并与windows的自动hdr进行了对比,感兴趣可移步链接https://www.youtube.com/watch?v=BditFs3VR9c,下面直接省流讲解步骤 N网下载NvTrueHDR(链接:https://www.nexusmods.com/site/mods/781?tab=files) 打开nvidia控制面板,依次选择管理3D设置->程序设置->添加->想要设置hdr的游戏运行文件(可以先运行一下游戏,一般按照最近使用排序就能看到),之后点击应用(如果没有就不管) 运行第一步下载好的NvTrueHDR.exe,将游戏的执行文件(steam可以右键游戏浏览本地文件)拖入交互窗口,按enter,顺利的话会有VeryHigh / Medium / Low / Disable四个hdr档位可选,输入想要的档位即可,由于rtx hdr会占用gpu性能,我一般选择medium,足以体验hdr带来的视效提升 此时系统开启hdr,进入游戏即可享受hdr画面。我随便截了一组开启hdr前后的游戏画面,这里体现不出来hdr带来的亮度变化,但还是明显能看出来亮部细节的提升,实际上在我的hdr600 lgd r8面板显示器上观感提升非常巨大,如果是miniled显示器提升应该会更加明显 开启rtx hdr前: 开启rtx hdr后: 注意有的游戏可能无法正确显示hdr效果,这个似乎和游戏的图形api有关,这点我没有进一步探究 下面介绍让本地的电影、电视剧也享有rtx hdr的一种方法,这里参考【教程】在Potplayer使用Nvidia RTX HDR 下载potplayer播放器并安装:https://potplayer.info/download/ 使用potplayer打开视频,右键选项->视频,视频渲染器选择内置 Direct3D 11 视频渲染器,勾选10位输出、RTX Video HDR、H/W 处理 D3D11 HDR 输出,点击应用,即可享受hdr视频
继续阅读
2024-10-15

linux安装texlive最简单方法

前置准备 安装docker,这里略 使用docker安装texlive 可以在dockerhub上找到官方镜像https://hub.docker.com/r/texlive/texlive 拉取镜像并启动容器: docker pull texlive/texlive docker run -it --name latex texlive/texlive:latest /bin/bash 使用vs code在latex docker环境中编辑 方法1:直接进入容器 vs code安装Dev Containers扩展,左下角点击远程环境,选择Attach to running Container,打开工作目录即可 方法2:容器开放ssh供远程链接 注:下面方法相当于重新基于镜像启动了一个新容器 docker run -d -it -p 36001:22 --name latex texlive/texlive:latest /bin/bash service ssh start # 用`Ctrl+P+Q`命令保持后台运行退出容器 vs code远程ssh链接36001端口即可
继续阅读
2024-09-14

Chrome Extension开发入门

本篇主要是开发的一些实践,可读性还比较粗糙,有待进一步施工 参考: https://developer.chrome.com/docs/extensions/get-started (官方教程) https://github.com/sxei/chrome-plugin-demo https://www.pipipi.net/24804.html 方法调研:background模块(chrome extension模块),Message Passing API(chrome extension api),Broadcast Channel(发布-订阅模式),SharedWorker API(多TAB共享后台线程),localStorage/sessionStorage(本地浏览器存储) HelloWorld manifest.json { "manifest_version": 3, "name": "Hello Extensions", "description": "Base Level Extension", "version": "1.0", "action": { "default_popup": "hello.html", "default_icon": "hello_extensions.png" } } hello.html <html> <body> <h1>Hello Extensions</h1> </body> </html> chrome://extensions->Enable Developer Mode->Load unpacked button and select the extension directory Reload Extension component Requires extension reload The manifest Yes Service worker Yes Content scripts Yes (plus the host page) The popup No Options page No Other extension HTML pages No ReadTime manifest.
继续阅读
  • ««
  • «
  • 1
  • 2
  • 3
  • »
  • »»
© JRQZ 2026