0
votes

I'm writing a vertex displacement shader. I successfully mapped the vertices of a plane to the brightness values of a video with a GLSL Shader and Three.js, but the GLSL Shader is mapping the values in a radial fashion which might be appropriate for texturing a sphere, but not this plane. There is radial distortion coming from the center outward. How do I fix this radial distortion?

RuttEtraShader = {

    uniforms: {

        "tDiffuse": { type: "t", value: null },
        "opacity":  { type: "f", value: 1.0 }
    },



    vertexShader: [

    'uniform sampler2D tDiffuse;',
    'varying vec3 vColor;',
    "varying vec2 vUv;",

    'void main() {',
        'vec4 newVertexPos;',
        'vec4 dv;',
        'float df;',
        "vUv = uv;",
        'dv = texture2D( tDiffuse, vUv.xy );',
        'df = 1.33*dv.x + 1.33*dv.y + 16.33*dv.z;',
        'newVertexPos = vec4( normalize(position) * df * 10.3, 0.0 ) + vec4( position, 1.0 );', 
        'vColor = vec3( dv.x, dv.y, dv.z );',

        'gl_Position = projectionMatrix * modelViewMatrix * newVertexPos;',
    '}'

    ].join("\n"),

    fragmentShader: [

      'varying vec3 vColor;',

      'void main() {',
          'gl_FragColor = vec4( vColor.rgb, 1.0 );',
      '}'



    ].join("\n")

};



texture = new THREE.Texture( video );
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.format = THREE.RGBFormat;
texture.generateMipmaps = true;


videoMaterial = new THREE.ShaderMaterial( {
    uniforms: {

        "tDiffuse": { type: "t", value: texture },
    },

    vertexShader: RuttEtraShader.vertexShader,
    fragmentShader: RuttEtraShader.fragmentShader,
    depthWrite: false,
    depthTest: true,
    transparent: true,
    overdraw: false

} );
videoMaterial.renderToScreen = true;



geometry = new THREE.PlaneGeometry(720, 480, 720, 480);
geometry.overdraw = false;
geometry.dynamic = true;
mesh = new THREE.Mesh( geometry, videoMaterial );

mesh.position.x = 0;
mesh.position.y = 0;
mesh.position.z = 0;

mesh.visible = true;

scene.add( mesh );
1
I apologize for my lack of vocabulary on the subject. Essentially I have a plane textured on one face with an image or video. The vertex shader seems to be mapping the brightness value of a pixel to the vertices of the plane mesh fine, except when I change the scalar for the overall displacement (10.3) in this line 'newVertexPos = vec4( normalize(position) * df * 10.3, 0.0 ) + vec4( position, 1.0 );' the mesh gets a radial distortion starting from center of the mesh and radiating outward. The higher the number the larger the radial distortion. How do I fix it?steveblue

1 Answers

1
votes

Your displacement is radiating from the center of the screen due to the fact that you are using a direction vector relative to the point (0,0,0) in Normalized Device Coordinates (NDC).

Without re-defining any of your matrices, you might be able to solve this simply by using newVertexPos = vec4( normalize(position - origin) * df * 10.3, 0.0 ) + vec4( position, 1.0 );, where origin is the point you want to radiate from. In NDC, vec3 origin = vec3 (-1.0,-1.0,0.0) would have everything radiate from the lower-left corner.

You will still have a very noticeable radial displacement if you only make this change, however. Another thing you might consider is using non-uniform scaling of your displacement. Instead of * df * 10.3, you might use * df * vec3 (1.0, 1.0, 10.3). This will make the Z displacement much more pronounced.

You can mix and match both approaches to find what looks best. I suspect that increasing the scale of the Z displacement by itself would produce the results you are looking for, but it is always helpful to understand why the displacement is radiating from the center of the screen nevertheless.

I have a feeling your plane may be situated at Z=0, so the Z displacement will always be 0 unless you move it back/forward. If you add 1.0 to position.z it will move it to the far plane and if you subtract 1.0 from position.z it will move it to the near plane.