2015-10-23 51 views
5

KontekstWebGL - rozmiary zmiennych tablicowych ponad vertex shader wzywa

Próbuję narysować krzywe Beziera w płótnie. Osiągnąłem, aby narysować krzywe kwadratowe i sześcienne z poziomu modułu cieniującego, ale miałem do tej pory zmienną jednolitą dla każdego punktu kontrolnego.

Klikam więc na moim płótnie, dodam punkty i gdy mam dość (odpowiednio 3 i 4), rysuję krzywą.

Teraz próbuję generalizować krzywe Beziera. Chociaż udało mi się to osiągnąć po stronie JavaScript, mam wrażenie, że lepiej byłoby zrobić to po stronie modułu cieniującego, ponieważ szybkość renderowania zostałaby znacznie zwiększona.

Chciałbym więc narysować moją krzywą, skoro tylko mam co najmniej dwa punkty. Mogłem jednak dodawać punkty i rysować krzywą za pomocą każdego punktu, w kolejności jako punktów kontrolnych.

Wyjaśnienie

Tak wiem, że to nie jest możliwe, aby ustawić dynamiczną tablicę w GLSL, ale jest to possibliy dynamicznie zadeklarować tablicę GLSL w oparciu o zmiennej JS?

Jeśli moje pytanie jest niejasne (wiem, że mam problemy z formułowaniem rzeczy od razu), pozwól mi wyjaśnić na przykładzie.

uniform vec2 uMyPoints[<length>]; 

Więc to jest to, co chciałbym osiągnąć, ale oczywiście rozmiar tablicy musi być stała, zgodnie z zaleceniami GLSL.

Jednak z mojego punktu widzenia mam wrażenie, że powinienem móc ustawić length ze zmiennej JS. Mam intuicję, że rozmiar tablicy w GLSL byłby stały przez cały czas wykonywania różnych shaderów podczas renderowania, ale mógł się zmieniać z jednego renderowania na inny.

Pytanie

Więc moje pytanie brzmi: Na podstawie tych Znasz dobry sposób lub sztuczki, aby móc zestaw stałym GLSL ze zmiennej javascript?

Jeśli wydaje się to możliwe, bardzo mi to pomoże. Dzięki za uwagę.

W gruncie porównania:?.. Jak moglibyśmy ustawić "numLights" in this example z JS

Odpowiedź

podstawienie String pasuje do moich potrzeb ładnie Chociaż jest to trochę trudne, to zrobić dobrze Dalsze badania pozwoliły mi dowiedzieć się, że ukryty rozmiar macierzy jest dostępny Open GL ES wersja 3, z której powinny korzystać przyszłe wersje WebGL, ale już nie.

Z drugiej strony druga sugestia nie odpowiada moim potrzebom Dokładnie chciałem tego uniknąć N punktów w module cieniującym, ponieważ ta liczba punktów może się zmienić.

Dzięki za odpowiedź;)

Odpowiedz

2

podstawienie String działa

<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); 

To co najbardziej skomplikowane programy zrobić dla shaderów. Generują shadery za pomocą sznurkowych manipulacji.

Oczywiście możesz użyć ładniejszej funkcji do zamiany ciągów znaków. Na przykład może coś

/** 
    * 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"; 
     }); 
    }; 
    }()); 

teraz, jeśli jesteś shader wygląda następująco

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

można zastąpić z

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

Można też oczywiście użyć `#define w moduł cieniujący

#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) { 
    ... 
    } 
} 

itd.

Ale, szczerze mówiąc, większość ludzi nie przekazałaby punktów kontroli beziera jako mundurów, ponieważ istnieje poważne ograniczenie liczby mundurów. Większość ludzi przekazywałaby punkty kontrolne beziera w atrybutach. Prawdopodobnie można nawet ustawić krok i offset Dzwoniąc gl.vertexAttribPointer tak, że jeśli punkty iść

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

można zrobić 4 atrybuty

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

i wskazać wszystkie z nich offsetowej i krok, aby ustawić 4 atrybuty więc punkty są wyciągane

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, 

etc ..