【问题标题】:Three.js Using 2D texture\sprite for animation (planeGeometry)Three.js 使用 2D texture\sprite 制作动画(planeGeometry)
【发布时间】:2013-04-08 09:20:33
【问题描述】:

我对 html5 和 three.js 还是很陌生。我一直在用它做一些实验,基本上我想做的是有一个网格(我使用的是 planeGeometry,因为我遵循的教程使用了它)。网格显示不同的纹理,这些纹理可以在以后更改。

我的代码如下所示:

angelTexture = THREE.ImageUtils.loadTexture("images/textures/chars/angel/angel.png");
angelTexture.offset.x = -0.75;
angelTexture.offset.y = -0.75;

angelMesh = new THREE.Mesh( new THREE.PlaneGeometry(79, 53, 79, 53), new THREE.MeshBasicMaterial( { map: angelTexture, wireframe: false } ));

angelMesh.position.x = 0;
angelMesh.position.y = 0;
scene.add(angelMesh);

问题在于,每当我偏移时,网格似乎足够大以显示所有其他精灵(我将纹理用作我偏移的 2D 精灵以对其进行动画处理)。结果是灾难性的,我仍在研究如何控制 Mesh 的大小,以便它只显示 Sprite 的一个快照。我所有的尝试似乎只是调整网格和底层纹理的大小,并且仍然显示所有精灵。

有人能指出我正确的方向吗?提前致谢。

...

我的朋友想出了一个解决方案... 我错过了重复属性。

angelTexture = THREE.ImageUtils.loadTexture("images/textures/chars/angel/angel.png");
angelTexture.offset.x = -0.75; 
angelTexture.offset.y = -0.75;

angelTexture.repeat.x = 0.25;
angelTexture.repeat.y = 0.25;   
scene.add(angelMesh);

希望这可以帮助其他遇到同样问题的人。

【问题讨论】:

  • 我的朋友想出了一个解决方案...我错过了重复属性。请参阅上面的编辑以获取说明

标签: javascript html three.js


【解决方案1】:

前段时间我有同样的问题,所以我写了一个完整的例子,使用 spritesheet 作为 PlaneGeometry 的纹理,然后定期更新纹理——查看示例

http://stemkoski.github.io/Three.js/Texture-Animation.html

并查看注释源代码以获得更多解释。


更新(2021 年):

这是我推荐使用的功能的更新版本。它修复了不正确的平铺显示顺序的问题,它会自动更新下一帧,并返回一个对象,您可以使用它来根据需要停止和重新启动动画。

function TextureAnimator(texture, tilesHoriz, tilesVert, tileDispDuration) 
{ 
  let obj = {};

  obj.texture = texture;
  obj.tilesHorizontal = tilesHoriz;
  obj.tilesVertical = tilesVert;
  obj.tileDisplayDuration = tileDispDuration;

  obj.numberOfTiles = tilesHoriz * tilesVert;

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

  obj.nextFrame = function()
  {
    obj.currentTile++;
    if (obj.currentTile == obj.numberOfTiles)
      obj.currentTile = 0;

    let currentColumn = obj.currentTile % obj.tilesHorizontal;
    obj.texture.offset.x = currentColumn / obj.tilesHorizontal;

    let currentRow = Math.floor( obj.currentTile / obj.tilesHorizontal );
    obj.texture.offset.y = obj.tilesVertical - currentRow / obj.tilesVertical;
  }

  obj.start = function()
  { obj.intervalID = setInterval(obj.nextFrame, obj.tileDisplayDuration); }

  obj.stop = function()
  { clearInterval(obj.intervalID); }

  obj.start();
  return obj;
}   

【讨论】:

  • 这段代码有缺陷。我不知道这个缺陷是从什么时候开始的,但是纹理被渲染到了平面的左下角,并且应该让你控制 Y 偏移的代码不起作用。我正在努力更好地理解这个问题,一旦我弄明白了就会回复。
  • 嗨,李!感谢您的功能,但 tileDispDuration 不适用于此更新。你能纠正吗?我找不到路。谢谢!
【解决方案2】:

我在对 Lee Stemkoski 的评论中指出,使用较新的 THREE.TextureLoader() 时,具有多行的精灵表的工作方式不同。

我在测试中使用以下 4x4 精灵图像。

假设您有一个完整的 16 个图块精灵表,无需修改 Lee Stemkoski 的 TextureAnimator 函数。

var texture = new THREE.TextureLoader().load('grid-sprite.jpg');
var annie = new TextureAnimator(texture, 4, 4, 16, 150);

动画纹理向后运行。 Codepen Demo

所以我自己做了我称之为???THREE.SpriteSheetTexture???

THREE.SpriteSheetTexture = function(imageURL, framesX, framesY, frameDelay, _endFrame) {

    var timer, frameWidth, frameHeight,
            x = 0, y = 0, count = 0, startFrame = 0, 
            endFrame = _endFrame || framesX * framesY,
            CORSProxy = 'https://cors-anywhere.herokuapp.com/',
            canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d'),
            canvasTexture = new THREE.CanvasTexture(canvas),
            img = new Image();

    img.crossOrigin = "Anonymous"
    img.onload = function(){
        canvas.width = frameWidth = img.width / framesX;
        canvas.height = frameHeight = img.height / framesY;
        timer = setInterval(nextFrame, frameDelay);
    }
    img.src = CORSProxy + imageURL;

    function nextFrame() {
        count++;

        if(count >= endFrame ) {
            count = 0;
        };

        x = (count % framesX) * frameWidth;
        y = ((count / framesX)|0) * frameHeight;

        ctx.clearRect(0, 0, frameWidth, frameHeight);
        ctx.drawImage(img, x, y, frameWidth, frameHeight, 0, 0, frameWidth, frameHeight);

        canvasTexture.needsUpdate = true;
    }

    return canvasTexture;
}

以及您需要了解的内容 imageURL 是您的 spritesheet 的 URL framesX 是沿 x 轴(左右)适合多少帧 framesY 是沿 y 轴(上下)适合多少帧 delay 是纹理等待更改到下一帧的时间 _endFrame 是可选的 - 有多少帧(以防它不使用整行)

一切看起来都像这样

texture = new THREE.SpriteSheetTexture('https://s3-us-west-2.amazonaws.com/s.cdpn.io/68819/grid-sprite.jpg', 4, 4, 100, 16);
var material = new THREE.MeshBasicMaterial({ 
    map: texture
});
geometry = new THREE.BoxGeometry( 200, 200, 200 );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );

还有很多欢乐!!! Codepen Demo Here

【讨论】:

【解决方案3】:

@Cmndo 使帧流以正确的顺序移动,您只需要更新它:

texture.offset.y = currentRow / this.tilesVertical;

到这里:

texture.offset.y = this.tilesVertical - (currentRow / this.tilesVertical);

在这个例子中: https://github.com/stemkoski/stemkoski.github.com/blob/master/Three.js/Texture-Animation.html

【讨论】:

    【解决方案4】:

    要使帧向正确的方向移动,请使用:

    texture.offset.y = (1 - currentRow / _tilesVertical) - (1 / _tilesVertical);
    

    而不是

    texture.offset.y = currentRow / this.tilesVertical;
    

    【讨论】:

      猜你喜欢
      • 2018-02-14
      • 1970-01-01
      • 2015-03-01
      • 1970-01-01
      • 2015-09-18
      • 2012-01-05
      • 2020-07-12
      • 2017-03-14
      • 2021-02-24
      相关资源
      最近更新 更多