如何在WebGL中使用大量纹理进行计算

如何在WebGL中使用大量纹理进行计算,webgl,gpu,textures,shader,Webgl,Gpu,Textures,Shader,仅关注单个顶点/片段着色器对的一致性/属性/变化,我想知道如何使用。关注2D 位置:当前对象的位置。 翻译:基于预先的一些CPU计算提出的对象。 速度:物体的速度。 旋转:下一个旋转的对象。 重力或碰撞等力:物体在每个方向上作用的合力。 温度:对象的温度。 质量/密度:对象的质量/密度。 曲率:沿预定义曲线移动,如缓和。 起初我想这样做: attribute vec3 a_position; attribute vec3 a_translation; attribute vec3 a_veloc

仅关注单个顶点/片段着色器对的一致性/属性/变化,我想知道如何使用。关注2D

位置:当前对象的位置。 翻译:基于预先的一些CPU计算提出的对象。 速度:物体的速度。 旋转:下一个旋转的对象。 重力或碰撞等力:物体在每个方向上作用的合力。 温度:对象的温度。 质量/密度:对象的质量/密度。 曲率:沿预定义曲线移动,如缓和。 起初我想这样做:

attribute vec3 a_position;
attribute vec3 a_translation;
attribute vec3 a_velocity;
attribute vec3 a_rotation;
attribute vec3 a_force;
attribute vec3 a_temperature;
attribute vec3 a_material; // mass and density
attribute vec4 a_color;
attribute vec4 a_curvature;
但这可能会遇到问题

于是我想起了这件事。没有太多细节,我只是想知道如何组织制服/属性/制服来实现这一点

attribute vec2 a_position_uv;
attribute vec2 a_translation_uv;
attribute vec2 a_velocity_uv;
attribute vec2 a_rotation_uv;
attribute vec2 a_force_uv;
attribute vec2 a_temperature_uv;
attribute vec2 a_material_uv;
attribute vec2 a_color_uv;
attribute vec2 a_curvature_uv;
如果我们这样做,属性都引用纹理坐标,那么纹理可能会存储vec4数据,因此我们可能会避免属性太多的问题

但我现在不确定如何为两个着色器定义纹理。不知道是不是这样的:

uniform sampler2D u_position_texture;
uniform sampler2D u_translation_texture;
uniform sampler2D u_velocity_texture;
uniform sampler2D u_rotation_texture;
uniform sampler2D u_force_texture;
uniform sampler2D u_temperature_texture;
uniform sampler2D u_material_texture;
uniform sampler2D u_color_texture;
uniform sampler2D u_curvature_texture;
然后在主要的顶点着色器中,我们可以使用纹理来计算位置

void main() {
  vec4 position = texture2D(u_position_texture, a_position_uv);
  vec4 translation = texture2D(u_translation_texture, a_translation_uv);
  // ...
  gl_Position = position * ...
}
通过这种方式,我们不需要顶点着色器中的任何变量来通过颜色,除非我们希望使用片段着色器中的计算结果。但我能理解这一部分。现在我只想知道是否有可能像这样构造着色器,因此最终的顶点着色器将是:

attribute vec2 a_position_uv;
attribute vec2 a_translation_uv;
attribute vec2 a_velocity_uv;
attribute vec2 a_rotation_uv;
attribute vec2 a_force_uv;
attribute vec2 a_temperature_uv;
attribute vec2 a_material_uv;
attribute vec2 a_color_uv;
attribute vec2 a_curvature_uv;

uniform sampler2D u_position_texture;
uniform sampler2D u_translation_texture;
uniform sampler2D u_velocity_texture;
uniform sampler2D u_rotation_texture;
uniform sampler2D u_force_texture;
uniform sampler2D u_temperature_texture;
uniform sampler2D u_material_texture;
uniform sampler2D u_color_texture;
uniform sampler2D u_curvature_texture;

void main() {
  vec4 position = texture2D(u_position_texture, a_position_uv);
  vec4 translation = texture2D(u_translation_texture, a_translation_uv);
  // ...
  gl_Position = position * ...
}
最后一个片段着色器可能是:

uniform sampler2D u_position_texture;
uniform sampler2D u_translation_texture;
uniform sampler2D u_velocity_texture;
uniform sampler2D u_rotation_texture;
uniform sampler2D u_force_texture;
uniform sampler2D u_temperature_texture;
uniform sampler2D u_material_texture;
uniform sampler2D u_color_texture;
uniform sampler2D u_curvature_texture;

varying vec2 v_foo
varying vec2 v_bar

void main() {
  // ...
  gl_Color = position * ... * v_foo * v_bar
}

<>你链接的问题不是太多的属性,而是太多的变量,它不仅与大多数平台上支持的纹理单元的最大数量相仿,而且假设你不需要将所有数据从顶点转移到片段着色器就应该是很好的。如果你不做任何更大的批量,你可以先用制服。也就是说,如果你出于任何原因决定使用纹理,你可能只会使用一个UV坐标并对齐所有数据纹理,否则你真的会无缘无故地将带宽需求增加了一倍


这样,您的数据集本身就可以被压缩很多。您可以将位置和旋转存储为四元数在2D中您甚至可以使用带有x、y、α的vec3原始数据集中缺少的速度和扭矩实际上只是当前位置和下一个位置的增量,因此您只需存储其中一个设置速度/扭矩或下一个位置/旋转,力似乎不相关,因为你会在CPU上应用它们,质量和温度是标量值,所以它们完全适合于一个vec2和一些其他jazz。但是我越是试图理解它,这看起来就越不成熟,你不能在GPU上真正进行模拟,但是你的一半属性是渲染不需要的模拟属性,感觉你过早地优化了一些甚至还不接近现有的东西,所以建议你:构建它,然后看看

>你链接的问题不是太多的属性,而是太多的变量,它不仅与大多数平台上支持的纹理单元的最大数量相仿,而且应该假设你不需要将所有数据从顶点转移到片段着色器。如果你不做任何更大的批量,你可以先用制服。也就是说,如果你出于任何原因决定使用纹理,你可能只会使用一个UV坐标并对齐所有数据纹理,否则你真的会无缘无故地将带宽需求增加了一倍


这样,您的数据集本身就可以被压缩很多。您可以将位置和旋转存储为四元数在2D中您甚至可以使用带有x、y、α的vec3原始数据集中缺少的速度和扭矩实际上只是当前位置和下一个位置的增量,因此您只需存储其中一个设置速度/扭矩或下一个位置/旋转,力似乎不相关,因为你会在CPU上应用它们,质量和温度是标量值,所以它们完全适合于一个vec2和一些其他jazz。但是我越是试图理解它,这看起来就越不成熟,你不能在GPU上真正进行模拟,但是你的一半属性是渲染不需要的模拟属性,感觉你过早地优化了一些甚至还不接近现有的东西,所以建议你:构建它,然后看看

LJ的答案可以说是正确的,但是如果你想在纹理中存储数据,你所需要的只是每个顶点的索引

attribute float index;

然后从中计算UV坐标

uniform vec2 textureSize;  // size of texture

float numVec4sPerElement = 8.;
float elementsPerRow = floor(textureSize.x / numVec4sPerElement);
float tx = mod(index, elementsPerRow) * numVec4sPerElement;
float ty = floor(index / elementsPerRow);
vec2 baseTexel = vec2(tx, ty) + 0.5;
现在可以提取数据了。注意:假设它是浮动纹理 等等

当然,您可能会更多地交错数据。比如说上面的位置是向量4,可能是位置,w是重力,平移,w是质量,等等

然后将数据放入纹理中

position0, translation0, velocity0, rotation0, forces0, .... 
position1, translation1, velocity1, rotation1, forces1, .... 
position2, translation2, velocity2, rotation2, forces2, .... 
position2, translation3, velocity3, rotation3, forces3, .... 
常数m4=twgl.m4; 常数v3=twgl.v3; const gl=document.querySelector'canvas.getContext'webgl'; const ext=gl.getExtension'OES_texture_float'; 如果分机{ 警报“需要纹理浮动”; } 常数vs=` 属性浮动指数; 均匀vec2织构化; 均匀的二维纹理; 统一mat4模型视图; 均匀mat4投影; 可变vec3 v_正常; 可变的vec4 v_颜色; 真空总管{ float numvec4sperelation=3;//位置、法线、颜色 float elementsPerRow=FloorTextureResize.x/numVec4sPerElement; float tx=修改索引,元素箭头*numvec4sperelation; 浮动ty=地板索引/元件箭头; vec2-baseTexel=vec2tx,ty+0.5; //现在可以提取数据了。 vec3位置=texture2ddataxture,baseTexel/textureSize.xyz; vec3 normal=texture2ddataxture,baseTexel+vec21,0/textureSize.xyz; vec4颜色=texture2DdataTexture,baseTexel+vec22,0/纹理化; gl_位置=投影*模型视图*矢量4位置,1; v_color=颜色; v_normal=正常; } `; 常数fs=` 高精度浮点; 可变vec3 v_正常; 可变的vec4 v_颜色; 方向一致; 真空总管{ 浮动灯光=点灯光方向,标准化EV_法线*.5+.5; gl_FragColor=vec4v_color.rgb*灯光,v_color.a; } `; //编译着色器、链接、查找位置 const programInfo=twgl.createProgramInfogl[vs,fs]; //制作一些顶点数据 常数半径=1; 常数厚度=.3; 常数radialSubdivisions=20; const bodysubsections=12; 常量顶点=twgl.primitives.CreateTorusVertexts 半径、厚度、半径细分、车身细分; /* 顶点现在是这样一个对象 { 位置:float32ArrayOfPositions, 普通:float32arrayfnormals, 索引:UINT16 ArrayoFindices, } */ //将顶点数据转换为纹理 常数=垂直位置长度/3; 常数vec4sperelation=3;//位置、正常、颜色 常量maxTextureWidth=2048;//你可以对此提出质疑 const elementsPerRow=maxTextureWidth/Vec4SperRelation | 0; const textureWidth=元素箭头*向量4sperelation; 常量纹理高度=numElements+元素箭头-1/ 元素箭头| 0; const data=new Float32ArraytextureWidth*texturehight*4; 对于let i=0;iLJ的答案可以说是正确的,但是如果你想在纹理中存储数据,你所需要的只是每个顶点的索引

attribute float index;

然后从中计算UV坐标

uniform vec2 textureSize;  // size of texture

float numVec4sPerElement = 8.;
float elementsPerRow = floor(textureSize.x / numVec4sPerElement);
float tx = mod(index, elementsPerRow) * numVec4sPerElement;
float ty = floor(index / elementsPerRow);
vec2 baseTexel = vec2(tx, ty) + 0.5;
现在可以提取数据了。注意:假设它是浮动纹理

vec4 position    = texture2D(dataTexture, baseTexel / textureSize);
vec4 translation = texture2D(dataTexture, (baseTexel + vec2(1,0)) / textureSize);
vec4 velocity    = texture2D(dataTexture, (baseTexel + vec2(2,0)) / textureSize);
vec4 rotation    = texture2D(dataTexture, (baseTexel + vec2(3,0)) / textureSize);
vec4 forces      = texture2D(dataTexture, (baseTexel + vec2(4,0)) / textureSize);
等等

当然,您可能会更多地交错数据。比如说上面的位置是向量4,可能是位置,w是重力,平移,w是质量,等等

然后将数据放入纹理中

position0, translation0, velocity0, rotation0, forces0, .... 
position1, translation1, velocity1, rotation1, forces1, .... 
position2, translation2, velocity2, rotation2, forces2, .... 
position2, translation3, velocity3, rotation3, forces3, .... 
常数m4=twgl.m4; 常数v3=twgl.v3; const gl=document.querySelector'canvas.getContext'webgl'; const ext=gl.getExtension'OES_texture_float'; 如果分机{ 警报“需要纹理浮动”; } 常数vs=` 属性浮动指数; 均匀vec2织构化; 均匀的二维纹理; 统一mat4模型视图; 均匀mat4投影; 可变vec3 v_正常; 可变的vec4 v_颜色; 真空总管{ float numvec4sperelation=3;//位置、法线、颜色 float elementsPerRow=FloorTextureResize.x/numVec4sPerElement; float tx=修改索引,元素箭头*numvec4sperelation; 浮动ty=地板索引/元件箭头; vec2-baseTexel=vec2tx,ty+0.5; //现在可以提取数据了。 vec3位置=texture2ddataxture,baseTexel/textureSize.xyz; vec3 normal=texture2ddataxture,baseTexel+vec21,0/textureSize.xyz; vec4颜色=texture2DdataTexture,baseTexel+vec22,0/纹理化; gl_位置=投影*模型视图*矢量4位置,1; v_color=颜色; v_normal=正常; } `; 常数fs=` 高精度浮点; 可变vec3 v_正常; 可变的vec4 v_颜色; 方向一致; 真空总管{ 浮动灯光=点灯光方向,标准化EV_法线*.5+.5; gl_FragColor=vec4v_color.rgb*灯光,v_color.a; } `; //编译着色器、链接、查找位置 const programInfo=twgl.createProgramInfogl[vs,fs]; //制作一些顶点数据 常数半径=1; 常数厚度=.3; 常数radialSubdivisions=20; const bodysubsections=12; 常量顶点=twgl.primitives.CreateTorusVertexts 半径、厚度、半径细分、车身细分; /* 顶点现在是这样一个对象 { 位置:float32ArrayOfPositions, 普通:float32arrayfnormals, 索引:UINT16 ArrayoFindices, } */ //将顶点数据转换为纹理 常数=垂直位置长度/3; 常数vec4sperelation=3;//位置、正常、颜色 常量maxTextureWidth=2048;//你可以对此提出质疑 const elementsPerRow=maxTextureWidth/Vec4SperRelation | 0; const textureWidth=元素箭头*向量4sperelation; 常量纹理高度=numElements+元素箭头-1/ 元素箭头| 0; const data=new Float32ArraytextureWidth*texturehight*4; 对于let i=0;i美丽的我没想到你们可以这样做,只是索引属性的一个浮动和一个纹理,太棒了!请注意,从纹理中提取数据比从属性中获取数据要慢。但是通过在纹理中使用它们,你可以访问相邻点的数据,这是一个巨大的胜利,我假设。然后你可以计算UV坐标,也许你可以解释这部分,方程,我不太明白。Why numvec4sperelation Why elementsPerRow,以及tx和ty的含义,以及baseTexel上的+0.5。对于*0.5,其余的请你解释一下,我会告诉你你是否正确。是一个格式奇怪的整数。mod是模数,但我不知道你为什么选择它。将首先在您的链接上阅读更多关于tx ty的信息,然后重试。很漂亮!我没想到你们可以这样做,只是索引属性的一个浮动和一个纹理,太棒了!请注意,从纹理中提取数据比从属性中获取数据要慢。但是通过在纹理中使用它们,你可以访问相邻点的数据,这是一个巨大的胜利,我假设。然后你可以计算UV坐标,也许你可以解释这部分,方程,我不太明白。Why numvec4sperelation Why elementsPerRow,以及tx和ty的含义,以及baseTexel上的+0.5。对于*0.5,其余的请你解释一下,我会告诉你你是否正确。是一个格式奇怪的整数。mod是模数,但我不知道你为什么选择它。将首先在链接上阅读有关tx ty的更多信息,然后重试。