2015-10-23 38 views
5

ContestoWebGL - dimensioni variabili array oltre vertex shader chiamate

sto cercando di disegnare curve di Bezier in una tela. Sono riuscito a disegnare curve quadratiche e cubiche dallo shader, ma fino ad ora avevo una variabile uniforme per ogni punto di controllo.

Così, clicco sulla mia tela, aggiungo punti e quando ne ho abbastanza (rispettivamente 3 e 4), disegno la mia curva.

Ora sto cercando di generalizzare le curve di Bezier. Anche se ho raggiunto questo risultato dal lato JavaScript, ritengo che sarebbe meglio farlo dal lato dello shader, poiché la velocità del rendering sarebbe notevolmente aumentata.

Quindi, vorrei disegnare la mia curva non appena ho almeno due punti. Ma potrei continuare ad aggiungere punti e disegnare la mia curva usando ogni punto, in ordine di punti di controllo.

Spiegazione

Quindi so che non è possibile impostare una matrice dinamica in GLSL, ma è vero possibliy di dichiarare in modo dinamico una matrice GLSL basato su una variabile JS?

Se la mia domanda non è chiara (so che ho problemi a formulare le cose subito), lasciatemi spiegare con un esempio.

uniform vec2 uMyPoints[<length>]; 

Quindi questo è quello che vorrei realizzare, ma naturalmente, la dimensione della matrice deve essere una costante, secondo le specifiche GLSL.

Tuttavia, dal mio punto di vista, mi sento come se dovessi essere in grado di impostare length da una variabile JS. La mia intuizione è che la dimensione dell'array in GLSL sarebbe costante per la durata dell'esecuzione dei diversi shader durante il rendering, ma potrebbe cambiare da un rendering all'altro.

Domanda

Quindi la mia domanda è: sulla base di queste, si fa a sapere nulla di buono modo o trucchi per essere impostato in grado una costante in GLSL da una variabile javascript?

Se ciò sembra possibile, questo mi sarebbe di grande aiuto. Grazie per la tua considerazione.

È un dato di confronto:?.. Come potremmo impostare "numLights" in this example da JS

risposta

stringa di sostituzione adatta alle mie esigenze ben Anche se è un po 'complicato, ma farà bene Ulteriori la ricerca mi ha portato a sapere che la dimensione implicita dell'array è disponibile Open GL ES versione 3, che dovrebbe essere utilizzata dalle future versioni di WebGL, ma non adesso

D'altra parte, il secondo suggerimento non soddisfa i miei bisogni come Volevo proprio evitare di averlo N punti nello shader, poiché tale quantità di punti può cambiare.

Grazie per la risposta;)

risposta

2

sostituzione delle stringhe lavora

<script id="vs" type="notjs">  
uniform vec2 uMyPoints[<length>]; 
... 
</script> 

js

var numPoints = 10; 
var vSrc = document.getElementById("vs").text; 
vSrc = vSrc.replace(/<length>/g, numPoints); 

Questo è ciò che i programmi più complessi fanno per shader. Generano gli shader con la manipolazione delle stringhe.

Naturalmente è possibile utilizzare una funzione più semplice per eseguire la sostituzione delle stringhe. Per esempio forse qualcosa di simile

/** 
    * Replace %(id)s in strings with values in objects(s) 
    * 
    * Given a string like `"Hello %(name)s from $(user.country)s"` 
    * and an object like `{name:"Joe",user:{country:"USA"}}` would 
    * return `"Hello Joe from USA"`. 
    * 
    * @function 
    * @param {string} str string to do replacements in 
    * @param {Object|Object[]} params one or more objects. 
    * @returns {string} string with replaced parts 
    * @memberOf module:Strings 
    */ 
    var replaceParams = (function() { 
    var replaceParamsRE = /%\(([^\)]+)\)s/g; 

    return function(str, params) { 
     if (!params.length) { 
     params = [params]; 
     } 

     return str.replace(replaceParamsRE, function(match, key) { 
     var keys = key.split('.'); 
     for (var ii = 0; ii < params.length; ++ii) { 
      var obj = params[ii]; 
      for (var jj = 0; jj < keys.length; ++jj) { 
      var part = keys[jj]; 
      obj = obj[part]; 
      if (obj === undefined) { 
       break; 
      } 
      } 
      if (obj !== undefined) { 
      return obj; 
      } 
     } 
     console.error("unknown key: " + key); 
     return "%(" + key + ")s"; 
     }); 
    }; 
    }()); 

Ora, se siete degli shader assomiglia a questo

uniform Lights u_lights[%(numLights)s]; 
uniform vec2 u_points[%(numPoints)s]; 

si può sostituire con

vSrc = replaceParams(vsrc, { 
    numLights: 4, 
    numPoints: 10, 
}); 

È possibile anche, naturalmente, usare `#define nel shader

#define NUM_LIGHTS %(numLights)s 
#define NUM_POINTS %(numPoints)s 

uniform Lights u_lights[NUM_LIGHTS]; 
uniform vec2 u_points[NUM_POINTS]; 

void main() { 
    for (int i = 0; i < NUM_LIGHTS; ++i) { 
    ... 
    } 
} 

ecc.

Ma, onestamente la maggior parte delle persone non passerebbe più punti di controllo più semplici come uniformi perché c'è una severa restrizione sul numero di uniformi. La maggior parte delle persone passerebbe più punti di controllo in attributi. Probabilmente si può anche impostare il passo e offset quando si chiama gl.vertexAttribPointer in modo che se i punti vanno

[pt0, pt1, pt2, pt3, pt4, pt5, pt6, pt7, pt8, ..] 

È possibile effettuare 4 attributi

attribute vec2 p0; 
attribute vec2 p1; 
attribute vec2 p2; 
attribute vec2 p3; 

e il punto tutti loro con una falcata offset e per impostare la 4 attributi in modo che i punti vengono tirati fuori

p0 = pt0, p1 = pt1, p2 = pt2, p3 = pt3, 
p0 = pt1, p1 = pt2, p2 = pt3, p3 = pt4, 
p0 = pt2, p1 = pt3, p2 = pt4, p3 = pt5, 
p0 = pt3, p1 = pt4, p2 = pt5, p3 = pt6, 

ecc ..