gpt4 book ai didi

three.js - 如果数据纹理不是正方形,则会出现奇怪的行为(1 :1)

转载 作者:行者123 更新时间:2023-12-02 22:06:21 27 4
gpt4 key购买 nike

我有一对着色器程序,如果我的数据纹理是正方形 (1:1),则一切正常,但如果其中一个或两者的比例为 2:1(宽度:高度),则行为会变得困惑。我可以使用未使用的填充符扩展每个缓冲区,以确保它们始终是方形的,但从长远来看,这似乎不必要地昂贵(内存方面),因为两个缓冲区大小之一一开始就相当大。在这种情况下有没有办法处理 2:1 缓冲区?

我有一对着色器程序:

  1. 第一个是单个碎片着色器,用于计算我的程序的物理特性(它写出纹理tPositions以供第二组着色器读取)。它由 Three.js 的 GPUComputeRenderer 脚本驱动(分辨率设置为我最大缓冲区的大小。)
  2. 第二对着色器(vert 和 frag)使用第一个着色器程序生成的数据纹理 tPositions 来渲染可视化效果(分辨率设置为窗口大小)。

可视化是不同形状的粒子云的网格。在着色器程序中,有两种不同尺寸的纹理:较小尺寸的纹理包含每个粒子云的信息(每个云一个纹理像素),较大尺寸的纹理包含所有云中每个粒子的信息(每个粒子一个纹理像素) )。两者的末端都粘有一定量未使用的填充物,以将其填充到 2 的幂。

每粒子纹理像素大小的纹理(大): tPositionstOffsets

每云纹理大小的纹理(小): tGridPositionsAndSeedstSelectionFactors

正如我之前所说,问题是当这两个缓冲区大小(大和小)的比例为 1:1(宽度:高度)时,程序运行得很好;然而,当其中一个或两者的比例为 2:1(宽度:高度)时,行为就会变得一团糟。造成这种情况的原因是什么?我该如何解决?提前致谢!

更新:问题是否与我在第二个着色器的 position 属性中容纳纹理像素坐标以读取 tPosition 纹理有关着色器程序?如果是这样,也许这个Github issue关于 position 属性中的纹素坐标可能相关,尽管我在此处找不到相应的问题/答案。

更新2:我也在研究这是否可能是 unpack alignment issue 。想法?

这是第一个着色器程序在 Three.js 中的设置:

function initComputeRenderer() {

textureData = MotifGrid.getBufferData();

gpuCompute = new GPUComputationRenderer( textureData.uPerParticleBufferWidth, textureData.uPerParticleBufferHeight, renderer );

dtPositions = gpuCompute.createTexture();
dtPositions.image.data = textureData.tPositions;

offsetsTexture = new THREE.DataTexture( textureData.tOffsets, textureData.uPerParticleBufferWidth, textureData.uPerParticleBufferHeight, THREE.RGBAFormat, THREE.FloatType );
offsetsTexture.needsUpdate = true;

gridPositionsAndSeedsTexture = new THREE.DataTexture( textureData.tGridPositionsAndSeeds, textureData.uPerMotifBufferWidth, textureData.uPerMotifBufferHeight, THREE.RGBAFormat, THREE.FloatType );
gridPositionsAndSeedsTexture.needsUpdate = true;

selectionFactorsTexture = new THREE.DataTexture( textureData.tSelectionFactors, textureData.uPerMotifBufferWidth, textureData.uPerMotifBufferHeight, THREE.RGBAFormat, THREE.FloatType );
selectionFactorsTexture.needsUpdate = true;

positionVariable = gpuCompute.addVariable( "tPositions", document.getElementById( 'position_fragment_shader' ).textContent, dtPositions );
positionVariable.wrapS = THREE.RepeatWrapping; // repeat wrapping for use only with bit powers: 8x8, 16x16, etc.
positionVariable.wrapT = THREE.RepeatWrapping;

gpuCompute.setVariableDependencies( positionVariable, [ positionVariable ] );

positionUniforms = positionVariable.material.uniforms;
positionUniforms.tOffsets = { type: "t", value: offsetsTexture };
positionUniforms.tGridPositionsAndSeeds = { type: "t", value: gridPositionsAndSeedsTexture };
positionUniforms.tSelectionFactors = { type: "t", value: selectionFactorsTexture };
positionUniforms.uPerMotifBufferWidth = { type : "f", value : textureData.uPerMotifBufferWidth };
positionUniforms.uPerMotifBufferHeight = { type : "f", value : textureData.uPerMotifBufferHeight };
positionUniforms.uTime = { type: "f", value: 0.0 };
positionUniforms.uXOffW = { type: "f", value: 0.5 };

}

这是第一个着色器程序(仅用于物理计算的片段):

   // tPositions is handled by the GPUCompute script
uniform sampler2D tOffsets;
uniform sampler2D tGridPositionsAndSeeds;
uniform sampler2D tSelectionFactors;
uniform float uPerMotifBufferWidth;
uniform float uPerMotifBufferHeight;
uniform float uTime;
uniform float uXOffW;

[...skipping a noise function for brevity...]

void main() {

vec2 uv = gl_FragCoord.xy / resolution.xy;

vec4 offsets = texture2D( tOffsets, uv ).xyzw;
float alphaMass = offsets.z;
float cellIndex = offsets.w;

if (cellIndex >= 0.0) {

float damping = 0.98;

float texelSizeX = 1.0 / uPerMotifBufferWidth;
float texelSizeY = 1.0 / uPerMotifBufferHeight;
vec2 perMotifUV = vec2( mod(cellIndex, uPerMotifBufferWidth)*texelSizeX, floor(cellIndex / uPerMotifBufferHeight)*texelSizeY );
perMotifUV += vec2(0.5*texelSizeX, 0.5*texelSizeY);

vec4 selectionFactors = texture2D( tSelectionFactors, perMotifUV ).xyzw;
float swapState = selectionFactors.x;
vec4 gridPosition = texture2D( tGridPositionsAndSeeds, perMotifUV ).xyzw;
vec2 noiseSeed = gridPosition.zw;
vec4 nowPos;
vec2 velocity;

nowPos = texture2D( tPositions, uv ).xyzw;
velocity = vec2(nowPos.z, nowPos.w);

if ( swapState == 0.0 ) {
nowPos = texture2D( tPositions, uv ).xyzw;
velocity = vec2(nowPos.z, nowPos.w);
} else { // if swapState == 1
//nowPos = vec4( -(uTime) + gridPosition.x + offsets.x, gridPosition.y + offsets.y, 0.0, 0.0 );
nowPos = vec4( -(uTime) + offsets.x, offsets.y, 0.0, 0.0 );
velocity = vec2(0.0, 0.0);
}

[...skipping the physics for brevity...]

vec2 newPosition = vec2(nowPos.x - velocity.x, nowPos.y - velocity.y);
// Write new position out
gl_FragColor = vec4(newPosition.x, newPosition.y, velocity.x, velocity.y);
}

这是第二个着色器程序的设置:注意:此部分的渲染器是窗口大小的 WebGLRenderer

function makePerParticleReferencePositions() {

var positions = new Float32Array( perParticleBufferSize * 3 );

var texelSizeX = 1 / perParticleBufferDimensions.width;
var texelSizeY = 1 / perParticleBufferDimensions.height;

for ( var j = 0, j3 = 0; j < perParticleBufferSize; j ++, j3 += 3 ) {

positions[ j3 + 0 ] = ( ( j % perParticleBufferDimensions.width ) / perParticleBufferDimensions.width ) + ( 0.5 * texelSizeX );
positions[ j3 + 1 ] = ( Math.floor( j / perParticleBufferDimensions.height ) / perParticleBufferDimensions.height ) + ( 0.5 * texelSizeY );
positions[ j3 + 2 ] = j * 0.0001; // this is the real z value for the particle display

}

return positions;
}

var positions = makePerParticleReferencePositions();

...

// Add attributes to the BufferGeometry:
gridOfMotifs.geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
gridOfMotifs.geometry.addAttribute( 'aTextureIndex', new THREE.BufferAttribute( motifGridAttributes.aTextureIndex, 1 ) );
gridOfMotifs.geometry.addAttribute( 'aAlpha', new THREE.BufferAttribute( motifGridAttributes.aAlpha, 1 ) );
gridOfMotifs.geometry.addAttribute( 'aCellIndex', new THREE.BufferAttribute(
motifGridAttributes.aCellIndex, 1 ) );

uniformValues = {};
uniformValues.tSelectionFactors = motifGridAttributes.tSelectionFactors;
uniformValues.uPerMotifBufferWidth = motifGridAttributes.uPerMotifBufferWidth;
uniformValues.uPerMotifBufferHeight = motifGridAttributes.uPerMotifBufferHeight;

gridOfMotifs.geometry.computeBoundingSphere();

...

function makeCustomUniforms( uniformValues ) {

selectionFactorsTexture = new THREE.DataTexture( uniformValues.tSelectionFactors, uniformValues.uPerMotifBufferWidth, uniformValues.uPerMotifBufferHeight, THREE.RGBAFormat, THREE.FloatType );
selectionFactorsTexture.needsUpdate = true;

var customUniforms = {
tPositions : { type : "t", value : null },
tSelectionFactors : { type : "t", value : selectionFactorsTexture },
uPerMotifBufferWidth : { type : "f", value : uniformValues.uPerMotifBufferWidth },
uPerMotifBufferHeight : { type : "f", value : uniformValues.uPerMotifBufferHeight },
uTextureSheet : { type : "t", value : texture }, // this is a sprite sheet of all 10 strokes
uPointSize : { type : "f", value : 18.0 }, // the radius of a point in WebGL units, e.g. 30.0
// Coords for the hatch textures:
uTextureCoordSizeX : { type : "f", value : 1.0 / numTexturesInSheet },
uTextureCoordSizeY : { type : "f", value : 1.0 }, // the size of a texture in the texture map ( they're square, thus only one value )
};
return customUniforms;
}

这是相应的着色器程序(vert & frag):

顶点着色器:

    uniform sampler2D tPositions;
uniform sampler2D tSelectionFactors;
uniform float uPerMotifBufferWidth;
uniform float uPerMotifBufferHeight;
uniform sampler2D uTextureSheet;
uniform float uPointSize; // the radius size of the point in WebGL units, e.g. "30.0"
uniform float uTextureCoordSizeX; // vertical dimension of each texture given the full side = 1
uniform float uTextureCoordSizeY; // horizontal dimension of each texture given the full side = 1

attribute float aTextureIndex;
attribute float aAlpha;
attribute float aCellIndex;

varying float vCellIndex;
varying vec2 vTextureCoords;
varying vec2 vTextureSize;
varying float vAlpha;
varying vec3 vColor;
varying float vDensity;

[...skipping noise function for brevity...]

void main() {

vec4 tmpPos = texture2D( tPositions, position.xy );
vec2 pos = tmpPos.xy;
vec2 vel = tmpPos.zw;

vCellIndex = aCellIndex;

if (aCellIndex >= 0.0) { // buffer filler cell indexes are -1

float texelSizeX = 1.0 / uPerMotifBufferWidth;
float texelSizeY = 1.0 / uPerMotifBufferHeight;
vec2 perMotifUV = vec2( mod(aCellIndex, uPerMotifBufferWidth)*texelSizeX, floor(aCellIndex / uPerMotifBufferHeight)*texelSizeY );
perMotifUV += vec2(0.5*texelSizeX, 0.5*texelSizeY);

vec4 selectionFactors = texture2D( tSelectionFactors, perMotifUV ).xyzw;
float aSelectedMotif = selectionFactors.x;
float aColor = selectionFactors.y;
float fadeFactor = selectionFactors.z;

vTextureCoords = vec2( aTextureIndex * uTextureCoordSizeX, 0 );
vTextureSize = vec2( uTextureCoordSizeX, uTextureCoordSizeY );

vAlpha = aAlpha * fadeFactor;
vDensity = vel.x + vel.y;
vAlpha *= abs( vDensity * 3.0 );

vColor = vec3( 1.0, aColor, 1.0 ); // set RGB color associated to vertex; use later in fragment shader.

gl_PointSize = uPointSize;

} else { // if this is a filler cell index (-1)
vAlpha = 0.0;
vDensity = 0.0;
vColor = vec3(0.0, 0.0, 0.0);
gl_PointSize = 0.0;
}
gl_Position = projectionMatrix * modelViewMatrix * vec4( pos.x, pos.y, position.z, 1.0 ); // position holds the real z value. The z value of "color" is a component of velocity
}

片段着色器:

    uniform sampler2D tPositions;
uniform sampler2D uTextureSheet;

varying float vCellIndex;
varying vec2 vTextureCoords;
varying vec2 vTextureSize;
varying float vAlpha;
varying vec3 vColor;
varying float vDensity;

void main() {
gl_FragColor = vec4( vColor, vAlpha );

if (vCellIndex >= 0.0) { // only render out the texture if this point is not a buffer filler
vec2 realTexCoord = vTextureCoords + ( gl_PointCoord * vTextureSize );
gl_FragColor = gl_FragColor * texture2D( uTextureSheet, realTexCoord );
}
}

预期行为:我可以通过强制所有 DataTextures 为 1:1 来实现此目的 expected behavior - shaped particle clouds correctly assembled and displayed in an offset grid

奇怪的行为:当较小的DataTextures为2:1时,下图右上角的那些完全水平的云就会形成并扰乱物理。当较大的 DataTextures 为 2:1 时,网格会倾斜,并且云看起来会丢失部分(如下所示)。当小纹理和大纹理均为 2:1 时,会发生两种奇怪的行为(如下图所示)。 weird behavior - particle clouds incorrectly assembled and displayed in a skewed grid

最佳答案

感谢对我的相关问题的回答here ,我现在知道出了什么问题了。问题在于我使用索引数组(1,2,3,4,5...)来访问着色器中的 DataTextures 纹素的方式。

在此函数中(以及较大的 DataTextures 的函数)...

float texelSizeX = 1.0 / uPerMotifBufferWidth;
float texelSizeY = 1.0 / uPerMotifBufferHeight;
vec2 perMotifUV = vec2(
mod(aCellIndex, uPerMotifBufferWidth)*texelSizeX,
floor(aCellIndex / uPerMotifBufferHeight)*texelSizeY );
perMotifUV += vec2(0.5*texelSizeX, 0.5*texelSizeY);

...我假设为了为我的自定义 uv perMotifUV 创建 y 值,我需要除以 aCellIndex > 缓冲区的高度,uPerMotifBufferHeight(它是“垂直”尺寸)。然而,正如 SO Q&A here 中所解释的那样当然,索引应该除以缓冲区的宽度,然后它会告诉你有多少行!

因此,该函数应修改为...

float texelSizeX = 1.0 / uPerMotifBufferWidth;
float texelSizeY = 1.0 / uPerMotifBufferHeight;
vec2 perMotifUV = vec2(
mod(aCellIndex, uPerMotifBufferWidth)*texelSizeX,
floor(aCellIndex / uPerMotifBufferWidth)*texelSizeY ); **Note the change to uPerMotifBufferWidth here
perMotifUV += vec2(0.5*texelSizeX, 0.5*texelSizeY);

我的程序在方形 DataTextures (1:1) 上运行的原因是,在这种情况下,高度和宽度相等,因此我的函数实际上在错误的行中除以宽度,因为高度=宽度!

关于three.js - 如果数据纹理不是正方形,则会出现奇怪的行为(1 :1),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42789471/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com