Using d3-zoom to interact with WebGL

前端 未结 1 574
醉梦人生
醉梦人生 2021-01-06 03:34

I\'m trying to get a small example together that uses d3-zoom to provide simple interactivity to a canvas element that renders using WebGL. All I\'d like to do is provide pa

相关标签:
1条回答
  • 2021-01-06 03:57

    I just moved your vertices over to match your matrix

        var vertices = [
             .5,  -.5, 0.0, 1.0,
            1.5,  -.5, 0.0, 1.0,
             .5, -1.5, 0.0, 1.0,
            1.5, -1.5, 0.0, 1.0
        ];      
    

    var width = 300,
            height = 150;
    
        var zoom = d3.zoom()
            .on( 'zoom', zoomed );
    
        var canvas = d3.select( 'body' )
            .append( 'canvas' )
            .attr( 'width', width )
            .attr( 'height', height )
            .call( zoom );
    
        var gl = canvas.node().getContext( 'webgl' );
        var shader = basic_shader(gl);
    
        initialize_gl();
        set_transform( 1, 0, 0 );
    
        function zoomed () {
            var t = d3.event.transform;
            set_transform( t.k, t.x, t.y );
        }
    
        function initialize_gl () {
    
            var sb = d3.color('steelblue');
            gl.clearColor(sb.r / 255, sb.g / 255, sb.b / 255, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT);
    
            var vertices = [
                 .5,  -.5, 0.0, 1.0,
                1.5,  -.5, 0.0, 1.0,
                 .5, -1.5, 0.0, 1.0,
                1.5, -1.5, 0.0, 1.0
            ];        
    
            var colors = [
                1.0, 1.0, 1.0, 1.0,    // white
                1.0, 0.0, 0.0, 1.0,    // red
                0.0, 1.0, 0.0, 1.0,    // green
                0.0, 0.0, 1.0, 1.0     // blue
            ];
    
            var vertex_buffer = gl.createBuffer();
            var color_buffer = gl.createBuffer();
    
            gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
            gl.vertexAttribPointer(shader.color_attrib, 4, gl.FLOAT, false, 0, 0);
            gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
            gl.vertexAttribPointer(shader.vertex_attrib, 4, gl.FLOAT, false, 0, 0);
    
        }
    
        function set_transform ( k, tx, ty ) {
    
            var matrix = new Float32Array([
                k, 0, 0, 0,
                0, k, 0, 0,
                0, 0, 1, 0,
                2*tx/width-1.0, -2*ty/height+1.0, 0, 1
            ]);
    
            gl.uniformMatrix4fv( shader.matrix_uniform, false, matrix );
            gl.clear( gl.COLOR_BUFFER_BIT );
            gl.drawArrays( gl.TRIANGLE_STRIP, 0, 4 );
    
        }
    
        function basic_vertex () {
    
            return [
                'attribute vec4 vertex_position;',
                'attribute vec4 vertex_color;',
                'varying lowp vec4 vert_color;',
                'uniform mat4 matrix;',
                'void main( void ) {',
                '   gl_Position = matrix * vertex_position;',
                '   vert_color = vertex_color;',
                '}'
            ].join('\n');
    
        }
    
        function basic_fragment () {
    
            return [
                'varying lowp vec4 vert_color;',
                'void main( void ) {',
                '   gl_FragColor = vert_color;',
                '}'
            ].join('\n');
    
        }
    
        function basic_shader ( gl ) {
    
            var program = gl_program( gl, basic_vertex(), basic_fragment() );
    
            gl.useProgram( program );
            program.vertex_attrib = gl.getAttribLocation( program, 'vertex_position' );
            program.color_attrib = gl.getAttribLocation( program, 'vertex_color' );
            program.matrix_uniform = gl.getUniformLocation( program, 'matrix' );
            program.translate_uniform = gl.getUniformLocation( program, 'translate_matrix' );
            program.scale_uniform = gl.getUniformLocation( program, 'scale_matrix' );
            gl.enableVertexAttribArray( program.vertex_attrib );
            gl.enableVertexAttribArray( program.color_attrib );
    
            return program;
    
        }
    
        function gl_shader ( gl, type, code ) {
    
            var shader = gl.createShader( type );
            gl.shaderSource( shader, code );
            gl.compileShader( shader );
            return shader;
    
        }
    
        function gl_program ( gl, vertex_source, fragment_source ) {
    
            var shader_program = gl.createProgram();
            var vertex_shader = gl_shader( gl, gl.VERTEX_SHADER, vertex_source );
            var fragment_shader = gl_shader( gl, gl.FRAGMENT_SHADER, fragment_source );
    
            if ( shader_program && vertex_shader && fragment_shader ) {
    
                gl.attachShader( shader_program, vertex_shader );
                gl.attachShader( shader_program, fragment_shader );
                gl.linkProgram( shader_program );
    
                gl.deleteShader( vertex_shader );
                gl.deleteShader( fragment_shader );
    
                return shader_program;
    
            }
    
        }
    <script src="https://d3js.org/d3.v4.min.js"></script>

    But honestly I'd probably use a math library and use a few transforms. It's easier for me to understand the code that way. I'm not sure what the "space" of D3. I guess though it's just passing you an offset and a scale. In which case

            // change the space to be pixels with 0,0 in top left
            var matrix = m4.ortho(0, gl.canvas.width, gl.canvas.height, 0, -1, 1);
    
            // apply the d3 translate and zoom
            matrix = m4.translate(matrix, [tx, ty, 0]);
            matrix = m4.scale(matrix, [k, k, 1]);
    
            // translate the unit quad to the center 
            matrix = m4.translate(matrix, [width / 2, height / 2, 0]);
    
            // make the unit quad be half the size of the canvas
            matrix = m4.scale(matrix, [width / 2, height / 2 , 1]);
    

    var m4 = twgl.m4;
        var width = 300,
            height = 150;
    
        var zoom = d3.zoom()
            .on( 'zoom', zoomed );
    
        var canvas = d3.select( 'body' )
            .append( 'canvas' )
            .attr( 'width', width )
            .attr( 'height', height )
            .call( zoom );
    
        var gl = canvas.node().getContext( 'webgl' );
        var shader = basic_shader(gl);
    
        initialize_gl();
        set_transform( 1, 0, 0 );
    
        function zoomed () {
            var t = d3.event.transform;
            set_transform( t.k, t.x, t.y );
        }
    
        function initialize_gl () {
    
            var sb = d3.color('steelblue');
            gl.clearColor(sb.r / 255, sb.g / 255, sb.b / 255, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT);
    
            var vertices = [
                -.5,   .5, 0.0, 1.0,
                 .5,   .5, 0.0, 1.0,
                -.5,  -.5, 0.0, 1.0,
                 .5,  -.5, 0.0, 1.0
            ];        
    
            var colors = [
                1.0, 1.0, 1.0, 1.0,    // white
                1.0, 0.0, 0.0, 1.0,    // red
                0.0, 1.0, 0.0, 1.0,    // green
                0.0, 0.0, 1.0, 1.0     // blue
            ];
    
            var vertex_buffer = gl.createBuffer();
            var color_buffer = gl.createBuffer();
    
            gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
            gl.vertexAttribPointer(shader.color_attrib, 4, gl.FLOAT, false, 0, 0);
            gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
            gl.vertexAttribPointer(shader.vertex_attrib, 4, gl.FLOAT, false, 0, 0);
    
        }
    
        function set_transform ( k, tx, ty ) {
    
            // change the space to be pixels with 0,0 in top left
            var matrix = m4.ortho(0, gl.canvas.width, gl.canvas.height, 0, -1, 1);
            // apply the d3 translate and zoom
            matrix = m4.translate(matrix, [tx, ty, 0]);
            matrix = m4.scale(matrix, [k, k, 1]);
            // translate the unit quad to the center 
            matrix = m4.translate(matrix, [width / 2, height / 2, 0]);
            // make the unit quad be half the size of the canvas
            matrix = m4.scale(matrix, [width / 2, height / 2 , 1]);
    
            gl.uniformMatrix4fv( shader.matrix_uniform, false, matrix );
            gl.clear( gl.COLOR_BUFFER_BIT );
            gl.drawArrays( gl.TRIANGLE_STRIP, 0, 4 );
    
        }
    
        function basic_vertex () {
    
            return [
                'attribute vec4 vertex_position;',
                'attribute vec4 vertex_color;',
                'varying lowp vec4 vert_color;',
                'uniform mat4 matrix;',
                'void main( void ) {',
                '   gl_Position = matrix * vertex_position;',
                '   vert_color = vertex_color;',
                '}'
            ].join('\n');
    
        }
    
        function basic_fragment () {
    
            return [
                'varying lowp vec4 vert_color;',
                'void main( void ) {',
                '   gl_FragColor = vert_color;',
                '}'
            ].join('\n');
    
        }
    
        function basic_shader ( gl ) {
    
            var program = gl_program( gl, basic_vertex(), basic_fragment() );
    
            gl.useProgram( program );
            program.vertex_attrib = gl.getAttribLocation( program, 'vertex_position' );
            program.color_attrib = gl.getAttribLocation( program, 'vertex_color' );
            program.matrix_uniform = gl.getUniformLocation( program, 'matrix' );
            program.translate_uniform = gl.getUniformLocation( program, 'translate_matrix' );
            program.scale_uniform = gl.getUniformLocation( program, 'scale_matrix' );
            gl.enableVertexAttribArray( program.vertex_attrib );
            gl.enableVertexAttribArray( program.color_attrib );
    
            return program;
    
        }
    
        function gl_shader ( gl, type, code ) {
    
            var shader = gl.createShader( type );
            gl.shaderSource( shader, code );
            gl.compileShader( shader );
            return shader;
    
        }
    
        function gl_program ( gl, vertex_source, fragment_source ) {
    
            var shader_program = gl.createProgram();
            var vertex_shader = gl_shader( gl, gl.VERTEX_SHADER, vertex_source );
            var fragment_shader = gl_shader( gl, gl.FRAGMENT_SHADER, fragment_source );
    
            if ( shader_program && vertex_shader && fragment_shader ) {
    
                gl.attachShader( shader_program, vertex_shader );
                gl.attachShader( shader_program, fragment_shader );
                gl.linkProgram( shader_program );
    
                gl.deleteShader( vertex_shader );
                gl.deleteShader( fragment_shader );
    
                return shader_program;
    
            }
    
        }
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>

    0 讨论(0)
提交回复
热议问题