I just wrote a program that implements the waving effect in canvas2D.
Here is my implementation:
1. Save the image data of the origin canvas.
2. Calculate the new position of each point and give it the color of the old position.
3. Make the vibration amplitude of each point increase with distance.
4. Increasing the brightness of the monotone decreasing area, and decreasing the brightness of the monotone decreasing area.
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>
While after that done, I found that the performance is poor.
So I tried to rewrite it by webGL, hope that would help.
Now I can use webGL to create a simple cube,make some transformation,load a texture into a rect.
Can anyone provide an idea ? Best to show some core js or glsl code ..
thx.
+++++++++++++++update++++++++++++++++++
thx for help. I succeeded! https://codepen.io/oj8kay/pen/PBZjpe