我刚刚编写了一个在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代码..
thx。
+++++++++++++++++++++++++++++++++++
寻求帮助。 我成功了! https://codepen.io/oj8kay/pen/PBZjpe
答案 0 :(得分:1)
通过将所有计算委托给GPU,可以在WebGL中实现“波动”效果。 为此,您应该像下面的模式一样在三角形带中划分一个正方形(或矩形):
1 3 5 7
| /| /| /|
|/ |/ |/ |
2 4 6 8
将顶点1放置在坐标(0,0)处,将顶点2放置在(0,1)处,将顶点7放置在(1,0)处,将顶点8放置在(1,1)处。您可以轻松推断其余顶点的坐标。 这些坐标是纹理中用于显示图像的UV。此外,您可以使用这些坐标将顶点放置在屏幕上。 要获得“波浪”效果,可以根据时间上下移动顶点。
将为每个顶点并行执行顶点着色器。它的代码可以非常简单。这是一个示例:
// The time is the only variable value.
uniform float uniTime;
// Coords of the current vertex.
attribute vec2 attCoords;
// Propagate UV coords to the fragment shader
varying vec2 varUV;
void main() {
// Propagate UV coords to the fragment shader
varUV = attCoords;
// Separate X and Y coordinates.
float x = attCoords.x;
float y = attCoords.y;
// Compute the vertical shift of the vertex according to the time.
float h = cos( uniTime + x * 10.0 );
// The following line is not mandatory, but it make the move look
// more random.
h += cos( x * 3.0 - uniTime * 0.1751 );
// Define the size of the wave and make it steady on the left
// to simulate a fixing point on a stick.
y += h * x * 0.2;
// In WebGL, the visble space is between -1 and +1 in each direction.
gl_Position = vec4( 2.0 * x - 1.0, 0.5 - y, 0.0, 1.0 );
}
您可以在此处看到一个实时示例:https://jsfiddle.net/63sj1rpk/53/