Three.js - a vertex shader to color based on location of pixel on screen

こ雲淡風輕ζ 提交于 2019-12-06 09:14:13

问题


Using Three.js, I have written a vertex shader that colors each point in a plane according to which quadrant of the screen a pixel is rendered.

// vertex shader
uniform float width;
uniform float height;
varying float x;
varying float y;
void main() 
{ 
    vec4 v = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    x = v.x; 
    y = v.y;
    gl_Position = v;
}

// fragment shader
varying float x;
varying float y;
void main() 
{
    gl_FragColor = vec4(x, y, 0.0, 1.0);
}  

Live example at jsFiddle: http://jsfiddle.net/Stemkoski/ST4aM/

I would like to modify this shader so that x is equal to 0 on the left side of the screen and 1 on the right side of the screen, and similarly y equal to 0 on the top and 1 on the bottom. I (incorrectly) assumed that this would involve changing the values of x and y to x = v.x / width and y = v.y / height (where width and height store the window's width and height). However, with this change the colors at each screen pixel seem to change when zooming in and out on the plane.

How can I fix the shader code to have the desired effect?


回答1:


Your variable v is in clip space. You need to apply the perspective divide to map that to normalized device coordinate ( NDC ) space, which takes values in the range [ -1, 1 ]. Then, you need to map that value to the range [ 0, 1 ] like so:

    vec4 v = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    x = v.x / v.z;
    y = v.y / v.z;

    gl_FragColor = vec4( 0.5 * x + 0.5, - 0.5 * y + 0.5, 0.0, 1.0 );

fiddle: http://jsfiddle.net/ST4aM/4/

three.js r.62




回答2:


Just an addition to WestLangley's answer.

I encountered a small bug that my vertex position was being calculated slightly wrong. Seemed that it was in range of (-1.1, 1.1). So after experimenting it turned out that v.z is not exactly correct, it is dependent on near field clip plane, which people usually leave as 1 in camera setup. So adding 2 to v.z seems have fixed it. I don't understand why 2 and not 1.

x = v.x / (v.z + 2.0); // depth + 2 x near clip space plane dist (camera setting)

So if you are working with large objects like in WestLangley's example, you won't notice it, but if your objects are small and close to camera then the error will be noticeable.

I've modified above example to clip color if position is not within (0,1) for Y and fixed calculation for X. Plane size is 20, camera distance is 30.

jsFiddle

It's still not perfect. If object gets very close to the camera it still messes up the position, but at least this makes it work with medium sized objects.



来源:https://stackoverflow.com/questions/19776554/three-js-a-vertex-shader-to-color-based-on-location-of-pixel-on-screen

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!