相比fetch Api, axios 提供了更简洁、更直观的 API,使得发送 HTTP 请求和处理响应更加方便; 自动处理json对象(fetch 可以调用await response.json())1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17axios.post('/api/submit', this.editForm)
.then(response => {
console.log('Form submitted successfully:', response.data);
})
.catch(error => {
console.error('Error submitting form:', error);
});
axios.request({
url: '/api/submit',
method: 'post',
data: this.editForm
}).then(response => {
console.log('Form submitted successfully:', response.data);
}).catch(error => {
console.error('Error submitting form:', error);
});
instance1
2
3
4
5
6
7const instance = axios.create({ baseURL: '/api' });
// Works just like axios(config)
instance({
url: '/users',
method: 'get'
});
拦截器1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
},
{ synchronous: true, runWhen: () => /* This function returns true */}
);
// Add a response interceptor
axios.interceptors.response.use(function onFulfilled(response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
}, function onRejected(error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
Python —— FastAPI
FastAPI与Express.js的区别
| 特性 | FastAPI | Express.js |
|---|---|---|
| 开发语言 | Python | JavaScript/TypeScript |
| 性能 | 基于Starlette和Pydantic,异步处理性能优异 | 基于Node.js事件循环,适合I/O密集型操作 |
| 类型提示 | 原生支持Python类型注解,自动生成API文档 | 需要TypeScript才能获得类型提示 |
| API设计 | 声明式路由,依赖注入系统 | 命令式路由,中间件链 |
| 自动文档 | 自动生成Swagger和ReDoc文档 | 需要第三方库如Swagger UI |
| 数据验证 | Pydantic自动数据验证 | 需要手动验证或使用第三方库 |
| 生态系统 | Python生态(NumPy, Pandas, OpenCV等) | npm生态系统 |
| 学习曲线 | 相对平缓,Python开发者容易上手 | 前端开发者熟悉,学习曲线适中 |
库和项目
1 | pip install "fastapi[standard]" "uvicorn[standard]" |
uvicorn是应用服务器 相当于tomcat
类似express.js 可以写一个main.py 然后执行。 fastapi没有初始化项目的命令行工具 可以考虑官方项目模板: Full Stack FastAPI Template
1 |
1 | my_fastapi_project/ |
WPF Prism
安装依赖1
2
3
4<ItemGroup>
<PackageReference Include="HandyControl" Version="3.5.1" />
<PackageReference Include="Prism.Unity" Version="8.1.97" />
</ItemGroup>
app.xmal中Wpf:Application替换成prism:PrismApplication1
2
3
4
5
6
7
8
9<prism:PrismApplication
x:Class="WpfApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
xmlns:prism="http://prismlibrary.com/">
<Application.Resources>
</Application.Resources>
</prism:PrismApplication>
标记中删除了StartupUri=”MainWindow.xaml”(否则生成两个实例)
cs代码实现两个抽象方法RegisterTypes和CreateShell1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32// 创建程序主窗口
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry container)
{
// 注册导航页面和ViewModel
container.RegisterForNavigation<MainWindow, MainWindowViewModel>();
// 注册单例服务
container.RegisterSingleton<IMyService, MyService>();
// 配置文件基础路径
string programData = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
programData = Path.Combine(programData, "xxxx");
// 从注册表读取配置路径
using (var key = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\xxxx"))
{
if (key != null && key.GetValue("SolutionPath") != null)
{
programData = key.GetValue("SolutionPath").ToString();
}
}
// 初始化全局缓存
GlobalCache.Instance.FileBasePath = programData;
GlobalCache.Instance.InitPaths();
}
three.js中的材质
1. MeshStandardMaterial
- 用途:基于物理渲染(PBR),适用于追求真实感的场景,支持金属度、粗糙度、环境光遮蔽(AO)、法线贴图等。
- 优势:高度逼真,支持复杂光照模型,适合高质量渲染。
- 缺点:计算开销较大,不适合性能敏感的场景。
2. MeshLambertMaterial
- 用途:基于 Lambert 反射模型,是一种简化的漫反射材质,不考虑高光或复杂反射。
- 优势:计算简单,性能好,适合非金属、低光要求的物体。
- 缺点:缺乏真实感,不支持法线贴图、金属度等高级特性。
3. MeshPhongMaterial
- 用途:基于 Phong 反射模型,支持高光反射,可以模拟塑料、漆面等材质。
- 优势:比 Lambert 更真实,支持高光和法线贴图。
- 缺点:不是基于物理的渲染,效果不如 PBR 自然。
4. MeshDepthMaterial
- 用途:不显示颜色,只渲染深度信息(相机到物体的距离) QQs按:接近近投影面(camera.near)变明亮反之变暗 适合做雾效 寂静岭阴森视距。
- 优势:常用于后期处理、阴影生成、深度图分析等。
- 缺点:不适用于常规物体渲染。
5. MeshNormalMaterial
- 用途:显示法线方向,用于调试或特殊视觉效果。
- 优势:便于检查模型的法线是否正确。
- 缺点:无法用于真实渲染。
性能与适用场景的权衡
性能优化:在移动端或低性能设备上,使用
MeshLambertMaterial或MeshBasicMaterial可以显著提高渲染性能,而MeshStandardMaterial由于其复杂的光照计算,可能会造成帧率下降。特殊效果:例如,
MeshDepthMaterial可用于实现深度边缘检测、雾效或自定义的后期处理效果,这些是MeshStandardMaterial无法直接实现的。- 艺术风格:某些风格化渲染(如卡通渲染)更适合使用
MeshToonMaterial,而不是 PBR 材质。
三、兼容性与历史原因
- Three.js 作为一个成熟的 3D 渲染库,需要兼容多种渲染管线和设备。一些材质(如
MeshLambertMaterial和MeshPhongMaterial)在早期版本中就已经存在,它们为不支持 PBR 的设备或项目提供了替代方案。 - 在 WebGL 1.0 环境下,某些高级特性(如 PBR)可能不被完全支持,此时需要使用更简单的材质。
四、实际开发中的选择建议
| 材质类型 | 适用场景 | 是否支持贴图 | 性能 |
|---|---|---|---|
| MeshStandardMaterial | 高质量渲染、PBR 场景 | 支持所有贴图 | 较低 |
| MeshLambertMaterial | 简单漫反射、低性能设备 | 仅支持漫反射贴图 | 较高 |
| MeshPhongMaterial | 高光材质、塑料效果 | 支持高光、法线贴图 | 中等 |
| MeshDepthMaterial | 深度分析、后期处理 | 不支持颜色贴图 | 高 |
| MeshNormalMaterial | 法线调试、特殊效果 | 不支持颜色贴图 | 高 |
roughMap vs displacementMap
前者是PBR即作用于光线反射 后者是作用于顶点位移
React-Three-Fiber
@React-three/fiber
开箱即用(out of box) 组件化场景对象如
\
1 | npm i three @react-three/fiber |
额外的,transpile in Next.js, set in next.config.js:
1 | transpilePackages: ['three'], |
React Native中需要expo-gl
1 | # Automatically install |
set Metro boundle tool if use loader, gltf and so on
1 | // metro.config.js |
简单的栗子
1 | import React from 'react' |
@React-three/drei
@react-three/drei 是一个工具包(Utility Library),为 @react-three/fiber 提供了一系列高阶组件和实用函数,比如加载模型(useGLTF)、添加环境光(Environment)、设置相机控制(OrbitControls)等。 德语单词“Drei”,意思是“三”
从零探索@react-three/fiber @React-three/drei
Leva
1 | npm install leva@latest --save-dev |
1 | import { useControls } from 'leva' |
#
Three.js
Renderer
init scene
1 | const canvas = document.createElement('canvas') |
Caution! 虽设置canvas尺寸 但canvas初始化renderer时 其尺寸会受到影响 其结果仍使canvas超出父容器 出现滚动条
应使用renderer.setSize
1 | const renderer = new THREE.WebGLRenderer() |
另外onResize要加防抖 overflow hidden该加还是得加
Controls
1 | import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; |
Mesh和Geometry
两者都可以rotate, Geometry是”是什么(what)” Mesh是”如何(how)”
Animation
1 | tick(){ |
tick 调用频率是帧速率相关的 可以用Date或者THREE.Clock
1 | const clock = new THREE.Clock() |
Issue: 单纯调用gsap无效 需要配合requestAnimationFrame和render方法才能使模型运动生效
1 | gsap.to(group.position, { |
Camera
正交相机
1 | const camera = new THREE.OrthographicCamera( |
相机环绕
1 | // mouse rotate |
camera controls
- OrbitControl
- DeviceOrientationControls
- FirstPersionControls
- FlyControls
- PointLockControls
- TrackballControls
debug tool:
dat.gui (out of date) -> lil-gui
control panel
controlkit
Guify
Oui
纹理映射
1 | const loader = new THREE.TextureLoader() |
material properties:
- transparent true/false
- opacity 透明度0~1
- wireframe 显示线框
- side 材质应用到外侧(THREE.FrontSide)或者内侧(THREE.BackSide)
- flatshading
matcap
environmentMap and HDRI(High Dynamic Range Imaging 高动态范围成像)
在宏大场景中,计算周围环境在物体上的倒影是巨大的运算负担,于是聪明的图形工作者想到了将环境贴图直接贴在反光物体上的想法
在Three.js中支持将立方体环境的图像映射到物体上 常用HDRI生成立方环境贴图的免费网站:https://polyhaven.com/hdris 原HDRIHeaven
或使用blender工具
3D Text
TextBufferGeometry
facetype.js 转换.ttf字体成json
QQs: 包含中文的字体转换后出现问题,json中以‘字-坐标’作key-value,中文(甚至字母和数字)转换失败在json中显示为方框,于是输入的字无法找到映射。loader导入这样的字体会报 character “xxx” does not exists in font family XXX
1 | import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js'; |
阴影
雾
例如地面模型 向远处延伸 添加雾以达成模型尽头与背景融为一体的效果 可用于控制视距(线性雾)或更真实地笼罩场景(指数评分雾)
1 | scene.background = new THREE.Color(0xbfd1e5); // 浅蓝色背景 |
雾效果的原理是在shader计算中 根据距离混合物体的颜色和雾的颜色,或许增加了物体渲染的运算 但是配合视距控制的效果 可以编写递进加载逻辑 从而优化渲染性能和体验
粒子
THREE.Points 用于绘制点云 如果每个点都是炫酷的材质 就是所谓的粒子特效
1 | // A. 创建几何体 (BufferGeometry) |
多camera与离线渲染
同场景多个viewport CAD四视图
同场景 离线渲染到 RenderTarget 本质是将场景在GPU额外渲染一次 输出一个texture 这个texture可以贴在场景中的物体(比如镜子)上
官方反射镜 Reflector mirror example
物理引擎
- Cannon.js
- Rapier
可视化优化
- 及时dispose释放资源
- 减少segment
- 复用geometry实例
- 优化requestAnimationFrame 降低帧率和简化回调
webGPU
Three.js 支持webGPU,使用webGPU需要浏览器对该功能的支持 见openGL
对于没有原生支持的浏览器可以通过Polyfill实现
线性代数
向量点乘
内积 数量积
$\vec{a}$·$\vec{b}$ = $x_1 x_2$ + $y_1y_2$ + $z_1z_2$= |$\vec{a}$||$\vec{b}$|cosθ
标量结果 一个向量在另一个向量方向的投影与被投影向量模的乘积
几何意义 对于单位向量 点乘结果取决于向量方向夹角 反映了方向的一致性
向量叉乘
外积 向量积
名字由来是坐标分量做交叉相乘然后相减的操作
方向垂直与向量所在平面 符合右手法则
几何意义 叉乘结果的正负可以反映方向关系
$\vec{a}$ × $\vec{b}$ > 0 ,$\vec{a}$ 在 $\vec{b}$ 右侧
$\vec{a}$ × $\vec{b}$ < 0 ,$\vec{a}$ 在 $\vec{b}$ 左侧
正交矩阵
共轭变换
特征值、特征向量
对于一个 n 阶方阵 A,如果存在一个实数 λ 和一个非零的 n 维列向量 x,使得满足等式 Ax = λx,则称:
- λ 为矩阵 A 的一个特征值(或本征值)。
- x 为矩阵 A 对应于特征值 λ 的一个特征向量(或本征向量)。
其几何意义在于向量x经过A变换 其方向没有改变(或者仅正负颠倒)
在空间运动中 向量x是空间变换A的旋转轴
近似解 最小二乘法
方程组过定(无精确解)时,用一个矩阵 X 去让误差平方和最小
AX ≈ B
正规方程
SVD
Godot
Godot是C++开发的基于opengl的游戏引擎,MIT开源协议,完全免费。支持一键导出到多个平台,包括主流的桌面平台(Linux、macOS、Windows)、移动平台(Android、iOS)、基于 Web 的平台以及主机平台。
UniAnimate
LLM
Token
Token 是大型语言模型处理文本的基本单位。不同模型采用不同的分词方式(分词器),当我们将一段文字输入模型时,模型会先将其拆解成 Token 序列,然后通过这些序列进行预测。
分词器的具体执行原理较为复杂。我们可以简化地将分词器视为一个字典,对于字典中存在的内容,按照字典进行切分并替换为对应的数字
Hello 你好呀 —> Hello | _ | 你好 | 呀 (character: 9, token: 4)
神经网络结构
经典的卷积神经网络(CNN)结构包括以下层:
输入层→卷积层→池化层→全连接层
例如,假设要对0-9十个数字的图片进行分类,则全连接层的输出维度通常要设置为10,与输出分类一一对应。最后通过Softmax层,程序就可以将输出转换为每个类别的概率,概率最高的类别即为预测结果
理解了CNN的输出层维度与分类任务的关系,我们也可以将这个概念迁移到对Transformer语言模型的理解上。尽管二者架构迥异,但是它们在输出层维度及分类任务的原理上仍有共性。
语言模型本质上仍然是一种预测模型,它的核心目标,就是预测给定上下文的下一token。输入层在复杂的网络中传播,最终到达输出层,并且形成 N 个维度的输出。而每个维度正对应着分词表中的一个token。
例如,如果分词表包含50000个token,那么Transformer模型的输出层将输出一个50000维的向量,向量中的每个元素代表对应token的概率。模型会选择概率最高的token作为预测的下一个token。
早期llm的词表(Vocabulary)规模非常小,对应的输出维度也很小,因此相同环境下的理论计算性能更优。但是词表中没有出现的罕见词,有可能被拆分成子词甚至字符。就如ChatGPT 4.0及以前的Vocabulary,大部分中文字符,都会被拆分为2-3个子词token。显然,小规模的Vocabulary有更低的信息密度,相同的输入输出会占据更大的序列长度,这对于输入与输出都有很大的负面影响。
以Llama2-7B模型为例,当词表从32k扩展至64k时,理论的嵌入矩阵参数量从32,000×4096增至65,536×4096,但平均序列长度缩短约30%,实际运行中的整体推理速度提升了15%。
Transformer
Transformer语言模型是基于自注意力机制构建的深度学习架构,已在自然语言处理领域引发革命性变革。
核心架构:
自注意力机制:通过计算序列中每个元素与其他元素的相关性权重(Q/K/V矩阵),捕捉长距离依赖关系。相比RNN/CNN,并行计算效率提升3-8倍(论文7、10)。
多头注意力:将输入切分为多个子空间并行处理,可同时学习语法、语义等不同特征维度(论文3、12)。
位置编码:采用正弦函数生成绝对位置编码(论文1)或相对位置编码(论文18),解决序列顺序建模问题。
它的核心目标,就是预测给定上下文的下一token。
这意味着,Transformer语言模型每输出一个token,输入数据便在神经网络经过了一次完整的传播。最终从词表查询到token string,展示在你眼前的,无论是一个字母,一个单词,甚至一个短语,从模型的角度来看,它们都是“平等的”——从模型角度来看,它们都是一个独立的预测单元,最终对应到词表中的一个 token。
从输入角度上看,正如我们之前提到的,transformer的自注意力模型会将上下文加载到注意力矩阵中,上下文token数直接决定了矩阵的规模,由于O(n²)的时间复杂度,以及O(n²d)的空间复杂度(d为隐藏层维度),小规模词表所带来的低密度信息,可能反而削弱计算性能,增加资源消耗。
从输出角度上看,更小的词表同样意味着单位token包含的信息更少,完成同样的一句输出将会经过更多的推理次数。
本地部署运行大模型:
- 个人调试 ollama
- 企业常用 vllm
1 | pip install sentence-transformers ctransformers ollama |
Ollama 自动启动http服务 默认监听 http://localhost:11434
Ollama命令
1 | ollama list |
如果是微调过的模型 需要先注册到list中 再run起来(待补充)
outlines 输出结构化 结构化的诊疗建议 对接传统业务
关于vllm的性能提升 pagedattention解决kv碎片化 推测解码加速decode 效率是ollama的2-3倍
另:SGlang 在多轮对话
PD分离(Prefill Decode)