【发布时间】:2018-07-06 10:53:39
【问题描述】:
我刚刚写了一个在canvas2D中实现挥动效果的程序。
这是我的实现:
1.保存原始画布的图像数据。
2.计算每个点的新位置,并赋予旧位置的颜色。
3.使每个点的振动幅度随着距离的增加而增加。
4.增加单调递减区域的亮度,降低单调递减区域的亮度。
var IMG_MAX_WIDTH = 600
var IMG_MAX_HEIGHT = 600
var imgWidth, imgHeight
var oImgData, imgData
var oPixels, pixels
var ctx, canvasWidth, canvasHeight
var image = new Image()
image.crossOrigin = 'anonymous'
image.src = 'https://i.imgur.com/ZKMnXce.png'
var amplitude = 15
var period = 2
var coX
image.onload = function () {
imgWidth = Math.floor(image.width)
imgHeight = Math.floor(image.height)
var canvas = document.getElementById('flagCanvas')
var scale = 1
if (imgWidth > IMG_MAX_WIDTH) {
scale = IMG_MAX_WIDTH / imgWidth
}
if (imgHeight > IMG_MAX_HEIGHT) {
scale = scale * IMG_MAX_HEIGHT / imgHeight
}
canvasWidth = imgWidth
canvasHeight = imgHeight + amplitude * 2
canvas.width = canvasWidth
canvas.height = canvasHeight
canvas.style.transform = 'translate3d(-50%,-50%,0) scale(' + scale + ')'
// offscreenCtx = offscreenCanvas.getContext('2d')
ctx = canvas.getContext('2d')
ctx.drawImage(image, 0, amplitude, imgWidth, imgHeight)
imgData = ctx.getImageData(0, 0, canvasWidth, canvasHeight)
pixels = imgData.data
oImgData = ctx.createImageData(canvasWidth, canvasHeight)
oPixels = pixels.slice()
oImgData.data = oPixels
coX = 2 * Math.PI / (imgWidth / period)
tick()
}
var stop = false
var timeNow = Date.now()
var timeLast = timeNow
var delta = 0
var interval
var fps = 70
var offset = 10
interval = 1000 / fps
var tick = function () {
if (stop) return false
timeNow = Date.now()
delta = timeNow - timeLast
if (delta > interval) {
timeLast = timeNow
ctx.clearRect(0, 0, canvasWidth, canvasHeight)
var y0 = amplitude * (1 / imgWidth) * Math.sin(timeNow / 200)
var yBuf = new Array(canvasWidth)
var lastY = 0
var r
var g
var b
var a
var oR
var oG
var oB
var oA
for (var i = 0; i < canvasHeight; i++) {
for (var j = 0; j < canvasWidth; j++) {
if (i === 0) {
yBuf[j] = amplitude * (j / imgWidth) * Math.sin(j * coX - timeNow / 200) + y0
}
r = (i * canvasWidth + j) * 4
g = r + 1
b = r + 2
a = r + 3
oR = r + (~~(0.5 + yBuf[j])) * canvasWidth * 4
oG = oR + 1
oB = oR + 2
oA = oR + 3
offset = j === 0 ? 0 : (yBuf[j] - lastY) * 100
pixels[r] = oPixels[oR] + offset
pixels[g] = oPixels[oG] + offset
pixels[b] = oPixels[oB] + offset
pixels[a] = oPixels[oA]
lastY = yBuf[j]
}
}
ctx.putImageData(imgData, 0, 0)
}
requestAnimationFrame(tick)
}
* {
margin: 0;
padding: 0;
}
html, body {
width: 100%;
height: 100%;
}
body {
position: relative;
background: lightgrey;
}
#flagCanvas {
position: absolute;
top: 50%;
left: 50%;
transform-origin: center;
transform: translate3d(-50%, -50%, 0);
}
<canvas id="flagCanvas"></canvas>
完成之后,我发现性能很差。
所以我尝试用 webGL 重写它,希望能有所帮助。
现在我可以使用 webGL 创建一个简单的立方体,进行一些转换,将纹理加载到矩形中。
谁能提供一个想法?最好展示一些核心 js 或 glsl 代码..
谢谢。
+++++++++++++++++更新++++++++++++++++++++
谢谢帮助。 我成功了! https://codepen.io/oj8kay/pen/PBZjpe
【问题讨论】:
-
那么...webgl 代码在哪里?
-
如果您希望您的画布版本更快,请考虑使用
drawImage。它需要一个源矩形和一个目标矩形。没有理由使用慢速getImageData和putImageData。向您展示如何在 WebGL 中执行此操作可以说是一个太大的话题。 Consider reading some tutorials. -
@gman 但是我想模拟反射效果,所以我需要改变每个像素的颜色,
drawImage做不到。你可以认为我可以理解 webgl 并给我一些想法或者代码,我研究一下。 -
您可以通过使用
fillRect和alpha -
您可以使用一些techniques covered here 来制作类似于您上面的挥舞旗帜。