Предопределенные атрибуты / формы шейдеров ThreeJS

Я начал с рендерера WebGL от ThreeJS после того, как выполнил «обычный» WebGL без дополнительных библиотек + шейдеры GLSL. Сейчас я пытаюсь писать собственные шейдеры в своей программе ThreeJS, и я заметил, что ThreeJS заботится о многих стандартных вещах, таких как матрицы проекции и модель / представление. Мой простой вершинный шейдер теперь выглядит так:

// All of these seem to be predefined:
// vec3 position;
// mat4 projectionMatrix;
// mat4 modelViewMatrix;
// mat3 normalMatrix;
// vec3 normal;

// I added this
varying vec3 vNormal;

void main() {
    vNormal = normalMatrix * vec3(normal);
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

Мой вопрос: какие еще переменные (я предполагаю, что они унифицированные) предопределены для вершинных и фрагментных шейдеров, которые я мог бы использовать? Помогает ли ThreeJS, например, с векторами света / цветом света (конечно, при условии, что я добавил один или несколько источников света в свою сцену ThreeJS)?

Обновление (9 октября 2014 г.): этот вопрос получил довольно много просмотров, и пользователь Killah упомянул, что существующие ответы больше не приводят к решению с текущей версией three.js . Я добавил и принял свой ответ, см. Ниже.


person Grüse    schedule 27.03.2013    source источник


Ответы (4)


Для униформы краткий ответ будет следующим:

В вершинном шейдере

"uniform mat4 modelMatrix;",
"uniform mat4 modelViewMatrix;",
"uniform mat4 projectionMatrix;",
"uniform mat4 viewMatrix;",
"uniform mat3 normalMatrix;",
"uniform vec3 cameraPosition;",

и во фрагментном шейдере

"uniform mat4 viewMatrix;",
"uniform vec3 cameraPosition;",

Для получения полного ответа, включая униформу и атрибуты, в ваши пользовательские шейдеры предварительно добавлены строковые переменные prefixVertex и prefixFragment.

var vertexGlsl = prefixVertex + vertexShader;
var fragmentGlsl = prefixFragment + fragmentShader;

var glVertexShader = THREE.WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
var glFragmentShader = THREE.WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );

Определения переменных prefixVertex и prefixFragment можно найти в WebGLProgram.js или в неминифицированной версии three.js.

РЕДАКТИРОВАТЬ: Обновлено до three.js r.73

person WestLangley    schedule 27.03.2013
comment
Извините, последний раздел вашего (очень полезного) ответа меня смущает. Что именно делают эти определения переменных? Вы перечисляете var glVertexShader = new THREE.WebGLShader( _gl, _gl.VERTEX_SHADER, prefix_vertex + vertexShader );, но я не уверен, когда они нам понадобятся. - person Startec; 24.11.2015

Униформа, которую вы можете использовать в шейдерах, зависит от того, как вы настраиваете материал: включили ли вы свет? цвета вершин? снятие шкуры? ...

Three JS создает программу, которая сильно зависит от некоторых определений (#ifdef в коде), которые вводятся в начало программы в зависимости от параметров, о которых я говорил выше.

Я обнаружил, что лучший способ узнать, что происходит, - это распечатать шейдеры, генерируемые тремя JS: поскольку вы уже знаете GLSL, вы легко поймете, что означает код и какую униформу вы можете использовать. Ищите buildProgram в трех источниках JS, затем (r57):

var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader );
var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader );

После этих строк добавьте:

console.log("fragment shader:", prefix_fragment + fragmentShader);
console.log("vertex shader:", prefix_vertex + vertexShader);

И вы сможете увидеть содержимое шейдеров.

[РЕДАКТИРОВАТЬ] Перечитывая ваш вопрос, я понимаю, что ответил немного неверно, поскольку вы создаете свои собственные шейдеры ...

Вы можете посмотреть строки 6463 и 6490 WebGLRenderer (https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js#L6463): вы увидите стандартные униформы / атрибуты, которые три JS внедряют в ваши шейдеры. Вы можете заглянуть в Wiki, где у вас есть запись об этом (https://github.com/mrdoob/three.js/wiki - Какие атрибуты / формы / вариации по умолчанию доступны в пользовательских шейдерах?), но он направляет вас к строкам, которые я обрисовал выше.

person Popov    schedule 27.03.2013
comment
Ссылка на код устарела, строки изменились с момента получения ответа. - person klh; 25.03.2014
comment
@Killah Я изучу и дополню этот вопрос другим ответом. Спасибо за предупреждение - person Grüse; 03.06.2014

Этот вопрос получил довольно много просмотров, и пользователь Killah упомянул, что существующие ответы больше не приводят к решению с текущей версией three.js. Вот почему я снова попытался решить эту проблему и хотел бы выделить несколько вариантов, которые я нашел:

  • Самый быстрый и простой способ (хотя и не очень элегантный) - просто добавить случайную ошибку в ваш шейдер. Вы получите консольную ошибку со всем кодом шейдера, включая все, что добавляет three.js.

  • Лучшее решение - вывести источник шейдера из того места, где он скомпилирован, а именно THREE.WebGLShader (в текущей версии three.js, r68). Я сделал быстрое копирование и вставку, которые должны вывести все источники шейдеров до их компиляции.

    Добавьте это после включения three.js и перед собственным кодом:

    THREE.WebGLShader = ( function () {
        var addLineNumbers = function ( string ) {
            var lines = string.split( '\n' );
            for ( var i = 0; i < lines.length; i ++ ) {
                lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
            }
            return lines.join( '\n' );
        };
        return function ( gl, type, string ) {
            var shader = gl.createShader( type ); 
            console.log(string);
            gl.shaderSource( shader, string );
            gl.compileShader( shader );
            if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {
                console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' );
            }
            if ( gl.getShaderInfoLog( shader ) !== '' ) {
                console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ) );
                console.warn( addLineNumbers( string ) );
            }
            return shader;
        };
    } )();
    

    Обратите внимание, что этот фрагмент просто скопирован (и очень немного изменен) из источников three.js и должен быть удален перед фактическим использованием кода. Просто для отладки!

  • Есть еще один вариант, который менее инвазивен: вы можете проверить свой ShaderMaterial после его создания и визуализации хотя бы один раз, например:

    var material = new THREE.ShaderMaterial({
        uniforms: {
            uColorMap: { type: 't', value: THREE.ImageUtils.loadTexture('./img/_colors.png') },
            uSpecularMap: { type: 't', value: THREE.ImageUtils.loadTexture('./img/_spec.png') }, 
            uNormalMap: { type: 't', value: THREE.ImageUtils.loadTexture('./img/_normal.png') }
        },
        vertexShader: document.getElementById('vShader').innerText,
        fragmentShader: document.getElementById('fShader').innerText
    });
    

    Затем после визуализации объекта хотя бы один раз:

    console.log(material.program.attributes);
    console.log(material.program.uniforms);
    

Надеюсь, это поможет всем! Не стесняйтесь добавлять свои комментарии, если вы знаете больше и / или лучшие способы получить код шейдера.

person Grüse    schedule 09.10.2014

Ответ на этот вопрос теперь можно найти в документации three.js: https://threejs.org/docs/#api/renderers/webgl/WebGLProgram

person Kalisen    schedule 12.04.2015