Create erasable surface

I’m guessing there’s more to it than just mainTexture = tempTexture?

On a side note, would I be able to use pc.Material getParameter to get the diffuse and opacity maps from my material and assign those to the texture and tempTexture?

I know it’s different, I was asking if I were to just use the html canvas and render my scratch surface on it, would I be able to use the eraser function in the example to rub parts of it out.

Of course. Let’s create one more RenderTarget for temporary texture and in onPostRender copy that into main one via pc.app.graphicsDevice.copyRenderTarget

You can just material.opacityMap as well.

Probably you can, but it would so much slower.

Alright, so let’s call the new renderTarget tempRender then I do renderTarget.copy(tempRender, true, true)

No, without depth map. You don’t need that.

So now you have two render targets.

In one you always render your layer, the second one is for opacity, okay.

Next step is shader.

I got this from the custom shaders tutorial, obviously there;s more I have to do:

varying vec2 vUv0;

uniform sampler2D uDiffuseMap;
uniform sampler2D uHeightMap;
uniform float uTime;

void main(void)
{
    float height = texture2D(uHeightMap, vUv0).r;
    vec4 color = texture2D(uDiffuseMap, vUv0);
    if(height < uTime)
    {
        color = vec4(0,0.2,1,0.1);
    }
    gl_FragColor = color;
}

This one is fragment shader.

You need vertex shader at first.
It should convert your vertex position to screen space and pass into fragment shader

vec2 getScreenCoords(vec3 position) {
    vec4 world_position = matrix_model * vec4(position, 1.0);
    vec4 view_position = matrix_viewProjection * world_position;    
    return vec2((view_position.x + 10.0 ) / 20.0 , (view_position.y + 10.0) / 20.0);
}

I use this function. It works. but not correct sometimes. I don’t know why, probably you have to look for another solution.

I’m assuming all this is in the GLSL file for the shader, what exactly should it look like? Should I have what I have above as well as the vertex shader in there or should I have something like this:

var vertexShader = this.vs.resource;

// dynamically set the precision depending on device.
var fragmentShader = "precision " + gd.precision + " float;\n";
fragmentShader = fragmentShader + this.fs.resource;


// A shader definition used to create a new shader.
var shaderDefinition = {
    attributes: {
        aPosition: pc.gfx.SEMANTIC_POSITION,
        aUv0: pc.gfx.SEMANTIC_TEXCOORD0
    },
    vshader: vertexShader,
    fshader: fragmentShader
};

Yes, that’s right.
You need two assets, how can you see.

Put there your shaders (VS and FS) and build shader from definition.

Okay, so 2 GLSL asset files, one is fragment, the other vertex, and the code from my last post goes in a JS file?

Yes, and show me your shaders.

I just used the basic ones I found, but here they are:

Vertex:

attribute vec3 aPosition;
attribute vec2 aUv0;

uniform mat4 matrix_model;
uniform mat4 matrix_viewProjection;

varying vec2 vUv0;

void main(void)
{
    vUv0 = aUv0;
    gl_Position = matrix_viewProjection * matrix_model * vec4(aPosition, 1.0);
}

Fragment:

varying vec2 vUv0;

uniform sampler2D uDiffuseMap;
uniform sampler2D uHeightMap;
uniform float uTime;

void main(void)
{
    float height = texture2D(uHeightMap, vUv0).r;
    vec4 color = texture2D(uDiffuseMap, vUv0);
    if(height < uTime)
    {
        color = vec4(0,0.2,1,0.1);
    }
    gl_FragColor = color;
}

Remove junk from fragment shader (time, heightMap) in gl_FragColor just set vec4(1.0);

So it should look like this:

varying vec2 vUv0;

uniform sampler2D uDiffuseMap;

void main(void)
{
    float height = texture2D(uHeightMap, vUv0).r;
    vec4 color = texture2D(uDiffuseMap, vUv0);

    gl_FragColor = vec4(0.1);
}

Almost.

vec4(1.0);

And remove height calculations.
And sample from uDiffuseMap, because you don’t have uHeightMap anymore.

Okay, so shader definition should look something like this then:

var Shader = pc.createScript('shader');

Shader.attributes.add('material', {type: 'asset', assetType: 'material'});
Shader.attributes.add('vs', {type: 'asset', assetType: 'shader', title: 'Vertex Shader'});
Shader.attributes.add('fs', {type: 'asset', assetType: 'shader', title: 'Fragment Shader'});

// initialize code called once per entity
Shader.prototype.initialize = function() 
{   
    var vertexShader = this.vs.resource;

    // dynamically set the precision depending on device.
    var fragmentShader = "precision " + gd.precision + " float;\n";
    fragmentShader = fragmentShader + this.fs.resource;


    // A shader definition used to create a new shader.
    var shaderDefinition = {
        attributes: {
            aPosition: pc.gfx.SEMANTIC_POSITION,
            aUv0: pc.gfx.SEMANTIC_TEXCOORD0
        },
        vshader: vertexShader,
        fshader: fragmentShader
    };
    
    this.matRes = this.material.resource;
    var graphicsDevice = this.app.graphicsDevice;
    
    var layer = this.app.scene.layers.getLayerByName("Surface");
    var opacity = new pc.Texture(graphicsDevice,
    {
        width: 64,
        height: 32,
        format: pc.PIXELFORMAT_R8_G8_B8_A8
    });
    var tempTexture = new pc.Texture(graphicsDevice,
    {
        width: 64,
        height: 32,
        format: pc.PIXELFORMAT_R8_G8_B8_A8
    });

    var renderTarget = new pc.RenderTarget(graphicsDevice, opacity);
    var tempRender = new pc.RenderTarget(graphicsDevice, tempTexture);
     
    this.matRes.opacityMap = opacity;
    this.matRes.update();
    
    layer.renderTarget = renderTarget;
    layer.onPostRender = function(cameraIndex)
    {
        opacity = tempTexture;
        renderTarget.copy(tempRender, true);
    };
};

Good. So, try your scene now.
Do you see your material is not scratched?

I get gd is not defined, what would gd need to be? and yes, it’s not scratched

Gd mostly for graphicsDevice. Where have you got that?

Line 13: var fragmentShader = "precision " + gd.precision + " float;\n";

Oh, replace gd for graphicsDevice and move this var on the top of function