ShaderToy学习笔记 05.3D旋转
1. 3D旋转
1.1. 汇制立方体
由于立方体没有旋转,所以正对着看过去时,看起来是正方形的,所以需要旋转一下,才能看到立方体的样子。
常见几何体的SDF
BOX 的SDF为
float sdBox( vec3 p, vec3 b )
{vec3 q = abs(p) - b;return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0);
}
添加了offset及color的公式为
SDFResult sdBox( vec3 p, vec3 b,vec3 offset,vec3 color )
{vec3 q = abs(p-offset) - b;return SDFResult(length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0),color);
}
完整代码如下
#define PIXW (1./iResolution.y)const int MAX_STEPS = 100;
const float START_DIST = 0.001;
const float MAX_DIST = 100.0;
const float EPSILON = 0.0001;struct SDFResult
{float d;vec3 color;
};vec3 getBackgroundColor(vec2 uv)
{
//uv.y [-1,1]
//y: [0,1] float y=(uv.y+1.)/2.; return mix(vec3(1,0,1),vec3(0,1,1),y);
}SDFResult sdSphere(vec3 p, float r,vec3 offset,vec3 color)
{return SDFResult(length(p-offset)-r,color);
}
SDFResult sdBox( vec3 p, vec3 b,vec3 offset,vec3 color )
{vec3 q = abs(p-offset) - b;return SDFResult(length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0),color);
}SDFResult minWithColor(SDFResult a,SDFResult b)
{if (a.d<b.d){return a;}return b;
}
SDFResult sdScene(vec3 p)
{SDFResult result1=sdSphere(p,1.0,vec3(-2.5,0.5,-2),vec3(0.,0.8,0.8));SDFResult result2=sdSphere(p,1.0,vec3(2.5,0.5,-2),vec3(1.,0.58,0.29));//SDFResult result=minWithColor(result1,result2);SDFResult result=sdBox(p,vec3(1.0,1.0,.5),vec3(0.2,0.2,0.2),vec3(1.,0.,0.));return result;
}
//法线计算
vec3 calcNormal(vec3 p) {vec2 e = vec2(1.0, -1.0) * 0.0005; // epsilonfloat r = 1.; // radius of spherereturn normalize(e.xyy * sdScene(p + e.xyy).d +e.yyx * sdScene(p + e.yyx).d +e.yxy * sdScene(p + e.yxy).d +e.xxx * sdScene(p + e.xxx).d);
}SDFResult rayMarch(vec3 ro, vec3 rd,float start,float end)
{float d=start;float r=1.0;SDFResult result;for(int i=0;i<MAX_STEPS;i++){vec3 p=ro+rd*d;result=sdScene(p);d+=result.d;if(result.d<EPSILON || d>end) break;}result.d=d;return result;
}void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.xx;float r=0.3;vec3 backgroundColor = vec3(0.835, 1, 1);//vec3 c=getBackgroundColor(uv);vec3 c=backgroundColor;vec3 ro = vec3(0, 0, 3); // ray origin that represents camera positionvec3 rd = normalize(vec3(uv, -1)); // ray directionSDFResult result=rayMarch(ro,rd,START_DIST,MAX_DIST);float d=result.d;if(d<MAX_DIST){//平行光源的漫反射计算vec3 p=ro+rd*d;vec3 n=calcNormal(p);vec3 lightPosition=vec3(2,2,7);//vec3 light_direction=normalize(vec3(1,0,5));vec3 light_direction=normalize(lightPosition-p);vec3 light_color=vec3(1,1,1);float diffuse=max(0.0,dot(n,light_direction));diffuse=clamp(diffuse,0.1,1.0);c=light_color*diffuse*result.color+backgroundColor*0.2;}// Output to screenfragColor = vec4(vec3(c),1.0);
}
1.2. 旋转
在三维空间中,我们需要分别考虑绕 X 轴、Y 轴和 Z 轴的旋转。每个轴的旋转都有其对应的旋转矩阵:
绕 X 轴旋转 θ 角度的矩阵:
R x ( θ ) = ( 1 0 0 0 0 cos θ − sin θ 0 0 sin θ cos θ 0 0 0 0 1 ) R_x(\theta) = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos\theta & -\sin\theta & 0 \\ 0 & \sin\theta & \cos\theta & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} Rx(θ)= 10000cosθsinθ00−sinθcosθ00001
绕 Y 轴旋转 θ 角度的矩阵:
R y ( θ ) = ( cos θ 0 sin θ 0 0 1 0 0 − sin θ 0 cos θ 0 0 0 0 1 ) R_y(\theta) = \begin{pmatrix} \cos\theta & 0 & \sin\theta & 0 \\ 0 & 1 & 0 & 0 \\ -\sin\theta & 0 & \cos\theta & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} Ry(θ)= cosθ0−sinθ00100sinθ0cosθ00001
绕 Z 轴旋转 θ 角度的矩阵:
R z ( θ ) = ( cos θ − sin θ 0 0 sin θ cos θ 0 0 0 0 1 0 0 0 0 1 ) R_z(\theta) = \begin{pmatrix} \cos\theta & -\sin\theta & 0 & 0 \\ \sin\theta & \cos\theta & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} Rz(θ)= cosθsinθ00−sinθcosθ0000100001
对于任意点 P(x, y, z),旋转后的坐标 P’(x’, y’, z’) 可以通过矩阵乘法得到:
P ′ = R ⋅ P P' = R \cdot P P′=R⋅P
如果需要进行多个轴的组合旋转,最终的旋转矩阵是各个轴向旋转矩阵的乘积。注意矩阵乘法的顺序会影响最终结果:
R t o t a l = R z ⋅ R y ⋅ R x R_{total} = R_z \cdot R_y \cdot R_x Rtotal=Rz⋅Ry⋅Rx
在实际应用中,我们通常会使用四阶矩阵(4x4)来表示这些变换,以便与其他变换(如平移、缩放)进行组合。
1.3. X 轴旋转
代码实现
mat4 rotationX(float theta)
{return mat4(1.0, 0.0, 0.0, 0.0,0.0, cos(theta), -sin(theta), 0.0,0.0, sin(theta), cos(theta), 0.0,0.0, 0.0, 0.0, 1.0);
}SDFResult sdBox( vec3 p, vec3 b,vec3 offset,vec3 color ,mat4 transform)
{p=(transform*vec4(p-offset,1.0)).xyz;vec3 q = abs(p) - b;return SDFResult(length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0),color);
}
因为 GLSL 中矩阵乘法是右乘的,vec3 类型的点需要先扩展为 vec4(齐次坐标),然后与 mat4 相乘,最后提取出 .xyz 部分。
1.3.1. 完整代码
#define PIXW (1./iResolution.y)const int MAX_STEPS = 100;
const float START_DIST = 0.001;
const float MAX_DIST = 100.0;
const float EPSILON = 0.0001;
const float PI = 3.1415926535897932384626433832795;
struct SDFResult
{float d;vec3 color;
};mat4 rotationX(float theta)
{return mat4(1.0, 0.0, 0.0, 0.0,0.0, cos(theta), -sin(theta), 0.0,0.0, sin(theta), cos(theta), 0.0,0.0, 0.0, 0.0, 1.0);
}
vec3 getBackgroundColor(vec2 uv)
{
//uv.y [-1,1]
//y: [0,1] float y=(uv.y+1.)/2.; return mix(vec3(1,0,1),vec3(0,1,1),y);
}SDFResult sdSphere(vec3 p, float r,vec3 offset,vec3 color)
{return SDFResult(length(p-offset)-r,color);
}
SDFResult sdBox( vec3 p, vec3 b,vec3 offset,vec3 color ,mat4 transform)
{p=(transform*vec4(p-offset,1.0)).xyz;vec3 q = abs(p) - b;return SDFResult(length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0),color);
}SDFResult minWithColor(SDFResult a,SDFResult b)
{if (a.d<b.d){return a;}return b;
}
SDFResult sdScene(vec3 p)
{SDFResult result1=sdSphere(p,1.0,vec3(-2.5,0.5,-2),vec3(0.,0.8,0.8));SDFResult result2=sdSphere(p,1.0,vec3(2.5,0.5,-2),vec3(1.,0.58,0.29));//SDFResult result=minWithColor(result1,result2);SDFResult result=sdBox(p,vec3(1.0,1.0,.5),vec3(0.2,0.2,0.2),vec3(1.,0.,0.),rotationX(0.05*PI*iTime));return result;
}
//法线计算
vec3 calcNormal(vec3 p) {vec2 e = vec2(1.0, -1.0) * 0.0005; // epsilonfloat r = 1.; // radius of spherereturn normalize(e.xyy * sdScene(p + e.xyy).d +e.yyx * sdScene(p + e.yyx).d +e.yxy * sdScene(p + e.yxy).d +e.xxx * sdScene(p + e.xxx).d);
}SDFResult rayMarch(vec3 ro, vec3 rd,float start,float end)
{float d=start;float r=1.0;SDFResult result;for(int i=0;i<MAX_STEPS;i++){vec3 p=ro+rd*d;result=sdScene(p);d+=result.d;if(result.d<EPSILON || d>end) break;}result.d=d;return result;
}void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.xx;float r=0.3;vec3 backgroundColor = vec3(0.835, 1, 1);//vec3 c=getBackgroundColor(uv);vec3 c=backgroundColor;vec3 ro = vec3(0, 0, 3); // ray origin that represents camera positionvec3 rd = normalize(vec3(uv, -1)); // ray directionSDFResult result=rayMarch(ro,rd,START_DIST,MAX_DIST);float d=result.d;if(d<MAX_DIST){//平行光源的漫反射计算vec3 p=ro+rd*d;vec3 n=calcNormal(p);vec3 lightPosition=vec3(2,2,7);//vec3 light_direction=normalize(vec3(1,0,5));vec3 light_direction=normalize(lightPosition-p);vec3 light_color=vec3(1,1,1);float diffuse=max(0.0,dot(n,light_direction));diffuse=clamp(diffuse,0.1,1.0);c=light_color*diffuse*result.color+backgroundColor*0.2;}// Output to screenfragColor = vec4(vec3(c),1.0);
}
1.4. 绕x,y,z轴旋转
核心代码
mat4 rotationX(float theta)
{return mat4(1.0, 0.0, 0.0, 0.0,0.0, cos(theta), -sin(theta), 0.0,0.0, sin(theta), cos(theta), 0.0,0.0, 0.0, 0.0, 1.0);
}mat4 rotationY(float theta)
{return mat4(cos(theta), 0.0, sin(theta), 0.0,0.0, 1.0, 0.0, 0.0,-sin(theta), 0.0, cos(theta), 0.0,0.0, 0.0, 0.0, 1.0);
}
mat4 rotationZ(float theta)
{return mat4(cos(theta), -sin(theta), 0.0, 0.0,sin(theta), cos(theta), 0.0, 0.0,0.0, 0.0, 1.0, 0.0,0.0, 0.0, 0.0, 1.0);
}
完整代码
#define PIXW (1./iResolution.y)const int MAX_STEPS = 100;
const float START_DIST = 0.001;
const float MAX_DIST = 100.0;
const float EPSILON = 0.0001;
const float PI = 3.1415926535897932384626433832795;
struct SDFResult
{float d;vec3 color;
};mat4 rotationX(float theta)
{return mat4(1.0, 0.0, 0.0, 0.0,0.0, cos(theta), -sin(theta), 0.0,0.0, sin(theta), cos(theta), 0.0,0.0, 0.0, 0.0, 1.0);
}mat4 rotationY(float theta)
{return mat4(cos(theta), 0.0, sin(theta), 0.0,0.0, 1.0, 0.0, 0.0,-sin(theta), 0.0, cos(theta), 0.0,0.0, 0.0, 0.0, 1.0);
}
mat4 rotationZ(float theta)
{return mat4(cos(theta), -sin(theta), 0.0, 0.0,sin(theta), cos(theta), 0.0, 0.0,0.0, 0.0, 1.0, 0.0,0.0, 0.0, 0.0, 1.0);
}vec3 getBackgroundColor(vec2 uv)
{
//uv.y [-1,1]
//y: [0,1] float y=(uv.y+1.)/2.; return mix(vec3(1,0,1),vec3(0,1,1),y);
}SDFResult sdSphere(vec3 p, float r,vec3 offset,vec3 color)
{return SDFResult(length(p-offset)-r,color);
}
SDFResult sdBox( vec3 p, vec3 b,vec3 offset,vec3 color ,mat4 transform)
{p=(transform*vec4(p-offset,1.0)).xyz;vec3 q = abs(p) - b;return SDFResult(length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0),color);
}SDFResult minWithColor(SDFResult a,SDFResult b)
{if (a.d<b.d){return a;}return b;
}
SDFResult sdScene(vec3 p)
{SDFResult result1=sdSphere(p,1.0,vec3(-2.5,0.5,-2),vec3(0.,0.8,0.8));SDFResult result2=sdSphere(p,1.0,vec3(2.5,0.5,-2),vec3(1.,0.58,0.29));//SDFResult result=minWithColor(result1,result2);SDFResult result=sdBox(p,vec3(1.0,1.0,.5),vec3(0.2,0.2,0.2),vec3(1.,0.,0.),rotationX(0.05*PI*iTime)*rotationY(0.05*PI*iTime)*rotationY(0.05*PI*iTime)* rotationZ(0.05*PI*iTime));return result;
}
//法线计算
vec3 calcNormal(vec3 p) {vec2 e = vec2(1.0, -1.0) * 0.0005; // epsilonfloat r = 1.; // radius of spherereturn normalize(e.xyy * sdScene(p + e.xyy).d +e.yyx * sdScene(p + e.yyx).d +e.yxy * sdScene(p + e.yxy).d +e.xxx * sdScene(p + e.xxx).d);
}SDFResult rayMarch(vec3 ro, vec3 rd,float start,float end)
{float d=start;float r=1.0;SDFResult result;for(int i=0;i<MAX_STEPS;i++){vec3 p=ro+rd*d;result=sdScene(p);d+=result.d;if(result.d<EPSILON || d>end) break;}result.d=d;return result;
}void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.xx;float r=0.3;vec3 backgroundColor = vec3(0.835, 1, 1);//vec3 c=getBackgroundColor(uv);vec3 c=backgroundColor;vec3 ro = vec3(0, 0, 3); // ray origin that represents camera positionvec3 rd = normalize(vec3(uv, -1)); // ray directionSDFResult result=rayMarch(ro,rd,START_DIST,MAX_DIST);float d=result.d;if(d<MAX_DIST){//平行光源的漫反射计算vec3 p=ro+rd*d;vec3 n=calcNormal(p);vec3 lightPosition=vec3(2,2,7);//vec3 light_direction=normalize(vec3(1,0,5));vec3 light_direction=normalize(lightPosition-p);vec3 light_color=vec3(1,1,1);float diffuse=max(0.0,dot(n,light_direction));diffuse=clamp(diffuse,0.1,1.0);c=light_color*diffuse*result.color+backgroundColor*0.2;}// Output to screenfragColor = vec4(vec3(c),1.0);
}
1.5. 缩放
缩放是指改变物体的大小。在计算机图形学中,我们可以使用矩阵来表示缩放。为了按我们预期的方式缩放物体,网格的中心需要是(0, 0, 0)。即缩放矩阵是针对网格的中心点进行缩放的,而不是针对世界空间的原点进行缩放。
1.5.1. 二维空间的缩放矩阵
在二维空间中,我们可以使用一个缩放矩阵来改变物体的大小。
缩放矩阵的形式为:
S = |sx 0||0 sy|
其中,sx 和 sy 分别表示物体在 x 轴和 y 轴上的缩放比例。
对于任意点 A(x, y),缩放后的坐标 A’(x’, y’) 可以通过矩阵乘法得到:
A' = S * A
展开后得到缩放公式:
x' = sx * x
y' = sy * y
1.5.2. 三维空间的缩放矩阵
在三维空间中,我们需要分别考虑物体在 x 轴、y 轴和 z 轴上的缩放。
缩放矩阵的形式为:
S = |sx 0 0 0 ||0 sy 0 0 ||0 0 sz 0 ||0 0 0 1 |
其中,sx、sy 和 sz 分别表示物体在 x 轴、y 轴和 z 轴上的缩放比例。
对于任意点 A(x, y, z),缩放后的坐标 A’(x’, y’, z’) 可以通过矩阵乘法得到:
A' = S * A
展开后得到缩放公式:
x' = sx * x
y' = sy * y
z' = sz * z
1.6. 组合变换
在计算机图形学中,我们经常需要将多个变换组合在一起,以创建更复杂的变换效果。例如,我们可以将缩放、旋转和平移组合在一起,以创建更复杂的变换效果。
其处理过程为:先进行缩放,再进行旋转,最后进行平移
由于矩阵乘法不满足交换律,所以变换的顺序十分关键。按照“先缩放,再旋转,最后平移”的顺序,最终的变换矩阵 M 为:
M = T * R * S
其中,T 是平移矩阵,R 是旋转矩阵,S 是缩放矩阵。
2. 参考
- 常见几何体的SDF
- Rendering Worlds with Two Triangles with raytracing on the GPU in 4096 bytes
- OpenGL shader开发实战学习笔记:第五章 使物体动起来-CSDN博客
相关文章:
ShaderToy学习笔记 05.3D旋转
1. 3D旋转 1.1. 汇制立方体 由于立方体没有旋转,所以正对着看过去时,看起来是正方形的,所以需要旋转一下,才能看到立方体的样子。 常见几何体的SDF BOX 的SDF为 float sdBox( vec3 p, vec3 b ) {vec3 q abs(p) - b;return len…...
编程日志4.24
栈的链表基础表示结构 #include<iostream> #include<stdexcept> using namespace std; //模板声明,表明Stack类是一个通用的模板,可以用于存储任何类型的元素T template<typename T> //栈的声明 //Stack类的声明,表示一…...
通信设备制造数字化转型中的创新模式与实践探索
在数字化浪潮下,通信设备制造企业积极探索创新模式,推动数字化转型,以提升竞争力和适应市场变化。 在生产模式创新方面,企业引入工业互联网平台,实现设备互联互通与生产过程智能化监控。通过在生产设备上安装传感器&a…...
同一个路由器接口eth0和ppp0什么不同?
答案摘自 百度知道, eth0是以太网接口,是表示以太网连接的物理接口,路由器可能会有不止一个以太网接口,因此可能会eth0,eht1之类的。 ppp0是经以太网接口PPP拨号时创建的链路接口,用以建PPP拨号连接的&am…...
零训练成本优化LLM: 11种LLM权重合并策略原理与MergeKit实战配置
随着大语言模型的快速发展,如何在不消耗大量计算资源的情况下优化模型性能成为业界关注焦点。模型权重合并技术提供了一种零训练成本的高效解决方案,能够智能整合多个专业微调模型的优势,无需额外训练即可显著提升性能表现。本文系统剖析11种…...
基于tabula对pdf中多个excel进行识别并转换成word中的优化(五)
优化地方:处理合并的单元格内容。 1、修改为stream"complex" 2、增加换行符f"{table_data[i - 1][j]}\n{table_data[i][j]}".strip() 一、pdf中excel样例 二、完整代码 import tabula import numpy as np from docx import Document from docx…...
QT中的网络编程
Qt中的网络编程是通过封装操作系统的API进行实现的 C标准库中,并没有提供网络编程的封装接口 进行网络编程时本质是在编写应用层代码,需要传输层提供支持 传输层最核心的协议为UDP/TCP 使用Qt网络编程的API时,需要在.pro文件中添加network模块…...
0.5 像素边框实现
0.5 像素边框怎么实现 文章目录 0.5 像素边框怎么实现方法 1:使用 transform: scale() 缩放(推荐)方法 2:直接使用 0.5px 边框(部分浏览器支持)方法 3:使用 box-shadow 模拟边框方法 4ÿ…...
【Vagrant+VirtualBox创建自动化虚拟环境】Ansible测试Playbook
文章目录 Vagrant安装vagrant安装 VirtualBox如何使用 Ansible安装AnsiblePlaybook测试创建hosts文件创建setup.yml文件 Vagrant Vagrant是一个基于Ruby的工具,用于创建和部署虚拟化开发环境。它使用Oracle的开源VirtualBox虚拟化系统,使用 Chef创建自动…...
“连接世界的桥梁:深入理解计算机网络应用层”
一、引言 当你浏览网页、发送邮件、聊天或观看视频时,这一切都离不开计算机网络中的应用层(Application Layer)。 应用层是网络协议栈的最顶层,直接为用户的各种应用程序提供服务。它为用户进程之间建立通信桥梁,屏蔽了…...
Vulkan与OpenGL的对比
传统图形API与现代图形API 传统图形API指的是OpenGL/DirectX11这类简单易用、驱动托管严重的图形接口;而现代图形API则指的是Vulkan/Metal/DirectX12这类使用复杂、暴露更多底层硬件功能来显式控制的弱驱动设计的图形接口。 现代图形API与传统图形API相比ÿ…...
海外社交App的Web3革命:去中心化社交与Token经济实战指南
一、Web3社交的核心组件:从身份到经济的重构 去中心化身份(DID)技术栈:Ceramic IDX协议构建链上身份图谱代码示例:javascript// 创建DID const ceramic new CeramicClient() const did new DID({ provider: cerami…...
凯撒密码算法的实现
在密码学里,凯撒密码(也叫恺撒密码、移位密码、恺撒代码或者恺撒移位)是一种简单且广为人知的加密技术。它属于替换密码的一种,在这种加密方式中,明文中的每个字母都会被替换成字母表中往后移动固定位数的字母。例如&a…...
Chrome的插件扩展程序安装目录是什么?在哪个文件夹?
目录 前提 直接复制到浏览器中打开 Mac下Chrome extension 安装路径 最近换了mac pro用起来虽然方便,但是对常用的一些使用方法还是不熟悉。这不为了找到mac上chrome插件的安装路径在哪里,花费了不少时间。我想应用有不少像小编一样刚刚使用mac的小白…...
C++23中的std::forward_like:完美转发的增强
文章目录 一、背景与动机(一)完美转发的局限性(二)std::forward_like的提出 二、std::forward_like的设计与实现(一)基本语法(二)实现原理(三)与std::forward…...
AI与软件测试的未来:如何利用智能自动化改变测试流程
用工作流生成测试用例和自动化测试脚本! 随着人工智能(AI)技术的迅猛发展,软件测试作为软件开发生命周期中的关键环节,正在经历一场前所未有的变革。传统的测试方法已经无法满足现代快速迭代和持续交付的需求ÿ…...
React Native 动态切换主题
React Native 动态切换主题 创建主题配置和上下文创建主题化高阶组件主应用组件主屏幕组件(类组件形式) 创建主题配置和上下文 // ThemeContext.jsimport React, { Component, createContext } from react;import { Appearance, AsyncStorage } from rea…...
得物 小程序 6宫格 分析
声明 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 逆向过程 部分python代码 if result …...
PocketFlow一个最小的Agent框架
1、背景 PocketFlow 2、使用 python 的版本需要python3.10 在cookbook中有如何使用的说明,如图所示 在tuils.py中修改代码 def call_llm(messages):# client OpenAI(api_keyos.environ.get("OPENAI_API_KEY", "your-api-key"))client Op…...
Objective-C Block 底层原理深度解析
Objective-C Block 底层原理深度解析 1. Block 是什么? 1.1 Block 的本质 Block 是 Objective-C 中的特殊对象,实现了匿名函数的功能 通过 isa 指针继承自 NSObject,可以响应(如 copy、retain、release)等内存管理方…...
AlDente Pro for Mac电脑 充电限制保护工具 安装教程【简单,轻松上手】
AlDente Pro for Mac电脑 充电限制保护工具 安装教程【简单,轻松上手】 AlDente Pro for Mac,是一款充电限制保护工具,是可以限制最大充电百分比来保护电池的工具。锂离子和聚合物电池(如 MacBook 中的电池)在40&…...
Linux systemd 从理论到实践:现代系统管理的核心工具
文章目录 引言:为什么需要 systemd?第一部分:systemd 核心理论1.1 systemd 的设计哲学1.2 核心组件1.3 单元文件(Unit File)结构 第二部分:实战操作指南2.1 基础命令2.2 服务管理高级操作2.3 日志管理&…...
分享一个移动端项目模板:React-Umi4-mobile
分享一个移动端项目模板:React-Umi4-mobile 大家好,今天想和大家分享一个我最近做的移动端项目模板 React-Umi4-mobile。 模板的主要内容 这个模板主要包括: 基于 Umi 4 框架使用了 antd-mobile 组件库配置了 px 自动转 vw(基…...
Tailwind CSS 响应式设计解析(含示例)
本文内容: Tailwindcss V4 中如何使用响应式设计功能,包括默认断点、自定义断点、断点范围控制以及容器查询的各种技巧,帮助你在不离开 HTML 的前提下优雅构建响应式页面。 🌟 默认断点用法(移动优先) Tail…...
ElasticSearch入门
1 elasticsearch概述 1.1 elasticsearch 简介 官网: https://www.elastic.co/ ElasticSearch是一个基于 Lucene 的搜索服务器,基于RESTful web接口。Elasticsearch是用Java开发的,开源的企业级搜索引擎。 Elastic官方宣布Elasticsearch进入Version 8…...
强化学习之基于无模型的算法之时序差分法
2、时序差分法(TD) 核心思想 TD 方法通过 引导值估计来学习最优策略。它利用当前的估计值和下一个时间步的信息来更新价值函数, 这种方法被称为“引导”(bootstrapping)。而不需要像蒙特卡罗方法那样等待一个完整的 episode 结束才进行更新&…...
【网络原理】TCP异常处理(二):连接异常
目录 一. 由进程崩溃引起的连接断开 二. 由关机引起的连接断开 三. 由断电引起的连接断开 四. 由网线断开引起的连接断开 一. 由进程崩溃引起的连接断开 在一般情况下,进程无论是正常结束,还是异常崩溃,都会触发回收文件资源,…...
[stm32] 4-1 USART(1)
文章目录 前言4-1 USARTUSART简介什么是USART?USART名字的含义?如何使用USART? USART的工作原理什么是串并转换?为什么要进行串并转换?移位寄存器串并行转换电路 USART寄存器组和完整框图 前言 本笔记内容,为本人依据…...
C++多线程与锁机制
1. 基本多线程编程 1.1 创建线程 #include <iostream> #include <thread>void thread_function() {std::cout << "Hello from thread!\n"; }int main() {std::thread t(thread_function); // 创建并启动线程t.join(); // 等待线程结束return 0; …...
【MCP Node.js SDK 全栈进阶指南】高级篇(4):自定义传输层开发
引言 在MCP(Model Context Protocol)应用开发中,传输层是连接客户端与服务器的关键环节,直接影响应用的性能、可靠性和扩展性。默认的传输方式虽然能满足基本需求,但在复杂场景下,自定义传输层能够为应用提供更高的灵活性和优化空间。本文将深入探讨MCP TypeScript-SDK中…...
当向量数据库与云计算相遇:AI应用全面提速
如果将AI比作一台高速运转的机器引擎,那么数据便是它的燃料。 然而,存储数据的燃料库--传统数据库,在AI时代的效率瓶颈愈发明显,已经无法满足AI对于数据的全新需求。 因此,向量数据库近年来迅速崛起。向量数据库通过…...
【2024-NIPS-版权】Evaluating Copyright Takedown Methods for Language Models
1.背景 目前 LLMs 在训练过程中使用了大量的受版权保护数据,这些数据会导致大模型记忆并生成与训练数据相似的内容,从而引发版权问题。随着版权所有者对模型训练和部署中的版权问题提起诉讼(例如 Tremblay v. OpenAI, Inc. 和 Kadrey v. Met…...
【PyTorch动态计算图原理精讲】从入门到灵活应用
目录 前言技术背景与价值当前技术痛点解决方案概述目标读者说明一、技术原理剖析核心概念图解核心作用讲解关键技术模块说明技术选型对比二、实战演示环境配置要求核心代码实现案例1:基础计算图构建案例2:条件分支动态图案例3:循环结构动态图运行结果验证三、性能对比测试方…...
阿里巴巴Qwen3发布:登顶全球开源模型之巅,混合推理模式重新定义AI效率
今天凌晨,阿里巴巴正式开源了新一代通义千问大模型Qwen3,这一举措不仅标志着国产大模型技术的又一里程碑,更以“混合推理”“极致性能”“超低成本”三大核心优势,刷新了全球开源模型的竞争格局。Qwen3在多项评测中超越DeepSeek-R…...
5. 配置舵机ID(具身智能机器人套件)
1. 连接舵机 waveshare驱动器板使用9-12v供电Type-C连接电脑DVG连接一个舵机 2. 使用FT SCServo Debug软件 设置串口设置波特率(默认1000000,100万)打开串口编程界面修改ID 3. 依次修改所有舵机ID 分别使用waveshare驱动板连接舵机&…...
Nacos源码—2.Nacos服务注册发现分析四
大纲 5.服务发现—服务之间的调用请求链路分析 6.服务端如何维护不健康的微服务实例 7.服务下线时涉及的处理 8.服务注册发现总结 7.服务下线时涉及的处理 (1)Nacos客户端服务下线的源码 (2)Nacos服务端处理服务下线的源码 (3)Nacos服务端发送服务变动事件给客户端的源码…...
从Windows开发迁移到信创开发的指南:国产替代背景下的技术路径与实践
🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C、C#等开发语言,熟悉Java常用开…...
从数据到决策:安科瑞EIoT如何让每一度电“清晰可见”?
安科瑞顾强 在能源管理迈向精细化与数字化的今天,安科瑞EIoT能源物联网平台以“数据驱动能源价值”为核心理念,融合物联网、云计算与大数据技术,打通从设备感知到云端决策的全链路闭环,助力工商业企业、园区、物业等场景实现用电…...
10.学习笔记-MyBatisPlus(P105-P110)
1.MyBatisPlus入门案例 (1)MyBatisPlus(简称Mp)是基于MyBatis框架基础上开发的增强型工具,目的是简化开发,提高效率。 (2)开发方式:基于MyBatis使用MyBatisPlusÿ…...
LayerSkip: Enabling Early Exit Inference and Self-Speculative Decoding
TL;DR 2024 年 Meta FAIR 提出了 LayerSkip,这是一种端到端的解决方案,用于加速大语言模型(LLMs)的推理过程 Paper name LayerSkip: Enabling Early Exit Inference and Self-Speculative Decoding Paper Reading Note Paper…...
fastapi和flaskapi有什么区别
FastAPI 和 Flask 都是 Python 的 Web 框架,但设计目标和功能特性有显著差异。以下是它们的核心区别: 1. 性能与异步支持 FastAPI 基于 Starlette(高性能异步框架)和 Pydantic(数据校验库)…...
在 JMeter 中使用 BeanShell 获取 HTTP 请求体中的 JSON 数据
在 JMeter 中,您可以使用 BeanShell 处理器来获取 HTTP 请求体中的 JSON 数据。以下是几种方法: 方法一:使用前置处理器获取请求体 如果您需要在发送请求前访问请求体: 添加一个 BeanShell PreProcessor 到您的 HTTP 请求采样器…...
Go 1.25为什么要废除核心类型
关于核心类型为什么要1.25里要移除,作者Robert在博客Goodbye core types - Hello Go as we know and love it!里给了详细耐心的解答。 背景:Go 1.18 引入了泛型(generics),带来了类型参数…...
flask中的Response 如何使用?
在 Flask 中,Response 对象用于生成 HTTP 响应并返回给客户端。以下是其常见用法及示例: 1. 直接返回字符串或 HTML 视图函数返回的字符串会被自动包装为 Response 对象,默认状态码为 200,内容类型为 text/html: app…...
基于SpringAI实现简易聊天对话
简介 本文旨在记录学习和实践 Spring AI Alibaba 提供的 ChatClient 组件的过程。ChatClient 是 Spring AI 中用于与大语言模型(LLM)进行交互的高级 API,它通过流畅(Fluent)的编程接口,极大地简化了构建聊天…...
STM32单片机入门学习——第49节: [15-2] 读写内部FLASH读取芯片ID
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.29 STM32开发板学习——第49节: [15-2] 读写内部FLASH&读取芯片ID 前言开发板说…...
第14讲:科研图表的导出与排版艺术——高质量 PDF、TIFF 输出与投稿规范全攻略!
目录 📘 前言:导出,不只是“保存”! 🎯 一、你需要掌握的导出目标 🖼️ 二、TIFF / PNG 导出规范(适用于投稿) 🧲 三、PDF 矢量图导出(排版首选) 🧩 四、强烈推荐组合:showtext + Cairo 🧷 五、多个图的组合导出技巧 🧪 六、特殊投稿需求处理 �…...
SRIO IP调试问题记录(ready信号不拉高情况)
问题:调试过程中遇到有时写入数据后数据不发送,并且ready信号在写入一定数据后一直拉低的情况(偶发,不是每次必然出现)。buf空间设置为16时,写入15包数据,写完第16包包头后,ready信号…...
使用DDR4控制器实现多通道数据读写(十)
一、本章概述 本章节对目前单通道的读写功能进项测试,主要验证读写的数据是否正确,并观察该工程可以存储的最大容量。通过空满信号进行读写测试,根据ila抓取fifo和ddr4全部满的时刻,可以观察到最大容量。再通过debug逻辑可以测试读…...
从 BERT 到 GPT:Encoder 的 “全局视野” 如何喂饱 Decoder 的 “逐词纠结”
当 Encoder 学会 “左顾右盼”:Decoder 如何凭 “单向记忆” 生成丝滑文本? 目录 当 Encoder 学会 “左顾右盼”:Decoder 如何凭 “单向记忆” 生成丝滑文本?引言一、Encoder vs Decoder:核心功能与基础架构对比1.1 本…...