gpt4 book ai didi

javascript - 纹理坐标拾取

转载 作者:行者123 更新时间:2023-12-03 10:57:49 24 4
gpt4 key购买 nike

我正在尝试检测用户单击对象上纹理中的位置,以便我可以重新绘制纹理作为响应。

我知道我可以使用颜色编码纹理将对象渲染到单独的渲染目标,并使用 gl.readPixels 来查看单击了哪个编码像素,然后计算回纹理中的 X 和 Y 坐标.

我似乎能够对 Y 轴可靠地执行此操作,但不能对 X 轴执行此操作。

这是我的(删除了无关的代码)Three.js 设置:

var canvas = document.getElementByID("output"),
renderer = new THREE.WebGLRenderer({
canvas: canvas,
alpha: true,
antialias: true
}),
back = new THREE.WebGLRenderTarget(canvas.width, canvas.height),
scene = new THREE.Scene(),
pickingScene = new THREE.Scene(),
pickingPixelBuffer = new Uint8Array(4),
camera = new THREE.PerspectiveCamera(50, canvas.width / canvas.height, 0.1, 1000),
textureWidth = 1024,
textureHeight = 1024,
texture = generateTexture(textureWidth, textureHeight),
pickingTexture = generatePickingTexture(textureWidth, textureHeight),
obj = textured(shell(w, 5, 10), texture),
objPicker = textured(shell(w, 5, 10), pickingTexture);

back.generateMipmaps = false;

scene.add(camera);
scene.add(obj);
pickingScene.add(objPicker);

对于这样的对象: enter image description here

拾取纹理最终看起来像这样: the picking texture

generateTexture 函数实际上并不那么重要。 textured 函数只是将纹理应用于几何对象的简写:

function textured(geometry, txt){
var material = new THREE.MeshBasicMaterial({
color: 0xffffff,
map: txt,
transparent: false,
shading: THREE.FlatShading,
side: THREE.DoubleSide
});

var obj = new THREE.Mesh(geometry, material);
return obj;
}

generatePickingTexture 函数如下:

function generatePickingTexture(w, h){
var canvas = document.createElement("canvas");
canvas.width = w;
canvas.height = h;
var texture = new THREE.Texture(canvas);
var gfx = texture.image.getContext("2d"),
l = w * h,
pixels = gfx.createImageData(w, h);
for(var i = 0, p = 0;
i < l;
++i, p += 4){
pixels.data[p] = (0xff0000 & i) >> 16;
pixels.data[p+1] = (0x00ff00 & i) >> 8;
pixels.data[p+2] = 0x0000ff & i;
pixels.data[p+3] = 0xff;
}
gfx.putImageData(pixels, 0, 0);

texture.needsUpdate = true;
return texture;
}

然后我尝试执行挑选:

function pick(){
renderer.render(pickingScene, camera, back, true);

var gl = renderer.getContext();
gl.readPixels(pointerX, canvas.height - pointerY, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pickingPixelBuffer);
var i = (pickingPixelBuffer[0] << 16) |
(pickingPixelBuffer[1] << 8) |
pickingPixelBuffer[2],
// x = i % textureWidth,
x = (i - Math.floor(textureWidth / 512) * 256) % textureWidth, // EDIT2: this is the hack
y = i / textureWidth;
console.log(x, y);
}

正如我所说,y 坐标效果非常好。但x坐标偏离了很多。当我在屏幕上向下拖动鼠标时,x 坐标会向右扭曲,跳跃约纹理宽度的 1/4。当我在屏幕上拖动鼠标时,如果可以避免任何垂直鼠标移动,则 x 坐标会以正确的偏移量移动,但不在正确的位置。每次我击中 1/4 标记之一时,它似乎都会跳转位置。

由于它 1/4,看来我生成纹理的数学是错误的。但对于我的一生来说,我看不到它。

编辑:确实,如果我将纹理限制为只有 256 像素宽,它就可以完美工作。

EDIT2:我已经找到了解决问题的 pick 函数的破解方法,但我不明白它为什么起作用。

<罢工>

EDIT3:嗯,“工作”的条件是对象在屏幕上的显示比例为 1:1。不同方向仍然存在一些问题,但这与其他问题无关。我怀疑这与纹理的重新采样有关。

EDIT4:这是默认的纹理过滤设置。

最佳答案

哦!整个过程都是纹理过滤。我需要将我的 generatePickingTexture 函数更改为:

function generatePickingTexture(w, h){
var canvas = document.createElement("canvas");
canvas.width = w;
canvas.height = h;
var texture = new THREE.Texture(canvas, THREE.UVMapping, THREE.RepeatWrapping, THREE.RepeatWrapping, THREE.NearestFilter, THREE.NearestFilter);
var gfx = canvas.getContext("2d"),
l = w * h,
pixels = gfx.createImageData(w, h);
for(var i = 0, p = 0; i < l; ++i, p += 4){
pixels.data[p] = (0xff0000 & i) >> 16;
pixels.data[p+1] = (0x00ff00 & i) >> 8;
pixels.data[p+2] = (0x0000ff & i) >> 0;
pixels.data[p+3] = 0xff;
}
gfx.putImageData(pixels, 0, 0);

texture.needsUpdate = true;
return texture;
}

关于javascript - 纹理坐标拾取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28201530/

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