emergency: make emergency lights visible outside night

This commit is contained in:
Richard Zink committed 2026-10-13 07:08:20 +02:00
1 parent 4f5cae83c9
commit 03ae45e0e5
2 files changed
+108 -65

No files matched your search

+1 -1
View File
@@ -134,7 +134,7 @@ window.CONFIG = {
rankMax: 1, // 0=city, 1=town rankMax: 1, // 0=city, 1=town
color: [0.22, 0.55, 1.0], color: [0.22, 0.55, 1.0],
flashHz: 2.2, flashHz: 2.2,
nightOnly: true, nightOnly: false,
bright: 1.35 bright: 1.35
// emergencyVehicles: { enabled: false } // emergencyVehicles: { enabled: false }
// emergencyVehicles: { count: 6, speedKmh: 110, minKm: 25, maxKm: 120 } // emergencyVehicles: { count: 6, speedKmh: 110, minKm: 25, maxKm: 120 }
+107 -64
View File
@@ -4256,11 +4256,59 @@ var CARP_FRAG_SRC = [
// piece in the evening and goes dark piece by piece in the morning. // piece in the evening and goes dark piece by piece in the morning.
'float thr = mix(uLightHi, uLightLo, hash1(vSeed * 1.618 + 5.13));', 'float thr = mix(uLightHi, uLightLo, hash1(vSeed * 1.618 + 5.13));',
'float lit = 1.0 - smoothstep(thr - uLightSoft, thr + uLightSoft, uSunAlt);', 'float lit = 1.0 - smoothstep(thr - uLightSoft, thr + uLightSoft, uSunAlt);',
'if (uEmergency > 0.5 && uEmergencyNightOnly < 0.5) lit = 1.0;',
'if (lit <= 0.001) discard;', 'if (lit <= 0.001) discard;',
'gl_FragColor = vec4(col * inten * g * lit * df, 1.0);', 'gl_FragColor = vec4(col * inten * g * lit * df, 1.0);',
'}' '}'
].join('\n'); ].join('\n');
function ensureCarPtsProgram(gl) {
if (carPtsProg) return carPtsProg;
var cpp = makeProgram(gl, CARP_VERT_SRC, CARP_FRAG_SRC);
if (!cpp) return null;
carPtsProg = cpp;
carPtsAttribs = {
pos: gl.getAttribLocation(cpp, 'aPos'),
meta: gl.getAttribLocation(cpp, 'aMeta'),
dens: gl.getAttribLocation(cpp, 'aDens'),
seed: gl.getAttribLocation(cpp, 'aSeed'),
len: gl.getAttribLocation(cpp, 'aLen')
};
carPtsUniforms = {
proj: gl.getUniformLocation(cpp, 'uProj'),
view: gl.getUniformLocation(cpp, 'uView'),
camPos: gl.getUniformLocation(cpp, 'uCamPos'),
earthRadius: gl.getUniformLocation(cpp, 'uEarthRadius'),
curvatureOn: gl.getUniformLocation(cpp, 'uCurvatureOn'),
time: gl.getUniformLocation(cpp, 'uTime'),
night: gl.getUniformLocation(cpp, 'uNight'),
speed: gl.getUniformLocation(cpp, 'uSpeed'),
dash: gl.getUniformLocation(cpp, 'uDash'),
laneW: gl.getUniformLocation(cpp, 'uLaneW'),
lanePx: gl.getUniformLocation(cpp, 'uLanePx'),
pxW: gl.getUniformLocation(cpp, 'uPxW'),
traffic: gl.getUniformLocation(cpp, 'uTraffic'),
minPx: gl.getUniformLocation(cpp, 'uMinPx'),
maxPx: gl.getUniformLocation(cpp, 'uMaxPx'),
boost: gl.getUniformLocation(cpp, 'uBoost'),
dens: gl.getUniformLocation(cpp, 'uDens'),
bright: gl.getUniformLocation(cpp, 'uBright'),
fadeA: gl.getUniformLocation(cpp, 'uFadeA'),
fadeB: gl.getUniformLocation(cpp, 'uFadeB'),
sunAlt: gl.getUniformLocation(cpp, 'uSunAlt'),
lightHi: gl.getUniformLocation(cpp, 'uLightHi'),
lightLo: gl.getUniformLocation(cpp, 'uLightLo'),
lightSoft: gl.getUniformLocation(cpp, 'uLightSoft'),
wet: gl.getUniformLocation(cpp, 'uWet'),
wetGain: gl.getUniformLocation(cpp, 'uWetGain'),
emergency: gl.getUniformLocation(cpp, 'uEmergency'),
emergencyColor: gl.getUniformLocation(cpp, 'uEmergencyColor'),
emergencyFlashHz: gl.getUniformLocation(cpp, 'uEmergencyFlashHz'),
emergencyNightOnly: gl.getUniformLocation(cpp, 'uEmergencyNightOnly')
};
return cpp;
}
// ---- Off-main-thread geo build ------------------------------------------- // ---- Off-main-thread geo build -------------------------------------------
// Chain stitching, the motorway distance field and the car/settlement // Chain stitching, the motorway distance field and the car/settlement
// ribbon geometry are pure functions of plain data, so they run in a Web // ribbon geometry are pure functions of plain data, so they run in a Web
@@ -7148,51 +7196,7 @@ window.clouds3dRender = function(target) {
carDrawGroup(carVboB, carCountB, CAR_B_DENS); carDrawGroup(carVboB, carCountB, CAR_B_DENS);
// -- vehicle lights: round point sprites -- // -- vehicle lights: round point sprites --
if (carPtsCountM || carPtsCountB) { if (carPtsCountM || carPtsCountB) {
if (!carPtsProg) { ensureCarPtsProgram(gl);
var cpp = makeProgram(gl, CARP_VERT_SRC, CARP_FRAG_SRC);
if (cpp) {
carPtsProg = cpp;
carPtsAttribs = {
pos: gl.getAttribLocation(cpp, 'aPos'),
meta: gl.getAttribLocation(cpp, 'aMeta'),
dens: gl.getAttribLocation(cpp, 'aDens'),
seed: gl.getAttribLocation(cpp, 'aSeed'),
len: gl.getAttribLocation(cpp, 'aLen')
};
carPtsUniforms = {
proj: gl.getUniformLocation(cpp, 'uProj'),
view: gl.getUniformLocation(cpp, 'uView'),
camPos: gl.getUniformLocation(cpp, 'uCamPos'),
earthRadius: gl.getUniformLocation(cpp, 'uEarthRadius'),
curvatureOn: gl.getUniformLocation(cpp, 'uCurvatureOn'),
time: gl.getUniformLocation(cpp, 'uTime'),
night: gl.getUniformLocation(cpp, 'uNight'),
speed: gl.getUniformLocation(cpp, 'uSpeed'),
dash: gl.getUniformLocation(cpp, 'uDash'),
laneW: gl.getUniformLocation(cpp, 'uLaneW'),
lanePx: gl.getUniformLocation(cpp, 'uLanePx'),
pxW: gl.getUniformLocation(cpp, 'uPxW'),
traffic: gl.getUniformLocation(cpp, 'uTraffic'),
minPx: gl.getUniformLocation(cpp, 'uMinPx'),
maxPx: gl.getUniformLocation(cpp, 'uMaxPx'),
boost: gl.getUniformLocation(cpp, 'uBoost'),
dens: gl.getUniformLocation(cpp, 'uDens'),
bright: gl.getUniformLocation(cpp, 'uBright'),
fadeA: gl.getUniformLocation(cpp, 'uFadeA'),
fadeB: gl.getUniformLocation(cpp, 'uFadeB'),
sunAlt: gl.getUniformLocation(cpp, 'uSunAlt'),
lightHi: gl.getUniformLocation(cpp, 'uLightHi'),
lightLo: gl.getUniformLocation(cpp, 'uLightLo'),
lightSoft: gl.getUniformLocation(cpp, 'uLightSoft'),
wet: gl.getUniformLocation(cpp, 'uWet'),
wetGain: gl.getUniformLocation(cpp, 'uWetGain'),
emergency: gl.getUniformLocation(cpp, 'uEmergency'),
emergencyColor: gl.getUniformLocation(cpp, 'uEmergencyColor'),
emergencyFlashHz: gl.getUniformLocation(cpp, 'uEmergencyFlashHz'),
emergencyNightOnly: gl.getUniformLocation(cpp, 'uEmergencyNightOnly')
};
}
}
if (carPtsProg) { if (carPtsProg) {
gl.useProgram(carPtsProg); gl.useProgram(carPtsProg);
gl.uniformMatrix4fv(carPtsUniforms.proj, false, proj); gl.uniformMatrix4fv(carPtsUniforms.proj, false, proj);
@@ -7246,25 +7250,64 @@ window.clouds3dRender = function(target) {
}; };
carPtsGroup(carPtsVboM, carPtsCountM, CAR_M_DASH, CAR_M_SPEED, CAR_M_DENS); carPtsGroup(carPtsVboM, carPtsCountM, CAR_M_DASH, CAR_M_SPEED, CAR_M_DENS);
carPtsGroup(carPtsVboB, carPtsCountB, CAR_B_DASH, CAR_B_SPEED, CAR_B_DENS); carPtsGroup(carPtsVboB, carPtsCountB, CAR_B_DASH, CAR_B_SPEED, CAR_B_DENS);
var emergencyDrawCount = updateEmergencyVehicles(now);
if (emergencyDrawCount > 0) { }
if (!emergencyVbo) emergencyVbo = gl.createBuffer(); }
gl.bindBuffer(gl.ARRAY_BUFFER, emergencyVbo); var emergencyDrawCount = updateEmergencyVehicles(now);
gl.bufferData(gl.ARRAY_BUFFER, emergencyPts.subarray(0, emergencyDrawCount * 10), gl.DYNAMIC_DRAW); if (emergencyDrawCount > 0 && (!EMERGENCY_NIGHT_ONLY || carNight > 0.01)) {
gl.vertexAttribPointer(carPtsAttribs.pos, 3, gl.FLOAT, false, 40, 0); ensureCarPtsProgram(gl);
gl.vertexAttribPointer(carPtsAttribs.meta, 4, gl.FLOAT, false, 40, 12); if (carPtsProg) {
gl.vertexAttribPointer(carPtsAttribs.dens, 1, gl.FLOAT, false, 40, 28); var emergencyPxScale = Math.max(0.45, Math.min(1.25, gl.drawingBufferHeight / 1080));
gl.vertexAttribPointer(carPtsAttribs.seed, 1, gl.FLOAT, false, 40, 32); gl.useProgram(carPtsProg);
gl.vertexAttribPointer(carPtsAttribs.len, 1, gl.FLOAT, false, 40, 36); gl.uniformMatrix4fv(carPtsUniforms.proj, false, proj);
gl.uniform1f(carPtsUniforms.dash, 0.0); gl.uniformMatrix4fv(carPtsUniforms.view, false, view);
gl.uniform1f(carPtsUniforms.speed, 0.0); gl.uniform3f(carPtsUniforms.camPos, camX, camY, camZ);
gl.uniform1f(carPtsUniforms.dens, 1.0); gl.uniform1f(carPtsUniforms.earthRadius, EARTH_RADIUS_UNITS);
gl.uniform1f(carPtsUniforms.bright, EMERGENCY_BRIGHT); gl.uniform1f(carPtsUniforms.curvatureOn, CURVATURE_ON ? 1.0 : 0.0);
gl.uniform1f(carPtsUniforms.emergency, 1.0); gl.uniform1f(carPtsUniforms.time, now);
gl.drawArrays(gl.POINTS, 0, emergencyDrawCount); gl.uniform1f(carPtsUniforms.night, carNight);
gl.uniform1f(carPtsUniforms.emergency, 0.0); gl.uniform1f(carPtsUniforms.sunAlt, window.__currentSunAlt || 0);
gl.uniform1f(carPtsUniforms.bright, CAR_BRIGHT); gl.uniform1f(carPtsUniforms.lightHi, LIGHT_HI);
} gl.uniform1f(carPtsUniforms.lightLo, LIGHT_LO);
gl.uniform1f(carPtsUniforms.lightSoft, LIGHT_SOFT);
gl.uniform1f(carPtsUniforms.laneW, CAR_LANE_W);
gl.uniform1f(carPtsUniforms.lanePx, CAR_LANE_PX * emergencyPxScale);
gl.uniform1f(carPtsUniforms.pxW, 1.1547 / gl.drawingBufferHeight);
gl.uniform1f(carPtsUniforms.traffic, CAR_TRAFFIC);
gl.uniform1f(carPtsUniforms.minPx, CAR_MIN_PX * emergencyPxScale * 1.35);
gl.uniform1f(carPtsUniforms.maxPx, CAR_MAX_PX * emergencyPxScale * 1.6);
gl.uniform1f(carPtsUniforms.boost, CAR_BOOST * emergencyPxScale * 1.4);
gl.uniform1f(carPtsUniforms.bright, EMERGENCY_BRIGHT);
gl.uniform1f(carPtsUniforms.fadeA, CAR_FADE_A);
gl.uniform1f(carPtsUniforms.fadeB, CAR_FADE_B);
gl.uniform1f(carPtsUniforms.wet, _roadWet);
gl.uniform1f(carPtsUniforms.wetGain, WET_LIGHT_GAIN);
gl.uniform1f(carPtsUniforms.emergency, 1.0);
gl.uniform3f(carPtsUniforms.emergencyColor, EMERGENCY_COLOR[0], EMERGENCY_COLOR[1], EMERGENCY_COLOR[2]);
gl.uniform1f(carPtsUniforms.emergencyFlashHz, EMERGENCY_FLASH_HZ);
gl.uniform1f(carPtsUniforms.emergencyNightOnly, EMERGENCY_NIGHT_ONLY ? 1.0 : 0.0);
gl.uniform1f(carPtsUniforms.dash, 0.0);
gl.uniform1f(carPtsUniforms.speed, 0.0);
gl.uniform1f(carPtsUniforms.dens, 1.0);
gl.enable(gl.DEPTH_TEST);
gl.depthMask(false);
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE);
if (!emergencyVbo) emergencyVbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, emergencyVbo);
gl.bufferData(gl.ARRAY_BUFFER, emergencyPts.subarray(0, emergencyDrawCount * 10), gl.DYNAMIC_DRAW);
gl.enableVertexAttribArray(carPtsAttribs.pos);
gl.vertexAttribPointer(carPtsAttribs.pos, 3, gl.FLOAT, false, 40, 0);
gl.enableVertexAttribArray(carPtsAttribs.meta);
gl.vertexAttribPointer(carPtsAttribs.meta, 4, gl.FLOAT, false, 40, 12);
gl.enableVertexAttribArray(carPtsAttribs.dens);
gl.vertexAttribPointer(carPtsAttribs.dens, 1, gl.FLOAT, false, 40, 28);
gl.enableVertexAttribArray(carPtsAttribs.seed);
gl.vertexAttribPointer(carPtsAttribs.seed, 1, gl.FLOAT, false, 40, 32);
gl.enableVertexAttribArray(carPtsAttribs.len);
gl.vertexAttribPointer(carPtsAttribs.len, 1, gl.FLOAT, false, 40, 36);
gl.drawArrays(gl.POINTS, 0, emergencyDrawCount);
gl.uniform1f(carPtsUniforms.emergency, 0.0);
} }
} }
gl.disable(gl.BLEND); gl.disable(gl.BLEND);