【发布时间】:2023-04-10 16:11:01
【问题描述】:
我正在努力处理片段着色器中的坐标。
简而言之,我只想使用世界空间的(x,y,z) 用片段着色器绘制圆圈。但由于相机位置和圆中心位置的z,我无法获得实际正确投影的x 和y 坐标。
假设我的相机放置在(0, 0, 1000) 并以
- 视野:45度
- 方面与
screen_width/screen_height - Z 附近:1
- 远:10000
相机看(0,0)。在这种情况下使用three.js,我可以获得相机的projectionMatrix 和ModelViewMatrix(例如PerspectiveCamera.projectionMatrix),并且默认情况下我可以在ShaderMaterial 的fragmentShader 中使用viewMatrix three.js。
所以在 fragmentShader 中,为了计算放置(300, 300, -1000) 的圆的投影坐标,我写了我的VertexShader 和FragmentShader,如下所示。
我的顶点着色器仅用于将projectionMatrix 和modelViewMatrix 设置为P 和MV。
// vertexShader
varying mat4 P;
varying mat4 MV;
void main(){
P = projectionMatrix;
MV = modelViewMatrix;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
然后,我只需使用 P 和 MV 计算 x 和 y,如下所示。
// fragmentShader
varying mat4 P;
varying mat4 MV;
uniform float x;
uniform float y;
uniform float z;
uniform float r;
uniform vec2 u_resolution;
float circle(vec2 _st, vec2 _center, float _radius){
vec2 dist = _st - _center + u_resolution;
return 1.-smoothstep(_radius-(_radius*0.01),
_radius+(_radius*0.01),
length(dist));
}
void main(){
vec2 coord = (P * MV * vec4(x, y, z, 1.0)).xy;
float point = circle(gl_FragCoord.xy, coord, r); // ignore r scaling.
gl_FragColor = vec4(vec4(point), point);
}
但结果与我的预期不符。并且还发现了一些奇怪的行为。
- 不管
z的制服是什么,都没有任何变化。 - 像素比可能是某种原因(例如视网膜显示器的像素比为 2),但从我的实验来看,这与此无关。
我犯了什么错误?还是有什么误导? (不知何故,circle 函数可能有错误,但我认为这不会造成严重问题..)
【问题讨论】:
-
哇是
u_resolution,你对_st - _center + u_resolution有什么期望?不应该是(_st - _center) / u_resolution之类的东西吗?请注意,gl_FragCoord.xy是窗口(像素)坐标。 -
嗨。我希望圆圈放置在
(x,y)并且因为gl_FragCoord 从左下角的(0,0)开始,我添加了u_resolution(这也是因为_center是来自(0,0)的坐标,表示屏幕中心。 -
为什么你的投影和模型视图矩阵作为
varyings 传递? -
嗯,很可能,您的矩阵一开始是
uniforms,因此它们已经可用于程序中的所有着色器阶段,将它们作为varyings 传递只是一种巨大的浪费资源。 -
但这里的主要问题是您的计算没有任何意义。您尝试使用原点的剪辑空间位置和窗口空间片段坐标来定义一个圆。我不清楚的是您实际想要实现的目标:实际的 2D、不失真的圆,或某个圆的正确透视图像。
标签: three.js glsl shader fragment-shader perspectivecamera