AI 精选动态
智能评分 60
Ethan Mollick 对比 GPT-5.2 与 GLM-5.2 Deep Think Max Shader 生成
AI 推荐理由
提供了可直接运行的对比代码,可直观评估两模型在复杂几何与程序化生成任务上的代码质量差异。核心解读
Ethan Mollick 对比了 7 个月前的 GPT-5.2 与 GLM-5.2 Deep Think Max 在单次生成 Twigl 着色器任务上的表现,任务为创建部分淹没在风暴海洋中的无限新哥特式塔楼城市,GLM-5.2 出现几处错误。
全文
Compare GPT-5.2 from 7 months ago with the new GLM-5.2 Deep Think Max's: "create a visually interesting shader that can run in twigl with an infinite city of neo-gothic towers partially drowned in a stormy ocean with large waves" "Make it better"
GLM-5.2 also had a couple errors https://t.co/335KN2j1Jy
https://video.twimg.com/amplify_video/2066963414887329792/vid/avc1/1888x668/KIoSH8XKr4Ev_sps.mp4?tag=28
> **引用原帖 Ethan Mollick (@emollick):**
> Had early access to GPT-5.2. Its an impressive model.
> Here is GPT 5.2 Pro's version of "create a visually interesting shader that can run in twigl-dot-app make it like an infinite city of neo-gothic towers partially drowned in a stormy ocean with large waves," single shot. https://t.co/ZLeXZ7OIIn
> https://x.com/emollick/status/1999185085719887978
Ethan Mollick (@emollick): precision highp float;
uniform vec2 resolution;
uniform float time;
// --- Hash & Noise Functions ---
float hash(vec2 p) {
p = fract(p * vec2(123.34, 456.21));
p += dot(p, p + 45.32);
return fract(p.x * p.y);
}
float noise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
f = f * f * (3.0 - 2.0 * f);
return mix(mix(hash(i), hash(i + vec2(1.0, 0.0)), f.x),
mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), f.x), f.y);
}
float fbm(vec2 p) {
float v = 0.0;
float a = 0.5;
mat2 m = mat2(1.6, 1.2, -1.2, 1.6);
for(int i = 0; i < 5; i++) {
v += a * noise(p);
p = m * p;
a *= 0.5;
}
return v;
}
// --- SDFs ---
float sdOctagon(vec2 p, float r) {
p = abs(p);
float d = max(p.x, p.y) - r;
d = max(d, dot(p, vec2(0.70710678)) - r * 1.12);
return d;
}
float sdCone(vec3 p, vec2 dim) {
vec2 q = vec2(length(p.xz), p.y);
return max(dot(q, vec2(dim.y, -dim.x)), -q.y - dim.x);
}
// --- Ocean (Gerstner-inspired waves) ---
float waveHeight(vec2 p) {
float t = time * 1.5;
float h = 0.0;
h += sin(p.x * 0.15 + t) * 3.0;
h += sin(p.y * 0.25 - t * 1.3) * 2.0;
h += sin((p.x + p.y) * 0.3 + t * 1.7) * 1.5;
h += fbm(p * 0.4 + vec2(t * 0.2, -t * 0.3)) * 5.0;
return h;
}
// --- Scene Map ---
vec2 map(vec3 p) {
float oceanBase = -1.5;
float ocean = p.y - (oceanBase + waveHeight(p.xz));
float city = 1000.0;
float cellSize = 18.0;
vec2 id = floor(p.xz / cellSize);
vec2 q = mod(p.xz, cellSize) - cellSize * 0.5;
float rnd = hash(id);
float rnd2 = hash(id + 1.0);
if (rnd > 0.15) {
float w = 2.5 + rnd * 1.5;
float h = 35.0 + rnd2 * 70.0;
float baseY = -25.0;
// Tapered Main Body
float taperY = clamp((p.y - baseY) / max(0.1, h - baseY), 0.0, 1.0);
float taper = mix(1.3, 0.5, taperY);
float dOct = sdOctagon(q / taper, w) * taper;
// Gothic Vertical Ribs
float angle = atan(q.x, q.y);
float ribs = cos(angle * 8.0) * 0.15;
dOct += ribs * smoothstep(h, h - 15.0, p.y) * smoothstep(baseY, baseY + 10.0, p.y);
float body = max(dOct, max(p.y - h, baseY - p.y));
city = min(city, body);
// Central Spire
if (p.y > h - 2.0) {
float spireH = 20.0 + rnd2 * 15.0;
float spire = sdCone(vec3(q.x, p.y - h, q.y), vec2(w * 0.8, spireH));
city = min(city, spire);
}
// Corner Spires (Buttresses)
vec2 cornerOffset = vec2(w + 1.5);
for(int i = 0; i < 4; i++) {
vec2 c = cornerOffset;
if(i == 1) c.x = -c.x;
if(i == 2) c.y = -c.y;
if(i == 3) c = -c;
vec2 cq = q - c;
float c_h = h * 0.75 + rnd2 * 10.0;
float c_taperY = clamp((p.y - baseY) / max(0.1, c_h - baseY), 0.0, 1.0);
float c_taper = mix(1.2, 0.4, c_taperY);
float c_dOct = sdOctagon(cq / c_taper, 0.8) * c_taper;
float cBody = max(c_dOct, max(p.y - c_h, baseY - p.y));
city = min(city, cBody);
// Small spires on corners
if (p.y > c_h - 1.0) {
float c_spireH = 10.0 + rnd2 * 5.0;
float c_spire = sdCone(vec3(cq.x, p.y - c_h, cq.y), vec2(0.7, c_spireH));
city = min(city, c_spire);
}
// Flying Buttresses connecting to main tower
if (p.y > baseY && p.y < c_h) {
vec2 dir = normalize(-c);
vec2 perp = vec2(-dir.y, dir.x);
float dist = dot(q - c, dir);
float rad = abs(dot(q - c, perp));
float arch = sin(clamp(dist / length(cornerOffset), 0.0, 3.14) * 0.5) * 2.0;
float buttress = max(rad - 0.4, max(p.y - (c_h * 0.6 + arch), dist - length(cornerOffset)));
city = min(city, buttress);
}
}
}
if (city < ocean) return vec2(city, 1.0);
return vec2(ocean, 0.0);
}
vec3 calcNormal(vec3 p) {
vec2 e = vec2(1.0, -1.0) * 0.02;
return normalize(
e.xyy * map(p + e.xyy).x +
e.yyx * map(p + e.yyx).x +
e.yxy * map(p + e.yxy).x +
https://t.co/6lZjGExq0y * map(p + https://t.co/6lZjGExq0y).x
);
}
// --- Lightning System ---
float getLightningFlash() {
float flashTime = floor(time * 1.5);
float flashRnd = hash(vec2(flashTime, 1.0));
if (flashRnd > 0.92) {
float flashFrac = fract(time * 1.5);
return pow(1.0 - flashFrac, 6.0) + step(0.8, flashRnd) * step(flashFrac, 0.2);
}
return 0.0;
}
float lightningBolt(vec3 ro, vec3 rd, float seed) {
vec3 p = vec3(hash(vec2(seed, 1.0)) * 40.0 - 20.0, 30.0, 50.0);
vec3 dir = normalize(vec3(hash(vec2(seed, 2.0)) * 2.0 - 1.0, -1.0, -0.2));
float dist = 1000.0;
for(int i = 0; i < 8; i++) {
vec3 toP = p - ro;
float t = dot(toP, rd);
vec3 closest = ro + rd * t;
dist = min(dist, length(closest - p));
// Move bolt point down
p += dir * 5.0;
// Jitter direction
dir.x += (hash(vec2(seed, float(i))) - 0.5) * 0.8;
dir = normalize(dir);
}
return 0.005 / (dist * dist + 0.01);
}
// --- ACES Tonemapping ---
vec3 ACESFilm(vec3 x) {
float a = 2.51;
float b = 0.03;
float c = 2.43;
float d = 0.59;
float e = 0.14;
return clamp((x * (a * x + b)) / (x * (c * x + d) + e), 0.0, 1.0);
}
void main() {
vec2 uv = (gl_FragCoord.xy - resolution.xy * 0.5) / resolution.y;
// Cinematic High Altitude Camera (Sweeping over the city)
// Starts at Z=40.0 so we are immediately over the city, not empty ocean
vec3 ro = vec3(sin(time * 0.08) * 25.0, 55.0 + sin(time * 0.2) * 8.0, time * 5.0 + 40.0);
vec3 ta = vec3(sin(time * 0.08 + 0.5) * 12.0, 10.0 + sin(time * 0.4) * 3.0, ro.z + 50.0);
vec3 ww = normalize(ta - ro);
vec3 uu = normalize(cross(ww, vec3(0.0, 1.0, 0.0)));
vec3 vv = normalize(cross(uu, ww));
// Chromatic Aberration
float ca = 0.003;
vec3 rd = normalize(uv.x * uu + uv.y * vv + 1.4 * ww);
vec3 rdR = normalize((uv.x - ca) * uu + uv.y * vv + 1.4 * ww);
vec3 rdB = normalize((uv.x + ca) * uu + uv.y * vv + 1.4 * ww);
// Raymarch
float t = 0.0, tR = 0.0, tB = 0.0;
float matID = -1.0;
for(int i = 0; i < 120; i++) {
vec3 p = ro + rd * t;
vec2 res = map(p);
if(res.x < 0.01) { matID = res.y; break; }
t += res.x * 0.8; // slow down near surfaces for precision
if(t > 250.0) break;
}
// Accurate Chromatic Aberration Depth
if(matID > -1.0) {
tR = t; tB = t;
for(int i = 0; i < 6; i++) {
float dR = map(ro + rdR * tR).x;
if(dR < 0.01) break;
tR += dR * 0.5;
}
for(int i = 0; i < 6; i++) {
float dB = map(ro + rdB * tB).x;
if(dB < 0.01) break;
tB += dB * 0.5;
}
}
float lightning = getLightningFlash();
vec3 moonColor = vec3(0.3, 0.4, 0.6);
vec3 lightningColor = vec3(0.9, 0.95, 1.0);
vec3 col = vec3(0.0);
if(matID >= 0.0) {
vec3 p = ro + rd * t;
vec3 pR = ro + rdR * tR;
vec3 pB = ro + rdB * tB;
vec3 n = calcNormal(p);
vec3 lightDir = normalize(vec3(0.5, 0.6, 0.3));
if(matID < 0.5) {
// Ocean
float spec = pow(max(0.0, dot(reflect(-lightDir, n), -rd)), 80.0);
vec3 baseCol = mix(vec3(0.01, 0.02, 0.03), vec3(0.05, 0.1, 0.12), n.y);
float foam = smoothstep(2.0, 5.0, waveHeight(p.xz));
baseCol = mix(baseCol, vec3(0.6, 0.7, 0.75), foam);
col = baseCol * (n.y * 0.5 + 0.5);
col += spec * moonColor * 1.2;
col += spec * lightningColor * lightning * 10.0;
// Foam color separation
col.r += smoothstep(2.0, 5.0, waveHeight(pR.xz)) * 0.2;
col.b += smoothstep(2.0, 5.0, waveHeight(pB.xz)) * 0.2;
} else {
// Gothic City
float diff = max(0.0, dot(n, lightDir));
// Slightly brightened ambient so towers aren't invisible between lightning strikes
vec3 baseCol = vec3(0.07, 0.08, 0.09) * (diff * 0.6 + 0.4);
float spec = pow(max(0.0, dot(reflect(-lightDir, n), -rd)), 24.0);
baseCol += spec * moonColor * 0.3;
baseCol += spec * lightningColor * lightning * 5.0;
// Glowing Windows (Simplified and robust logic)
vec2 id = floor(p.xz / 18.0);
vec2 lq = mod(p.xz, 18.0) - 9.0;
float wr = 2.5 + hash(id) * 1.5;
// Window strips
float winX = abs(mod(lq.x, 1.5) - 0.75);
float winShape = step(winX, 0.2);
float winY = abs(fract(p.y * 0.25) - 0.5);
winShape *= step(winY, 0.35);
float winId = hash(id + floor(p.y * 0.25));
float winMask = winShape * step(0.6, winId);
vec3 winCol = vec3(1.0, 0.6, 0.2) * winMask * 2.0; // Brighter glow
winCol *= 0.7 + 0.3 * sin(time * 8.0 + winId * 100.0);
baseCol += winCol;
col = baseCol;
// Window CA
float winShapeR = step(abs(mod(lq.x, 1.5) - 0.75), 0.2) * step(abs(fract(pR.y * 0.25) - 0.5), 0.35);
col.r += winShapeR * step(0.6, hash(id + floor(pR.y * 0.25))) * 1.0;
float winShapeB = step(abs(mod(lq.x, 1.5) - 0.75), 0.2) * step(abs(fract(pB.y * 0.25) - 0.5), 0.35);
col.b += winShapeB * step(0.6, hash(id + floor(pB.y * 0.25))) * 1.0;
}
// Volumetric Height Fog
vec3 fogCol = mix(vec3(0.01, 0.02, 0.03), vec3(0.05, 0.07, 0.09), clamp(rd.y * 0.5 + 0.5, 0.0, 1.0));
fogCol += lightningColor * lightning * 0.4;
float fogDensity = exp(-p.y * 0.05) * 0.04;
float fog = 1.0 - exp(-t * fogDensity);
col = mix(col, fogCol, clamp(fog, 0.0, 0.9));
} else {
// Sky
vec3 skyCol = mix(vec3(0.005, 0.01, 0.02), vec3(0.04, 0.05, 0.07), clamp(rd.y * 0.5 + 0.5, 0.0, 1.0));
// Volumetric Clouds
if(rd.y > 0.0) {
vec2 skyUV = rd.xz / rd.y;
float clouds = fbm(skyUV * 1.5 + vec2(time * 0.05, 0.0));
clouds = smoothstep(0.4, 0.8, clouds) * rd.y;
skyCol = mix(skyCol, vec3(0.02, 0.03, 0.04), clouds);
skyCol += lightningColor * lightning * (1.0 - rd.y) * 0.5;
}
// Lightning Bolts
float boltSeed = floor(time * 1.5);
if(hash(vec2(boltSeed, 1.0)) > 0.92) {
skyCol += lightningColor * lightningBolt(ro, rd, boltSeed) * 50.0;
if(hash(vec2(boltSeed, 2.0)) > 0.5) {
skyCol += lightningColor * lightningBolt(ro, rd, boltSeed + 1.0) * 50.0;
}
}
col = skyCol;
}
// Driving Rain (Parallax layers)
for(float i = 1.0; i <= 4.0; i++) {
vec2 rUV = uv * (5.0 + i * 3.0);
rUV.y += time * (15.0 + i * 5.0); // Speed
rUV.x += sin(time * 1.0 + i) * 2.0 - ro.z * 0.1; // Wind + Camera Z movement
float d = abs(rUV.x - floor(rUV.x + 0.5));
float rain = smoothstep(0.06, 0.0, d) * smoothstep(0.5, 0.4, fract(rUV.y));
col += rain * vec3(0.5, 0.6, 0.7) * (0.2 / i);
}
// Color Grading & Vignette
col = ACESFilm(col * 1.1);
col = pow(col, vec3(0.9, 0.95, 1.0)); // Slight color shift
float vignette = smoothstep(1.4, 0.3, length(uv));
col *= vignette;
// Film Grain
col += (hash(gl_FragCoord.xy + time) - 0.5) * 0.03;
gl_FragColor = vec4(col, 1.0);
}