ShaderSource: примеры (JAVASCRIPT)

ShaderSource в JavaScript: примеры использования WebGL
Раздел: WebGL, Шейдеры
shaderSource(shader: WebGLShader, source: String): undefined

Описание функции shaderSource

Функция shaderSource(shader, source) является методом объекта WebGLRenderingContext. Она связывает исходный код шейдера с объектом шейдера WebGLShader. Используется при настройке конвейера рендеринга WebGL для определения программируемых этапов обработки графики.

Аргументы:

  • shader - объект типа WebGLShader, созданный функцией createShader
  • source - строка, содержащая исходный код шейдера на языке GLSL

Возвращаемое значение: Отсутствует (void).

Функция не проверяет синтаксис GLSL, а лишь загружает код. Валидация происходит на этапе компиляции через compileShader.

Базовые примеры использования

Создание вершинного шейдера:

const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl');

const vertexShader = gl.createShader(gl.VERTEX_SHADER);
const vertexShaderSource = `
  attribute vec4 aPosition;
  void main() {
    gl_Position = aPosition;
  }
`;

gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
Шейдер создан, код загружен в объект

Создание фрагментного шейдера:

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
const fragmentShaderSource = `
  precision mediump float;
  uniform vec4 uColor;
  void main() {
    gl_FragColor = uColor;
  }
`;

gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
Фрагментный шейдер готов к компиляции

Похожие функции в JavaScript

createShader - создает пустой объект шейдера, с которым затем используется shaderSource.

compileShader - компилирует шейдер после загрузки кода через shaderSource.

getShaderParameter - позволяет получить статус компиляции шейдера.

attachShader - присоединяет скомпилированный шейдер к программе WebGL.

Все эти функции работают вместе в процессе настройки графического конвейера.

Аналоги в других языках программирования

C/C++ (OpenGL): Используется функция glShaderSource с аналогичной сигнатурой.

GLuint shader = glCreateShader(GL_VERTEX_SHADER);
const char* source = "#version 330 core\nlayout(location=0) in vec3 aPos;\nvoid main(){gl_Position=vec4(aPos,1.0);}";
glShaderSource(shader, 1, &source, NULL);

Python (PyOpenGL): Интерфейс практически идентичен C-версии.

from OpenGL.GL import *
shader = glCreateShader(GL_VERTEX_SHADER)
source = '''#version 330 core
layout(location=0) in vec3 aPos;
void main() {
    gl_Position = vec4(aPos, 1.0);
}'''
glShaderSource(shader, source)
glCompileShader(shader)

В PHP и MySQL аналоги отсутствуют, так как эти технологии не работают с графическим конвейером.

Типичные ошибки

Передача неверного типа объекта:

const gl = canvas.getContext('webgl');
const wrongObject = {};
gl.shaderSource(wrongObject, 'void main() {}');
// Ошибка: WebGL error INVALID_OPERATION
Uncaught TypeError: Failed to execute 'shaderSource' on 'WebGLRenderingContext': parameter 1 is not of type 'WebGLShader'.

Использование после удаления шейдера:

const shader = gl.createShader(gl.VERTEX_SHADER);
gl.deleteShader(shader);
gl.shaderSource(shader, 'void main() {}');
// Ошибка: WebGL error INVALID_OPERATION
WebGL: INVALID_OPERATION: shaderSource: shader not from this context

Передача null или undefined вместо строки:

gl.shaderSource(vertexShader, null);
WebGL: INVALID_VALUE: shaderSource: source is empty

Изменения в последних версиях

Функция shaderSource остаётся стабильной с момента введения WebGL 1.0 (2011 год). В WebGL 2.0 изменений в API функции не было, однако расширились возможности языка GLSL, которые можно передавать в source.

Современные браузеры поддерживают передачу строк с шаблонными литералами ES6, что упрощает написание многострочных шейдеров.

Расширенные примеры

Динамическая генерация кода шейдера:

Пример javascript
function createShaderWithUniforms(gl, uniformCount) {
    const shader = gl.createShader(gl.FRAGMENT_SHADER);
    let uniformDeclarations = '';
    for(let i = 0; i < uniformCount; i++) {
        uniformDeclarations += `uniform float uValue${i};\n`;
    }
    
    const source = `
        precision highp float;
        ${uniformDeclarations}
        void main() {
            float sum = 0.0;
            ${Array.from({length: uniformCount}, (_, i) => `sum += uValue${i};`).join('\n            ')}
            gl_FragColor = vec4(vec3(sum), 1.0);
        }
    `;
    
    gl.shaderSource(shader, source);
    return shader;
}

Загрузка шейдера из внешнего файла:

Пример javascript
async function loadShaderFromURL(gl, type, url) {
    const response = await fetch(url);
    const source = await response.text();
    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);
    
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        console.error('Shader compilation error:', gl.getShaderInfoLog(shader));
        gl.deleteShader(shader);
        return null;
    }
    return shader;
}

Многострочные шейдеры с комментариями:

Пример javascript
const complexShaderSource = `// Вершинный шейдер с трансформациями
#version 300 es
in vec4 aVertexPosition;
in vec2 aTextureCoord;

uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;

out vec2 vTextureCoord;

void main() {
    // Вычисление конечной позиции
    gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
    vTextureCoord = aTextureCoord;
}`;

JS shaderSource function comments

En
ShaderSource Sets the source code of a WebGLShader