2017-01-30 4 views
0

Ich nehme einen Kurs in WebGL bei NTNU. Ich untersuche gerade, was die Shader machen und wie ich sie nutzen kann.Ist es möglich, Code einmal pro Zeichenaufruf in WebGL auszuführen?

Ein Beispiel, das wir haben, zeigt uns, dass wir eine Projektionsmatrix berechnen, setzen Sie es dann in den Vertex-Shader, dann machen Sie einen Zeichnungsaufruf. Ich wollte versuchen, diese Matrixberechnung in einem Shader durchzuführen.

Das bedeutet, ich muss den Code irgendwo anders als die main() Funktion in den Vertex-Shader setzen, da dieser mehrmals pro Zeichenaufruf aufgerufen wird.

Vertex-Shader:

uniform vec3 camRotation; 
attribute vec3 position; 
void main() { 

    // I want this code to run only once per draw call 
    float rX = camRotation[0]; 
    float rY = camRotation[1]; 
    float rZ = camRotation[2]; 
    mat4 camMatrix = mat4(
     cos(rY) * cos(rZ), cos(rZ) * sin(rX) * sin(rY) - cos(rX) * sin(rZ), sin(rX) * sin(rZ) + cos(rX) * cos(rZ) * sin(rY), 0, // 
     cos(rY) * sin(rZ), cos(rX) * cos(rZ) + sin(rX) * sin(rY) * sin(rZ), cos(rX) * sin(rY) * sin(rZ) - cos(rZ) * sin(rX), 0, // 
     -sin(rY), cos(rY) * sin(rX), cos(rX) * cos(rY), 0, // 
     0, 0, 0, 1 
    ); 
    // End of code in question 

    gl_Position = camMatrix * vec4(position, 1); 
    gl_PointSize = 5.0; 
} 

Ist es möglich? Bin ich ein Idiot, wenn ich es versuche?

+0

Sie finden [diese Artikel nützlich] (http://webglfundamentals.org) – gman

Antwort

3

AFAIK, es gibt keine Möglichkeit, das zu tun. Sie sollten camMatrix in Ihrem JS-Code berechnen und sie an den Shader über einheitliche passieren:

uniform mat4 camMatrix; 
attribute vec3 position; 
void main() { 
    gl_Position = camMatrix * vec4(position, 1); 
    gl_PointSize = 5.0; 
} 

Jetzt müssen Sie Matrix in JS berechnen:

// assuming that program is your compiled shader program and 
// gl is your WebGL context. 
const cos = Math.cos; 
const sin = Math.sin; 
gl.uniformMatrix4fv(gl.getUniformLocation(program, 'camMatrix'), [ 
    cos(rY) * cos(rZ), cos(rZ) * sin(rX) * sin(rY) - cos(rX) * sin(rZ), sin(rX) * sin(rZ) + cos(rX) * cos(rZ) * sin(rY), 0, 
    cos(rY) * sin(rZ), cos(rX) * cos(rZ) + sin(rX) * sin(rY) * sin(rZ), cos(rX) * sin(rY) * sin(rZ) - cos(rZ) * sin(rX), 0, 
    -sin(rY), cos(rY) * sin(rX), cos(rX) * cos(rY), 0, 
    0, 0, 0, 1 
]); 
+0

Danke für die Antwort. Ich bin mir der Methode bewusst, die Sie zur Verfügung stellen, ich bin neugierig zu sehen, ob ich diese Berechnungen (wie 'cos (rY)') im Shader einmal pro Aufruf ausführen kann. – gromit190

+1

@Birger Ich wäre sehr überrascht wegen wie GPU führt Shader aus. Um grob zu beschreiben, erhält jede Ausführung eines Shaders (für jeden Vertex, wenn wir über Vertex-Shader sprechen, und für jeden Pixel im Falle von Fragment-Shadern) seinen eigenen Status und Speicher. Und die Synchronisation und der Datenaustausch zwischen ihnen wäre etwas umständlich und möglicherweise langsam. –

2

Nein es ist nicht möglich, das gesamte Konzept von Shadern soll vektorisierbar sein, damit sie parallel laufen können. Selbst wenn Sie dort nicht viel gewinnen könnten, da der GPU-Geschwindigkeitsvorteil (neben anderen Dingen) inhärent auf seiner Fähigkeit beruht, Berechnungen parallel durchzuführen. Abgesehen davon haben Sie normalerweise eine kombinierte Ansichts-Projektionsmatrix, die während aller Zeichenaufrufe (eines Rahmens) und einer Modell/Welt-Matrix, die an jedes Objekt, das Sie zeichnen, angehängt ist, statisch bleibt.

Die Projektionsmatrix macht, was ihr Name bedeutet, die Punkte entweder perspektivisch oder orthogonal projiziert (Sie können sich das als Linse Ihrer Kamera vorstellen). Die Ansichtsmatrix ist eine Transformation, die diese Projektion (Kameraposition und -ausrichtung) übersetzt/rotiert, während die pro-Objekt-Welt/Modellmatrix die Transformationen (Translation, Rotation und Skalierung) des einzelnen Objekts enthält.

In Ihrem Shader verwandeln Sie dann Ihre Vertexposition für den Weltraum mit der pro-Objektmodell/Weltmatrix und dann schließlich zur Kamera Raum verwandeln sie die premultiplied ViewProjection Matrix:

gl_Position = matViewProjection * (matWorld * vPosition) 

Wie du bist je nach Anwendungsfall können Sie die Weltmatrix auf nur einen Übersetzungsvektor reduzieren.

+0

Das ist sehr aufschlussreich, danke! – gromit190

Verwandte Themen