Three.js uniform dashed line relative to camera
我正在使用 three.js 以 3D 显示几何图形。
当您(手动)将隐藏线绘制为虚线时,"虚线"对于所有这些都是常规的。这意味着平行于相机平面的线或垂直于相机平面的线(几乎)应该具有相同的长度和间隙。
但这似乎不适用于 LineDashedMaterial。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 ); var renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); var geometry = new THREE.BoxGeometry( 2, 2, 2 ); var LINES_DASHED = new THREE.LineSegments( new THREE.EdgesGeometry(geometry), new THREE.LineDashedMaterial({ linewidth: 2, color: 0x000000, dashSize: 0.2, gapSize: 0.1, depthTest: false, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 1 }) ); LINES_DASHED.computeLineDistances(); scene.add( LINES_DASHED ); scene.background = new THREE.Color( 0xffffff); camera.position.z = 5; var animate = function () { requestAnimationFrame( animate ); LINES_DASHED.rotation.x += 0.01; LINES_DASHED.rotation.y += 0.01; renderer.render( scene, camera ); }; animate(); |
1 2 | body { margin: 0; } canvas { width: 100%; height: 100% } |
1 | <script src="https://threejs.org/build/three.min.js"> |
工作示例:
https://bs4.scolcours.ch/_dev/3js_ex.php
我认为使用:
1 | line.computeLineDistance(); |
将解决问题。但它似乎计算了 3D 空间中的线长(这似乎是合乎逻辑的)。
有什么我错过的吗?
感谢您的帮助!
那是国外的任务。似乎
但是可以编写着色器并使用
诀窍是在片段着色器中知道一行的开始。一般来说,这很容易通过使用
遗憾的是 WebGL 1.0 / GLSL ES 1.00 不支持这个。所以我们必须使用 WebGL 2.0 / GLSL ES 3.00。
在 OpenGL ES 中存在扩展
所以让我们用 WebGL2 上下文创建一个
1 2 3 | var canvas = document.createElement( 'canvas' ); var context = canvas.getContext( 'webgl2' ); var renderer = new THREE.WebGLRenderer( { canvas: canvas, context: context } ); |
顶点着色器必须将标准化的设备坐标传递给片段着色器。一次使用默认插值,一次没有 (
1 2 3 4 5 6 7 8 9 | flat out vec3 startPos; out vec3 vertPos; void main() { vec4 pos = projectionMatrix * modelViewMatrix * vec4(position, 1.0); gl_Position = pos; vertPos = pos.xyz / pos.w; startPos = vertPos; } |
除了不同的输入,片段着色器还有统一的变量。
所以可以计算出从开始到实际片段的线长度:
1 2 | vec2 dir = (vertPos.xy-startPos.xy) * u_resolution/2.0; float dist = length(dir); |
并且可以通过
1 2 | if (fract(dist / (u_dashSize + u_gapSize)) > u_dashSize/(u_dashSize + u_gapSize)) discard; |
片段着色器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | precision highp float; flat in vec3 startPos; in vec3 vertPos; uniform vec3 u_color; uniform vec2 u_resolution; uniform float u_dashSize; uniform float u_gapSize; void main(){ vec2 dir = (vertPos.xy-startPos.xy) * u_resolution/2.0; float dist = length(dir); if ( fract(dist / (u_dashSize + u_gapSize)) > u_dashSize/(u_dashSize + u_gapSize) ) discard; gl_FragColor = vec4(u_color.rgb, 1.0); } |
设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var uniforms = { u_resolution: {type: 'v2', value: {x: vpSize[0], y: vpSize[1]}}, u_dashSize : {type:'f', value: 10.0}, u_gapSize : {type:'f', value: 5.0}, u_color : {type: 'v3', value: {x:0.0, y:0.0, z:0.0} } }; var material = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: document.getElementById('vertex-shader').textContent, fragmentShader: document.getElementById('fragment-shader').textContent }); var LINES_DASHED = new THREE.LineSegments( new THREE.EdgesGeometry(geometry), material); |
注意,如果画布的分辨率发生变化,则必须设置
例如
1 2 | LINES_DASHED.material.uniforms.u_resolution.value.x = window.innerWidth; LINES_DASHED.material.uniforms.u_resolution.value.y = window.innerHeight; |
我将这些建议应用于您的原始代码。查看预览和示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera( 60, window.innerWidth/window.innerHeight, 0.1, 1000 ); var canvas = document.createElement( 'canvas' ); var context = canvas.getContext( 'webgl2' ); var renderer = new THREE.WebGLRenderer( { canvas: canvas, context: context } ); var vpSize = [window.innerWidth, window.innerHeight]; renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); var geometry = new THREE.BoxGeometry( 2, 2, 2 ); var uniforms = { u_resolution: {type: 'v2', value: {x: vpSize[0], y: vpSize[1]}}, u_dashSize : {type:'f', value: 10.0}, u_gapSize : {type:'f', value: 5.0}, u_color : {type: 'v3', value: {x:0.0, y:0.0, z:0.0} } }; var material = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: document.getElementById('vertex-shader').textContent, fragmentShader: document.getElementById('fragment-shader').textContent }); var LINES_DASHED = new THREE.LineSegments( new THREE.EdgesGeometry(geometry), material); LINES_DASHED.computeLineDistances(); scene.add( LINES_DASHED ); scene.background = new THREE.Color( 0xffffff); camera.position.z = 5; var animate = function () { requestAnimationFrame( animate ); LINES_DASHED.rotation.x += 0.01; LINES_DASHED.rotation.y += 0.01; renderer.render( scene, camera ); }; window.onresize = function() { vpSize = [window.innerWidth, window.innerHeight]; LINES_DASHED.material.uniforms.u_resolution.value.x = window.innerWidth; LINES_DASHED.material.uniforms.u_resolution.value.y = window.innerHeight; renderer.setSize(window.innerWidth, window.innerHeight); camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); } animate(); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <script type='x-shader/x-vertex' id='vertex-shader'> flat out vec3 startPos; out vec3 vertPos; void main() { vec4 pos = projectionMatrix * modelViewMatrix * vec4(position, 1.0); gl_Position = pos; vertPos = pos.xyz / pos.w; startPos = vertPos; } <script type='x-shader/x-fragment' id='fragment-shader'> precision highp float; flat in vec3 startPos; in vec3 vertPos; uniform vec3 u_color; uniform vec2 u_resolution; uniform float u_dashSize; uniform float u_gapSize; void main(){ vec2 dir = (vertPos.xy-startPos.xy) * u_resolution.xy/2.0; float dist = length(dir); if (fract(dist / (u_dashSize + u_gapSize)) > u_dashSize/(u_dashSize + u_gapSize)) discard; gl_FragColor = vec4(u_color.rgb, 1.0); } <script src="https://rawcdn.githack.com/mrdoob/three.js/r128/build/three.js"> |