Feng - 2024年3月
type: channel
link: http://fengyitong.name/index.php/2024/03/
description: 半山腰的风采
items: Threejs实现Points对象实时指向指定坐标

Threejs实现Points对象实时指向指定坐标
type: item
date: 2024-03-23T17:37:00+08:00
description: 全景图里常常会往场景里添加箭头,希望箭头可以指向某个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源码及demogithub源码地址示例demo