2015-01-28 3 views
0

Я пытаюсь обнаружить, где в текстуре на объекте пользователь щелкнул, чтобы я мог перерисовать текстуру в ответ.Выбор координаты текстуры

Я знаю, что я могу визуализировать объекты с цветной текстурой отдельной целью рендеринга и использовать 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/4th, кажется вероятным, что моя математика для генерации текстуры неверна. Но для моей жизни я не вижу этого.

EDIT: действительно, если я ограничу свою текстуру только шириной в 256 пикселей, она отлично работает.

EDIT2: Я выяснил взломанную функцию pick, которая устраняет проблему, но я не понимаю, почему она работает.

EDIT3: Хорошо, «работает» под условием, что объект имеет коэффициент отображения 1 к 1 для экрана. Есть еще некоторые проблемы с разными ориентациями, но это не связано с этой другой проблемой. Я подозреваю, что это связано с повторной выборкой текстуры.

EDIT4: это настройки фильтрации текстуры по умолчанию.

ответ

1

OH! Все это было текстурной фильтрацией. Мне нужно было изменить свою функцию 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; 
} 
Смежные вопросы