0%

3D Gaussian Splatting 2023年

使用 3D Gaussian 球表示三维模型,并通过 Splatting 技术渲染出来。3DGS 是在离散和连续间的一个平衡:在高斯球内部是连续的、可微的;在整个空间中,每个高斯球又是离散的。

ShaderMaterial

1
2
3
4
5
6
7
8
const material = new THREE.ShaderMaterial( {
uniforms: {
time: { value: 1.0 },
resolution: { value: new THREE.Vector2() }
},
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );

RawShaderMaterial

1
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
let flowerImg;
let plants = [];
const NUM_PLANTS = 45; // 花朵总数

function preload() {
// 关键:在这里加载你的手绘花朵模板图片
// 确保图片背景是透明的 (PNG格式)
flowerImg = loadImage('./flower.png');
}

function setup() {
createCanvas(600, 800);
imageMode(CENTER); // 让图片以中心点为基准绘制

// 初始化所有植物数据
for (let i = 0; i < NUM_PLANTS; i++) {
plants.push(new Plant());
}
}

function draw() {
// 绘制蓝色渐变背景 (模拟视频里的背景)
setGradient(0, 0, width, height, color(40, 60, 90), color(120, 160, 200));

// 绘制花盆 (用简单图形模拟,你也可以替换为 loadImage)
drawPot();

// 遍历并绘制每根茎和花朵
for (let i = 0; i < plants.length; i++) {
// 利用索引 i 让每根茎的生长开始时间错开,产生层次感
if (frameCount > i * 4) {
plants[i].grow();
plants[i].display();
}
}
}

// 定义植物类
class Plant {
constructor() {
// 生长起点统一在花盆口中心
this.startX = width / 2;
this.startY = height - 150;

// 关键点1:参差不齐与向外散开
// 终点的 X 随机向左右散开,Y 随机高度
this.endX = width / 2 + random(-250, 250);
this.endY = height - random(300, 650);

// 生成贝塞尔曲线的两个控制点,让茎有自然的弯曲弧度
this.cp1X = this.startX + random(-50, 50);
this.cp1Y = this.startY - random(50, 100);
this.cp2X = this.endX + random(-100, 100);
this.cp2Y = this.endY + random(100, 200);

// t 代表生长进度,从 0 生长到 1
this.t = 0;
this.speed = random(0.005, 0.015); // 每根茎生长速度不同,增加参差感

this.flowerScale = 0;
this.maxFlowerScale = random(0.03, 0.08); // 花朵最终大小随机

// 关键点2:随机的花朵颜色深浅
// 使用 tint() 可以在不改变原图结构的情况下叠加颜色
// 这里生成随机深浅的色调 (以偏黄色调为例,你可以调整 RGB 值)
let shade = random(100, 255);
this.flowerTint = color(shade, shade, shade); // 比如让黄色呈现不同深浅
}

grow() {
// 1. 茎先生长
if (this.t < 1) {
this.t += this.speed*2;
}
// 2. 茎长到 100% 后,花朵开始膨胀长出
else if (this.flowerScale < this.maxFlowerScale) {
this.flowerScale += 0.01;
}
}

display() {
noFill();
stroke(45, 140, 45); // 茎的绿色
strokeWeight(4);

// 关键点3:绘制生长的茎
// 不是直接画一条线,而是计算从起点到当前进度 t 的贝塞尔曲线点
beginShape();
for (let i = 0; i <= this.t; i += 0.02) {
let px = bezierPoint(this.startX, this.cp1X, this.cp2X, this.endX, i);
let py = bezierPoint(this.startY, this.cp1Y, this.cp2Y, this.endY, i);
vertex(px, py);
}
// 补上当前尖端的精确位置,防止锯齿断层
let currentX = bezierPoint(this.startX, this.cp1X, this.cp2X, this.endX, this.t);
let currentY = bezierPoint(this.startY, this.cp1Y, this.cp2Y, this.endY, this.t);
vertex(currentX, currentY);
endShape();

// 当茎长完后,在终点绘制花朵
if (this.t >= 1 && this.flowerScale > 0) {
push();
translate(this.endX, this.endY); // 移动到茎的顶端
scale(this.flowerScale); // 花朵缩放动画
tint(this.flowerTint); // 应用随机深浅颜色滤镜

// 绘制加载的手绘模板图片
if (flowerImg) {
image(flowerImg, 0, 0);
} else {
// 如果图片加载失败的备用绘制 (粉色圆圈)
fill(255, 100, 150);
noStroke();
ellipse(0, 0, 50, 50);
}
pop();
}
}
}

// --- 辅助函数:绘制渐变背景 ---
function setGradient(x, y, w, h, c1, c2) {
noFill();
for (let i = y; i <= y + h; i++) {
let inter = map(i, y, y + h, 0, 1);
let c = lerpColor(c1, c2, inter);
stroke(c);
line(x, i, x + w, i);
}
}

// --- 辅助函数:绘制简单的花盆 ---
function drawPot() {
fill(250, 245, 235); // 陶瓷白
noStroke();

// 盆体
beginShape();
vertex(width/2 - 70, height);
vertex(width/2 + 70, height);
vertex(width/2 + 90, height - 150);
vertex(width/2 - 90, height - 150);
endShape(CLOSE);

// 盆口边缘
rectMode(CENTER);
rect(width/2, height - 150, 190, 20, 10);
}

数字艺术

GLSL(OpenGL Shading Lauguage)是现代GPU编程标准语言 是现代图形学的基石

Pixi.js P5.js Shader都用到GLSL

工具和插件

Shader languages support for VS Code

VS Code扩展 提供GLSL语法高亮 函数签名提示等

vite-plugin-glsl

Vite工程中引入GLSL 和 WGSL 着色器文件

1
npm i vite-plugin-glsl --save-dev
1
2
3
4
5
6
import { defineConfig } from 'vite'
import glsl from 'vite-plugin-glsl'

export default defineConfig({
plugins: [glsl()]
})

GLSL编程语言

类型

  • attribute
  • vec2 vec3 vec4: float元素的矢量(列向量)
  • ivec2 ivec3 ivec4: int元素的矢量
  • bvec2 bvec3 bvec4: bool元素的矢量
  • mat2 mat3 mat4: 2×2 3×3 4×4 float元素的矩阵

方法

exp mod clamp限定范围

cross dot mix线性内插 step步进函数 smoothstep length矢量长度 distance reflect矢量反射

refract normalize

Shaderific
Khronos Group registery
Book of Shaders glossary

矩阵构造函数

1
2
3
4
5
6
vec2 v2_1 = vec2(1.0, 3.0)
vec2 v2_2 = vec2(2.0, 4.0)
mat2 m2_1 = mat2(v2_1, v2_2) // 1.0 2.0
// 3.0 4.0
mat2 m2 = mat2(1.0, 3.0, v2_2)
mat4 m4 = mat4(1.0) // 四阶单位阵

分量

1
2
3
4
// 可以使用xyzw,rgba,stpq分别获取各位置分量
vec3 v3 = vec3(1.0, 2.0, 3.0)
f = v3.x
vec2 = v3.xy

取样器

1
uniform sampler2D u_Sampler

其他

continue break discard(跳过当前片元)

链路:西门子 S7-200 + MCGS 触摸屏 + 蓝蜂物联网网关

工具:

  • STEP 7-Micro/WIN V4.0 SP9 编程软件
  • MCGSPro / MCGS Embed 触摸屏设计软件
  • 蓝蜂配置工具

OPC UA(OLE Process Control Unified Architecture) 用于过程控制的接口(Object link&Embeded OLE)统一架构

用于不同PLC厂商的通信协议封装集成 介于上位机/云端 与设备之间 配合网关 代理服务 避免上位机保持几十上百个tcp连接

通过协议传输语义化数据 描述 文档等

PLC实现的核心控制功能

  • 开关与逻辑控制
  • 模拟量与过程控制 数模转换 比例、积分、微分、模糊控制
  • 脉冲接受或输出
  • 累计现场数据

了解Pascal风格的ST(structured text)编程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// -----------------------------------------------------------------
// 1. 指令边缘捕捉
// -----------------------------------------------------------------
rtEnable(CLK := mbSV_Enable);
rtDisable(CLK := mbSV_Disable);

// -----------------------------------------------------------------
// 2. 核心逻辑控制 (修正使能逻辑)
// -----------------------------------------------------------------

// ON 指令触发 -> 开启使能
IF rtEnable.Q THEN
bServoPowerOn := TRUE;
mbSV_Enable := FALSE;
END_IF

// OFF 指令触发 -> 强制关闭使能
IF rtDisable.Q THEN
bServoPowerOn := FALSE;
mbSV_Disable := FALSE;
END_IF
...
IF fbMoveAbs.Done OR fbMoveAbs.Error THEN mbSV_MoveAbs := FALSE; END_IF

fb是功能块

串口 RS232 RS485 都是物理层标准
RS485

其中RS232使用较高差异的电平(±3-12v)区分逻辑 结构简单 用在芯片之间通讯 或在1m以内的PLC与上位机通讯

RS485使用差分信号区分逻辑(如A>B为逻辑0 反之为1) 使用缠绕双绞线以抗干扰 传输距离可以在1200m 半双工!

上位机编程一般直接根据串口逻辑进行(使用通用串口总线)

Modbus

ModBus链路

ModBus链路

一个项目中还可能有多条 同一链路上使用相同波特率 主站->从站 以实现轮询/问答

仪表要配置 站地址(站号) 通讯参数(波特率 校验 数据位 停止位)

  • Modebus RTU (Remote Terminal Unit) 远程终端设备
  • Modebus TCP

寄存器

  • 线圈寄存器 bit 可读可写
  • 离散输入寄存器 bit 可读
  • 保持寄存器 word(16bit) 可读可写
  • 输入寄存器 word(16bit) 可读可写

功能码

功能码 (Hex) 操作名称 读写权限 对应地址前缀 典型用途与场景
01 读线圈 0x (00001-) 查看开关输出状态
例如:检查继电器是否吸合、电机是否运行、指示灯状态。
02 读离散输入 1x (10001-) 读取外部开关信号
例如:读取按钮按下状态、限位开关触发、传感器到位信号。
03 读保持寄存器 读/写 4x (40001-) 最常用的功能
读取/设置设备参数(如目标温度、PID参数)、读取模拟量输出值。
04 读输入寄存器 只读 3x (30001-) 采集实时测量值
读取传感器数据(如当前电压、电流、温度、压力),通常不可修改。
05 写单个线圈 0x (00001-) 控制开关动作
远程启动/停止电机、强制置位继电器、开关阀门。
06 写单个保持寄存器 4x (40001-) 修改单个参数
修改变频器的频率设定、调整温控器的设定值。
10 (16) 写多个保持寄存器 4x (40001-) 批量下发配置
一次性写入一组PID参数、设置多段速运行指令,提高效率。

视觉设计到刀版图

刀版图Texture

设计交互

editor

[Github QDesign]