Подтвердить что ты не робот

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

Я начал с 3DJS WebGL рендеринга после выполнения некоторого "обычного" 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 года): этот вопрос получил довольно много просмотров, и пользователь Киллах отметил, что существующие ответы больше не приводят к решению проблемы с текущей версией Three.js. Я добавил и принял свой собственный ответ, см. Ниже.

4b9b3361

Ответ 1

Этот вопрос получил довольно много просмотров, и пользователь Киллах сказал, что существующие ответы больше не приводят к решению с текущей версией 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);
    

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

Ответ 2

Для униформ короткий ответ таков:

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

"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.

EDIT: обновлено до трёх .js r.73

Ответ 3

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

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

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

[EDIT] Перечитывая свой вопрос, я понимаю, что немного ответил, когда вы создаете свои собственные шейдеры...

Вы можете взглянуть на строки 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 - Какие атрибуты/униформы/изменения по умолчанию доступны в пользовательских шейдерах?), Но это направляет вас к строкам, указанным выше.