[SOLVED] Problem with UVs

Good night,

I have made a script tha maps the UV coordinates of a mesh by the camera view (like the window mapping of blender 3D), but when i apply this script on a mesh that isn’t a playcanvas primitive, the UV mapping is distorted. this is showed by the image below.

Problem

The first object (on the left), is the one that i’ve created and the other two are playcanvas primitives.

My project is located here: https://playcanvas.com/project/547528/overview/camera-mapping-tests
And below is my “CameraMapping” script:


CameraMapping.attributes.add('camera',{
    type:'entity',
    entityType:'camera'
});

// Re-map when mouse is pressed
CameraMapping.prototype.initialize = function() {
    //this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.map, this);
};

CameraMapping.prototype.map = function(){
    var buffer = this.entity.model.model.meshInstances[0].mesh.vertexBuffer;
    var iterator = new pc.VertexIterator(buffer);

    // Iterate though all verticles 
    for(i = 0; i < buffer.getNumVertices(); i++) {

        // Current vertex's position
        var posSem = iterator.element[pc.SEMANTIC_POSITION];
        var posUV = iterator.element[pc.SEMANTIC_TEXCOORD0];
        
        // Graphics device width and height
        var width = this.app.graphicsDevice.width;
        var height = this.app.graphicsDevice.height;
        
        var position = this.getVertexPosition(posSem);
        var screenPosition = this.screenPosition(position);

        // Set vertex UV position
        posUV.array[posUV.index] = screenPosition.x / width;
        posUV.array[posUV.index+1] = 1 - (screenPosition.y / height);
        posUV.array[posUV.index+2] = 0;
        
        //this.pointVertice(position);
        
        // Move to the next vertex
        iterator.next();
    }

    iterator.end();
};

CameraMapping.prototype.getVertexPosition = function(posSem){
    // Get vertex position
    var posX = posSem.array[posSem.index];
    var posY = posSem.array[posSem.index + 1];
    var posZ = posSem.array[posSem.index + 2];
    return new pc.Vec3(posX, posY, posZ);
};

CameraMapping.prototype.screenPosition = function (position){
    return this.camera.camera.worldToScreen(position);
};

CameraMapping.prototype.pointVertice = function(position){
    var entity = new pc.Entity();
    entity.addComponent('model',{
        type:'sphere'
    });
    entity.setLocalScale(0.05, 0.05, 0.05);
    entity.setPosition(position);
    this.app.root.addChild(entity);
};

// update code called every frame
CameraMapping.prototype.update = function(dt) {
    this.map();
};

Someone have an idea of how to solve this problem?

Could you share a link to the project please?

1 Like

https://playcanvas.com/project/547528/overview/camera-mapping-tests

Use shader instead of that. It would be much easy.

1 Like

can you explain please? You mean to write a custom shader?

Yes.

You can achieve this effect easily by custom shader and post-effect.

But I don’t know your final goal and solution depends on that.

Anyway, you have to pass into pixel shader your texture.
Then you need to know coords to sample from it. In case of post-effect, if would be so much easy.

Probably, you can figure them out and in regular shader too, but I don’t know how.

But still, if you are using post-effect, check is current pixel’s color equal to your background color. if it is - discard this pixel.

Then just use texture2D in order to sample from your texture and return this color.

1 Like

Look what I have here…

Your problem was in coords.

You haven’t transform your vertex position by world matrix.
And for primitives it was okay. but not for mesh.

Before loop:

var matrixLocal = this.entity.model.model.meshInstances[0].node.getWorldTransform();

Then, in loop

var position = this.getVertexPosition(posSem, matrixLocal);
var screenPosition = this.screenPosition(position);

And finally, getVertexPosition

CameraMapping.prototype.getVertexPosition = function(posSem, matrixLocal){
    // Get vertex position
    var posX = posSem.array[posSem.index];
    var posY = posSem.array[posSem.index + 1];
    var posZ = posSem.array[posSem.index + 2];
    
    var pos = new pc.Vec3(posX, posY, posZ);
    matrixLocal.transformPoint(pos, pos);
    
    return pos;
};

But there are still artifacts somewhere. I don’t know how we can fix it :frowning:
Probably we need to transform it somehow…

image

1 Like

Thank you very much. I needed to do that way to remap the object only in some moments of the application and your explication suits perfectly on my goals

Yea, but it inspired me to create a nice shader, which makes entity looks like it’s invisible, but still receives shadows, refracts light etc.

Like, Predator, you know?

I want to get current renderTarget’s colorBuffer and pass it into this shader like texture you have now.

So the only thing I need to fix are this little artifacts.

Maybe somebody with more experience knows better.
I tried to transform points by other matrix (view and project and both) but had no luck.

Cool! If you have some result on clear these little artifacts please let me know. This is an issue that i will need to bare with sometime.

And about the shader that you created, can i look the project? I’ve done by script because i still dont know well how to create shaders.

I was able to see that the projection glitch is related to the distance that the objects are from the camera (distant objects have a perfect projection, while near objects distort). Perhaps the problem comes from perspective. But still no idea of solution.

I didnt write it yet, waiting for upcoming new post-effect system.

Maybe I have to mul world matrix by projection one… Nope.

Me again! I found an article that describe that problem as a perspective glitch. As i don’t know well how to write shaders, i couldn’t understand how it works yet, but you should do a good use of this.

2 Likes

УOMG it really works!

And I also implemented this for pc.StandardMaterial

CameraMapping.prototype.initialize = function() {
    this.entity.model.material.chunks.startVS = "void main(void) { \n gl_Position = getPosition(); \n gl_Position /= gl_Position.w; \n ";
    this.entity.model.material.update();
};

Thats what I call team work :smiley:

2 Likes

Great! I have to say thanks again. Now all is running perfectly!

1 Like