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 .