Precision control in TSL?

I’m noticing some weird issues I can’t explain other than TSL not having precision control ??

In a glsl I have a shader working with things like:

                precision mediump float;
                precision mediump sampler2D;

But when making the TSL port of it, something is off. Testing arround I’ve noticed that for example decimals are ignored after the first one. So 0.01 = 0 Let’s say If I wanted to scroll the UV by vec2(0.01,0) it wont move at all…

My tests show Three.js TSL is innocent. A texture shift of 0.01 is visible:

3 Likes

I’m going nuts here… do you see why this might fail? Same settings on both…

GLSL

                precision highp float;
                precision highp sampler2D;

                varying vec2 vUv;
                uniform sampler2D uVelocity; 
                uniform sampler2D uSource; 
                uniform vec2 texelSize;
                uniform vec2 dyeTexelSize;
                uniform float dt;
                uniform float dissipation;
                uniform bool sourceIsVelocity; 

                void main () {
 
                        vec2 coord = vUv - dt * texture2D(uVelocity, vUv).gb * texelSize;
                        vec4 result = texture2D(uSource, coord);
                
                        float decay = 1.0 + dissipation * dt;
                        result /= decay;

                        if( sourceIsVelocity )
                        {
                            vec4 data = texture2D(uVelocity, vUv);
                            gl_FragColor = vec4( data.r, result.g, result.b, data.a);
                        }
                        else 
                        {
                            gl_FragColor = result;
                        }
                }

But in TSL

type Sampler2D = ShaderNodeObject<TextureNode>;
class AdvectShader extends MeshBasicNodeMaterial {
    readonly sourceIsVelocity = uniform(0);
    readonly delta = uniform(0);
    readonly dissipation = uniform(0.2);
    readonly uSource:Sampler2D = texture(placeholderTexture);

    constructor( uVelocity:Sampler2D, textelSize:UniformVec2 ) {
        super(); 
        this.colorNode = Fn(()=>{   
 
       
            const velocity = uVelocity.sample(uv()).gb ; 
            const coord = uv().sub( this.delta.mul( velocity ).mul( textelSize ) );  
            const result = this.uSource.sample( coord ).toVar(); 

            const decay = add( 1.0, this.dissipation.mul( this.delta ) );
            result.divAssign( decay );

            If( this.sourceIsVelocity , ()=>
            {   
                const original = uVelocity.sample( uv() );

                result.assign(vec4(
                    original.r,
                    result.gb,
                    original.a
                )); 

            } ) ;

            return result;
 
        })();
    }
}

There’s an issue with the precision…

If on a TSL node you set a pixel with a value like vec4(0,0,0,123)

Then that 123 is lost and clamped to a value of 1…

And if another material needs to re-use this data, the pixel sampled at .a will equal 1 not 123…

Chatgpt says : By default, WebGPU render targets might use RGBA8Unorm (0–1 range).

That might be a clue…

How to make it use precision highp float ?

Went into a rabbit hole, but it is solved… the problem was a miss-interpretation on my part… I was setting the material.colorNode assuming I had control over the alpha channel but apparently only the RGB is controled by that node.

Solution → material.fragmentNode

Time wasted: 2 days.

Headaches: innumerable.

1 Like