[SOLVED] Texture instead of color

Hi!
Can I use a texture instead of color in ribbon.js?

var Ribbon = pc.createScript('ribbon');

Ribbon.attributes.add("lifetime", {type:"number", default:0.5});
Ribbon.attributes.add("xoffset", {type:"number", default:-0.8});
Ribbon.attributes.add("yoffset", {type:"number", default:1});
Ribbon.attributes.add("height", {type:"number", default:0.4});
Ribbon.attributes.add('texture', { type: 'asset', assetType: 'texture'});

var MAX_VERTICES = 600;//150;//600;
var VERTEX_SIZE = 4;

Ribbon.prototype.create = function (entity) {
//    this.entity = entity;

    this.timer = 0;

    // The node generating this ribbon
    this.node = null;
    // The generated ribbon vertices
    this.vertices = [];

    // Vertex array to receive ribbon vertices
    this.vertexData = new Float32Array(MAX_VERTICES * VERTEX_SIZE);

    this.entity.model = null;
};

Ribbon.prototype.initialize = function () {
    this.create();
    console.log(this.texture.resource);
    var shaderDefinition = {
        attributes: {
            aPositionAge: pc.SEMANTIC_POSITION,
            //texture:this.texture
        },
        vshader: [
            "attribute vec4 aPositionAge;",
            "",
            "uniform mat4 matrix_viewProjection;",
            "uniform float trail_time;",
            "",
            "varying float vAge;",
            "",
            "void main(void)",
            "{",
            "    vAge = trail_time - aPositionAge.w;",
            "    gl_Position = matrix_viewProjection * vec4(aPositionAge.xyz, 1.0);",
            "}"
        ].join("\n"),
        fshader: [
            "precision mediump float;",
            "",
            "varying float vAge;",
            "",
            "uniform float trail_lifetime;",
            "",
            "vec3 rainbow(float x)",
            "{",
                    "float level = floor(x * 1.0);",
                    "float r = float(level <= 2.0) + float(level > 4.0) * 0.5;",
                    "float g = max(1.0 - abs(level - 2.0) * 0.5, 0.0);",
                    "float b = (1.0 - (level - 4.0) * 0.5) * float(level >= 4.0);",
                    "return vec3(r, g, b);",
            "}",
            "void main(void)",
            "{",
            "    gl_FragColor = vec4(rainbow(vAge / trail_lifetime), (1.0 - (vAge / trail_lifetime)) * 0.5);",
            "}"
        ].join("\n")
    };
    
//    var shader = new pc.Shader(context.graphicsDevice, shaderDefinition);
    var shader = new pc.Shader(this.app.graphicsDevice, shaderDefinition);

    var material = new pc.scene.Material();
    material.setShader(shader);
    material.setParameter('trail_time', 0);
    material.setParameter('trail_lifetime', this.lifetime);
    material.cull = pc.CULLFACE_NONE;
    material.blend = true;
    material.blendSrc = pc.BLENDMODE_SRC_ALPHA;
    material.blendDst = pc.BLENDMODE_ONE_MINUS_SRC_ALPHA;
    material.blendEquation = pc.BLENDEQUATION_ADD;
    material.depthWrite = false;

    // Create the vertex format
    var vertexFormat = new pc.VertexFormat(this.app.context.graphicsDevice, [
        { semantic: pc.SEMANTIC_POSITION, components: 4, type: pc.ELEMENTTYPE_FLOAT32 }
    ]);

    // Create a vertex buffer
    var vertexBuffer = new pc.VertexBuffer(this.app.context.graphicsDevice, vertexFormat, MAX_VERTICES * VERTEX_SIZE, pc.USAGE_DYNAMIC);

    var mesh = new pc.scene.Mesh();
    mesh.vertexBuffer = vertexBuffer;
    mesh.indexBuffer[0] = null;
    mesh.primitive[0].type = pc.PRIMITIVE_TRISTRIP;
    mesh.primitive[0].base = 0;
    mesh.primitive[0].count = 0;
    mesh.primitive[0].indexed = false;

    var node = new pc.scene.GraphNode();

    var meshInstance = new pc.scene.MeshInstance(node, mesh, material);
    meshInstance.layer = pc.scene.LAYER_WORLD;
    meshInstance.updateKey();

    this.entity.model = new pc.scene.Model();
    this.entity.model.graph = node;
    this.entity.model.meshInstances.push(meshInstance);

    this.model = this.entity.model;

    this.setNode(this.entity);
};


Ribbon.prototype.reset = function () {
    this.timer = 0;
    this.vertices = [];
};
        
Ribbon.prototype.spawn = function () {
    var node = this.node;
    var pos = node.getPosition();
    var yaxis = node.up.clone().scale(this.height);

    var s = this.xoffset;
    var e = this.yoffset;
    this.vertices.unshift({
        spawnTime: this.timer,
        vertexPair: [
            pos.x + yaxis.x * s, pos.y + yaxis.y * s, pos.z + yaxis.z * s, 
            pos.x + yaxis.x * e, pos.y + yaxis.y * e, pos.z + yaxis.z * e
        ]
    });
};
        
Ribbon.prototype.clearOld = function () {
    for (var i = this.vertices.length - 1; i >= 0; i--) {
        var vp = this.vertices[i];
        if (this.timer - vp.spawnTime >= this.lifetime) {
            this.vertices.pop();
        } else {
            return;
        }
    }
};
        
Ribbon.prototype.copyToArrayBuffer = function () {
    for (var i = 0; i < this.vertices.length; i++) {
        var vp = this.vertices[i];

        this.vertexData[i * 8 + 0] = vp.vertexPair[0];
        this.vertexData[i * 8 + 1] = vp.vertexPair[1];
        this.vertexData[i * 8 + 2] = vp.vertexPair[2];
        this.vertexData[i * 8 + 3] = vp.spawnTime;

        this.vertexData[i * 8 + 4] = vp.vertexPair[3];
        this.vertexData[i * 8 + 5] = vp.vertexPair[4];
        this.vertexData[i * 8 + 6] = vp.vertexPair[5];
        this.vertexData[i * 8 + 7] = vp.spawnTime;
    }
};
        
Ribbon.prototype.updateNumActive = function () {
    this.model.meshInstances[0].mesh.primitive[0].count = this.vertices.length * 2;
};

Ribbon.prototype.update = function (dt) {
    this.timer += dt;
    var material = this.model.meshInstances[0].material;
    material.setParameter('trail_time', this.timer);

    this.clearOld();
    this.spawn();

    if (this.vertices.length > 1) {
        this.copyToArrayBuffer();
        this.updateNumActive();

        var vertexBuffer = this.model.meshInstances[0].mesh.vertexBuffer;
        var vertices = new Float32Array(vertexBuffer.lock());
        vertices.set(this.vertexData);
        vertexBuffer.unlock();

        if (!this.app.scene.containsModel(this.model)) {
            console.log("Added model");
            this.app.scene.addModel(this.model);
        }
    } else {
        if (this.app.scene.containsModel(this.model)) {
            console.log("Removed model");
            this.app.scene.removeModel(this.model);
        }
    }
};

Ribbon.prototype.setNode = function (node) {
    this.node = node;
};

What is this script supposed to do?

This script create a ribbon, it is follow for entity, i want use a texture instead of color:

"vec3 rainbow(float x)",
            "{",
                    "float level = floor(x * 1.0);",
                    "float r = float(level <= 2.0) + float(level > 4.0) * 0.5;",
                    "float g = max(1.0 - abs(level - 2.0) * 0.5, 0.0);",
                    "float b = (1.0 - (level - 4.0) * 0.5) * float(level >= 4.0);",
                    "return vec3(r, g, b);",
            "}"

here is rainbow color are enabled, i want to use my texture instead

So you will have to add a uniform to your shader to reference a texture, and then use it in your shader.

Take a look at this tutorial on how to do that.

https://developer.playcanvas.com/en/tutorials/custom-shaders/

1 Like

I tryed to use it like in example, but I have an error .WebGL-000001C6FD6E8C80] GL_INVALID_OPERATION: Mismatch between texture format and sampler type (signed/unsigned/float/shadow).

this is my project, can you look in?
https://playcanvas.com/project/680197/overview/move

In your shader the uniform you added is called uDiffuseMap so you need to use that name when you pass the texture resource reference.

Update your code with this:

material.setParameter('uDiffuseMap', this.texture.resource);
1 Like

ah, thank you!