Многие объекты в Three.js имеют собственность UndionUpdate, и они редко писаются в документах (но в Three.js не так много документов, и многие проблемы все еще должны полагаться на проблемы на GitHub). Они не знают, как написать это в различных учебниках в Интернете, потому что для простых вводных программ это свойство не может быть использовано.
Так для чего используется этот атрибут? Короче говоря, я говорю рендереру, что я должен обновить кэш в этом кадре. Хотя его очень просто использовать в качестве бита флага, потому что вам нужно знать, почему вам нужно обновить кэш и какие кэши для обновления, все еще необходимо тщательно понять его.
Зачем нуждатьсяПрежде всего, давайте посмотрим, почему нужен кэш. Существование кеша, как правило, состоит в том, чтобы сократить количество времени передачи данных, тем самым сокращая время, затрачиваемое на передачу данных. Здесь также верно, что для объекта (сетка) на экране нелегко отображаться на экране. Это должно быть перенесено на поле битвы три раза.
Во -первых, прочитать все данные вершины и текстуру с локального диска в память через программу.
Затем, после того, как программа выполнила соответствующую обработку в памяти, она должна передавать данные вершины и текстуру данных объектов, которые необходимо провести на экран на видео память.
Наконец, при рендеринге каждого кадра данные данных и текстуры вершины в видео памяти промываются в GPU для сборки и рисунка.
Согласно модели передачи данных, подобной пирамиде, первый шаг, очевидно, самый медленный. Если он передается через сеть в такой среде, как WebGL, это будет еще медленнее. Второе - время от памяти до видео памяти, которая будет простым тестом данных позже.
Тогда есть частота использования этих трех шагов. Для небольших сценариев первым шагом является одноразовый, то есть каждый раз, когда инициализируется программа, все данные сценария будут загружены в память. Для больших сценариев некоторая асинхронная загрузка может быть сделана, но в настоящее время это не проблема, которую мы рассматриваем. Частота второго шага должна быть самой важной вещью, чтобы поговорить об этом времени. Во -первых, напишите простую программу для проверки потребления, вызванного выполнением этого шага передачи.
var canvas = document.createElement ('canvas');
var _gl = canvas.getContext ('Experimental-webgl');
var vertices = [];
для (var i = 0; i <1000*3; i ++) {
vertices.push (i * math.random ());
}
var buffer = _gl.createbuffer ();
console.profile ('buffer_test');
BindBuffer ();
console.profileend ('buffer_test');
функция bindbuffer () {
для (var i = 0; i <1000; i ++) {
_gl.bindbuffer (_gl.array_buffer, buffer);
_gl.bufferdata (_gl.array_buffer, new float32array (вершины), _gl.static_draw);
}
}
Давайте сначала объясним эту программу. Вершины - это массив, который экономит вершины. Здесь 1000 вершин генерируются случайным образом. Поскольку каждая вершина имеет три координаты x, y и z, необходим массив 3000 размер. Команда _gl.createbuffer открывает кэш для хранения данных вершины в видео памяти, а затем использует _gl.bufferdata для передачи сгенерированных данных вершины из памяти в видео память. Здесь мы предполагаем, что в сцене есть 1000 объектов с 1000 вершин, каждая вершина составляет 3 32-разрядных 4 байт данных. Рассчитайте данные почти 1000 x 1000 x 12 = 11m. Профиль занимает около 15 мс. Здесь мы можем увидеть, как 15 мс - это всего лишь немного времени. Тем не менее, для программы в реальном времени, если вы хотите обеспечить частоту кадров 30 кадров в секунду, время, необходимое для каждого кадра, должно контролироваться примерно в 30 мс. Как может занять половину времени, чтобы просто сделать передачу данных? Вы должны знать, что большая голова должна быть операциями рисования в графическом процессоре и различной обработке в процессоре, и вы должны быть скупыми с каждым этапом операции во всем процессе рендеринга.
Следовательно, количество передач на этом этапе должно быть сведено к минимуму. Фактически, его можно использовать для передачи всех данных вершины и текстур из памяти в видео память при загрузке. Это то, что делает Three.js сейчас. Данные вершины объекта, который необходимо нарисовать, перенесены в видео память в первый раз, и кэшируйте буфер с геометрией .__ Weblvertexbuffer. После этого, каждый раз, когда вы рисуете, вы будете судить о собственности геометрии Verticesneedupdate. Если вам не нужно обновлять, используйте текущий кэш напрямую. Если вы видите, что вершины верно истинно, данные вершины в геометрии будут переданы в геометрию .__ Weblvertexbuffer. Как правило, нам не нужен этот шаг для статических объектов. Однако, если мы сталкиваемся с объектами, которые часто меняются, такие как использование вершин в качестве систем частиц и сетка, которая использует анимации скелета, эти объекты изменят свои вершины в каждом кадре, поэтому каждый кадр должен установить свой свойство вершинам, чтобы сказать рендеринере, что мне нужно для повторного предоставления данных!
Фактически, в программах WebGL больше положений вершины будет изменено в вершинном шейдере, чтобы завершить эффекты частиц и анимацию скелета. Хотя проще расширять, если он находится на стороне процессора для расчета, из -за ограничений вычислительной мощности JavaScript больше этих вычислительных операций будет установлено на стороне GPU. В этом случае нет необходимости повторно передавать данные вершины, поэтому приведенный выше случай не используется в реальной программе, и речь идет о обновлении текстуры и кеша материала.
В приведенном выше случае в основном описывается сценарий, в котором передаются данные вершины. В дополнение к данным вершины, есть также большая голова, которая является текстурой. Текстура формата формата R8G8B8A8 размером 1024*1024 должна занимать до 4м размера памяти, поэтому посмотрите на следующий пример.
var canvas = document.createElement ('canvas');
var _gl = canvas.getContext ('Experimental-webgl');
var texture = _gl.createTexture ();
var img = новое изображение;
img.onload = function () {
console.profile ('test test');
BindTexture ();
console.profileend ('test test');
}
img.src = 'test_tex.jpg';
функция bindTexture () {
_gl.bindTexture (_gl.texture_2d, текстура);
_gl.teximage2d (_gl.texture_2d, 0, _gl.rgba, _gl.rgba, _gl.unsigned_byte, img);
}
Здесь нет необходимости повторять извращенные 1000 раз здесь. Требуется 30 мс для передачи текстуры 10241024 за раз, а изображение 256256 составляет почти 2 мс. Следовательно, в Three.js текстура должна передаваться только один раз в начале. После этого, если свойство Texture.needsupdate не установлено вручную для True, текстура, которая была перенесена в видео память, будет использоваться напрямую.
Какие кэши должны быть обновленыПриведенное выше описывается, почему Thir.js должен добавить такой атрибут потребностей в два случая. Затем перечислите несколько сценариев, чтобы узнать, при каких обстоятельствах вам нужно вручную обновить эти кеши.
Асинхронная загрузка текстурЭто маленькая яма, потому что переднее изображение загружается асинхронно. Если вы пишете Texture.needsupdate = true сразу после создания IMG, рендерерат Thre.js будет использовать _gl.teximage2d для передачи пустых данных текстуры в видео память в этом кадре, а затем установит этот флаг на false. Затем, когда изображение загружено, данные видео памяти не будут обновлены. Поэтому вы должны ждать загрузки всего изображения в событии Onload, прежде чем записать текстуру.needSupdate = true
Видео текстураБольшинство текстур похожи на случай, когда выше, чтобы загрузить и передавать изображения напрямую, но не для видео текстур, потому что видео представляет собой потоком изображений, а изображение, которое будет отображаться в каждом кадре, отличается, поэтому вам необходимо установить потребности в TRUE для каждого кадра для обновления данных текстуры на видеокарте.
Используйте буфер рендерингаРендерный буфер является относительно особенным объектом. Как правило, программа будет промыть непосредственно на экран после того, как будет вытянута вся сцена. Однако, если существует больше пост-обработки или xxx на основе экрана (например, на основе экрана), сцена должна быть нарисована сначала в буфере рендеринга. Этот буфер на самом деле является текстурой, но он генерируется предыдущим рисунком, не загруженным с диска. В Thre.js есть специальный объект текстуры WebRenderTarget для инициализации и сохранения renderBuffer. Эта текстура также должна быть установлена на истину в каждом кадре.
Потребности материалаМатериал описан в трех.js через три. Материал. На самом деле, у материала не так много данных для передачи, но зачем вам нужно сделать нуждающуюся? Здесь я расскажу о шейдере. Шейдер переводится как шейдер, который обеспечивает возможность программирования вершин и пикселей в графическом процессоре. В живописи есть затененный термин, чтобы представлять легкий и темный метод живописи. Затенение в графическом процессоре похожа. Свет и темнота света рассчитываются программой для выражения материала объекта. ОК, поскольку Shader - это программа, работающая на графическом процессоре, как и все программы, необходимо выполнить компиляцию и операцию связывания. В WebGL программа шейдера составлена во время выполнения, что, конечно, требует времени, поэтому лучше всего собирать и работать до конца программы. Таким образом, когда материал инициализируется в Three.js, программа шейдера составлена и связана, а объект программы, полученный после кэширования компиляции. Как правило, материал больше не нуждается в перекомпиляции всего шейдера. Чтобы отрегулировать материал, вам нужно только изменить однородные параметры шейдера. Однако, если вы замените весь материал, такой как замена оригинального шейдера Pong на шейдер Lambert, вам нужно установить материал. Тем не менее, эта ситуация встречается редко, и более распространенной является то, что упоминается ниже.
Добавить и удалить светЭто должно быть чаще в сцене. Возможно, многие люди, которые только начали использовать Three.js, попадут в эту яму. После динамического добавления света в сцену они обнаруживают, что свет не работает. Однако при использовании шейдера, встроенного в Three.js, например, Phong, Lambert, глядя на исходный код в рендерере, вы обнаружите, что Thre.js использует #define в встроенном коде шейдера для установки количества света в сцене. Значение этого #Define получается с помощью шейдера сплайсинга с посылением сплайсинга каждый раз, когда материал обновляется. Код выглядит следующим образом.
"#define max_dir_lights" + parameters.maxdirlights,
"#define max_point_lights" + parameters.maxpointlights,
"#define max_spot_lights" + parameters.maxspotlights,
"#define max_hemi_lights" + parameters.maxhemiLights,
Действительно, этот метод написания может эффективно снизить использование регистров графических процессоров. Если есть только один свет, вы можете объявить только единую переменную, необходимую для одного света. Однако, когда количество огней изменяется, особенно при добавлении, вам необходимо повторно снимать и компилировать и связать шейдер. В настоящее время вам также необходимо установить материал.
Изменить текстуруИзменение текстуры здесь не означает обновление данных текстуры, а скорее то, что исходный материал использовал текстуру, но не использовался позже, или исходный материал не использовал текстуру, а затем добавил ее. Если материал не обновлен вручную, окончательный эффект будет отличаться от того, что вы думаете. Причина этой проблемы аналогична упомянутому выше освещению, и это также потому, что в шейдер был добавлен макрос, чтобы определить, использовалась ли текстура.
Parameters.map? "#define use_map": "",
параметры. envmap? "#define use_envmap": "",
Parameters.lightmap? "#define use_lightmap": "",
параметры. Bumpmap? "#define use_bumpmap": "",
параметры. normalmap? "#define use_normalmap": "",
параметры. Specularmap? "#define use_specularmap": "",
Следовательно, каждый раз, когда карта, Encmap или LightMap изменяют истинное значение, вам необходимо обновить материал
Изменения в других данных вершиныНа самом деле, изменение текстуры, выше, создаст проблему. Это в основном потому, что во время инициализации нет текстуры. Однако в этой среде добавлено динамически, этого недостаточно, чтобы установить материал. Он также должен установить геометрию. Почему такая проблема? Это из -за оптимизации программы с помощью Three.js. При первой инициализации геометрии и материала в рендерере, если оно будет признано, что нет текстуры, хотя в данных в памяти есть каждая вершина УФ -данные, три. Оригинальное намерение должно состоять в том, чтобы сохранить какое -то ценное пространство видео памяти. Однако после добавления текстуры геометрия не будет интеллектуально передавать эти УФ -данные для использования текстуры. Мы должны вручную настроить Uvsneedsupdate, чтобы сообщить об этом, что пришло время обновлять УФ, этот вопрос действительно заставил меня обмануть в течение долгого времени в начале.
Для получения атрибутов eandyupdate нескольких типов данных вершины вы можете увидеть эту проблему
https://github.com/mrdoob/three.js/wiki/updates
наконецОптимизация Three.js делает хорошую работу, но она приносит различные ловушки, которые могут быть затронуты различными оптимизациями. Лучший способ сделать это - посмотреть на исходный код или перейти к GitHub, чтобы упомянуть проблемы