本章从“画颜色”到“发射射线”第一章的RenderPixel()只是根据像素坐标画 UV 渐变像素 (x, y) → 颜色第二章 把它变成了像素 (x, y) → 世界空间射线 Ray → 用射线方向当作颜色调试这一步是后续所有光线追踪章节的入口。只要你能从像素生成正确的射线后面就可以用这条射线去和球、圆盘、三角形等几何体求交最终计算光照。一句话总结摄像机负责把“屏幕上的一个像素”翻译成“世界空间中的一条射线”。运行效果1. 代码地图与运行结果1.1 新增与修改的文件文件状态职责Camera.h新增Camera类声明Initialize()、GetRay()、成员矩阵Camera.cpp新增构造视图/投影/视口/组合矩阵反投影生成射线Ray.h新增射线结构原点o、方向d、参数范围mint/maxtRenderer.h修改增加#include Camera.h和Camera mCameraRenderer.cpp修改构造时初始化相机RenderPixel()改为调用GetRay()Common.h修改增加#include glm/ext.hpp引入lookAtLH、perspectiveFovLH_ZO、inverse等1.2 本章没有变化的框架Renderer::Run()里的窗口创建、帧缓冲分配、多线程像素填充、mfb_update_ex()显示循环和第一章 基本一样。也就是说第一章 3D数学基础 解决“怎么把像素写到屏幕上”。第二章 摄像机与光线生成 解决“每个像素对应世界里的哪条射线”。第一章3D数学基础 里的多线程/缓冲区生命周期问题在本章仍然存在详见 第一章 3D 数学基础。本章把重点放在相机和射线生成上。1.3 运行结果运行 第二章 后画面不再是从左上到右下的 UV 渐变而是射线方向的可视化Ray raymCamera.GetRay(x,y);// 为什么要ray.d * 0.5f 0.5f// 因为 d 是单位向量范围是 [-1, 1]所有颜色值范围是 [0, 1]Color colorray.d*0.5f0.5f;画面中心射线方向接近(0, 0, 1)颜色约为(0.5, 0.5, 1)偏蓝。画面左右ray.d.x变化红色通道变化。画面上下ray.d.y变化绿色通道变化。画面边缘射线方向偏离中心颜色逐渐变化。这个画面不是最终渲染结果只是用来检查“相机射线是否算对了”的调试视图。2. 相机参数与坐标空间2.1 相机参数Renderer.cpp:13-21mCamera.Initialize(Vector3f(0,0,0),// 相机位置Vector3f(0,0,1),// 目标位置Vector3f(0.0f,1.0f,0.0f),// 上向量glm::radians(60.0f),// FOV0.1f,// 近裁剪面1000.0f,// 远裁剪面w,h// 视口宽高);参数含义本章取值p相机在世界空间中的位置(0, 0, 0)target相机看向的世界空间点(0, 0, 1)up相机的“上”方向用于确定画面朝向(0, 1, 0)fov垂直视场角单位弧度60°n近裁剪面距离0.1f远裁剪面距离1000W/H视口宽高1920 × 1080本章相机位于原点看向Z上方向是Y。因此相机的前方是Z。相机的右方是X。相机的上方是Y。这是一个左手系相机空间x向右、y向上、z向前。2.2 坐标空间的转换链渲染管线可以分成几个空间世界空间 World │ 视图矩阵 View ▼ 相机空间 Camera │ 投影矩阵 Projection ▼ 裁剪空间 Clip │ 透视除法 / w ▼ NDC标准化设备坐标 │ 视口矩阵 Viewport ▼ 屏幕空间 Screen本章的相机代码把后三步合并成一个矩阵M Viewport * Projection * ViewM把世界空间直接映射到屏幕空间。GetRay()则使用M的逆矩阵把屏幕空间反投影回世界空间。2.3 视锥体与 NDC透视相机的可视区域是一个视锥体frustum近裁剪面距离相机n。远裁剪面距离相机f。垂直张角fov。水平张角由fov和aspect W/H共同决定。投影之后可见区域被映射到 NDC约定x 范围y 范围z 范围OpenGL 风格NO[-1, 1][-1, 1][-1, 1]DirectX 风格ZO[-1, 1][-1, 1][0, 1]本章使用perspectiveFovLH_ZO所以近裁剪面 → NDC z 0 远裁剪面 → NDC z 1这就是GetRay()里p.z 0.0f的原因它选择的是近裁剪面上的点。3. 视图矩阵LookAtLH3.1 相机基向量给定相机位置eye、目标点center、上方向upf normalize(center - eye) // forward相机前方 s normalize(cross(up, f)) // side/right相机右方 u cross(f, s) // up相机上方注意叉积顺序lookAtLH使用s normalize(cross(up, f))。lookAtRH使用s normalize(cross(f, up))。叉积顺序不同得到的右方向相反最终画面会左右镜像。在左手系中相机看向Z所以f就是相机空间的Z轴。3.2 视图矩阵的数学形式glm::lookAtLH(eye, center, up)生成的矩阵用行×列写出来是V [ s.x s.y s.z -dot(s, eye) ] [ u.x u.y u.z -dot(u, eye) ] [ f.x f.y f.z -dot(f, eye) ] [ 0 0 0 1 ]它把世界点p变换到相机空间x_cam dot(s, p - eye) y_cam dot(u, p - eye) z_cam dot(f, p - eye)几何意义x_cam点相对于相机的左右位置。y_cam点相对于相机的上下位置。z_cam点沿相机前方到相机的距离。3.3 本章相机代入后的结果本章相机eye (0, 0, 0) center (0, 0, 1) up (0, 1, 0)计算f normalize((0,0,1) - (0,0,0)) (0, 0, 1) s normalize(cross((0,1,0), (0,0,1))) (1, 0, 0) u cross((0,0,1), (1,0,0)) (0, 1, 0)所以V 单位矩阵也就是说世界空间和相机空间在本章初始配置下是重合的相机在原点看向 Z上方向 Y。3.4 注释掉的手写版本Camera.cpp:9-21有一段被注释掉的代码//Vector3f l glm::normalize(target - p);//Vector3f r glm::normalize(glm::cross(up, l));//Vector3f u glm::cross(l, r);//Matrix4x4 viewMatrix glm::transpose(Matrix4x4(// r.x, r.y, r.z, 0.0f,// u.x, u.y, u.z, 0.0f,// l.x, l.y, l.z, 0.0f,// 0.0f, 0.0f, 0.0f, 1.0f//)) * MakeTranslation(-p);这段代码是在手写lookAtLH的等价过程l是前方forward对应lookAtLH的f。r normalize(cross(up, l))是右方对应lookAtLH的s。u cross(l, r)是上方对应lookAtLH的u。Matrix4x4(r, u, l, ...)按列放入r/u/l得到旋转矩阵R。transpose(R)把世界方向投影到相机基上。MakeTranslation(-p)把相机移到原点。顺序是transpose(R) * T(-p)表示先平移再旋转到相机空间。它与glm::lookAtLH(p, target, up)等价。实际代码使用 GLM 内置函数减少手写错误。注意这段手写代码也是LH 版本因为r cross(up, l)与lookAtLH的s cross(up, f)一致。不要把它误认为 RH 版本。3.5 为什么lookAtLH看向 Z在左手系中x 向右 y 向上 z 向前屏幕里面相机看向Z所以视图矩阵的第三行对应f。而在右手系中相机通常看向-Z视图矩阵的第三行会取-f。glm::lookAtLH和glm::lookAtRH的区别就在这里lookAtLH: s normalize(cross(up, f)), u cross(f, s), 第三行 f lookAtRH: s normalize(cross(f, up)), u cross(s, f), 第三行 -f3.6up与forward平行的边界情况如果up和f平行cross(up, f)为零向量归一化会得到NaN。例如eye (0, 0, 0) center (0, 1, 0) // 正上方 up (0, 1, 0) // 与 forward 平行此时lookAtLH无法确定“右方向”相机姿态退化。解决方法换一个不平行于forward的up。或在调用前检测并修正。后续实现相机控制器时通常会限制俯仰角避免正上方/正下方。4. 投影矩阵PerspectiveFovLH_ZO4.1 参数含义Camera.cpp:28Matrix4x4 projectionMatrixglm::perspectiveFovLH_ZO(fov,(float)W,(float)H,n,f);参数含义fov垂直视场角单位弧度W视口宽度像素H视口高度像素n近裁剪面距离f远裁剪面距离aspect W / H。注意perspectiveFovLH_ZO的第一个参数是垂直 FOV不是水平 FOV。如果你传入水平 FOV画面比例会不对。4.2 投影矩阵的推导设tanHalfFov tan(fov / 2) h 1 / tanHalfFov w h * H / W h / aspect投影矩阵数学行×列写法P [ w 0 0 0 ] [ 0 h 0 0 ] [ 0 0 f/(f-n) -f*n/(f-n) ] [ 0 0 1 0 ]GLM 的perspectiveFovLH_ZO内部实际写的是Result[0][0]w;Result[1][1]h;Result[2][2]zFar/(zFar-zNear);Result[2][3]1;Result[3][2]-(zFar*zNear)/(zFar-zNear);由于 GLM 是列主序Result[col][row]所以Result[2][3] 1对应数学矩阵第 3 行第 2 列即w z。Result[3][2] -f*n/(f-n)对应数学矩阵第 2 行第 3 列即z的常数项。4.3 近平面和远平面映射到哪里对相机空间中的点(x, y, z, 1)x_clip w * x y_clip h * y z_clip f/(f-n) * z - f*n/(f-n) w_clip z透视除法后x_ndc x_clip / w_clip y_ndc y_clip / w_clip z_ndc z_clip / w_clip代入近平面z nz_clip f/(f-n) * n - f*n/(f-n) 0 w_clip n z_ndc 0 / n 0代入远平面z fz_clip f/(f-n) * f - f*n/(f-n) f w_clip f z_ndc f / f 1所以近平面 → NDC z 0 远平面 → NDC z 1这就是_ZOZero-to-One的含义。4.4 与 OpenGL 约定的区别函数坐标系深度范围perspectiveFovLH_ZO左手系[0, 1]perspectiveFovLH_NO左手系[-1, 1]perspectiveFovRH_ZO右手系[0, 1]perspectiveFovRH_NO右手系[-1, 1]本章使用LH ZO更接近 DirectX 的约定。第一章 笔记里提到的 OpenGL 风格[-1, 1]对应NO。关键GetRay()里用z 0作为近平面是因为本章使用_ZO。如果换成_NO近平面应该是z -1。不过对于同一像素任意合法 z 反投影出的点都在同一条射线上方向相同取近平面主要是数值上更稳定、语义更清晰。4.5 深度精度透视投影的深度不是线性的靠近近平面时深度精度高。靠近远平面时深度精度低。如果近平面太小例如0.001远近比过大容易出现 z-fighting。本章用n0.1, f1000对光线追踪来说影响不大但在光栅化里需要注意。5. 视口矩阵Viewport5.1 作用投影之后得到 NDCx_ndc ∈ [-1, 1] y_ndc ∈ [-1, 1] z_ndc ∈ [0, 1]视口矩阵把 NDC 映射到屏幕像素坐标x_screen ∈ [0, W] y_screen ∈ [0, H]5.2 矩阵形式Camera.cpp:31-36Matrix4x4 viewportMatrixMatrix4x4(W/2.0f,0.0f,0.0f,0.0f,0.0f,-H/2.0f,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f,W/2.0f,H/2.0f,0.0f,1.0f);按列主序还原成数学矩阵Vp [ W/2 0 0 W/2 ] [ 0 -H/2 0 H/2 ] [ 0 0 1 0 ] [ 0 0 0 1 ]所以x_screen W/2 * x_ndc W/2 y_screen -H/2 * y_ndc H/2 z_screen z_ndc5.3 为什么 y 要取负NDC 的y轴向上y_ndc 1是画面上方。屏幕坐标的y轴向下y_screen 0是窗口顶部。所以要用-H/2翻转y_ndc 1 → y_screen 0 顶部 y_ndc -1 → y_screen H 底部如果忘记这个负号画面会上下颠倒。5.4 像素坐标的范围视口矩阵把 NDC 映射到[0, W] × [0, H]。但实际像素索引是x ∈ [0, W-1] y ∈ [0, H-1]像素中心在(x 0.5, y 0.5)本章GetRay(int x, int y)直接使用整数x, y相当于采样像素的左上角而不是像素中心。6. 组合矩阵与逆矩阵6.1 正向管线Camera.cpp:38Matrix4x4 combinedMatrixviewportMatrix*projectionMatrix*viewMatrix;对列向量p_screen Vp * P * V * p_world从右往左读世界空间 → View世界 → 相机 → Projection相机 → 裁剪 → 透视除法裁剪 → NDC → ViewportNDC → 屏幕注意透视除法不是矩阵乘法的一部分它发生在投影之后、视口之前。严格来说p_clip P * V * p_world p_ndc p_clip / p_clip.w p_screen Vp * p_ndc由于Vp是仿射矩阵且p_ndc.w 1可以写成p_screen Vp * P * V * p_world其中Vp * P * V是 4×4 矩阵但p_screen的最后一步仍然隐含了透视除法。6.2 逆矩阵Camera.cpp:39Matrix4x4 invCombinedMatrixglm::inverse(combinedMatrix);mInvCombinedMatrix把屏幕空间反投影回世界空间p_world_h M^{-1} * p_screen其中p_world_h是齐次坐标需要除以w才得到世界空间点p_world p_world_h / p_world_h.w6.3 为什么提前求逆每个像素都要生成一条射线。如果每个像素都重新构造视图/投影矩阵并求逆开销会很大。本章在Camera::Initialize()里只求一次逆矩阵GetRay()里只做一次矩阵-向量乘法每个像素4×4 矩阵 × 4D 向量 除法 减法 归一化这是光线追踪器里非常常见的优化。6.4mCombinedMatrix为什么存了却没用Camera.h:14声明了mCombinedMatrixCamera.cpp:41也保存了它但GetRay()只使用mInvCombinedMatrix。mCombinedMatrix可以用于把世界空间点投影到屏幕做调试。后续实现“鼠标拾取”或“投影包围盒”。验证正反变换是否一致。本章暂时没有用到属于预留成员。. GetRay从像素反投影出射线7.1 代码逐行Camera.cpp:45-56RayCamera::GetRay(intx,inty)const{Ray ray;ray.omPosition;Vector4fp(x,y,0.0f,1.0f);Vector4f worldPosmInvCombinedMatrix*p;worldPos/worldPos.w;// 齐次坐标除以w分量得到世界坐标ray.dglm::normalize(Vector3f(worldPos)-mPosition);returnray;}7.2 步骤拆解射线原点ray.omPosition;针孔相机的所有射线都从相机中心出发。后续做景深时才会从镜头上的不同点出发。构造屏幕空间齐次点Vector4fp(x,y,0.0f,1.0f);x, y像素坐标。z 0在_ZO约定下对应近裁剪面。w 1齐次坐标的点。反投影到世界空间Vector4f worldPosmInvCombinedMatrix*p;mInvCombinedMatrix把“屏幕空间点”变换到“世界空间齐次点”。齐次除法worldPos/worldPos.w;反投影结果不一定是w1除以w得到真正的三维世界坐标。求射线方向ray.dglm::normalize(Vector3f(worldPos)-mPosition);从相机位置指向近平面上的世界点归一化后就是射线方向。7.3 为什么可以用z 0在_ZO投影下z_ndc 0 → 近裁剪面 z_ndc 1 → 远裁剪面z 0选择近裁剪面上的点。对于同一个像素近平面上的点和远平面上的点在同一条射线上。因此normalize(worldPos_near - eye) normalize(worldPos_far - eye)取近平面主要是为了语义清晰明确是“穿过近平面的点”。数值稳定近平面离相机近坐标数量级更小。与_ZO约定一致。如果换成 OpenGL 的_NO投影近平面是z -1。但即使写成z 0反投影出的点仍然在同一条射线上方向通常也正确不过为了语义和稳健性应该使用对应约定的近平面 z。7.4 为什么方向要归一化Ray的后续使用者通常假设d是单位向量求交时t直接代表沿射线的距离。阴影射线、反射/折射方向计算更方便。颜色可视化时d的分量范围稳定在[-1, 1]。如果不归一化t的含义会随方向长度变化后续求交公式需要额外处理。7.5 手动射线公式对照理解除了“逆矩阵反投影”也可以直接根据相机参数构造射线。对于本章的 LH 相机看向 Zx_ndc 2 * (x 0.5) / W - 1 y_ndc 1 - 2 * (y 0.5) / H tanHalfFov tan(fov / 2) aspect W / H dir_camera normalize(Vector3f( x_ndc * tanHalfFov * aspect, y_ndc * tanHalfFov, 1.0f )) dir_world normalize(cameraToWorld * dir_camera)其中cameraToWorld inverse(viewMatrix)。两种方法的关系方法优点缺点逆矩阵反投影通用自动处理投影/视口与光栅化管线一致需要求逆理解上多一层手动构造射线直观容易看出 FOV/aspect 的作用不需要求逆只适用于特定相机模型容易漏掉像素中心/坐标系约定建议先用逆矩阵方法跑通再手动实现一遍做对比。两者结果应该一致除了半像素偏移。或者把GetRay()的参数改成float x, float y由调用者传入像素中心。半像素偏移不会让画面完全错误但会让射线方向整体偏移一点。后续做抗锯齿、超采样时像素中心会非常重要。8. Ray 结构Ray.h:4-11structRay{Vector3f o;Vector3f d;floatmint0.0f;floatmaxtFLT_MAX;};成员含义o射线原点origind射线方向direction通常归一化mint参数t的最小值maxt参数t的最大值射线方程p(t) o t * d t ∈ [mint, maxt]本章mint 0从相机位置开始。maxt FLT_MAX射线无限远。后续章节会用到阴影射线mint设为一个小的正数如1e-3避免与自身表面相交。阴影射线maxt设为到光源的距离避免检测光源后面的物体。反射/折射继续使用新的射线。FLT_MAX来自cfloat。Ray.h目前没有显式包含它依赖Common.h的传递包含。建议补上#include cfloat。9. 射线方向可视化Renderer.cpp:59-67ColorRenderer::RenderPixel(intx,inty){// 本节课重点GetRay()函数...Ray raymCamera.GetRay(x,y);// 把ray.d打印到屏幕上Color colorray.d*0.5f0.5f;returncolor;}9.1 为什么是d * 0.5 0.5ray.d是单位向量每个分量在[-1, 1]d.x ∈ [-1, 1] d.y ∈ [-1, 1] d.z ∈ [-1, 1]颜色通道需要[0, 1]所以color d * 0.5 0.5映射关系-1 → 0 0 → 0.5 1 → 19.2 预期画面本章相机看向 Z中心像素d ≈ (0, 0, 1)→color ≈ (0.5, 0.5, 1)偏蓝。向右d.x 0→ 红色增强。向左d.x 0→ 红色减弱。向上d.y 0→ 绿色增强。向下d.y 0→ 绿色减弱。所以画面应该是一个以蓝色为基调、红绿随方向变化的平滑渐变。9.3 这不是最终颜色本章只是把射线方向“可视化”color direction → RGB后续RenderPixel()会变成color GetRadiance(ray)也就是沿着射线去求交、计算光照、递归追踪。射线方向可视化只是调试手段。10. 公式速查10.1 相机基向量f normalize(target - eye) s normalize(cross(up, f)) u cross(f, s)10.2 视图矩阵V [ s.x s.y s.z -dot(s, eye) ] [ u.x u.y u.z -dot(u, eye) ] [ f.x f.y f.z -dot(f, eye) ] [ 0 0 0 1 ]10.3 投影矩阵h 1 / tan(fov / 2) w h * H / W P [ w 0 0 0 ] [ 0 h 0 0 ] [ 0 0 f/(f-n) -f*n/(f-n) ] [ 0 0 1 0 ]10.4 视口矩阵Vp [ W/2 0 0 W/2 ] [ 0 -H/2 0 H/2 ] [ 0 0 1 0 ] [ 0 0 0 1 ]10.5 组合与反投影M Vp * P * V p_world_h M^{-1} * (x, y, 0, 1) p_world p_world_h / p_world_h.w d normalize(p_world - eye)10.6 手动射线x_ndc 2 * (x 0.5) / W - 1 y_ndc 1 - 2 * (y 0.5) / H aspect W / H tanHalfFov tan(fov / 2) dir_camera normalize(( x_ndc * tanHalfFov * aspect, y_ndc * tanHalfFov, 1.0 )) dir_world normalize(cameraToWorld * dir_camera)10.7 射线方程p(t) o t * d t ∈ [mint, maxt]s normalize(up × f)u f × s相机看向 Z。投影h 1/tan(fov/2)w h * H/W_ZO近 0 远 1。视口x 从[-1,1]到[0,W]y 翻转后到[0,H]。组合Viewport * Projection * View列向量从右往左读。反投影invM * (x,y,0,1)除以w再减相机位置。
企业数字化 ERP 产品动态
相关推荐
MTP 猜字 vs Mobius 心算:书生S2家族的两条提速路线,谁更香? MTP 猜字 vs Mobius 心算:书生S2家族的两条提速路线,谁更香?
用过 AI 的人大概都体验过那种“急人”的感觉:问题敲进去,光标闪啊闪,屏幕上像挤牙膏一样一个字一个字往外蹦。写一段三百字的文案,… · 2026/11/3 2:40:26
第五次作业【C 输入 输出】 本节课【C 输入 & 输出】知识点总结基于菜鸟教程输入输出章节,期末笔试 上机考点一、核心基础
C 语言没有自带输入输出语句,输入输出功能来自 stdio.h 头文件,printf()(输出)、scanf()(输入࿰… · 2026/11/3 2:40:26
高性能序列化库选型与优化实战指南 1. 为什么我们需要高性能序列化库在分布式系统开发中,数据需要在不同节点间频繁传输。我曾参与过一个电商平台的微服务改造项目,当系统从单体架构拆分为20多个微服务后,服务间的通信开销突然成为性能瓶颈。通过火焰图分析,我们发现… · 2026/11/3 3:13:32
MySQL数据可视化实战:FineBI与SQL高效结合 1. 为什么数据可视化是MySQL学习的必经之路作为从业十年的数据分析师,我见过太多人把MySQL仅仅当作数据存储工具。直到某次给管理层汇报时,面对满屏的SQL查询结果,我才真正理解可视化的重要性——数据只有被看见,才能产生价值。Fi… · 2026/11/3 3:13:32
PSpice模型创建全链路:从参数修改、符号导入到宏模型与验收 简介:面向电路仿真初学者与需要自定义元器件模型的硬件工程师,这份文档围绕 PSpice 模型的建立与调用展开,重点解决软件自带模型库参数难以满足实际设计需求、新建元件缺少可用仿真模型这两类问题。内容先从模型参数修改入手,说明… · 2026/11/3 3:13:32
Pandas高效处理百万级数据的实战技巧 ## 1. 为什么百万级数据要从Excel说起刚入行数据分析时,我见过同事用Excel处理10万行数据时电脑卡死的尴尬场景。事实上,Excel在约100万行数据时就会达到性能瓶颈,而现代企业的订单表、用户行为日志动辄千万级记录。这就是为什么我们需要Pand… · 2026/11/3 3:13:32
编程语言演进:从机器码到自然语言编程 1. 编程范式的历史演进编程语言的发展历程可以看作是一部计算机抽象层级不断提升的历史。从最早的机器语言、汇编语言,到后来的Fortran、C等高级语言,再到现代的Python、JavaScript等脚本语言,每一代编程语言都在努力降低人与机器之间的沟通成… · 2026/11/3 3:13:32
零基础备考软考高级信息系统项目管理师:三科机考45分通关路线 简介:这份2025年软考高级信息系统项目管理师备考攻略面向计划参加机考的考生,围绕综合知识、案例分析、论文写作三科展开,系统梳理报名与考试时间、官方教材及辅导资料选择、历年真题用法和三阶段复习路径,并涉及项目管理五大过程… · 2026/11/3 3:12:32
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18