2016-02-16 9 views
6

Sto lavorando attraverso lo Tavares WebGL tutorial e rimango bloccato nel fango.Disegnare un singolo pixel in WebGL utilizzando GL.points

Desidero disegnare i pixel singoli utilizzando GL.points. Qualcosa è chiaramente sbagliato nel mio array. Vedere in FF o Chrome Canary:

http://codepen.io/anon/pen/EPJVjK

/** 
* Creates a program, attaches shaders, links the program. 
* @param {WebGLShader[]} shaders. The shaders to attach. 
*/ 
var createGLProgram = function(gl, shaders) { 
    var program = gl.createProgram(); 
    for (var i = 0; i < shaders.length; i += 1) { 
     gl.attachShader(program, shaders[ i ]); 
    } 

    gl.linkProgram(program); 

    // Check the link status 
    var linked = gl.getProgramParameter(program, gl.LINK_STATUS); 
    if (!linked) { 

     // Something went wrong with the link 
     var lastError = gl.getProgramInfoLog(program); 
     window.console.error("Error in program linking: " + lastError); 

     gl.deleteProgram(program); 
     return null; 
    } 
    return program; 
}; 

var myCreateShader = function(gl, shaderScriptText, shaderType) { 

    // Create the shader object 
    var shader = gl.createShader(shaderType); 

    // Load the shader source 
    gl.shaderSource(shader, shaderScriptText); 

    // Compile the shader 
    gl.compileShader(shader); 
    return shader; 
}; 

// Get A WebGL context. 
var canvas = document.getElementById("canvas"); 

var gl = canvas.getContext("webgl", { antialias: false }) 

var vertexShader = myCreateShader(gl, 
    `attribute vec2 a_position; 

    uniform vec2 u_resolution; 

    void main() { 
    // convert the rectangle from pixels to 0.0 to 1.0 
     vec2 zeroToOne = a_position/u_resolution; 

     // convert from 0 -> 1 to 0 -> 2 
     vec2 zeroToTwo = zeroToOne * 2.0; 

     // convert from 0 -> 2 to -1 -> +1 (clipspace) 
     vec2 clipSpace = zeroToTwo - 1.0; 

     // Flip 0,0 from bottom left to conventional 2D top left. 
     gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); 
    }`, gl.VERTEX_SHADER); 

var fragmentShader = myCreateShader(gl, 
    `precision mediump float; 

    uniform vec4 u_color; 

    void main() { 
    gl_FragColor = u_color; 
    }`, gl.FRAGMENT_SHADER); 

var program = createGLProgram(gl, [ vertexShader, fragmentShader ]); 
gl.useProgram(program); 

// Store color location. 
var colorLocation = gl.getUniformLocation(program, "u_color"); 

// Look up where the vertex data needs to go. 
var positionLocation = gl.getAttribLocation(program, "a_position"); 

// Set the resolution. 
var resolutionLocation = gl.getUniformLocation(program, "u_resolution"); 
gl.uniform2f(resolutionLocation, canvas.width, canvas.height); 

// Create a buffer. 
var buffer = gl.createBuffer(); 
gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 
gl.enableVertexAttribArray(positionLocation); 

// Send the vertex data to the shader program. 
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); 

// Set color to black. 
gl.uniform4f(colorLocation, 0, 0, 0, 1); 

function drawOneBlackPixel(gl, x, y) { 
    // Fills the buffer with a single point? 
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 
     x,  y, 
      0,  y, 
      x,  0, 
      x,  0, 
      0,  y, 
      0,  0]), gl.STATIC_DRAW); 

    // Draw one point. 
    gl.drawArrays(gl.POINTS, 0, 1); 
} 


// These tests are supposed to be x,y coordinates from top left. 
drawOneBlackPixel(gl, 0, 0); 
drawOneBlackPixel(gl, 1, 1); 
drawOneBlackPixel(gl, 2, 2); 
drawOneBlackPixel(gl, 3, 3); 
drawOneBlackPixel(gl, 4, 4); 
drawOneBlackPixel(gl, 5, 5); 
drawOneBlackPixel(gl, 6, 6); 
drawOneBlackPixel(gl, 7, 7); 
drawOneBlackPixel(gl, 10, 5); 
drawOneBlackPixel(gl, 15, 5); 
drawOneBlackPixel(gl, 20, 5); 
drawOneBlackPixel(gl, 12, 34); 
drawOneBlackPixel(gl, 42, 42); 

problemi sono che i pixel non sono rendering abbastanza a posto. (0,0) non dipinge nell'angolo in alto a sinistra. E quella che dovrebbe essere una linea diagonale di pixel è invece "scalinata" in blocchi di due pixel. Un Codepen funzionante sarebbe l'ideale.

Come seconda domanda "bonus", desidero successivamente essere in grado di raggruppare più pixel su una singola chiamata drawArrays, chiamata requestAnimationFrame. Consigli su come fare al meglio sarebbe molto apprezzato.

P.S. Ho letto:

How can I set the color of a pixel on a canvas using WebGL?

ma il mio errore sembra un po 'di livello inferiore a quello. E per favore non mi consiglia di usare canvas2D. Voglio che le prestazioni di WebGL, e sto cercando di imparare da zero :)

+0

Continua a leggere le esercitazioni. Mentre quel vertex shader è spiegato in diversi passaggi alcuni articoli dopo verrà compresso in una riga che è molto più flessibile – gman

risposta

7

Parecchie cose:

In primo luogo è necessario aggiungere gl_PointSize = 1.0; al vertex shader per raccontare WebGL la dimensione del vostro gl.POINT.

In secondo luogo, la coordinata si passa sei il centro di ogni pixel, piuttosto che a sinistra-top-angolo di ogni pixel, in tal modo,

function drawOneBlackPixel(gl, x, y) { 
    // Fills the buffer with a single point? 
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 
     x+0.5,  y+0.5]), gl.STATIC_DRAW); 

    // Draw one point. 
    gl.drawArrays(gl.POINTS, 0, 1); 
} 

è quello che volete.

Codice di lavoro: http://codepen.io/anon/pen/pgBjBy.

Domanda bonus: ciò che è necessario fare qui è la gestione manuale della memoria dello gl.buffer (rantolo) in modo da poter eseguire gl.drawArrays(gl.POINTS, 0, x); per disegnare x punti. Ad esempio, se si desidera disegnare 3 punti a (0,0) (1,1), (2,2), è necessario eseguire gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0.5, 0.5, 1.5, 1.5, 2.5, 2.5], gl.STATIC_DRAW) e quindi gl.drawArrays(gl.POINTS, 0, 3);

Ad esempio, è possibile prima allocare un Float32Array con spazio per 4 punti, quindi ogni volta che si chiama drawOneBlackPixel si dovrebbe prima impostare il Float32Array su [p1x, p1y, 0,0,0,0,0,0] e sul prossimo drawOneBlackPixel impostare l'array su [p1x, p1y, p2x , p2y, 0,0,0,0] e così via. Naturalmente, devi gestire altre cose, come la crescita e la copia di Float32Array, se necessario, e caricare Float32Array sulla GPU quando apporti una modifica. Come gestire la "cancellazione" dei punti è anche qualcosa da tenere a mente.

Problemi correlati