我已经成功地使用了在这里描述的“键石”技术,通过html5画布将透视效果添加到翻转的“硬封面”书页中。
本质上,一个图像/画布元素被定义为源纹理。在每个渲染循环期间,它被分成一定宽度的段(1px是最佳质量),并且每个段的高度取决于其在纹理的X轴上的位置。
这创造了一个很好的透视错觉,可以从下面的示例中看出:
这对于“硬封面”页面翻转很有效,纹理以及任何包含的文本都给人留下了很好的透视印象。然而,我需要将同样的键石应用于“软”页面翻转。问题在于简单的透视变换不起作用,因为页面本身是带曲线定义的,如下所示:
目前,页面纹理被缩放到页面翻转的任何给定点处的曲线的最大高度,并且页面边缘二次曲线路径被设置为剪裁图像/纹理。由于我使用各种标准画布函数动态绘制阴影和页面线条,因此看起来很可接受,因为页面线条(用二次曲线绘制)为页面翻转提供了自然的透视。
然而,文本本身(源自另一个缓存的画布/图像元素)并不够好看,在任何时候都是完全平的。
我想做的是以某种方式应用上面提到的相同的切片/分段/缩放键石技术,但是通过计算每个1px段的高度,基于二次曲线(用
在我的示例图像中,它实际上看起来还不错,但是当文本接近页面的顶部/底部时,扭曲效果当然应该更大。不仅如此,我们还需要计算一个水平比例因子来挤压最靠近页面折叠的文本。
我真的无法提供任何示例代码。但是本质上,我们正在以与我提供的链接中描述的key-stoning非常相似的方式进行操作。总之,我需要能够使用二次曲线坐标/值来计算下面显示的切片/渲染函数中每个段的比例因子:
本质上,一个图像/画布元素被定义为源纹理。在每个渲染循环期间,它被分成一定宽度的段(1px是最佳质量),并且每个段的高度取决于其在纹理的X轴上的位置。
这创造了一个很好的透视错觉,可以从下面的示例中看出:
![enter image description here](https://istack.dev59.com/cZVFs.webp)
![enter image description here](https://istack.dev59.com/3iLk9.webp)
然而,文本本身(源自另一个缓存的画布/图像元素)并不够好看,在任何时候都是完全平的。
我想做的是以某种方式应用上面提到的相同的切片/分段/缩放键石技术,但是通过计算每个1px段的高度,基于二次曲线(用
ctx.quadraticCurveTo();
绘制)路径和画布内的垂直位置。在我的示例图像中,它实际上看起来还不错,但是当文本接近页面的顶部/底部时,扭曲效果当然应该更大。不仅如此,我们还需要计算一个水平比例因子来挤压最靠近页面折叠的文本。
我真的无法提供任何示例代码。但是本质上,我们正在以与我提供的链接中描述的key-stoning非常相似的方式进行操作。总之,我需要能够使用二次曲线坐标/值来计算下面显示的切片/渲染函数中每个段的比例因子:
function keystoneAndDisplayImage(ctx, img, x, y, pixelWidth, scalingFactor) {
var h = img.height,
w = img.width,
// The number of slices to draw.
numSlices = Math.abs(pixelWidth),
// The width of each source slice.
sliceWidth = w / numSlices,
// Whether to draw the slices in reverse order or not.
polarity = (pixelWidth > 0) ? 1 : -1,
// How much should we scale the width of the slice
// before drawing?
widthScale = Math.abs(pixelWidth) / w,
// How much should we scale the height of the slice
// before drawing?
heightScale = (1 - scalingFactor) / numSlices;
for(var n = 0; n < numSlices; n++) {
// Source: where to take the slice from.
var sx = sliceWidth * n,
sy = 0,
sWidth = sliceWidth,
sHeight = h;
// Destination: where to draw the slice to
// (the transformation happens here).
var dx = x + (sliceWidth * n * widthScale * polarity),
dy = y + ((h * heightScale * n) / 2),
dWidth = sliceWidth * widthScale,
dHeight = h * (1 - (heightScale * n));
ctx.drawImage(img, sx, sy, sWidth, sHeight,
dx, dy, dWidth, dHeight);
}
}
...但我真的不知道从哪里开始。任何帮助都将不胜感激。
编辑:
经过思考,我意识到通过这种方法实现3D纹理映射的完美表示可能要求过高。因此,我将非常满意任何能够根据在html5画布中定义的二次曲线改变每个段的高度比例和y位置的答案。
这是一个更好的示例图像:
如您所见,更大的文本使用单个非键控图像纹理完全保持直线,而我需要1像素宽度的段根据曲线因子和其y位置进行计算,以便它自然地跟随页面翻转。如果无法实现这一点,则任何其他“hack”或方法在这种情况下实现半逼真的透视效果都将非常有帮助。