Html Three.js 使用 2D 纹理\精灵做动画(planeGeometry)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16029103/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 07:35:17  来源:igfitidea点击:

Three.js Using 2D texture\sprite for animation (planeGeometry)

javascripthtmlthree.js

提问by Spolarium7

I'm quite new in html5 and three.js. I've been experimenting a bit with it, and basically what I want done is to have a Mesh (I'm using planeGeometry, as the tutorial I followed used it). The Mesh shows different Textures, which can change later on.

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

Here's what my code looks like:

这是我的代码的样子:

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);

The problem is that whenever I offset, the Mesh seems big enough to show all the other Sprites (I'm using the texture as a 2D Sprite that I offset to animate it). The result is quite disastrous and I am still figuring out how to control how big the Mesh is so that it shows only one snapshot of the Sprite. All my attempts seem only to resize the Mesh as well as the underlying Texture and still shows all the Sprites.

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

Can someone point me in the right direction? Thanks in advance.

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

...

...

My friend came up with a solution... I missed the repeat property.

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

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);

Hope this helps others having the same problem.

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

回答by Lee Stemkoski

I had the same question a while ago, and so I have written up a complete example of animating using a spritesheet as the texture for a PlaneGeometry, and then updating the texture at regular intervals -- check out the example at

不久前我有同样的问题,所以我写了一个完整的示例,使用 spritesheet 作为 PlaneGeometry 的纹理进行动画处理,然后定期更新纹理 - 查看示例

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

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

and view the commented source code for additional explanation.

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

回答by Cmndo

I've noted in my comment to Lee Stemkoski that spritesheets that have more than one row do not work the same when using the newer THREE.TextureLoader().

我在对 Lee Stemkoski 的评论中指出,当使用较新的THREE.TextureLoader().

I am using the following 4x4 sprite image in my tests.

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

Image showing quadrant highlighted for each expected tile

图像显示为每个预期图块突出显示的象限

With no modification to Lee Stemkoski's TextureAnimatorfunction, assuming you have a full 16 tile spritesheet.

没有修改 Lee Stemkoski 的TextureAnimator函数,假设您有一个完整的 16 块 spritesheet。

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

The animated texture runs backwards. Codepen Demo

动画纹理向后运行。 代码笔演示

enter image description here

在此处输入图片说明

So I made my own which I call THREE.SpriteSheetTexture

所以我自己做了我称之为 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;
}

And what you need to know about it imageURLis the URL of your spritesheet framesXis how many frames fit along the x axis (left and right) framesYis how many frames fit along the y axis (up and down) delayis how long it the texture waits to change to the next frame _endFrameis optional - How many frames are there (in case it doesnt use a full row)

你需要知道的 imageURL是你的 spritesheet 的 URL framesX是多少帧沿 x 轴(左和右) framesY是多少帧沿 y 轴(向上和向下) delay是它的纹理等待多长时间更改到下一帧 _endFrame是可选的 - 有多少帧(以防它不使用整行)

That all looks something like this

这一切看起来像这样

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 );

And there was much rejoicing!!! Codepen Demo Here

有很多的欣喜!!! Codepen 演示在这里