Line above ThreeJS Texture?

So I have loaded a 2D character into a 3D world & for some reason I get this line above my character’s head. Is there a way to fix this?

Here’s the screenshot :

line-above-texture

Here’s the Spritesheet ( 64 x 32 | 8 tiles | indices : 0 - 7 ( for frames ) ) :

link-walk

So inside SpriteMixer.js, I have changed it from SpriteMaterial to MeshBasicMaterial with a 3D plane in order to allow certain effects to happen to the sprite that you normally wouldn’t be able to do, and the code remains pretty much the same except where I changed it to a 3D plane & MeshBasicMaterial. It also still caused the line with SpriteMaterial as well.

Everything else works great.

Here’s the link to demo :

http://babylontesting.epizy.com/Three.js/link-controller/


view-source:http://babylontesting.epizy.com/Three.js/link-controller/js/game.js
view-source:http://babylontesting.epizy.com/Three.js/link-controller/js/libs/SpriteMixer.js


The following line{s} are inside of game.js

Line{s} 2 - 43 :

this.__CreateEntity = function ( __objData )

{

   // Access the Data Object{s}

   this.__objData = __objData;

   // ACTIONSPRITE & ACTIONS INITIALIZATION

   // An ActionSprite is initialized with these arguments :: 

   // - which THREE.Texture to use

   // - the number of columns in your animation
   // - the number of rows in your animation

   // Create & Setup Link's Walk Texture{s}

   this.__link_walkTexture = this.__objData.__loader.load ( "assets/textures/link-walk.png" );
   this.__link_walkTexture.magFilter = THREE.NearestFilter;
   this.__link_walkTexture.minFilter = THREE.NearestFilter;
   this.__link_walk = this.__spriteMixer.ActionSprite ( this.__objData.__scene, this.__link_walkTexture, 4, 2 );
   this.__link_walkLeft = this.__spriteMixer.Action ( this.__link_walk, 4, 5, 200 );
   this.__link_walkRight = this.__spriteMixer.Action ( this.__link_walk, 6, 7, 200 );
   this.__link_walk.setFrame ( 6 );
   this.__link_walk.position.set ( 0.0, 0.1, 0.0 );
   this.__link_walk.scale.set ( 1, 1, 0.01 );
   this.__link_walk.visible = true;

   // Create Link's "Entity"

   this.__link = new THREE.Group ( );
   this.__link.scale.set ( 1, 1, 0.001 );
   this.__link.add ( this.__link_walk );
   this.__objData.__scene.add ( this.__link );

   // Return Link's "Entity"

   return this.__link;

}

Line{s} 149 - 160 :

this.__loader = new THREE.TextureLoader ( );
this.__scene = new THREE.Scene ( );

this.__camera = new THREE.PerspectiveCamera

(

	65.0, ( window.innerWidth / window.innerHeight ), 1.0, 

	10000.0

);

this.__camera.position.z = 1.0;
this.__controls = new THREE.OrbitControls ( this.__camera );
this.__spriteMixer = SpriteMixer ( );

// Create Link
this.__link = this.__CreateEntity

(

	{

		__loader : this.__loader, __scene : this.__scene, 

	}

);

The following line{s} are inside of SpriteMixer.js

Line{s} 213 - 246 :

function ActionSprite( scene, texture, tilesHoriz, tilesVert ) {

texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 1/tilesHoriz, 1/tilesVert );

spriteGeometry = new THREE.PlaneBufferGeometry( 1, 1, 1, 1 );

spriteMaterial = new THREE.MeshBasicMaterial({
	map:texture, color: 0xffffff, side: THREE.DoubleSide, alphaTest : 0.5, });

var actionSprite = new THREE.Mesh ( spriteGeometry, spriteMaterial );
scene.add( actionSprite );

actionSprite.isIndexedSprite = true ;

actionSprite.tilesHoriz = tilesHoriz;
actionSprite.tilesVert = tilesVert;
actionSprite.tiles = (tilesHoriz * tilesVert);
actionSprite.currentDisplayTime = 0;
actionSprite.currentTile = 0;
actionSprite.paused = true;
actionSprite.currentAction;

actionSprite.setFrame = setFrame;
actionSprite.getRow = getRow;
actionSprite.getColumn = getColumn;
	
offsetTexture( actionSprite );

actionSprites.push( actionSprite );

return actionSprite;

};

This is quite a simple one. It’s a sampling error. You should include some padding around your sprites, some Dead Space™, say 1-2 pixels in your case.Why does this happen? Because of floating point rounding error, most likely. Anyway, just move your sprites apart a little and you’ll be golden.

Pretty much every serious sprite solution will have some form of “padding” in it. Just roll with it :slight_smile:

Alternatively, reduce your sprite UVs by a tiny amount, to push the error into the sprite boundary. Like so:

const error = 0.0001;
uv.x0 += error;
uv.y0 += error;
uv.x1 -= error;
uv.y1 -= error;
2 Likes

@unsul : Thank you for the explanation. Much appreciated! :slight_smile: I tried that, and it would like cut off feet & hat, etc… I thought that textures MUST be power of 2 in ThreeJS or it complains. Also, how do I use that code?

I’m not sure :smiley:

Based on a quick look at your code - it looks like the UVs are handled by the “sprite mixer”, so that’s where you’d be doing the error offsets. The code that I wrote is pseudo-code. It assumes that your UVs for a sprite are defined by 2 points: x0,y0(top left) and x1,y1 (bottom right).

@Usnul This is the line where the UVs are set with SpriteMixer :

texture.repeat.set( 1/tilesHoriz, 1/tilesVert );

that’s part of it. This would control the sprite size, but not the offset. I’m not familiar with the SpriteMixer, so I’m not sure exactly what’s going on in there. Maybe ping @felixmariotto?

@Aerion Usnul already told you what to do

Just tried that. I added some dead space. It seems to cut off part of the sprite if I do that. As you see in the spritesheet, I have already added some dead space.

I’ve actually been messing with spritesheet all day & to no avail. I tried different areas of deadspace on the 64x32 spritesheet above & no use.

Does anyone have this problem?

Ok, I think I finally fixed it, but I had to make it non power of 2.

I also had to comment this line out in SpriteMixer.js :

// texture.wrapS = texture.wrapT = THREE.RepeatWrapping;

Here’s the final result :

link-walk