Three.js - 基于屏幕上像素位置着色的顶点着色器

时间:2013-11-04 20:30:24

标签: javascript three.js webgl fragment-shader vertex-shader

使用Three.js,我编写了一个顶点着色器,根据渲染像素的屏幕的象限,为平面中的每个点着色。

// 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);
}  

enter image description here

jsFiddle的实例:http://jsfiddle.net/Stemkoski/ST4aM/

我想修改此着色器,使x在屏幕左侧等于0,在屏幕右侧等于1,同样y等于0顶部和底部1。我(错误地)认为这会涉及将xy的值更改为x = v.x / widthy = v.y / height(其中widthheight存储窗户的宽度和高度)。但是,通过此更改,在平面上放大和缩小时,每个屏幕像素的颜色似乎都会发生变化。

如何修复着色器代码以获得所需效果?

2 个答案:

答案 0 :(得分:5)

您的变量v位于剪辑空间中。您需要应用透视分割以将其映射到规范化设备坐标(NDC)空间,该空间采用范围[-1,1]中的值。然后,您需要将该值映射到范围[0,1],如下所示:

    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 );

小提琴:http://jsfiddle.net/ST4aM/4/

three.js r.62

答案 1 :(得分:1)

只是WestLangley的回答。

我遇到了一个小错误,我的顶点位置计算错误。似乎它在(-1.1,1.1)的范围内。因此,在经过实验后发现v.z并不完全正确,它依赖于近场剪裁平面,人们通常在相机设置中将其保留为1。因此,向v.z添加2似乎已经修复了它。我不明白为什么2而不是1.

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

因此,如果您正在使用像WestLangley这样的大型对象,您将无法注意到它,但如果您的对象很小并且靠近相机,则错误将会很明显。

如果位置不在Y的(0,1)范围内,并且X的固定计算,我修改了上面的示例来修剪颜色。平面尺寸为20,相机距离为30。

vertex position calculation error

jsFiddle

它还不完美。如果物体非常接近相机,它仍然会弄乱位置,但至少这使得它适用于中等大小的物体。

error in super close proximity