Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >悬挂式检测着色器-如何返回顶点的坐标?

悬挂式检测着色器-如何返回顶点的坐标?
EN

Stack Overflow用户
提问于 2017-05-21 04:17:14
回答 2查看 464关注 0票数 1

我正试图用three.js在浏览器中编写一个支持生成应用程序,我已经尝试过许多方法,而且它们都是缓慢的,所以现在我决定让着色器计算悬置位置,我的程序构建了对这些点的支持。

悬挂式检测着色器输出:

现在的问题是,我不知道如何将那些红色区域返回到CPU /main JavaScript应用程序以生成对这些点的简单支持,我在这里读到了关于涉及FBO的GPU方法,但无法理解这一点,有没有办法将红色区域坐标返回到CPU?

我也可以在顶点着色器中计算这一点,以将非重叠顶点的位置更新为0,0,0,但问题是三个JavaScript中的顶点位置不会以这种方式更新,如果在顶点着色器执行后有某种方法得到更新的顶点位置,这可能是一个解决方案。

也许转换反馈?如何使用来自three.js的转换反馈?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-05-22 00:04:26

如果您只想获得呈现的映像(就像您在问题中链接的图像),可以在readPixels readRenderTargetPixels周围使用3的包装器。这将给您的图像像素值作为一个数组,您可以迭代它并找到红色的区域。此外,由于您的片段着色器似乎做了相当多的二进制决定(黑色或红色),您可以使用其他渠道存储其他信息,例如在顶点着色器中:

代码语言:javascript
运行
AI代码解释
复制
// ...
varying vec3 position;
// ...
void main(void) {
    // ...
    position = gl_Position.xyz / gl_Position.w;
}

在碎片着色器中:

代码语言:javascript
运行
AI代码解释
复制
// ...
varying highp vec3 position;
// ...
void main(void) {
    // ...
    gl_FragColor.xyz = 0.5 * (position + 1.0); // position'll be in (-1, 1) range, where as gl_FragColor's clamped to (0, 1)
    gl_FragColor.w = isOverhang ? 1.0 : 0.0;
}

然后在JS代码中:

代码语言:javascript
运行
AI代码解释
复制
// ...
const pixelBuffer = new Uint8Array(4 * w * h);
renderer.readRenderTargetPixels(renderTarget, 0, 0, w, h, pixelBuffer);
for (let y = 0, offset = 0; y < h; ++y) {
    for (let x = 0; x < w; ++x, offset += 4) {

         // does pixel correspond to overhang area?
         if (pixelBuffer[offset + 3] > 0) {
             const posX = 2 * pixelBuffer[offset] / 255 - 1;
             const posY = 2 * pixelBuffer[offset + 1] / 255 - 1;
             const posZ = 2 * pixelBuffer[offset + 2] / 255 - 1;
             // ...
         }
    }
}

然而,8位精度可能不足以满足您的需要。在这种情况下,您可以使用FLOATHALF_FLOAT呈现目标(如果浏览器支持的话)。

您也可以尝试GPGPU方法。基本上,大多数情况下,它使用片段着色器来计算一些值,然后将这些值存储在纹理中(通常也是FLOATHALF_FLOAT ),或者读取回CPU,或者在随后的绘图中采样以使用计算值。在WebGL中有很多关于GPGPU的信息,例如

关于变换反馈。是的,它专门用于在某个缓冲区中存储顶点着色器的结果,该缓冲区也可以被读取回CPU (很少)或在GPU上重用,例如作为另一个或甚至相同顶点着色器的输入。但是TF只能在WebGL 2中使用。

票数 0
EN

Stack Overflow用户

发布于 2017-06-03 18:52:42

您可以使用其他FBO或转换反馈。对于变换反馈,唯一的问题是AFAICT,没有办法丢弃顶点,所以就像你刚才提到的,在这种情况下,你能做的最好就是为不重叠的顶点写一些特殊的值。

要使用FBO,您可以制作浮点纹理并检查是否可以呈现给它。在WebGL1中,这意味着启用浮点纹理,将其绑定到框架缓冲区并调用checkFramebufferStatus。在WebGL 2中,它意味着检查和启用EXT_color_buffer_float (并且仍然调用checkFramebufferStatus)

然后,使用计数0、1、2、3、4、5、6等做一个缓冲区,使用它生成一个gl_Position,它将写入FBO中的下一个像素。

代码语言:javascript
运行
AI代码解释
复制
// WebGL2 
varying uint count; 
uniform uint2 resolutionOfFBO;

// compute output pixel
uint x = count % resolutinOfFBO.x;
uint y = count / resolutionOfFBO.x;

// set gl_Position so we'll write to that output pixel
gl_Position = vec4((vec2(x, y) + .5) / resolutionOfFBO, 0, 1);

将要写入的数据以不同的形式传递,并在片段着色器中写入该数据。然后使用POINTS进行渲染。

然后,您可以使用gl.readPixels读取数据。

解释转换反馈似乎有点长,但这里有一个简单的例子:输入是[1, 2, 3],输出是[2, 4, 6]

代码语言:javascript
运行
AI代码解释
复制
function main() {
  const gl = document.createElement("canvas").getContext("webgl2");
  
  const vs = `#version 300 es
    in float in_value;
    out float out_value;
    
    void main() {
       out_value = in_value * 2.;
    }
  `;
  const fs = `#version 300 es
    precision mediump float;
    layout (location = 0) out vec4 dummy;
    void main() {
      dummy = vec4(1);
    }
  `;
  const prog = createProgram(gl, [vs, fs], ["out_value"]);
  const inLoc = gl.getAttribLocation(prog, 'in_value');
  const outLoc = 0;  
  
  const numVaryings = gl.getProgramParameter(prog, gl.TRANSFORM_FEEDBACK_VARYINGS);

  const srcBuffer1 = createBuffer(gl, new Float32Array([1, 2, 3]));
  const srcVAO1 = createVAO(gl, srcBuffer1, inLoc);

  const dstBuffer = createBuffer(gl, Float32Array.BYTES_PER_ELEMENT * 3);
  const srcVAO2 = createVAO(gl, dstBuffer, inLoc);

  const tf = gl.createTransformFeedback();
  gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
  gl.useProgram(prog);
  gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, dstBuffer);
  // this binds the default (id = 0) TRANSFORM_FEEBACK buffer
  gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
  // This line is onky because of a bug in Chrome
  gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);

  runFeedback(gl, prog, srcVAO1, tf);  
  checkGLError(gl);
  
  const result = new Float32Array(3);
  gl.bindBuffer(gl.ARRAY_BUFFER, dstBuffer);
  gl.getBufferSubData(gl.ARRAY_BUFFER, 0, result);
  log(result);
}
main();

function runFeedback(gl, prog, srcVAO, tf, dstBufferInfo) {
  gl.enable(gl.RASTERIZER_DISCARD);

  gl.useProgram(prog);
  gl.bindVertexArray(srcVAO);
  
  gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
  gl.beginTransformFeedback(gl.TRIANGLES);
  gl.drawArrays(gl.TRIANGLES, 0, 3);
  gl.endTransformFeedback();
  
  gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);

  gl.disable(gl.RASTERIZER_DISCARD);
}

function checkGLError(gl) {
  const err = gl.getError();
  if (err) {
    log("GL ERROR:", err);
  }
}

function createShader(gl, shaderSource, shaderType) {
  var shader = gl.createShader(shaderType);
  gl.shaderSource(shader, shaderSource);
  gl.compileShader(shader);
  var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  if (!compiled) {
    console.error(gl.getShaderInfoLog(shader));
    gl.deleteShader(shader);
    return null;
  }
  return shader;
}

function createProgram(gl, shaderSources, outputs) {
  const shaderTypes = [gl.VERTEX_SHADER, gl.FRAGMENT_SHADER];
  const program = gl.createProgram();
  shaderSources.forEach(function(shaderSrc, ndx) {
    gl.attachShader(program, createShader(gl, shaderSrc, shaderTypes[ndx]));
  });
  
  if (outputs) {
    gl.transformFeedbackVaryings(program, outputs, gl.SEPARATE_ATTRIBS);
  }
  gl.linkProgram(program);

  var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
  if (!linked) {
    console.error(gl.getProgramInfoLog(program));
    gl.deleteProgram(program);
    return null;
  }
  return program;
}
 
function createBuffer(gl, dataOrSize) {
  const buf = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buf);
  gl.bufferData(gl.ARRAY_BUFFER, dataOrSize, gl.STATIC_DRAW);
  return buf;
}

function createVAO(gl, buf, inLoc) {
  const vao = gl.createVertexArray();
  gl.bindVertexArray(vao);
  gl.bindBuffer(gl.ARRAY_BUFFER, buf);
  gl.enableVertexAttribArray(inLoc);
  gl.vertexAttribPointer(inLoc, 1, gl.FLOAT, false, 0, 0);
  gl.bindBuffer(gl.ARRAY_BUFFER, null);  // this is not needed
  gl.bindVertexArray(null);
  return vao;
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}

简短的解释是转换反馈,你的输出变体从你的顶点着色器写到一个或多个缓冲区。

要做到这一点,您必须在链接时告诉您的着色器程序,您的输出与gl.transformFeedbackVaryings

然后创建一个转换反馈对象。转换反馈对象与顶点数组对象非常相似,只是用于输出而不是输入。通过对每个输出调用gl.bindBufferBase来指定输出,就像对顶点数组对象上的每个输入调用gl.vertexAttribPointer一样。

要实际生成输出,您可能需要告诉WebGL不要运行片段着色器

代码语言:javascript
运行
AI代码解释
复制
gl.enable(gl.RASTERIZER_DISCARD);

然后绑定转换反馈对象,打开转换反馈并绘制。

代码语言:javascript
运行
AI代码解释
复制
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
gl.beginTransformFeedback(gl.TRIANGLES);
gl.drawArrays(gl.TRIANGLES, 0, 3);
gl.endTransformFeedback();

当您链接程序时,您可以选择单独的或交错的attribtes。使用单独的属性,每个属性可以进入不同的缓冲区,但是您可以编写多少属性是有限制的(min至少是4)。在交错的情况下,所有的输出都会被写入,但是它们是交错的。例如,如果您同时写入位置和法线,则输出将是

代码语言:javascript
运行
AI代码解释
复制
position0, normal0, position1, normal1, position2, normal2

都放在同一个缓冲器里。

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

https://stackoverflow.com/questions/44096746

复制
相关文章
YbtOJ 915「欧拉函数」欧拉欧拉
规定一个正整数序列 a 是合法的,当且仅当它的长度为 k,且序列中的每一个 a_i 都小于等于 n。
yzxoi
2022/09/19
5330
算法模板——线性欧拉函数
实现功能:求出1-N的欧拉函数,然后应对若干个询问操作 其实就是个素数判定+欧拉函数性质的二合一 代码如下,我觉得应高不难懂,只要你知道欧拉函数的性质 var i,j,k,l,m,n:longint; a,b:array[0..10000005] of longint; procedure phi; var i,j:longint; begin m:=0;a[1]:=1; for i:=2 to
HansBug
2018/04/11
5610
算法模板——单个值欧拉函数
输入N,输出phi(N) 这样的单个值欧拉函数程序一般见于部分数论题,以及有时候求逆元且取模的数不是质数的情况(逆元:A/B=A*Bphi(p)-1 (mod p),一般常见题中p是质数,phi(p)-1=p-2) (Tip:我是来水经验的不解释,不过话说真的好久没写这个了TT) 1 var i:int64; 2 function Eula(x:int64):int64; 3 var res:int64;i:longint; 4 begin 5
HansBug
2018/04/10
6360
欧拉函数(欧拉筛)--模板
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; typedef long long llong; const int MAXN = 25000000 + 10; llong phi[MAXN + 200]; llong prime[MAXN + 200]; bool book[MAXN + 200]; void phi_prime (int n) { int i, j; mems
用户2965768
2018/08/30
4240
算法帝国里的牛人们:欧拉
点击标题下「大数据文摘」可快捷关注 1791年,著名奥地利作曲家约瑟夫·海顿出席了乔治·弗里德里希·亨德尔在伦敦威斯敏斯特大教堂的盛大清唱剧《弥赛亚》的演出。演出快要结束时,海顿被上千名合唱队和管弦乐
大数据文摘
2018/05/22
8480
微分方程与欧拉法
本文介绍了如何利用数值求解方法解决微分方程,包括欧拉法、龙格-库塔方法等,并给出了具体的MATLAB代码示例。
用户1147754
2018/01/03
1.1K0
微分方程与欧拉法
数论 欧拉函数_数论欧拉函数
其中p1, p2……pn为n的所有质因数,n是不为0的整数。φ(1)=1(唯一和1互质的数就是1本身)。
全栈程序员站长
2022/09/23
3510
数论 欧拉函数_数论欧拉函数
【acm】【数论】欧拉定理与欧拉函数
除此之外,还可以求有关阶,原根,指数相关的问题。有些题目也需要转化为带有欧拉函数的公式。
duadua
2022/10/31
7330
【acm】【数论】欧拉定理与欧拉函数
欧拉函数及其计算_计算n的欧拉函数
计算这个值的方法就叫做欧拉函数,用φ(n)表示。在1到8之中,与8形成互质关系的是1、3、5、7,所以 φ(n) = 4。
全栈程序员站长
2022/09/23
1.1K0
欧拉函数及其计算_计算n的欧拉函数
欧拉函数、欧拉定理学习笔记
\varphi(n) = \sum \limits _{i=1}^n \left[ i \nmid n \right]
Clouder0
2022/09/23
9600
欧拉图
1. 定义 1.1 欧拉通路 & 欧拉回路 通过图(无向图或有向图)中所有边一次且仅一次行遍所有顶点的通路称作欧拉通路。 通过图(无向图或有向图)中所有边一次且仅一次行遍所有顶点的回路称作欧拉回路。 【注】规定平凡图是欧拉图。 1.2 欧拉图 & 半欧拉图 具有欧拉回路的图称为欧拉图。 具有欧拉通路而无欧拉回路的图称作半欧拉图。 2. 性质 无向图 是欧拉图当且仅当 是连通图且没有奇度顶点。 无向图 是半欧拉图当且仅当 是连通的且恰有两个奇度顶点。 有向图 是欧拉图当且仅当
hotarugali
2022/03/01
8490
欧拉函数
通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn) 其中 p1, p2……pn 为 x 的所有质因数,x 是不为 0 的整数 φ(1)=1(唯一和 1 互质的数就是 1 本身)【注意:每种质因数只一个。比如 12=223】
Cell
2022/02/25
4670
欧拉函数
欧拉公式
欧拉公式、麦克斯韦方程组、牛顿第二定律、勾股定理、薛定谔方程、质能方程、德布罗意方程组、1+1=2、傅立叶变换、圆的周长公式。
小小杨
2021/10/13
3.4K0
欧拉函数
如果对于任意两个正整数m和n,均有f(mn)=f(m)f(n),就称为完全积性函数。
饶文津
2020/05/31
8980
欧拉回路与欧拉路径
欧拉回路与欧拉路径 如果图G中的一个路径包括每个边恰好一次,则该路径称为欧拉路径(欧拉通路)。 如果一个回路是欧拉路径,则称为欧拉回路(Euler circuit)。 说的直白点,欧拉回路就是从一个点
attack
2018/04/10
2.2K0
欧拉回路与欧拉路径
欧拉函数
欧拉函数 表示的是小于等于 且和 互质的正整数的个数。(易知 )
hotarugali
2022/03/13
1.1K0
欧拉 函数
什么是互质 如果两个正整数,除了1以外,没有其他公因子,我们就称这两个数是互质关系(coprime)。比如,15和32没有公因子,所以它们是互质关系。这说明,不是质数也可以构成互质关系。
全栈程序员站长
2022/09/23
4420
欧拉 函数
欧拉函数
问题:求[L, R]中K ( 假设φ(n)表示1..n-1中与n互质的数的个数。对于[L,R]中的任意一个除K 以外的整数y,满足φ(K)≤φ(y)且φ(K)=φ(y)时,K<y ),K是[L,R]中φ(n)最小并且值也最小的数。
全栈程序员站长
2022/09/06
4290
欧拉函数详解
欧拉函数 我们用 表示欧拉函数 定义: 表示对于整数n,小于等于n中与n互质的数的个数 性质 1. 为积性函数 证明: 此处证明需要用到下面计算方法1中的内容,建议先看后面再回过头来看这里 假设存在p,q,且 将n,p,q进行质因数分解 那么 因为 显然 这种方法也是常见的证明一个函数是积性函数的方法 2. 3.1到n中与n互质的数的和为 计算方法 计算单值欧拉函数 假设我们需要计算 分情况讨论
attack
2018/04/11
1.1K0
欧拉函数及其证明_欧拉函数证明题
计算这个值的方法就叫做欧拉函数,以φ(n)表示。在1到8之中,与8形成互质关系的是1、3、5、7,所以 φ(n) = 4。
全栈程序员站长
2022/09/23
4870
欧拉函数及其证明_欧拉函数证明题

相似问题

将显式欧拉转换为隐式欧拉(通过定点迭代)

13

带数组的欧拉隐式方法

20

ODEs积分的隐式欧拉法

13

用显式欧拉法(MATLAB)求解ODE系统

11

欧拉-拉格朗日的Sympy隐微分

10
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档