Three.js / WebGL:大型球体在交叉点处出现断裂 [英] Three.js/WebGL: Large spheres appear broken at intersection
问题描述
问题
我一开始就说我对3D图形没什么经验使用Three.js。我有两个领域(故意)在我的WebGL模型中碰撞。当我的球体非常大时,重叠的球体在它们相交处出现破碎,但小球体呈现完美。
我有一个非常具体的原因,单位的一些对象,并缩小对象是不是一个真正的选择。
示例
这里是大球的小提琴: http://jsfiddle.net/YSX7h/
以及较小的: http://jsfiddle.net/7Lca2/
代码
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();
函数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();
}
函数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);
};
})();
$ b $(函数animloop(){
requestAnimFrame(animloop);
render();
})();
函数render(){
var delta = clock.getDelta();
renderer.render(scene,camera);
}
为什么会发生这种情况?有什么我可以做的,以解决这个问题,缩小这些对象的缩小?
预先感谢。
简短的回答,设置你的z飞机离得更远
更改
camera = new THREE.PerspectiveCamera(
,window.innerWidth / window.innerHeight,0.1,3500000);
至
var zNear = 1000;
var zFar = 3500000;
camera = new THREE.PerspectiveCamera(
100,window.innerWidth / window.innerHeight,zNear,zFar);
注意:如果不尝试10000,我不知道1000是否可以工作。
一个zBuffer,以前能够判断哪些像素位于其他先前绘制的像素前面,具有有限的分辨率。在WebGL中它可能是16位,24位或32位。我猜24是最常见的。为了说明这一点,我们假设它只有4位。这意味着对于给定的z范围,只有16个可能的值。如果范围是 zNear = 0.1
并且 zFar = 3500000 $ c $>给定用于3D投影的标准数学,则在4位zbuffer上c> 16个可能的值类似于
0 = 0.100
1 = 0.107范围:0.007
2 = 0.115范围:0.008
3 = 0.125范围:0.010
4 = 0.136范围:0.011
5 = 0.150范围:0.014
6 = 0.167范围:0.017
7 = 0.187范围:0.021 $ b $ 8 = 0.214范围:0.027
9 = 0.250范围:0.036
10 = 0.300范围:0.050
11 = 0.375范围:0.075
12 = 0.500范围:0.125
13 = 0.750范围:0.250
14 = 1.500范围:0.750 $ b $ 15 = 3499999.993范围:3499998.493
正如您所看到的,值之间的范围呈指数级增长,这意味着几乎没有远离相机的分辨率。
如果我们将 zNear
增加到1000,我们会得到
0 = 1000.000
1 = 1071.407范围:71.407
2 = 1153.795范围:82.389 $ b $ 3 = 1249.911范围:96.115
4 = 1363.495范围:113.584
5 = 1499.786范围:136.291
6 = 1666.349范围:166.564
7 = 1874.531范围:208.182 $ b $ 8 = 2142.158范围:267.626
9 = 2498.929范围:356.771
10 = 2998.287范围:499.358
11 = 3747.056范围:748.769
12 = 4994.292范围:1247.236
13 = 7486.097范围:2491.805
14 = 14940.239范围:7454.142
15 = 3500000.000范围:3485059.761
您可以看到它开始展开一点。在 zNear
为0.1且 zFar
为3500000的24位深度缓冲区中,最后15个单元之间的范围为
16777201 = 115869.957范围:7485.454
16777202 = 124466.066范围:8596.109
16777203 = 134439.829范围:9973.763
16777204 = 146151.280范围:11711.451
16777205 = 160097.879范围:13946.599
16777206 = 176987.000范围:16889.122
16777207 = 197859.711范围:20872.711
16777208 = 224313.847范围:26454.135
16777209 = 258933.659范围:34619.812
16777210 = 306189.940范围:47256.281
16777211 = 374545.842范围:68355.902
16777212 = 482194.095范围:107648.253
16777213 = 676678.248范围:194484.154
16777214 = 1134094.478范围:457416.229
16777215 = 3499999.993范围:2365905.515
code> zNear 在1000,他们是
16777201 = 3489810.475范围:725.553
16777202 = 3490536.330范围:725.855
16777203 = 3491262.487范围:726.157
16777204 = 3491988.947范围:726.459
16777205 = 3492715.709范围:726.762
16777206 = 3493442.773范围:727.064
16777207 = 3494170.140范围:727.367
16777208 = 3494897.810范围:727.670
16777209 = 3495625.784范围:727.973
16777210 = 3496354.060范围:728.277
16777211 = 3497082.640范围:728.580
16777212 = 3497811.524范围:728.884
16777213 = 3498540.712范围:729.188
16777214 = 3499270.204范围:729.492
16777215 = 3500000.000范围:729.796
这可能更合理些?基本上说,当相机远离相机时,2点可能会小于〜728个单位。或者把它放在积极的光照下,只要距离相机至少有728个单位相距至少728个单位,它们就会被正确排序。
这一切都是要指出,你必须为你的应用程序适当地设置你的近剪裁平面。
我应该注意到,应用的数学只是最常用的数学方法,可能与three.js默认使用的算术方法相同。用你自己的顶点着色器,你可以让zbuffer做别的事情。 这是一篇很好的文章。
Let me preface this with saying I'm very inexperienced with 3D graphics.
Problem
I'm using Three.js. I have two spheres which (deliberately) collide in my WebGL model. When my spheres are incredibly large, the overlapping spheres appear "broken" where they intersect, but smaller spheres render perfectly fine.
I have a very specific reason for using such large units for some objects, and scaling down objects isn't really an option.
Example
Here is a fiddle for the larger spheres: http://jsfiddle.net/YSX7h/
and for the smaller ones: http://jsfiddle.net/7Lca2/
Code
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 );
}
Why, exactly, does this happen? And is there anything I can do to fix this, short of scaling down these objects?
Thanks in advance.
The short answer, set your z near plane further away
Change
camera = new THREE.PerspectiveCamera(
100, window.innerWidth / window.innerHeight, 0.1, 3500000);
to
var zNear = 1000;
var zFar = 3500000;
camera = new THREE.PerspectiveCamera(
100, window.innerWidth / window.innerHeight, zNear, zFar);
Note: I don't know if 1000 will work, if it doesn't try 10000.
A zBuffer, the thing used to be able to tell which pixels go in front of other previously drawn pixels, has limited resolution. In WebGL it could be 16bits, 24 or 32. I'm guessing 24 is the most common. For the point of illustration let's assume it was just 4 bits though. That would mean for a given z range there are only 16 possible values. Given the standard math used for 3D projection, on a 4 bit zbuffer, if the range was zNear = 0.1
and zFar = 3500000
the 16 possible values are something like
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
As you can see the range between values increase exponentially meaning there is almost no resolution far away from the camera.
If we increase zNear
to 1000 we get
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
You can see it starting to spread out a little. On a 24bit depth buffer with zNear
at 0.1 and zFar
at 3500000 the range between the last 15 units is
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
Where as with zNear
at 1000 they're
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
Which is probably a little more reasonable? It's basically saying 2 points that are less than ~728 units different when far away from the camera may be sorted incorrectly. Or to put it in a positive light, as long as 2 points are at least 728 units away from each other in their distance from the camera they'll be sorted correctly.
All of this is to point out that you have to set your near and far clipping planes appropriately for your application.
I should probably note that the math being applied is just the most common math and probably the same math that three.js used by default. With your own vertex shaders you could make the zbuffer do something else. Here's a good article on it.
这篇关于Three.js / WebGL:大型球体在交叉点处出现断裂的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!