Threejs实现Points对象实时指向指定坐标
全景图里常常会往场景里添加箭头,希望箭头可以指向某个3d坐标
matrial关键代码:
function createMaterial(size = 24) {
const vertexShader = `
attribute vec3 a_direction;
uniform float u_size;
uniform float u_aspect;
varying float v_rotation;
void main(){
gl_PointSize = u_size;
// 箭头的位置坐标
vec4 mvPosition = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
// 箭头指向的位置坐标
vec4 targetPos = projectionMatrix * modelViewMatrix * vec4(a_direction, 1.0);
vec2 dir = targetPos.xy/targetPos.w -mvPosition.xy/mvPosition.w;
float theta = atan(dir.y / u_aspect, dir.x);
v_rotation = theta; // mod( theta + PI, 2.0 * PI );
gl_Position = mvPosition;
}
`;
const fragmentShader = `
uniform vec3 u_color;
uniform float u_opacity;
uniform sampler2D u_map;
varying float v_rotation;
void main(){
vec2 uv = gl_PointCoord - vec2(0.5);
float xn = uv.x * cos(v_rotation) - uv.y * sin(v_rotation);
float yn = uv.x * sin(v_rotation) + uv.y * cos(v_rotation);
vec2 new_uv = vec2(xn +0.5, yn+0.5);
if(new_uv.x < 0.0 || new_uv.x > 1.0 || new_uv.y < 0.0 || new_uv.y > 1.0){
discard;
}
float mapColor = texture2D(u_map, new_uv).r;
gl_FragColor = vec4(u_color, u_opacity * mapColor);
}
`;
const texture = createCanvasTexture();
const usize = size * window.devicePixelRatio;
const material = new ShaderMaterial({
uniforms: {
u_size: { value: usize },
u_color: { value: new Color(0xff0000) },
u_opacity: { value: 1 },
u_map: { value: texture },
u_aspect: { value: aspect },
},
defines: {
PI: Math.PI,
},
vertexShader,
fragmentShader,
transparent: true,
});
return material;
}
需要注意的是shader里面获取到的向量还需要除以canvas真实宽高比,否则计算出来的角度会不对.
附上github源码及demo