tutorial three texture sphere raycaster examples javascript three.js geometry webgl

javascript - texture - Three.js/WebGL: las esferas grandes aparecen rotas en la intersección



three.js tutorial (3)

También puedes intentar usar un buffer de profundidad logarítmico :

renderer = new THREE.WebGLRenderer( { logarithmicDepthBuffer: true } );

Permítanme preceder esto diciendo que soy muy inexperto con gráficos en 3D.

Problema

Estoy usando Three.js. Tengo dos esferas que (deliberadamente) colisionan en mi modelo WebGL. Cuando mis esferas son increíblemente grandes, las esferas superpuestas aparecen "rotas" donde se cruzan, pero las esferas más pequeñas se vuelven perfectamente finas.

Tengo una razón muy específica para usar tales unidades grandes para algunos objetos, y la reducción de objetos no es realmente una opción.

Ejemplo

Aquí hay un violín para las esferas más grandes: http://jsfiddle.net/YSX7h/

y para los más pequeños: http://jsfiddle.net/7Lca2/

Código

var radiusUnits = 1790; // 179000000 var container; var camera, scene, renderer; var clock = new THREE.Clock(); var cross; var plane; var controls; var cube; var cubeMaterial = new THREE.MeshBasicMaterial( { color: 0xffffff, vertexColors: THREE.VertexColors } ); init(); animate(); function init() { camera = new THREE.PerspectiveCamera(100, window.innerWidth / window.innerHeight, 0.1, 3500000); controls = new THREE.OrbitControls(camera); camera.position.set(2000, 2000, 2000); camera.position.z = 500; scene = new THREE.Scene(); var texture = THREE.ImageUtils.loadTexture(''http://i.imgur.com/qDAEVoo.jpg''); var material = new THREE.MeshBasicMaterial({ color: 0xFFFFFF, map: texture, opacity:1 }); var material1 = new THREE.MeshBasicMaterial({ color: 0xFF0000, wireframe: true, opacity:1 }); var geometry = new THREE.SphereGeometry(radiusUnits, 32, 32); var geometry1 = new THREE.SphereGeometry(radiusUnits, 32, 32); var mesh = new THREE.Mesh(geometry, material); var mesh1 = new THREE.Mesh(geometry1, material1); mesh1.position.set(0, 1000, 0); mesh.position.set(0, -1000, 0); scene.add(mesh); scene.add(mesh1); renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } ); document.body.appendChild(renderer.domElement); renderer.setSize( window.innerWidth, window.innerHeight ); } function onWindowResize() { renderer.setSize( window.innerWidth, window.innerHeight ); render(); } function animate() { controls.update(); requestAnimationFrame( animate ); } window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function( callback ){ window.setTimeout(callback, 1000 / 60); }; })(); (function animloop(){ requestAnimFrame(animloop); render(); })(); function render() { var delta = clock.getDelta(); renderer.render( scene, camera ); }

¿Por qué, exactamente, sucede esto? ¿Y hay algo que pueda hacer para solucionar esto, salvo reducir estos objetos?

Gracias por adelantado.


Estás sufriendo un problema de precisión en el búfer de profundidad. Cuanto más grande sea la escala de tu escena, más pronunciada se vuelve, especialmente para objetos que abarcan una gran distancia. El buffer de profundidad tiene solo 32bits (punto flotante, creo) para trabajar. A medida que aumenta el rango Z de su cámara, la precisión disminuye. Una cámara estándar tiende a tener una mayor precisión cerca del plano "cercano", y se reduce a la distancia (aunque no estoy seguro de qué matriz está usando en realidad three.js).

O reduce el tamaño de la escena o aleja el plano más alejado de la cámara. Si busca el tema de los búferes de profundidad y la precisión, puede encontrar mucha información sobre este tema. Consulte también la información genérica de OpenGL, no solo three.js o WebGL.

Nota: Para aclarar, la razón por la cual las dos escenas son diferentes es porque no ha escalado la configuración de la cámara de la misma manera. En la escena que funciona, configure el plano cercano a "0.00001" y verá el mismo problema.


La respuesta corta, coloca tu z cerca del avión más lejos

Cambio

camera = new THREE.PerspectiveCamera( 100, window.innerWidth / window.innerHeight, 0.1, 3500000);

a

var zNear = 1000; var zFar = 3500000; camera = new THREE.PerspectiveCamera( 100, window.innerWidth / window.innerHeight, zNear, zFar);

Nota: No sé si 1000 funcionará, si no prueba 10000.

Un zBuffer, lo que solía ser capaz de decir qué píxeles van delante de otros píxeles dibujados previamente, tiene una resolución limitada. En WebGL podría ser 16bits, 24 o 32. Supongo que 24 es el más común. Para el punto de la ilustración, supongamos que solo fueron 4 bits. Eso significaría para un rango z dado que solo hay 16 valores posibles. Teniendo en cuenta la matemática estándar utilizada para la proyección 3D, en un zbuffer de 4 bits, si el rango era zNear = 0.1 y zFar = 3500000 los 16 valores posibles son algo así como

0 = 0.100 1 = 0.107 range: 0.007 2 = 0.115 range: 0.008 3 = 0.125 range: 0.010 4 = 0.136 range: 0.011 5 = 0.150 range: 0.014 6 = 0.167 range: 0.017 7 = 0.187 range: 0.021 8 = 0.214 range: 0.027 9 = 0.250 range: 0.036 10 = 0.300 range: 0.050 11 = 0.375 range: 0.075 12 = 0.500 range: 0.125 13 = 0.750 range: 0.250 14 = 1.500 range: 0.750 15 = 3499999.993 range: 3499998.493

Como puede ver, el rango entre los valores aumenta exponencialmente, lo que significa que casi no hay resolución lejos de la cámara.

Si aumentamos zNear a 1000 obtenemos

0 = 1000.000 1 = 1071.407 range: 71.407 2 = 1153.795 range: 82.389 3 = 1249.911 range: 96.115 4 = 1363.495 range: 113.584 5 = 1499.786 range: 136.291 6 = 1666.349 range: 166.564 7 = 1874.531 range: 208.182 8 = 2142.158 range: 267.626 9 = 2498.929 range: 356.771 10 = 2998.287 range: 499.358 11 = 3747.056 range: 748.769 12 = 4994.292 range: 1247.236 13 = 7486.097 range: 2491.805 14 = 14940.239 range: 7454.142 15 = 3500000.000 range: 3485059.761

Puedes ver que comienza a extenderse un poco. En un búfer de profundidad de 24 bits con zNear a 0.1 y zFar a 3500000, el rango entre las últimas 15 unidades es

16777201 = 115869.957 range: 7485.454 16777202 = 124466.066 range: 8596.109 16777203 = 134439.829 range: 9973.763 16777204 = 146151.280 range: 11711.451 16777205 = 160097.879 range: 13946.599 16777206 = 176987.000 range: 16889.122 16777207 = 197859.711 range: 20872.711 16777208 = 224313.847 range: 26454.135 16777209 = 258933.659 range: 34619.812 16777210 = 306189.940 range: 47256.281 16777211 = 374545.842 range: 68355.902 16777212 = 482194.095 range: 107648.253 16777213 = 676678.248 range: 194484.154 16777214 = 1134094.478 range: 457416.229 16777215 = 3499999.993 range: 2365905.515

Donde como con zNear en 1000 están

16777201 = 3489810.475 range: 725.553 16777202 = 3490536.330 range: 725.855 16777203 = 3491262.487 range: 726.157 16777204 = 3491988.947 range: 726.459 16777205 = 3492715.709 range: 726.762 16777206 = 3493442.773 range: 727.064 16777207 = 3494170.140 range: 727.367 16777208 = 3494897.810 range: 727.670 16777209 = 3495625.784 range: 727.973 16777210 = 3496354.060 range: 728.277 16777211 = 3497082.640 range: 728.580 16777212 = 3497811.524 range: 728.884 16777213 = 3498540.712 range: 729.188 16777214 = 3499270.204 range: 729.492 16777215 = 3500000.000 range: 729.796

¿Cuál es probablemente un poco más razonable? Básicamente dice que 2 puntos que son menos de ~ 728 unidades diferentes cuando está lejos de la cámara pueden clasificarse incorrectamente. O para ponerlo en una luz positiva, siempre y cuando 2 puntos estén separados por al menos 728 unidades el uno del otro a la distancia de la cámara, se ordenarán correctamente.

Todo esto es para señalar que debe configurar sus planos de recorte cercanos y lejanos para su aplicación.

Probablemente debería tener en cuenta que la matemática que se aplica es solo la matemática más común y, probablemente, la misma matemática que utiliza tres.js por defecto. Con tus propios sombreadores de vértices podrías hacer que el zbuffer haga algo más. Aquí hay un buen artículo sobre esto .