Start · Sprachen · JavaScript · Referenz · WebGL2RenderingContext.transformFeedbackVaryings()

WebGL2RenderingContext.transformFeedbackVaryings()

Methode

Legt fest, welche Ausgabevariablen (<code>out</code>) eines Shader-Programms per Transform Feedback in Puffer geschrieben werden. Muss vor <code>linkProgram()</code> aufgerufen werden.

seit JavaScript WebGL 2.0 – Baseline: alle modernen Browser Kategorie: webapi

Signatur

WebGL2RenderingContext.prototype.transformFeedbackVaryings(program, varyings, bufferMode)

Beschreibung

Mit transformFeedbackVaryings() bestimmst du, welche out-Variablen des Vertex-Shaders beim Transform Feedback aufgezeichnet werden. Transform Feedback erlaubt es, die Ergebnisse des Vertex-Shaders direkt auf der GPU in einen WebGLBuffer zurückzuschreiben – ganz ohne Umweg über die CPU. Typische Anwendungen sind GPU-Partikelsysteme, physikalische Simulationen oder allgemeine Berechnungen (GPGPU) auf Vertex-Ebene.

Die Methode wirkt erst beim nächsten Aufruf von gl.linkProgram(program). Sie muss also vor dem Linken aufgerufen werden; eine nachträgliche Änderung erfordert ein erneutes Linken. Die Namen im Array müssen exakt den out-Variablen im Vertex-Shader entsprechen, sonst schlägt das Linken fehl.

Über bufferMode legst du fest, ob alle Variablen verschachtelt in einen einzigen Puffer geschrieben werden (gl.INTERLEAVED_ATTRIBS) oder jede Variable in einen eigenen Puffer an einem separaten Bindungsindex (gl.SEPARATE_ATTRIBS). Die Puffer werden anschließend mit gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, index, buffer) gebunden, und die Aufzeichnung läuft zwischen beginTransformFeedback() und endTransformFeedback().

Parameter

Name Typ Default Beschreibung
$program Pflicht WebGLProgram Das Shader-Programm, dessen Ausgaben aufgezeichnet werden sollen. Muss noch (erneut) gelinkt werden.
$varyings Pflicht string[] Array mit den Namen der out-Variablen des Vertex-Shaders, die aufgezeichnet werden. Die Reihenfolge bestimmt die Anordnung im Puffer bzw. den Bindungsindex.
$bufferMode Pflicht GLenum gl.INTERLEAVED_ATTRIBS (alle Werte verschachtelt in einem Puffer) oder gl.SEPARATE_ATTRIBS (je Variable ein eigener Puffer).

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Fehler zeigen sich über gl.getError() bzw. den Link-Status des Programms.

Beispiele

Programm für Transform Feedback vorbereiten

const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2');

const vsSource = `#version 300 es
in float inValue;
out float outDoubled;
out float outSquared;
void main() {
  outDoubled = inValue * 2.0;
  outSquared = inValue * inValue;
}`;

const fsSource = `#version 300 es
precision highp float;
out vec4 color;
void main() { color = vec4(0.0); }`;

const compile = (type, src) => {
  const s = gl.createShader(type);
  gl.shaderSource(s, src);
  gl.compileShader(s);
  return s;
};

const program = gl.createProgram();
gl.attachShader(program, compile(gl.VERTEX_SHADER, vsSource));
gl.attachShader(program, compile(gl.FRAGMENT_SHADER, fsSource));

// WICHTIG: vor linkProgram()
gl.transformFeedbackVaryings(program, ['outDoubled', 'outSquared'], gl.SEPARATE_ATTRIBS);
gl.linkProgram(program);

console.log(gl.getProgramParameter(program, gl.LINK_STATUS));
console.log(gl.getProgramParameter(program, gl.TRANSFORM_FEEDBACK_VARYINGS));
true 2

Ergebnisse berechnen und auslesen (Fortsetzung)

const input = new Float32Array([1, 2, 3, 4]);

// Eingabepuffer
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
const inBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, inBuf);
gl.bufferData(gl.ARRAY_BUFFER, input, gl.STATIC_DRAW);
const loc = gl.getAttribLocation(program, 'inValue');
gl.enableVertexAttribArray(loc);
gl.vertexAttribPointer(loc, 1, gl.FLOAT, false, 0, 0);

// Ausgabepuffer (SEPARATE_ATTRIBS: je einer pro Varying)
const makeOut = () => {
  const b = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, b);
  gl.bufferData(gl.ARRAY_BUFFER, input.byteLength, gl.STATIC_READ);
  return b;
};
const outA = makeOut();
const outB = makeOut();
gl.bindBuffer(gl.ARRAY_BUFFER, null);

const tf = gl.createTransformFeedback();
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, outA);
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 1, outB);

gl.useProgram(program);
gl.enable(gl.RASTERIZER_DISCARD); // kein Rendering nötig
gl.beginTransformFeedback(gl.POINTS);
gl.drawArrays(gl.POINTS, 0, input.length);
gl.endTransformFeedback();
gl.disable(gl.RASTERIZER_DISCARD);
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);

const read = (buf) => {
  const result = new Float32Array(input.length);
  gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, buf);
  gl.getBufferSubData(gl.TRANSFORM_FEEDBACK_BUFFER, 0, result);
  return result;
};
console.log(read(outA));
console.log(read(outB));
Float32Array(4) [2, 4, 6, 8] Float32Array(4) [1, 4, 9, 16]

Verschachtelter Modus (INTERLEAVED_ATTRIBS)

// Beide Varyings landen abwechselnd in EINEM Puffer
gl.transformFeedbackVaryings(program, ['outDoubled', 'outSquared'], gl.INTERLEAVED_ATTRIBS);
gl.linkProgram(program); // erneut linken!

const info = gl.getTransformFeedbackVarying(program, 1);
console.log(info.name, info.size, info.type === gl.FLOAT);
// Pufferlayout: [d0, s0, d1, s1, ...]
outSquared 1 true

// Wichtig · Fallstricke

  • Reihenfolge: Der Aufruf wirkt erst beim nächsten linkProgram(). Wer nach dem Linken aufruft, ohne neu zu linken, ändert nichts.
  • Unbekannte oder falsch geschriebene Namen führen zu einem Link-Fehler – prüfe gl.getProgramInfoLog(program). Vom Compiler wegoptimierte (ungenutzte) out-Variablen gelten in der Regel dennoch als aktiv, solange sie im Array stehen.
  • Bei gl.SEPARATE_ATTRIBS ist die Anzahl begrenzt durch gl.MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS (mindestens 4); bei INTERLEAVED_ATTRIBS durch MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS (mindestens 64 Komponenten).
  • Ein Puffer darf nicht gleichzeitig als Vertex-Eingabe und als Transform-Feedback-Ziel gebunden sein – für Simulationen daher zwei Puffer abwechselnd verwenden („Ping-Pong“).
  • Ist das Programm während aktiver Transform-Feedback-Aufzeichnung in Benutzung, erzeugt ein erneutes Linken INVALID_OPERATION.
  • Nur in WebGL 2 verfügbar (alle modernen Browser); in WebGL 1 existiert Transform Feedback nicht. getBufferSubData() ist synchron und kann die Pipeline blockieren – in Produktivcode ggf. mit fenceSync() arbeiten.