0

I've just downloaded the latest Three.js master "mrdoob-three.js-d6384d2" , I've modified the "webgl_nearestneighbour.html" to show a transparent image and this is the result: http://i.share.pho.to/8cccac74_l.jpeg

I can't understand if it's by design , if it's a webgl error or if it's a three.js error but, as you can see in the bigger ball, near sprites are clipped while far sprites aren't. Any information is much appreciated (I'm new to webgl).

edit: here's the code.

<html>
	<head>
		<meta charset="utf-8">
		<title>three.js webgl - nearest neighbour</title>
		<style>
			html, body {
				width: 100%;
				height: 100%;
			}

			body {
				background-color: #ffffff;
				margin: 0;
				overflow: hidden;
				font-family: arial;
			}

			#info {
				text-align: center;
				padding: 5px;
				position: absolute;
				width: 100%;
				color: white;
			}
		</style>
	</head>
	<body>
		
		<div id="info"><a href="http://threejs.org" target="_blank">three.js</a> webgl - typed arrays - nearest neighbour for 500,000 sprites</div>
		
		<script src="../build/three.min.js"></script>
		<script src="js/TypedArrayUtils.js"></script>
		<script src="js/controls/FirstPersonControls.js"></script>
		<script type="x-shader/x-vertex" id="vertexshader">
			
			//uniform float zoom;
		
			attribute float alpha;

			varying float vAlpha;

			void main() {
			
				vAlpha = 1.0 - alpha;
				
				vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );

				gl_PointSize = 4.0 * ( 300.0 / length( mvPosition.xyz ) );

				gl_Position = projectionMatrix * mvPosition;

			}

		</script>

		<script type="x-shader/x-fragment" id="fragmentshader">

			uniform sampler2D tex1;

			varying float vAlpha;

			void main() {

				gl_FragColor = texture2D(tex1, gl_PointCoord);
				gl_FragColor.r = (1.0 - gl_FragColor.r) * vAlpha + gl_FragColor.r;

			}

		</script>
		<script>		
		
			var camera, scene, renderer;
			var geometry, material, mesh;
			var controls;

			var objects = [];

			var amountOfParticles = 500000, maxDistance = Math.pow(120, 2);
			var positions, alphas, particles, _particleGeom

			var clock = new THREE.Clock();

			var blocker = document.getElementById( 'blocker' );
			var instructions = document.getElementById( 'instructions' );
			
			
			function init() {

			    camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000000);

				scene = new THREE.Scene();

				controls = new THREE.FirstPersonControls( camera );
				controls.movementSpeed = 100;
				controls.lookSpeed = 0.1;

				var materials = [

					new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'textures/cube/skybox/px.jpg' ) } ), // right
					new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'textures/cube/skybox/nx.jpg' ) } ), // left
					new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'textures/cube/skybox/py.jpg' ) } ), // top
					new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'textures/cube/skybox/ny.jpg' ) } ), // bottom
					new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'textures/cube/skybox/pz.jpg' ) } ), // back
					new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'textures/cube/skybox/nz.jpg' ) } )  // front

				];

				mesh = new THREE.Mesh( new THREE.BoxGeometry( 10000, 10000, 10000, 7, 7, 7 ), new THREE.MeshFaceMaterial( materials ) );
				mesh.scale.x = - 1;
				scene.add(mesh);
				
				//

				renderer = new THREE.WebGLRenderer(); // Detector.webgl? new THREE.WebGLRenderer(): new THREE.CanvasRenderer()
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				document.body.appendChild( renderer.domElement );

				// create the custom shader
				var imagePreviewTexture = THREE.ImageUtils.loadTexture( 'textures/football.png');
				imagePreviewTexture.minFilter = THREE.LinearMipMapLinearFilter;
				imagePreviewTexture.magFilter = THREE.LinearFilter;
				
				pointShaderMaterial = new THREE.ShaderMaterial( {
					uniforms: {
						tex1: { type: "t", value: imagePreviewTexture },
						zoom: { type: 'f', value: 9.0 },
					},
					attributes: {
						alpha: { type: 'f', value: null },
					},
					vertexShader:   document.getElementById( 'vertexshader' ).textContent,
					fragmentShader: document.getElementById( 'fragmentshader' ).textContent,
					transparent: true
				});
				
				
				//create particles with buffer geometry
				var distanceFunction = function(a, b){
					return Math.pow(a[0] - b[0], 2) +  Math.pow(a[1] - b[1], 2) +  Math.pow(a[2] - b[2], 2);
				};

				positions = new Float32Array( amountOfParticles * 3 );
				alphas = new Float32Array( amountOfParticles );
				
				_particleGeom = new THREE.BufferGeometry();
				_particleGeom.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
				_particleGeom.addAttribute( 'alpha', new THREE.BufferAttribute( alphas, 1 ) );
				
				particles = new THREE.PointCloud( _particleGeom, pointShaderMaterial );
				
				for (var x = 0; x < amountOfParticles; x++) {
					positions[ x * 3 + 0 ] = Math.random() * 1000;
					positions[ x * 3 + 1 ] = Math.random() * 1000;
					positions[ x * 3 + 2 ] = Math.random() * 1000;
					alphas[x] = 1.0;
				}
				
				
				var measureStart = new Date().getTime();
				
				// creating the kdtree takes a lot of time to execute, in turn the nearest neighbour search will be much faster
				kdtree = new THREE.TypedArrayUtils.Kdtree( positions, distanceFunction, 3 );
				
				console.log('TIME building kdtree', new Date().getTime() - measureStart);
				
				// display particles after the kd-tree was generated and the sorting of the positions-array is done
				scene.add(particles);

				window.addEventListener( 'resize', onWindowResize, false );

			}

			function onWindowResize() {

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize( window.innerWidth, window.innerHeight );

				controls.handleResize();
			}

			function animate() {

				requestAnimationFrame( animate );

				//
				displayNearest(camera.position);

				controls.update( clock.getDelta() )

				renderer.render( scene, camera );

			}
			
			function displayNearest(position) {
				
				// take the nearest 200 around him. distance^2 'cause we use the manhattan distance and no square is applied in the distance function
				var imagePositionsInRange = kdtree.nearest([position.x, position.y, position.z], 100, maxDistance);
								
				// We combine the nearest neighbour with a view frustum. Doesn't make sense if we change the sprites not in our view... well maybe it does. Whatever you want.
				var _frustum = new THREE.Frustum();
				var _projScreenMatrix = new THREE.Matrix4();
				camera.matrixWorldInverse.getInverse( camera.matrixWorld );

				_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
				_frustum.setFromMatrix( _projScreenMatrix );
				
				for ( i = 0, il = imagePositionsInRange.length; i < il; i ++ ) {
					var object = imagePositionsInRange[i];
					var objectPoint = new THREE.Vector3().fromArray( object[ 0 ].obj );
					
					if (_frustum.containsPoint(objectPoint)){
					
						var objectIndex = object[0].pos;
						
						// set the alpha according to distance
						alphas[ objectIndex ] = 1.0 / maxDistance * object[1];
						// update the attribute
						_particleGeom.attributes.alpha.needsUpdate = true;
					}
				}
			}
			
			
			init();
			animate();
		</script>
	</body>
</html>

8
  • 1
    Have you tried to set depthWrite:false in the material properties ? Commented Jul 1, 2015 at 18:50
  • You need to provide the relevant code in your post so we know what you are doing and so others can benefit. Commented Jul 1, 2015 at 19:31
  • I've added the code, but I barely changed it from the original; I've only selected another image in this line of code: var imagePreviewTexture = THREE.ImageUtils.loadTexture( 'textures/football.png'); I was giving for granted the alpha capabilities. I see that this user had a similar problem but he didn't say if he has fixed it. stackoverflow.com/questions/22901015/… Commented Jul 1, 2015 at 19:57
  • 1
    You are using a point cloud, not a sprite. See: stackoverflow.com/questions/31037195/… Commented Jul 1, 2015 at 20:00
  • 1
    Did you follow the instructions in the answer I linked to and modify your fragment shader by adding this line: if ( gl_FragColor.a < 0.5 ) discard; ? Commented Jul 1, 2015 at 21:48

1 Answer 1

1

To recap what has been said in the comments, the solution to this problem is to disable alpha blending, and in the shader you have to discard the pixel drawn based on the alpha value of the input texture.

So that this...

void main() {
gl_FragColor = texture2D(tex1, gl_PointCoord);
gl_FragColor.r = (1.0 - gl_FragColor.r) * vAlpha + gl_FragColor.r;
}

...becomes this

void main() {
gl_FragColor = texture2D(tex1, gl_PointCoord);
gl_FragColor.r = (1.0 - gl_FragColor.r) * vAlpha + gl_FragColor.r;
if ( gl_FragColor.a < 0.5 ) discard;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.