diff --git a/project/plugins.js b/project/plugins.js index efad9d4..f846b0b 100644 --- a/project/plugins.js +++ b/project/plugins.js @@ -23355,17 +23355,17 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = ctx.shadowOffsetY = 0; core.drawBoxAnimate() // 绘制左页 - core.drawImage(ctx, this.paperpages[this.page - 1][0], 0, 0, 300, 400, dx, dy, this.width, this.height); + core.drawImage(ctx, this.paperpages[this.page - 1][0], 0, 0, 300 - this.ani.x / (this.width * 2), 400, dx, dy, 300 - this.ani.x / (this.width * 2), this.height); ctx.shadowColor = "transparent"; - core.drawImage(ctx, bookInfo.left.canvas, 0, 0, 300, 400, dx, dy, this.width, this.height); + core.drawImage(ctx, bookInfo.left.canvas, 0, 0, 300 - this.ani.x / (this.width * 2), 400, dx, dy, 300 - this.ani.x / (this.width * 2), this.height); ctx.shadowColor = "rgba(0,0,0,0.5)"; ctx.shadowBlur = 10; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; // 绘制右页 - core.drawImage(ctx, this.paperpages[this.page - 1][1], 0, 0, 300, 400, dx + this.width, dy, this.width, this.height); + core.drawImage(ctx, this.paperpages[this.page - 1][1], Math.max(0, this.ani.x - 300), 0, Math.min(600 - this.ani.x, 300), 400, dx + this.width + Math.max(0, this.ani.x - 300), dy, Math.min(600 - this.ani.x, 300), this.height); ctx.shadowColor = "transparent"; - core.drawImage(ctx, bookInfo.right.canvas, 0, 0, 300, 400, dx + this.width, dy, this.width, this.height); + core.drawImage(ctx, bookInfo.right.canvas, Math.max(0, this.ani.x - 300), 0, Math.min(600 - this.ani.x, 300), 400, dx + this.width + Math.max(0, this.ani.x - 300), dy, Math.min(600 - this.ani.x, 300), this.height); ctx.shadowColor = "rgba(0,0,0,0.5)"; ctx.shadowBlur = 10; ctx.shadowOffsetX = 0; @@ -24031,7 +24031,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = ctx.shadowOffsetY = 0; core.drawBoxAnimate() // 绘制左页 - core.drawImage(ctx, this.paperpages[this.page - 1][0], 0, 0, 300, 400, dx, dy, this.width, this.height); + core.drawImage(ctx, this.paperpages[this.page - 1][0], 0, 0, 300 - Math.max(0, this.ani.x - this.width) / this.width * 300, 400, dx, dy, 300 - Math.max(0, this.ani.x - this.width) / this.width * 300, this.height); ctx.shadowColor = "transparent"; core.drawImage(ctx, bookInfo.left.canvas, 0, 0, 300, 400, dx, dy, this.width, this.height); ctx.shadowColor = "rgba(0,0,0,0.5)"; @@ -24039,7 +24039,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; // 绘制右页 - core.drawImage(ctx, this.paperpages[this.page - 1][1], 0, 0, 300, 400, dx + this.width, dy, this.width, this.height); + core.drawImage(ctx, this.paperpages[this.page - 1][1], 0, 0, 300 - this.ani.x / (this.width * 2) * 300, 400, dx + this.width, dy, 300 - this.ani.x / (this.width * 2) * 300, this.height); ctx.shadowColor = "transparent"; core.drawImage(ctx, bookInfo.right.canvas, 0, 0, 300, 400, dx + this.width, dy, this.width, this.height); ctx.shadowColor = "rgba(0,0,0,0.5)"; @@ -24058,6 +24058,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = core.drawImage(ctx, this.paperpages[page - 1][1], 300 - this.ani.x / (this.width * 2) * 300, 0, this.ani.x / (this.width * 2) * 300, 400, 676 - dx - this.ani.x / 2, dy, this.ani.x / 2, this.height); ctx.shadowColor = "transparent"; core.drawImage(ctx, bookInfo.tempRight.canvas, 300 - this.ani.x / (this.width * 2) * 300, 0, this.ani.x / (this.width * 2) * 300, 400, 676 - dx - this.ani.x / 2, dy, this.ani.x / 2, this.height); + ctx.shadowColor = "rgba(0,0,0,0.5)"; ctx.shadowBlur = 10; ctx.shadowOffsetX = 0; @@ -24204,6 +24205,10 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = // 创建书页内容 (400px高,居中放置) const createPageContent = () => { + const canvas = document.createElement('canvas'); + canvas.width = 300; + canvas.height = 400; + const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); const contentCanvas = document.createElement('canvas'); contentCanvas.width = 300; contentCanvas.height = 400; @@ -24216,44 +24221,146 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = // 创建高度自然的基底纹理 const createOrganicBase = () => { - // 基础底色(轻微噪点纹理) - contentCtx.fillStyle = `hsl(${baseHue}, ${baseSaturation}%, ${baseLightness}%)`; - contentCtx.fillRect(0, 0, 300, 400); + if (gl) { + // 创建WebGL着色器程序 + const vertShader = gl.createShader(gl.VERTEX_SHADER); + gl.shaderSource(vertShader, ` + attribute vec2 position; + void main() { + gl_Position = vec4(position, 0.0, 1.0); + } + `); + gl.compileShader(vertShader); - // 生成有机噪点纹理(模拟羊皮纸纤维) - const noiseData = contentCtx.createImageData(300, 400); - for (let i = 0; i < noiseData.data.length; i += 4) { - // Perlin噪声生成更自然的纹理 - const x = (i / 4) % 300; - const y = Math.floor((i / 4) / 300); - const noiseVal = this.perlinNoise(x / 50, y / 50) * 0.5 + - this.perlinNoise(x / 20, y / 20) * 0.3 + - this.perlinNoise(x / 5, y / 5) * 0.2; + const fragShader = gl.createShader(gl.FRAGMENT_SHADER); + gl.shaderSource(fragShader, ` + precision highp float; + + // 噪声函数 + float noise(vec2 p) { + return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453); + } + + // 简化版Perlin噪声 + float perlinNoise(vec2 p) { + vec2 i = floor(p); + vec2 f = fract(p); + + // 四个角落的随机值 + float a = noise(i); + float b = noise(i + vec2(1.0, 0.0)); + float c = noise(i + vec2(0.0, 1.0)); + float d = noise(i + vec2(1.0, 1.0)); + + // 平滑插值 + vec2 u = f * f * (3.0 - 2.0 * f); + + return mix(a, b, u.x) + + (c - a) * u.y * (1.0 - u.x) + + (d - b) * u.x * u.y; + } + + // HSL转RGB + vec3 hsl2rgb(float h, float s, float l) { + float c = (1.0 - abs(2.0 * l - 1.0)) * s; + float x = c * (1.0 - abs(mod(h / 60.0, 2.0) - 1.0)); + float m = l - c / 2.0; + + if (h < 60.0) return vec3(c + m, x + m, m); + else if (h < 120.0) return vec3(x + m, c + m, m); + else if (h < 180.0) return vec3(m, c + m, x + m); + else if (h < 240.0) return vec3(m, x + m, c + m); + else if (h < 300.0) return vec3(x + m, m, c + m); + else return vec3(c + m, m, x + m); + } + + void main() { + vec2 uv = gl_FragCoord.xy / vec2(300.0, 400.0); + + // 多层Perlin噪声叠加 + float n = perlinNoise(uv * 10.0) * 0.5 + + perlinNoise(uv * 30.0) * 0.3 + + perlinNoise(uv * 60.0) * 0.2; + + // 基础颜色参数 + float baseHue = 45.0; + float baseSaturation = 0.35; + float baseLightness = 0.6; + + // 应用噪声变化 + float hue = mod(baseHue + n * 10.0, 360.0); + float saturation = clamp(baseSaturation + n * 0.15, 0.1, 0.7); + float lightness = clamp(baseLightness + n * 0.08, 0.7, 0.98); + + // 转换为RGB + vec3 color = hsl2rgb(hue, saturation, lightness); + + gl_FragColor = vec4(color, 1.0); + } + `); + gl.compileShader(fragShader); + const program = gl.createProgram(); + gl.attachShader(program, vertShader); + gl.attachShader(program, fragShader); + gl.linkProgram(program); + gl.useProgram(program); - // 基于噪声调整颜色 - const hueVar = noiseVal * 10; - const satVar = noiseVal * 15; - const lightVar = noiseVal * 8; + // 创建全屏四边形 + const buffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ + -1, -1, 1, -1, -1, 1, + -1, 1, 1, -1, 1, 1 + ]), gl.STATIC_DRAW); - noiseData.data[i] = this.HSLtoRGB( - (baseHue + hueVar) % 360, - Math.max(10, Math.min(70, baseSaturation + satVar)), - Math.max(70, Math.min(98, baseLightness + lightVar)) - ).r; - noiseData.data[i + 1] = this.HSLtoRGB( - (baseHue + hueVar) % 360, - Math.max(10, Math.min(70, baseSaturation + satVar)), - Math.max(70, Math.min(98, baseLightness + lightVar)) - ).g; - noiseData.data[i + 2] = this.HSLtoRGB( - (baseHue + hueVar) % 360, - Math.max(10, Math.min(70, baseSaturation + satVar)), - Math.max(70, Math.min(98, baseLightness + lightVar)) - ).b; - noiseData.data[i + 3] = 255; + const positionLoc = gl.getAttribLocation(program, "position"); + gl.enableVertexAttribArray(positionLoc); + gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0); + + // 渲染到canvas + gl.viewport(0, 0, 300, 400); + gl.drawArrays(gl.TRIANGLES, 0, 6); + contentCtx.drawImage(canvas, 0, 0, 300, 400) + } else { + console.warn("当前浏览器不支持webgl,回退使用canvas2d实现") + // 基础底色(轻微噪点纹理) + contentCtx.fillStyle = `hsl(${baseHue}, ${baseSaturation}%, ${baseLightness}%)`; + contentCtx.fillRect(0, 0, 300, 400); + + // 生成有机噪点纹理(模拟羊皮纸纤维) + const noiseData = contentCtx.createImageData(300, 400); + for (let i = 0; i < noiseData.data.length; i += 4) { + // Perlin噪声生成更自然的纹理 + const x = (i / 4) % 300; + const y = Math.floor((i / 4) / 300); + const noiseVal = this.perlinNoise(x / 50, y / 50) * 0.5 + + this.perlinNoise(x / 20, y / 20) * 0.3 + + this.perlinNoise(x / 5, y / 5) * 0.2; + + // 基于噪声调整颜色 + const hueVar = noiseVal * 10; + const satVar = noiseVal * 15; + const lightVar = noiseVal * 8; + + noiseData.data[i] = this.HSLtoRGB( + (baseHue + hueVar) % 360, + Math.max(10, Math.min(70, baseSaturation + satVar)), + Math.max(70, Math.min(98, baseLightness + lightVar)) + ).r; + noiseData.data[i + 1] = this.HSLtoRGB( + (baseHue + hueVar) % 360, + Math.max(10, Math.min(70, baseSaturation + satVar)), + Math.max(70, Math.min(98, baseLightness + lightVar)) + ).g; + noiseData.data[i + 2] = this.HSLtoRGB( + (baseHue + hueVar) % 360, + Math.max(10, Math.min(70, baseSaturation + satVar)), + Math.max(70, Math.min(98, baseLightness + lightVar)) + ).b; + noiseData.data[i + 3] = 255; + } + contentCtx.putImageData(noiseData, 0, 0); } - contentCtx.putImageData(noiseData, 0, 0); - }; createOrganicBase(); // 更自然的边缘破损效果 @@ -24448,7 +24555,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = // 超真实细节系统 const addHyperRealisticDetails = () => { // 3.1 纤维纹理(模拟羊皮纸纤维) - for (let i = 0; i < 2000; i++) { + for (let i = 0; i < 200; i++) { const x = Math.random() * 300; const y = Math.random() * 400; const length = 1 + Math.random() * 4; @@ -24461,7 +24568,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = x + Math.cos(angle) * length, y + Math.sin(angle) * length ); - contentCtx.strokeStyle = `hsla( ${baseHue + (Math.random() - 0.5) * 8}, ${baseSaturation * (0.7 + Math.random() * 0.6)}%,