如何在webGL中创建2D挥动标记?

时间:2018-07-06 10:53:39

标签: canvas webgl

我刚刚编写了一个在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

1 个答案:

答案 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/