首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在浏览器上,如何绘制100k序列,每个序列有64-128个点?

在浏览器上,如何绘制100k序列,每个序列有64-128个点?
EN

Stack Overflow用户
提问于 2018-08-08 21:29:29
回答 1查看 336关注 0票数 3

我想要绘制大约120k的序列,每个序列有64个点(下采样,如果使用实际采样率,128-512个点,甚至更大)

我曾尝试用dygraph来做这件事,但如果我使用超过1000个系列,它似乎会非常慢。

我尝试过使用香草WebGL,它的绘制速度非常快,但我的问题是获得鼠标的点击,然后决定它是哪个系列-有什么策略吗?(我认为它被称为非投影?)-由于存在100k+系列,所以使用不同的颜色来确定每个系列,而不是使用点击坐标的像素颜色来确定系列是不切实际的。还有其他的策略吗?

我目前的设计是将图形绘制为一个包含所有图形的大型PNG图集,加载速度很快,但在数据更改时,我必须在服务器上重新绘制PNG,然后再次显示它,这里还有一个“未投影”的问题--有没有办法解决这个问题?如果可能的话?

数据已经进行了相当大的下采样,进一步下采样可能会导致丢失我想要向最终用户展示的细节。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-08-09 09:44:44

绘制120k * 64个东西意味着2700x2700的每个像素都可以覆盖。换句话说,你可能想要显示太多的数据?它也是一个非常大量的东西,可能会很慢。

在任何情况下,通过WebGL绘制和挑选都是相对容易的。你可以使用任何你想要的技术来绘制场景。然后,当用户单独单击鼠标(或始终在鼠标下方)时,您可以将整个场景再次绘制到离屏帧缓冲区,为每个可选对象提供不同的颜色。假设默认情况下有32位颜色(8位红色,8位绿色,8位蓝色,8位alpha),则可以计算2^32-1个数。当然,使用其他缓冲区格式,您可以计算更高的值或绘制到多个缓冲区,但是存储2^32项的数据可能是更大的限制。

无论如何,这里有一个例子。这个生成1000个立方体(刚刚使用的立方体,因为这个样本已经存在)。你可以认为每个立方体都是你的“系列”中的一个,有8个点,尽管代码实际上是每个立方体绘制24个点。(设置primType = gl.TRIANGLES)以查看立方体。它将所有的立方体放在同一个缓冲区中,这样一次绘图调用就可以绘制所有的立方体。这使得它比我们使用单独的绘图调用绘制每个立方体要快得多。

重要的部分是为每个系列创建一个系列ID。在下面的代码中,一个立方体的所有点都有相同的ID。

代码将场景绘制两次。一次使用每个立方体的颜色,再次使用每个立方体的ID到屏幕外纹理中(作为帧缓冲区附件)。为了知道哪个立方体在鼠标下方,我们查看鼠标下方的像素,将其颜色转换回ID,并更新该立方体的顶点颜色以突出显示它。

代码语言:javascript
运行
复制
const gl = document.querySelector('canvas').getContext("webgl");
const m4 = twgl.m4;
const v3 = twgl.v3;
// const primType = gl.TRIANGLES;
const primType = gl.POINTS;

const renderVS = `
attribute vec4 position;
attribute vec4 color;

uniform mat4 u_projection;
uniform mat4 u_modelView;

varying vec4 v_color;

void main() {
  gl_PointSize = 10.0;
  gl_Position = u_projection * u_modelView * position;
  v_color = color;
}
`;

const renderFS = `
precision mediump float;
varying vec4 v_color;
void main() {
  gl_FragColor = v_color;
}
`;

const idVS = `
attribute vec4 position;
attribute vec4 id;

uniform mat4 u_projection;
uniform mat4 u_modelView;

varying vec4 v_id;
void main() {
  gl_PointSize = 10.0;
  gl_Position = u_projection * u_modelView * position;
  v_id = id;  // pass the id to the fragment shader
}
`;

const idFS = `
precision mediump float;
varying vec4 v_id;
void main() {
  gl_FragColor = v_id;
}
`;

// creates shaders, programs, looks up attribute and uniform locations
const renderProgramInfo = twgl.createProgramInfo(gl, [renderVS, renderFS]);
const idProgramInfo = twgl.createProgramInfo(gl, [idVS, idFS]);

// create one set of geometry with a bunch of cubes
// for each cube give it random color (so every vertex
// that cube will have the same color) and give it an id (so
// every vertex for that cube will have the same id)
const numCubes = 1000;
const positions = [];
const normals = [];
const colors = [];
const timeStamps = [];
const ids = [];
// Save the color of each cube so we can restore it after highlighting
const cubeColors = [];
const radius = 25;

// adapted from http://stackoverflow.com/a/26127012/128511
// used to space the cubes around the sphere
function fibonacciSphere(samples, i) {
  const rnd = 1.;
  const offset = 2. / samples;
  const increment = Math.PI * (3. - Math.sqrt(5.));

  //  for i in range(samples):
  const y = ((i * offset) - 1.) + (offset / 2.);
  const r = Math.sqrt(1. - Math.pow(y ,2.));

  const phi = ((i + rnd) % samples) * increment;

  const x = Math.cos(phi) * r;
  const z = Math.sin(phi) * r;

  return [x, y, z];
}

const addCubeVertexData = (function() {
  const CUBE_FACE_INDICES = [
    [3, 7, 5, 1],  // right
    [6, 2, 0, 4],  // left
    [6, 7, 3, 2],  // ??
    [0, 1, 5, 4],  // ??
    [7, 6, 4, 5],  // front
    [2, 3, 1, 0],  // back
  ];

  const cornerVertices = [
    [-1, -1, -1],
    [+1, -1, -1],
    [-1, +1, -1],
    [+1, +1, -1],
    [-1, -1, +1],
    [+1, -1, +1],
    [-1, +1, +1],
    [+1, +1, +1],
  ];

  const faceNormals = [
    [+1, +0, +0],
    [-1, +0, +0],
    [+0, +1, +0],
    [+0, -1, +0],
    [+0, +0, +1],
    [+0, +0, -1],
  ];

  const quadIndices = [0, 1, 2, 0, 2, 3];

  return function addCubeVertexData(id, matrix, color) {
    for (let f = 0; f < 6; ++f) {
      const faceIndices = CUBE_FACE_INDICES[f];
      for (let v = 0; v < 6; ++v) {
        const ndx = faceIndices[quadIndices[v]];
        const position = cornerVertices[ndx];
        const normal = faceNormals[f];

        positions.push(...m4.transformPoint(matrix, position));
        normals.push(...m4.transformDirection(matrix, normal));
        colors.push(color);
        ids.push(id);
        timeStamps.push(-1000);
      }
    }
  };
}());

for (let i = 0; i < numCubes; ++i) {
  const direction = fibonacciSphere(numCubes, i);
  const cubePosition = v3.mulScalar(direction, radius);
  const target = [0, 0, 0];
  const up = [0, 1, 0];
  const matrix = m4.lookAt(cubePosition, target, up);
  const color = (Math.random() * 0xFFFFFF | 0) + 0xFF000000;
  cubeColors.push(color);
  addCubeVertexData(i + 1, matrix, color);
}

const colorData = new Uint32Array(colors);
const cubeColorsAsUint32 = new Uint32Array(cubeColors);
const timeStampData = new Float32Array(timeStamps);

// pass color as Uint32. Example 0x0000FFFF; // blue with alpha 0
function setCubeColor(id, color) {
  // we know each cube uses 36 vertices. If each model was different
  // we need to save the offset and number of vertices for each model
  const numVertices = 36;
  const offset = (id - 1) * numVertices;
  colorData.fill(color, offset, offset + numVertices);
}

function setCubeTimestamp(id, timeStamp) {
  const numVertices = 36;
  const offset = (id - 1) * numVertices;
  timeStampData.fill(timeStamp, offset, offset + numVertices);
}

// calls gl.createBuffer, gl.bufferData
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
  position: positions,
  normal: normals,
  color: new Uint8Array(colorData.buffer),
  // the colors are stored as 32bit unsigned ints
  // but we want them as 4 channel 8bit RGBA values
  id: {
    numComponents: 4,
    data: new Uint8Array((new Uint32Array(ids)).buffer),
  },
  timeStamp: {
    numComponents: 1,
    data: timeStampData,
  },
});

const lightDir = v3.normalize([3, 5, 10]);

// creates an RGBA/UNSIGNED_BYTE texture
// and a depth renderbuffer and attaches them
// to a framebuffer.
const fbi = twgl.createFramebufferInfo(gl);

// current mouse position in canvas relative coords
let mousePos = {x: 0, y: 0};
let lastHighlightedCubeId = 0;
let highlightedCubeId = 0;
let frameCount = 0;

function getIdAtPixel(x, y, projection, view, time) {
  // calls gl.bindFramebuffer and gl.viewport
  twgl.bindFramebufferInfo(gl, fbi);

  // no reason to render 100000s of pixels when
  // we're only going to read one
  gl.enable(gl.SCISSOR_TEST);
  gl.scissor(x, y, 1, 1);

  gl.clearColor(0, 0, 0, 0);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  gl.enable(gl.DEPTH_TEST);

  drawCubes(idProgramInfo, projection, view, time);

  gl.disable(gl.SCISSOR_TEST);

  const idPixel = new Uint8Array(4);
  gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, idPixel);
  // convert from RGBA back into ID.
  const id = (idPixel[0] <<  0) +
             (idPixel[1] <<  8) +
             (idPixel[2] << 16) +
             (idPixel[3] << 24);
  return id;
}

function drawCubes(programInfo, projection, modelView, time) {
  gl.useProgram(programInfo.program);
  // calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);

  // calls gl.uniformXXX
  twgl.setUniforms(programInfo, {
    u_projection: projection,
    u_modelView: modelView,  // drawing at origin so model is identity
  });

  gl.drawArrays(primType, 0, bufferInfo.numElements);
}


function render(time) {
  time *= 0.001;
  ++frameCount;

  if (twgl.resizeCanvasToDisplaySize(gl.canvas)) {
    // resizes the texture and depth renderbuffer to
    // match the new size of the canvas.
    twgl.resizeFramebufferInfo(gl, fbi);
  }

  const fov = Math.PI * .35;
  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  const zNear = 0.1;
  const zFar = 1000;
  const projection = m4.perspective(fov, aspect, zNear, zFar);

  const radius = 45;
  const angle = time * .2;
  const eye = [
    Math.cos(angle) * radius,
    0,
    Math.sin(angle) * radius,
  ];
  const target = [0, 0, 0];
  const up = [0, 1, 0];
  const camera = m4.lookAt(eye, target, up);
  const view = m4.inverse(camera);

  if (lastHighlightedCubeId > 0) {
    // restore the last highlighted cube's color
    setCubeColor(
      lastHighlightedCubeId,
      cubeColorsAsUint32[lastHighlightedCubeId]);
    lastHighlightedCubeId = -1;
  }

  {
    const x = mousePos.x;
    const y = gl.canvas.height - mousePos.y - 1;
    highlightedCubeId = getIdAtPixel(x, y, projection, view, time);
  }

  if (highlightedCubeId > 0) {
    const color = (frameCount & 0x2) ? 0xFF0000FF : 0xFFFFFFFF;
    setCubeColor(highlightedCubeId, color);
    setCubeTimestamp(highlightedCubeId, time);
    lastHighlightedCubeId = highlightedCubeId;
  }

  highlightedCubeId = Math.random() * numCubes | 0;

  // NOTE: We could use `gl.bufferSubData` and just upload
  // the portion that changed.

  // upload cube color data.
  gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.attribs.color.buffer);
  gl.bufferData(gl.ARRAY_BUFFER, colorData, gl.DYNAMIC_DRAW);
  // upload the timestamp
  gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.attribs.timeStamp.buffer);
  gl.bufferData(gl.ARRAY_BUFFER, timeStampData, gl.DYNAMIC_DRAW);

  // calls gl.bindFramebuffer and gl.viewport
  twgl.bindFramebufferInfo(gl, null);

  gl.enable(gl.DEPTH_TEST);

  drawCubes(renderProgramInfo, projection, view, time);

  requestAnimationFrame(render);
}
requestAnimationFrame(render);

function getRelativeMousePosition(event, target) {
  target = target || event.target;
  const rect = target.getBoundingClientRect();

  return {
    x: event.clientX - rect.left,
    y: event.clientY - rect.top,
  }
}

// assumes target or event.target is canvas
function getNoPaddingNoBorderCanvasRelativeMousePosition(event, target) {
  target = target || event.target;
  const pos = getRelativeMousePosition(event, target);

  pos.x = pos.x * target.width  / target.clientWidth;
  pos.y = pos.y * target.height / target.clientHeight;

  return pos;
}

gl.canvas.addEventListener('mousemove', (event, target) => {
  mousePos = getRelativeMousePosition(event, target);
});
代码语言:javascript
运行
复制
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
代码语言:javascript
运行
复制
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>

上面的代码使用与画布相同大小的屏幕外帧缓冲区,但它使用剪刀测试仅绘制单个像素(鼠标下的像素)。它仍然可以在没有剪刀测试的情况下运行,只是速度会更慢。

我们也可以使用屏幕外的单个像素帧缓冲区,并使用投影数学来使其工作,这样事情就会解决。

代码语言:javascript
运行
复制
const gl = document.querySelector('canvas').getContext("webgl");
const m4 = twgl.m4;
const v3 = twgl.v3;
// const primType = gl.TRIANGLES;
const primType = gl.POINTS;

const renderVS = `
attribute vec4 position;
attribute vec4 color;

uniform mat4 u_projection;
uniform mat4 u_modelView;

varying vec4 v_color;

void main() {
  gl_PointSize = 10.0;
  gl_Position = u_projection * u_modelView * position;
  v_color = color;
}
`;

const renderFS = `
precision mediump float;
varying vec4 v_color;
void main() {
  gl_FragColor = v_color;
}
`;

const idVS = `
attribute vec4 position;
attribute vec4 id;

uniform mat4 u_projection;
uniform mat4 u_modelView;

varying vec4 v_id;
void main() {
  gl_PointSize = 10.0;
  gl_Position = u_projection * u_modelView * position;
  v_id = id;  // pass the id to the fragment shader
}
`;

const idFS = `
precision mediump float;
varying vec4 v_id;
void main() {
  gl_FragColor = v_id;
}
`;

// creates shaders, programs, looks up attribute and uniform locations
const renderProgramInfo = twgl.createProgramInfo(gl, [renderVS, renderFS]);
const idProgramInfo = twgl.createProgramInfo(gl, [idVS, idFS]);

// create one set of geometry with a bunch of cubes
// for each cube give it random color (so every vertex
// that cube will have the same color) and give it an id (so
// every vertex for that cube will have the same id)
const numCubes = 1000;
const positions = [];
const normals = [];
const colors = [];
const timeStamps = [];
const ids = [];
// Save the color of each cube so we can restore it after highlighting
const cubeColors = [];
const radius = 25;

// adapted from http://stackoverflow.com/a/26127012/128511
// used to space the cubes around the sphere
function fibonacciSphere(samples, i) {
  const rnd = 1.;
  const offset = 2. / samples;
  const increment = Math.PI * (3. - Math.sqrt(5.));

  //  for i in range(samples):
  const y = ((i * offset) - 1.) + (offset / 2.);
  const r = Math.sqrt(1. - Math.pow(y ,2.));

  const phi = ((i + rnd) % samples) * increment;

  const x = Math.cos(phi) * r;
  const z = Math.sin(phi) * r;

  return [x, y, z];
}

const addCubeVertexData = (function() {
  const CUBE_FACE_INDICES = [
    [3, 7, 5, 1],  // right
    [6, 2, 0, 4],  // left
    [6, 7, 3, 2],  // ??
    [0, 1, 5, 4],  // ??
    [7, 6, 4, 5],  // front
    [2, 3, 1, 0],  // back
  ];

  const cornerVertices = [
    [-1, -1, -1],
    [+1, -1, -1],
    [-1, +1, -1],
    [+1, +1, -1],
    [-1, -1, +1],
    [+1, -1, +1],
    [-1, +1, +1],
    [+1, +1, +1],
  ];

  const faceNormals = [
    [+1, +0, +0],
    [-1, +0, +0],
    [+0, +1, +0],
    [+0, -1, +0],
    [+0, +0, +1],
    [+0, +0, -1],
  ];

  const quadIndices = [0, 1, 2, 0, 2, 3];

  return function addCubeVertexData(id, matrix, color) {
    for (let f = 0; f < 6; ++f) {
      const faceIndices = CUBE_FACE_INDICES[f];
      for (let v = 0; v < 6; ++v) {
        const ndx = faceIndices[quadIndices[v]];
        const position = cornerVertices[ndx];
        const normal = faceNormals[f];

        positions.push(...m4.transformPoint(matrix, position));
        normals.push(...m4.transformDirection(matrix, normal));
        colors.push(color);
        ids.push(id);
        timeStamps.push(-1000);
      }
    }
  };
}());

for (let i = 0; i < numCubes; ++i) {
  const direction = fibonacciSphere(numCubes, i);
  const cubePosition = v3.mulScalar(direction, radius);
  const target = [0, 0, 0];
  const up = [0, 1, 0];
  const matrix = m4.lookAt(cubePosition, target, up);
  const color = (Math.random() * 0xFFFFFF | 0) + 0xFF000000;
  cubeColors.push(color);
  addCubeVertexData(i + 1, matrix, color);
}

const colorData = new Uint32Array(colors);
const cubeColorsAsUint32 = new Uint32Array(cubeColors);
const timeStampData = new Float32Array(timeStamps);

// pass color as Uint32. Example 0x0000FFFF; // blue with alpha 0
function setCubeColor(id, color) {
  // we know each cube uses 36 vertices. If each model was different
  // we need to save the offset and number of vertices for each model
  const numVertices = 36;
  const offset = (id - 1) * numVertices;
  colorData.fill(color, offset, offset + numVertices);
}

function setCubeTimestamp(id, timeStamp) {
  const numVertices = 36;
  const offset = (id - 1) * numVertices;
  timeStampData.fill(timeStamp, offset, offset + numVertices);
}

// calls gl.createBuffer, gl.bufferData
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
  position: positions,
  normal: normals,
  color: new Uint8Array(colorData.buffer),
  // the colors are stored as 32bit unsigned ints
  // but we want them as 4 channel 8bit RGBA values
  id: {
    numComponents: 4,
    data: new Uint8Array((new Uint32Array(ids)).buffer),
  },
  timeStamp: {
    numComponents: 1,
    data: timeStampData,
  },
});

const lightDir = v3.normalize([3, 5, 10]);

// creates an 1x1 pixel RGBA/UNSIGNED_BYTE texture
// and a depth renderbuffer and attaches them
// to a framebuffer.
const fbi = twgl.createFramebufferInfo(gl, [
  { format: gl.RGBA, type: gl.UNSIGNED_BYTE, minMag: gl.NEAREST, wrap: gl.CLAMP_TO_EDGE, },
  { format: gl.DEPTH_STENCIL, },
], 1, 1);

// current mouse position in canvas relative coords
let mousePos = {x: 0, y: 0};
let lastHighlightedCubeId = 0;
let highlightedCubeId = 0;
let frameCount = 0;

function getIdAtPixel(x, y, projectionInfo, view, time) {
  // calls gl.bindFramebuffer and gl.viewport
  twgl.bindFramebufferInfo(gl, fbi);

  gl.clearColor(0, 0, 0, 0);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  gl.enable(gl.DEPTH_TEST);

  drawCubes(idProgramInfo, projectionInfo, {
    totalWidth: gl.canvas.width,
    totalHeight: gl.canvas.height,
    partWidth: 1,
    partHeight: 1,
    partX: x,
    partY: y,
  }, view, time);

  const idPixel = new Uint8Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, idPixel);
  // convert from RGBA back into ID.
  const id = (idPixel[0] <<  0) +
             (idPixel[1] <<  8) +
             (idPixel[2] << 16) +
             (idPixel[3] << 24);
  return id;
}

function drawCubes(programInfo, projectionInfo, partInfo, modelView, time) {

  const projection = projectionForPart(projectionInfo, partInfo);

  gl.useProgram(programInfo.program);
  // calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);

  // calls gl.uniformXXX
  twgl.setUniforms(programInfo, {
    u_projection: projection,
    u_modelView: modelView,  // drawing at origin so model is identity
  });

  gl.drawArrays(primType, 0, bufferInfo.numElements);
}

function projectionForPart(projectionInfo, partInfo) {
  const {fov, zNear, zFar} = projectionInfo;
  const {
    totalWidth,
    totalHeight,
    partX,
    partY,
    partWidth,
    partHeight,
  } = partInfo;
  
  const aspect = totalWidth / totalHeight;
  
  // corners at zNear for total image
  const zNearTotalTop = Math.tan(fov) * 0.5 * zNear;
  const zNearTotalBottom = -zNearTotalTop;
  const zNearTotalLeft = zNearTotalBottom * aspect;
  const zNearTotalRight = zNearTotalTop * aspect;
  
  // width, height at zNear for total image
  const zNearTotalWidth = zNearTotalRight - zNearTotalLeft;
  const zNearTotalHeight = zNearTotalTop - zNearTotalBottom;
  
  const zNearPartLeft = zNearTotalLeft + partX * zNearTotalWidth / totalWidth;   const zNearPartRight = zNearTotalLeft + (partX + partWidth) * zNearTotalWidth / totalWidth;
  const zNearPartBottom = zNearTotalBottom + partY * zNearTotalHeight / totalHeight;
  const zNearPartTop = zNearTotalBottom + (partY + partHeight) * zNearTotalHeight / totalHeight;

  return m4.frustum(zNearPartLeft, zNearPartRight, zNearPartBottom, zNearPartTop, zNear, zFar);
}

function render(time) {
  time *= 0.001;
  ++frameCount;

  twgl.resizeCanvasToDisplaySize(gl.canvas);

  const projectionInfo = {
    fov: Math.PI * .35,
    zNear: 0.1,
    zFar: 1000,
  };

  const radius = 45;
  const angle = time * .2;
  const eye = [
    Math.cos(angle) * radius,
    0,
    Math.sin(angle) * radius,
  ];
  const target = [0, 0, 0];
  const up = [0, 1, 0];
  const camera = m4.lookAt(eye, target, up);
  const view = m4.inverse(camera);

  if (lastHighlightedCubeId > 0) {
    // restore the last highlighted cube's color
    setCubeColor(
      lastHighlightedCubeId,
      cubeColorsAsUint32[lastHighlightedCubeId]);
    lastHighlightedCubeId = -1;
  }

  {
    const x = mousePos.x;
    const y = gl.canvas.height - mousePos.y - 1;
    highlightedCubeId = getIdAtPixel(x, y, projectionInfo, view, time);
  }

  if (highlightedCubeId > 0) {
    const color = (frameCount & 0x2) ? 0xFF0000FF : 0xFFFFFFFF;
    setCubeColor(highlightedCubeId, color);
    setCubeTimestamp(highlightedCubeId, time);
    lastHighlightedCubeId = highlightedCubeId;
  }

  highlightedCubeId = Math.random() * numCubes | 0;

  // NOTE: We could use `gl.bufferSubData` and just upload
  // the portion that changed.

  // upload cube color data.
  gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.attribs.color.buffer);
  gl.bufferData(gl.ARRAY_BUFFER, colorData, gl.DYNAMIC_DRAW);
  // upload the timestamp
  gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.attribs.timeStamp.buffer);
  gl.bufferData(gl.ARRAY_BUFFER, timeStampData, gl.DYNAMIC_DRAW);

  // calls gl.bindFramebuffer and gl.viewport
  twgl.bindFramebufferInfo(gl, null);

  gl.enable(gl.DEPTH_TEST);

  drawCubes(renderProgramInfo, projectionInfo, {
    totalWidth: gl.canvas.width,
    totalHeight: gl.canvas.height,
    partWidth: gl.canvas.width,
    partHeight: gl.canvas.height,
    partX: 0,
    partY: 0,
  }, view, time);

  requestAnimationFrame(render);
}
requestAnimationFrame(render);

function getRelativeMousePosition(event, target) {
  target = target || event.target;
  const rect = target.getBoundingClientRect();

  return {
    x: event.clientX - rect.left,
    y: event.clientY - rect.top,
  }
}

// assumes target or event.target is canvas
function getNoPaddingNoBorderCanvasRelativeMousePosition(event, target) {
  target = target || event.target;
  const pos = getRelativeMousePosition(event, target);

  pos.x = pos.x * target.width  / target.clientWidth;
  pos.y = pos.y * target.height / target.clientHeight;

  return pos;
}

gl.canvas.addEventListener('mousemove', (event, target) => {
  mousePos = getRelativeMousePosition(event, target);
});
代码语言:javascript
运行
复制
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
代码语言:javascript
运行
复制
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>

请注意,在WebGL中绘制POINTS通常比相同大小的绘图2 TRIANGLES慢。如果我将立方体的数量设置为100k,并将primType设置为TRIANGLES,它将绘制100k的立方体。在我的集成GPU上,代码片段窗口的运行速度约为10-20fps。当然,有这么多的立方体,不可能选择一个。如果我将半径设置为250,我至少可以看到拾取仍在工作。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51747996

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档