完成主要交互、高性能组件、国际化和A型传感器数据包接收

This commit is contained in:
2026-01-13 16:34:28 +08:00
parent 47e6dc7244
commit 1960e6a5b9
84 changed files with 7752 additions and 332 deletions

View File

@@ -7,6 +7,7 @@ uniform vec2 uViewport;
// 以像素为单位的网格间距:细网格/粗网格
uniform float uMinorStep;
uniform float uMajorStep;
uniform bool uLightMode;
// 生成抗锯齿网格线(返回 0..11 表示在线上)
float gridLine(float stepPx) {
@@ -22,21 +23,28 @@ float gridLine(float stepPx) {
void main() {
vec2 viewport = max(uViewport, vec2(1.0));
vec2 uv = gl_FragCoord.xy / viewport; // 0..1
vec3 topCol, botCol, minorCol, majorCol;
float minorStrength, majorStrength;
float vignettePow, vignetteStrength;
// 背景渐变:上更亮、下稍灰,常见 3D 软件的“科技感”底色
vec3 topCol = vec3(0.99, 0.99, 1.00);
vec3 botCol = vec3(0.94, 0.95, 0.98);
topCol = vec3(0.99, 0.99, 1.00);
botCol = vec3(0.94, 0.95, 0.98);
minorCol = vec3(0.80, 0.82, 0.87);
majorCol = vec3(0.70, 0.73, 0.80);
minorStrength = 0.22;
majorStrength = 0.35;
vignettePow = 0.12;
vignetteStrength = 0.35;
vec3 col = mix(botCol, topCol, uv.y);
// 网格线:细线 + 粗线(每隔一段更深一点)
float minor = gridLine(max(uMinorStep, 1.0));
float major = gridLine(max(uMajorStep, 1.0));
vec3 minorCol = vec3(0.80, 0.82, 0.87);
vec3 majorCol = vec3(0.70, 0.73, 0.80);
col = mix(col, minorCol, minor * 0.22);
col = mix(col, majorCol, major * 0.35);
col = mix(col, minorCol, minor * minorStrength);
col = mix(col, majorCol, major * majorStrength);
// 轻微 vignette四角略暗让画面更“聚焦”
vec2 p = uv * 2.0 - 1.0;

View File

@@ -117,19 +117,31 @@ void main() {
float value01 = clamp((vValue - uMinV) / max(1e-6, (uMaxV - uMinV)), 0.0, 1.0);
vec3 dataCol = dataColorRamp(value01);
bool hasData = (uHasData != 0);
vec3 baseColor = hasData ? dataCol : metalBase;
// bool hasData = (uHasData != 0);
// vec3 baseColor = hasData ? dataCol : metalBase;
vec3 baseColor = metalBase;
// dataViz: flat/unlit, no lighting modulation (keep pure baseColor)
if (uRenderMode == 1) {
FragColor = vec4(clamp(baseColor, 0.0, 1.0), 1.0);
return;
}
// Mostly flat, with a slight bevel near the edge to catch highlights.
float slope = mix(0.06, 0.28, smoothstep(0.55, 1.0, r01));
vec3 N = normalize(vec3(p.x * slope, 1.0, p.y * slope));
// Face the camera: dots live on the panel front face (XY plane), so the base normal points -Z.
// vec3 N = normalize(vec3(p.x * slope, p.y * slope, -1.0));
vec3 N = normalize(vec3(0.0, 0.15, -1.0));
vec3 V = normalize(uCameraPos - vWorldPos);
float metallic = hasData ? 0.0 : 0.90;
float roughness = hasData ? 0.78 : ((uRenderMode == 1) ? 0.70 : 0.55);
// float metallic = hasData ? 0.0 : 0.90;
// float roughness = hasData ? 0.78 : ((uRenderMode == 1) ? 0.70 : 0.55);
float metallic = 0.90;
float roughness = 0.55;
vec3 keyL = normalize(vec3(0.55, 1.00, 0.25));
vec3 fillL = normalize(vec3(-0.30, 0.70, -0.80));
// "Front light": make the light come from the camera direction (like a headlight/flashlight).
vec3 keyL = V;
vec3 fillL = V;
vec3 keyC = vec3(1.00, 0.98, 0.95) * 1.8;
vec3 fillC = vec3(0.85, 0.90, 1.00) * 0.9;

View File

@@ -12,18 +12,18 @@ out vec3 vWorldPos;
uniform mat4 uMVP; // Projection * View * Model这里 Model 约等于单位矩阵)
uniform float uDotRadius; // dot 半径(世界坐标单位)
uniform float uBaseY; // dot 的高度(通常 = panel 顶面 y + 一点点偏移)
uniform float uBaseZ; // dot 的高度(通常 = panel 顶面 y + 一点点偏移)
void main() {
vUV = aUV;
vValue = iValue;
// 先确定 dot 的中心点(世界坐标)
vec3 world = vec3(iOffsetXZ.x, uBaseY, iOffsetXZ.y);
vec3 world = vec3(iOffsetXZ.x, iOffsetXZ.y, uBaseZ);
// 再把单位 quad 按半径缩放并加到中心点上(让 quad 落在 XZ 平面)
world.x += qQuadPos.x * uDotRadius;
world.z += qQuadPos.y * uDotRadius;
world.y += qQuadPos.y * uDotRadius;
// 输出裁剪空间坐标(最终会进行透视除法与视口映射,变成屏幕上的像素)
vWorldPos = world;

View File

@@ -12,6 +12,7 @@ uniform int uCols;
uniform float uPitch;
uniform float uDotRadius;
uniform int uRenderMode; // 0=realistic, 1=dataViz
uniform bool uLightMode;
const float PI = 3.14159265359;
@@ -146,10 +147,31 @@ void main() {
// ------------------------------------------------------------
// Industrial engineering model: neutral matte gray panel (support layer only)
// ------------------------------------------------------------
vec3 topBase = vec3(0.30, 0.31, 0.32);
vec3 sideBase = vec3(0.27, 0.28, 0.29);
vec3 topBase, sideBase;
vec3 edgeCol, rimCol;
if (uLightMode) {
topBase = vec3(0.30, 0.31, 0.32);
sideBase = vec3(0.27, 0.28, 0.29);
edgeCol = vec3(0.020);
rimCol = vec3(0.015);
}
else {
topBase = vec3(0.78, 0.80, 0.84);
sideBase = vec3(0.68, 0.70, 0.74);
edgeCol = vec3(0.010, 0.12, 0.16);
rimCol = vec3(0.12, 0.14, 0.18);
}
vec3 baseColor = mix(sideBase, topBase, isTop);
// dataViz: flat/unlit, no lighting modulation (keep pure baseColor)
if (uRenderMode == 1) {
FragColor = vec4(clamp(baseColor, 0.0, 1.0), 1.0);
return;
}
vec2 xz = vWorldPos.xz;
float dotContact = 0.0;
if (isTop > 0.5 && uDotRadius > 0.0) {
@@ -158,9 +180,11 @@ void main() {
dotContact = 1.0 - smoothstep(uDotRadius, uDotRadius + w, d);
}
vec3 L = normalize(vec3(0.45, 1.00, 0.20));
// "Front light": make the light come from the camera direction (like a headlight/flashlight).
vec3 L = V;
// L = normalize(vec3(0.0, 0.15, -1.0));
float diff = saturate(dot(N, L));
float lighting = 0.90 + 0.10 * diff;
float lighting = uLightMode ? (0.90 + 0.10 * diff) : (0.95 + 0.12 * diff);
float hw = max(1e-6, uPanelW * 0.5);
float hd = max(1e-6, uPanelD * 0.5);
@@ -172,8 +196,8 @@ void main() {
float ao = 1.0 - dotContact * 0.08;
vec3 col = baseColor * lighting * ao;
col += edgeLine * vec3(0.020);
col += rim * vec3(0.015);
col += edgeLine * edgeCol;
col += rim * rimCol;
// Slightly deepen the bottom face to read as thickness, but keep it subtle.
float isBottom = step(0.75, -N.y);

108
shaders/room.frag Normal file
View File

@@ -0,0 +1,108 @@
#version 330 core
in vec3 vWorldPos;
in vec3 vWorldNormal;
out vec4 FragColor;
uniform vec3 uCameraPos;
uniform vec3 uRoomHalfSize;
uniform float uMinorStep;
uniform float uMajorStep;
uniform int uRenderMode; // 0=realistic, 1=dataViz (flat/unlit)
uniform bool uLightMode;
uniform bool uShowGrid;
float saturate(float x) {
return clamp(x, 0.0, 1.0);
}
float gridLine(vec2 coord, float stepSize) {
stepSize = max(stepSize, 1e-4);
vec2 q = coord / stepSize;
vec2 g = abs(fract(q - 0.5) - 0.5) / fwidth(q);
return 1.0 - min(min(g.x, g.y), 1.0);
}
vec2 pickGridPlane(vec3 N, vec3 P) {
// 根据朝向选择在哪个平面画网格:
// - 地面/天花板(法线接近 ±Y用 XZ
// - 前后墙(法线接近 ±Z用 XY
// - 左右墙(法线接近 ±X用 ZY
vec3 a = abs(N);
if (a.y > a.x && a.y > a.z) return P.xz;
if (a.z > a.x) return P.xy;
return P.zy;
}
void main() {
vec3 N = normalize(vWorldNormal);
vec3 V = normalize(uCameraPos - vWorldPos);
// 区分地面/天花板/墙面配色(简单做个“房间感”)
float isFloor = step(0.8, N.y);
float isCeil = step(0.8, -N.y);
vec3 floorCol;
vec3 wallCol;
vec3 ceilCol;
vec3 minorCol;
vec3 majorCol;
vec3 fogCol;
if (uLightMode) {
floorCol = vec3(0.90, 0.90, 0.92);
wallCol = vec3(0.96, 0.96, 0.98);
ceilCol = vec3(0.98, 0.98, 1.00);
minorCol = vec3(0.78, 0.80, 0.85);
majorCol = vec3(0.68, 0.70, 0.77);
fogCol = vec3(0.985, 0.987, 0.995);
} else {
floorCol = vec3(0.12, 0.13, 0.15);
wallCol = vec3(0.16, 0.17, 0.20);
ceilCol = vec3(0.18, 0.19, 0.22);
minorCol = vec3(0.22, 0.24, 0.28);
majorCol = vec3(0.30, 0.33, 0.40);
fogCol = vec3(0.10, 0.11, 0.13);
}
vec3 baseCol = wallCol;
baseCol = mix(baseCol, floorCol, isFloor);
baseCol = mix(baseCol, ceilCol, isCeil);
// 在不同面上画网格:小格 + 大格
if (uShowGrid) {
vec2 plane = pickGridPlane(N, vWorldPos);
float minor = gridLine(plane, uMinorStep);
float major = gridLine(plane, uMajorStep);
baseCol = mix(baseCol, minorCol, minor * 0.18);
baseCol = mix(baseCol, majorCol, major * 0.28);
}
// dataViz: flat/unlit, no lighting modulation (keep pure baseCol + grid)
if (uRenderMode == 1) {
FragColor = vec4(clamp(baseCol, 0.0, 1.0), 1.0);
return;
}
// 简单两盏灯:主光 + 补光(够用就好)
// "Front light": make the light come from the camera direction (like a headlight/flashlight).
vec3 keyL = V;
vec3 fillL = V;
float diff1 = max(dot(N, keyL), 0.0);
float diff2 = max(dot(N, fillL), 0.0);
float lighting = 0.65 + 0.25 * diff1 + 0.10 * diff2;
// 角落稍微压暗,增强“箱体/房间”感觉
vec3 p = abs(vWorldPos / max(uRoomHalfSize, vec3(1e-4)));
float corner = pow(max(p.x, max(p.y, p.z)), 6.0);
float cornerDark = mix(1.0, 0.80, corner);
// 轻微雾化:远处更亮一点点,让边界更柔和
float dist = length(uCameraPos - vWorldPos);
float fog = exp(-dist * 0.06);
vec3 col = baseCol * lighting * cornerDark;
col = mix(fogCol, col, saturate(fog));
// 增加一点边缘轮廓(靠观察方向)
float rim = pow(1.0 - saturate(dot(N, V)), 2.0);
col += rim * 0.04;
FragColor = vec4(clamp(col, 0.0, 1.0), 1.0);
}

19
shaders/room.vert Normal file
View File

@@ -0,0 +1,19 @@
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aN;
out vec3 vWorldPos;
out vec3 vWorldNormal;
uniform mat4 uMVP;
uniform vec3 uRoomHalfSize;
void main() {
// 把单位立方体 [-1,1] 缩放成房间大小
vec3 world = aPos * uRoomHalfSize;
vWorldPos = world;
vWorldNormal = aN;
gl_Position = uMVP * vec4(world, 1.0);
}