imbrizi
imbrizi

Reputation: 3838

Read vertex positions as pixels in Three.js

In a scenario where vertices are displaced in the vertex shader, how to retrieve their transformed positions in WebGL / Three.js?

Other questions here suggest to write the positions to a texture and then read the pixels, but the resulting value don't seem to be correct.

In the example below the position is passed to the fragment shader without any transformations:

// vertex shader
varying vec4 vOut;

void main() {
    gl_Position = vec4(position, 1.0);
    vOut = vec4(position, 1.0);
}

// fragment shader
varying vec4 vOut;

void main() {
    gl_FragColor = vOut;
}

Then reading the output texture, I would expect pixel[0].r to be identical to positions[0].x, but that is not the case.

enter image description here

Here is a jsfiddle showing the problem: https://jsfiddle.net/brunoimbrizi/m0z8v25d/2/

What am I missing?

Upvotes: 1

Views: 1070

Answers (2)

pailhead
pailhead

Reputation: 5431

You're not writing the vertices out correctly.

https://jsfiddle.net/ogawzpxL/

First off you're clipping the geometry, so your vertices actually end outside the view, and you see the middle of the quad without any vertices.

You can use the uv attribute to render the entire quad in the view.

gl_Position = vec4( uv * 2. - 1. , 0. ,1.);

Everything in the buffer represents some point on the quad. What seems to be tricky is when you render, the pixel will sample right next to your vertex. In the fiddle i've applied an offset to the world space thing by how much it would be in pixel space, and it didn't really work.

The reason why it seems to work with points is that this is all probably wrong :) If you want to transform only the vertices, then you need to store them properly in the texture. You can use points for this, but ideally they wouldn't be spaced out so much. In your scenario, they would fill the first couple of rows of the texture (since it's much larger than it could be).

You might start running into problems as soon as you try to apply this to something other than PlaneGeometry. In which case this problem has to be broken down.

Upvotes: 1

imbrizi
imbrizi

Reputation: 3838

Solved. Quite a few things were wrong with the jsfiddle mentioned in the question.

  • width * height should be equal to the vertex count. A PlaneBufferGeometry with 4 by 4 segments results in 25 vertices. 3 by 3 results in 16. Always (w + 1) * (h + 1).
  • The positions in the vertex shader need a nudge of 1.0 / width.
  • The vertex shader needs to know about width and height, they can be passed in as uniforms.
  • Each vertex needs an attribute with its index so it can be correctly mapped.
  • Each position should be one pixel in the resulting texture.
  • The resulting texture should be drawn as gl.POINTS with gl_PointSize = 1.0.

Working jsfiddle: https://jsfiddle.net/brunoimbrizi/m0z8v25d/13/

Upvotes: 1

Related Questions