Improve WebGL reflection and texture quality

This commit is contained in:
2026-06-04 11:50:25 +02:00
parent bdec4590d2
commit 5127bbc743
+28 -21
View File
@@ -28,6 +28,9 @@ renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.VSMShadowMap; renderer.shadowMap.type = THREE.VSMShadowMap;
const generatedTextureCanvases = {}; const generatedTextureCanvases = {};
const maxTextureAnisotropy = renderer.capabilities.getMaxAnisotropy();
const reflectionPixelRatio = Math.min(window.devicePixelRatio || 1, 2);
const reflectionTargetSize = new THREE.Vector2();
const scene = new THREE.Scene(); const scene = new THREE.Scene();
scene.background = new THREE.Color(0x080604); scene.background = new THREE.Color(0x080604);
@@ -38,14 +41,16 @@ let tableShader = null;
let tableRoomReflectionTexture = createRoomReflectionTexture(); let tableRoomReflectionTexture = createRoomReflectionTexture();
let tableDustTexture = null; let tableDustTexture = null;
const tableTopY = -0.02; const tableTopY = -0.02;
const tableReflectionTarget = new THREE.WebGLRenderTarget(1024, 576, { const tableReflectionTarget = new THREE.WebGLRenderTarget(4096, 2304, {
colorSpace: THREE.SRGBColorSpace, colorSpace: THREE.SRGBColorSpace,
depthBuffer: true, depthBuffer: true,
stencilBuffer: false stencilBuffer: false,
samples: renderer.capabilities.isWebGL2 ? 8 : 0
}); });
tableReflectionTarget.texture.colorSpace = THREE.SRGBColorSpace; tableReflectionTarget.texture.colorSpace = THREE.SRGBColorSpace;
tableReflectionTarget.texture.minFilter = THREE.LinearFilter; tableReflectionTarget.texture.minFilter = THREE.LinearFilter;
tableReflectionTarget.texture.magFilter = THREE.LinearFilter; tableReflectionTarget.texture.magFilter = THREE.LinearFilter;
tableReflectionTarget.texture.anisotropy = maxTextureAnisotropy;
const tableReflectionCamera = new THREE.PerspectiveCamera(); const tableReflectionCamera = new THREE.PerspectiveCamera();
const tableReflectionMatrix = new THREE.Matrix4(); const tableReflectionMatrix = new THREE.Matrix4();
const tableReflectionBiasMatrix = new THREE.Matrix4().set( const tableReflectionBiasMatrix = new THREE.Matrix4().set(
@@ -96,7 +101,7 @@ const leftTexture = new THREE.CanvasTexture(leftCanvas);
const rightTexture = new THREE.CanvasTexture(rightCanvas); const rightTexture = new THREE.CanvasTexture(rightCanvas);
[leftTexture, rightTexture].forEach((texture) => { [leftTexture, rightTexture].forEach((texture) => {
texture.colorSpace = THREE.SRGBColorSpace; texture.colorSpace = THREE.SRGBColorSpace;
texture.anisotropy = renderer.capabilities.getMaxAnisotropy(); texture.anisotropy = maxTextureAnisotropy;
texture.minFilter = THREE.LinearMipmapLinearFilter; texture.minFilter = THREE.LinearMipmapLinearFilter;
texture.magFilter = THREE.LinearFilter; texture.magFilter = THREE.LinearFilter;
texture.generateMipmaps = true; texture.generateMipmaps = true;
@@ -261,11 +266,11 @@ function addCandle(x, y, z, intensity, height) {
const light = new THREE.PointLight(0xff9f45, baseLightIntensity, 4.35, 1.86); const light = new THREE.PointLight(0xff9f45, baseLightIntensity, 4.35, 1.86);
light.position.copy(flame.position); light.position.copy(flame.position);
light.castShadow = true; light.castShadow = true;
light.shadow.mapSize.set(1024, 1024); light.shadow.mapSize.set(2048, 2048);
light.shadow.bias = -0.00004; light.shadow.bias = -0.00004;
light.shadow.normalBias = 0.018; light.shadow.normalBias = 0.018;
light.shadow.radius = 5; light.shadow.radius = 7;
light.shadow.blurSamples = 12; light.shadow.blurSamples = 16;
light.shadow.camera.near = 0.04; light.shadow.camera.near = 0.04;
light.shadow.camera.far = 5.0; light.shadow.camera.far = 5.0;
candle.add(light); candle.add(light);
@@ -800,8 +805,8 @@ function createPageGeometry(side, width, height) {
function createPageCanvas(side) { function createPageCanvas(side) {
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
canvas.width = 1800; canvas.width = 3600;
canvas.height = 2500; canvas.height = 5000;
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
ctx.fillStyle = '#f5dfab'; ctx.fillStyle = '#f5dfab';
ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillRect(0, 0, canvas.width, canvas.height);
@@ -824,24 +829,24 @@ function createPageCanvas(side) {
ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = 'rgba(92, 63, 31, 0.18)'; ctx.strokeStyle = 'rgba(92, 63, 31, 0.18)';
ctx.lineWidth = 2; ctx.lineWidth = 4;
for (let y = 290; y < canvas.height - 190; y += 88) { for (let y = 580; y < canvas.height - 380; y += 176) {
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(170, y); ctx.moveTo(340, y);
ctx.lineTo(canvas.width - 160, y + Math.sin(y * 0.02) * 4); ctx.lineTo(canvas.width - 320, y + Math.sin(y * 0.02) * 8);
ctx.stroke(); ctx.stroke();
} }
ctx.fillStyle = inkColor; ctx.fillStyle = inkColor;
ctx.textBaseline = 'top'; ctx.textBaseline = 'top';
if (side === 'left') { if (side === 'left') {
drawCentered(ctx, 'Georg Tomitsch', 255, 44); drawCentered(ctx, 'Georg Tomitsch', 510, 88);
drawCentered(ctx, 'Eibenreith', 330, 92); drawCentered(ctx, 'Eibenreith', 660, 184);
drawCentered(ctx, 'Ein Kaiserpunk Abenteuer', 455, 54); drawCentered(ctx, 'Ein Kaiserpunk Abenteuer', 910, 108);
drawCentered(ctx, 'speech | autoplay | speed | new game | save | load | options', 610, 34); drawCentered(ctx, 'speech | autoplay | speed | new game | save | load | options', 1220, 68);
drawCentered(ctx, 'click on page or press spacebar to fast forward text animation', 720, 34); drawCentered(ctx, 'click on page or press spacebar to fast forward text animation', 1440, 68);
} else { } else {
drawParagraph(ctx, 'Click on new game or load to start the game', 210, 310, canvas.width - 420, 74, 1.35); drawParagraph(ctx, 'Click on new game or load to start the game', 420, 620, canvas.width - 840, 148, 1.35);
} }
return canvas; return canvas;
} }
@@ -1046,10 +1051,12 @@ function resize() {
renderer.setSize(width, height, false); renderer.setSize(width, height, false);
camera.aspect = width / height; camera.aspect = width / height;
camera.updateProjectionMatrix(); camera.updateProjectionMatrix();
const pixelRatio = renderer.getPixelRatio(); const reflectionWidth = Math.max(1024, Math.min(4096, Math.floor(width * reflectionPixelRatio * 1.5)));
const reflectionHeight = Math.max(576, Math.min(2304, Math.floor(height * reflectionPixelRatio * 1.5)));
reflectionTargetSize.set(reflectionWidth, reflectionHeight);
tableReflectionTarget.setSize( tableReflectionTarget.setSize(
Math.max(320, Math.min(1280, Math.floor(width * pixelRatio * 0.75))), reflectionTargetSize.x,
Math.max(180, Math.min(720, Math.floor(height * pixelRatio * 0.75))) reflectionTargetSize.y
); );
} }