使用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);
}
jsFiddle的实例:http://jsfiddle.net/Stemkoski/ST4aM/
我想修改此着色器,使x
在屏幕左侧等于0,在屏幕右侧等于1,同样y
等于0顶部和底部1。我(错误地)认为这会涉及将x
和y
的值更改为x = v.x / width
和y = v.y / height
(其中width
和height
存储窗户的宽度和高度)。但是,通过此更改,在平面上放大和缩小时,每个屏幕像素的颜色似乎都会发生变化。
如何修复着色器代码以获得所需效果?
答案 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。
它还不完美。如果物体非常接近相机,它仍然会弄乱位置,但至少这使得它适用于中等大小的物体。