pixijs / pixi-projection

MIT License
191 stars 34 forks source link

Should container projection respect sorting? #17

Open lucap86 opened 6 years ago

lucap86 commented 6 years ago

If I have a 2d projected container with 2 sprites inside, when the plane is "flipped" should i see child sprites in a reverse order?

an application can be a container containing 2 sprites inside in the same positon, representing the 2 faces of a card. container |----- face1 : z=0 |----- face2 : z=1

when i "flip" the container i should see "face1" instead of "face2"?

ivanpopelyshev commented 6 years ago

no, you need to write face detection for that - the vector cross product of axises will show which one is up :)

Pixi doesn't have cull_face and cull_back yet.

Btw, I'm working on that 3d thing again, I hope it'll be ready this weekend, and you'll be able to use my face detection :)

lucap86 commented 6 years ago

ty @ivanpopelyshev!

lucap86 commented 6 years ago

@ivanpkpelyshev what is the condition that i should use in order to detect which face is visible?

ivanpopelyshev commented 6 years ago

sign of cross-product of axises you put it.

in case of multiple containers chain - same, but look at two first columns of the resulting world transform inside projection component.

lucap86 commented 6 years ago

xAxis should be containerSprite.proj.matrix.mat3[0,1,2] y axis containerSprite.proj.matrix.mat3[3,4,5] right?

i have tried this but doesnt seems to be correct var a = containerSprite.proj.matrix.mat3 Math.sign((a[1]-a[0])(a[5]-a[3]))-((a[4]-a[3])(a[2]-a[0]));

ivanpopelyshev commented 6 years ago

do you have a stack of containers or just one? no, just a[0] * a[4] - a[1] * a[3], cross-product on 2d plane , and maybe multply by signs of 2 and 5

lucap86 commented 6 years ago

just one for now

lucap86 commented 6 years ago

like that?

Math.sign(a[0] a[4] - a[1] a[3]) Math.sign(a[2]) Math.sign(a[5])

ivanpopelyshev commented 6 years ago

Yes. Does it work for you?

lucap86 commented 6 years ago

nope try this examply and play with the red squares

var app = new PIXI.Application(800, 600, {backgroundColor: 0x1099bb});
document.body.appendChild(app.view);

var w = app.screen.width/2, h = app.screen.height/2;

function createSquare(x, y) {
    var square = new PIXI.Sprite(PIXI.Texture.WHITE);
    square.tint = 0xff0000;
    square.factor = 1;
    square.anchor.set(0.5);
    square.position.set(x, y);
    return square;
}

var squares = [
    createSquare(w-150, h-150),
    createSquare(w+150, h-150),
    createSquare(w+150, h+150),
    createSquare(w-150, h+150)
];

var quad = squares.map(function(s) { return s.position });

//add sprite itself
var containerSprite = new PIXI.projection.Sprite2d(new PIXI.Texture.fromImage('required/assets/SceneRotate.jpg'));
containerSprite.anchor.set(0.5);

app.stage.addChild(containerSprite);
squares.forEach(function(s) { app.stage.addChild(s); });

// Listen for animate update
app.ticker.add(function (delta) {
    var a = containerSprite.proj.matrix.mat3;
    console.log(Math.sign(a[0] * a[4] - a[1] * a[3]) * Math.sign(a[2]) * Math.sign(a[5]));
    containerSprite.proj.mapSprite(containerSprite, quad);
});

squares.forEach(function(s) { addInteraction(s); });

// let us add sprite to make it more funny

var bunny = new PIXI.projection.Sprite2d(new PIXI.Texture.fromImage('required/assets/flowerTop.png'));
bunny.anchor.set(0.5);
containerSprite.addChild(bunny);

addInteraction(bunny);

// === INTERACTION CODE  ===

function toggle(obj) {
}

function snap(obj) {
    if (obj == bunny) {
        obj.position.set(0);
    } else {
        obj.position.x = Math.min(Math.max(obj.position.x, 0), app.screen.width);
        obj.position.y = Math.min(Math.max(obj.position.y, 0), app.screen.height);
    }
}

function addInteraction(obj) {
    obj.interactive = true;
    obj
        .on('pointerdown', onDragStart)
        .on('pointerup', onDragEnd)
        .on('pointerupoutside', onDragEnd)
        .on('pointermove', onDragMove);
}

function onDragStart(event) {
    var obj = event.currentTarget;
    obj.dragData = event.data;
    obj.dragging = 1;
    obj.dragPointerStart = event.data.getLocalPosition(obj.parent);
    obj.dragObjStart = new PIXI.Point();
    obj.dragObjStart.copy(obj.position);
    obj.dragGlobalStart = new PIXI.Point();
    obj.dragGlobalStart.copy(event.data.global);
}

function onDragEnd(event) {
    var obj = event.currentTarget;
    if (obj.dragging == 1) {
        toggle(obj);
    } else {
        snap(obj);
    }
    obj.dragging = 0;
    obj.dragData = null;
    // set the interaction data to null
}

function onDragMove(event) {
    var obj = event.currentTarget;
    if (!obj.dragging) return;
    var data = obj.dragData; // it can be different pointer!
    if (obj.dragging == 1) {
        // click or drag?
        if (Math.abs(data.global.x - obj.dragGlobalStart.x) +
            Math.abs(data.global.y - obj.dragGlobalStart.y) >= 3) {
            // DRAG
            obj.dragging = 2;
        }
    }
    if (obj.dragging == 2) {
        var dragPointerEnd = data.getLocalPosition(obj.parent);
        // DRAG
        obj.position.set(
            obj.dragObjStart.x + (dragPointerEnd.x - obj.dragPointerStart.x),
            obj.dragObjStart.y + (dragPointerEnd.y - obj.dragPointerStart.y)
        );
    }
}

http://pixijs.io/examples/#/projection/quad-homo.js

I suppose to see -1 always when the rabbit ok t-shirt logo is flipped and 1 when is in the right side

ivanpopelyshev commented 6 years ago

Thank you! I'll look at it tomorrow :)

lucap86 commented 6 years ago

Hi @ivanpopelyshev any news about this?

ivanpopelyshev commented 6 years ago

Testing it right now. It doesnt work, im sick, i dont know what to do. Any ideas?

ivanpopelyshev commented 6 years ago

I'm sure that at a[2]=0 a[5]=0 its behaving bwrong, so i dont know how to add them to equation

ivanpopelyshev commented 6 years ago

Ok, i'm stupid.; That one works

Math.sign(a[0] * a[4] - a[1] * a[3]) * Math.sign(a[8])

lucap86 commented 6 years ago

Thabk you man! I will try it tomorrow

lucap86 commented 6 years ago

Question what does a[8] represent?

ivanpopelyshev commented 6 years ago

i guess that's a coefficient for whole matrix that we can divide everything on it. When I take vector (dx,0,1) and multiply by matrix, i get dx * (a[0] , a[1], a[2]) + (a[6], a[7], a[8]), and we have to divide everything by dx * a[2] + a[5] to make actual 2d vector. I take dx infinite small and it leaves only (a[0], a[1]) / a[8]. That's why a[8] sign is important.

ivanpopelyshev commented 6 years ago

@lucap86 important update: 0.2.1 version is released, it has 3d transforms and isFrontFace method for them :) https://github.com/pixijs/pixi-projection/blob/master/src/proj3d/Container3d.ts#L14

lucap86 commented 6 years ago

Hi @ivanpopelyshev great news!!! thank you for the update

just a question. you have provided the method to convert a supported object to 2d/3d

why not also toCamera3d?

ivanpopelyshev commented 6 years ago

Because camera3d does not have corresponding element in pixi. Why do you need it?

lucap86 commented 6 years ago

Ok but what if i already have a pixi container that i want to convert in a camera3d?

In the end a camera3d is an enhanced pixi3d container

ivanpopelyshev commented 6 years ago

write your own conversion method. assign all the properties for camera (far, near, focus), add projection, put certain values in projection

ivanpopelyshev commented 6 years ago

or create camera3d based on that container and move all the children there