Нахождение размера пикселя экрана в UV-координатах для использования фрагментным шейдером

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

Я думаю, что я могу запустить быстрый фильтр по соседним текстам и выбрать самое большое/наименьшее/самое интересное значение для рендеринга. Что я не уверен, как это сделать, так это узнать, нужно ли (и сколько) это делать. Когда пользователь увеличен в треугольнике, мне нужен стандартный поиск. При уменьшении масштаба один пиксель на экране сопоставляется многим пикселям текстуры.

Как мне получить оценку этого? Я делаю это как с ортогональными, так и с перспективными камерами.

Я думаю, что я мог бы каким-то образом использовать вершинный шейдер, чтобы получить оценку того, насколько велик один экранный пиксель в пространстве UV, и передать это как изменение фрагментному шейдеру, но я все еще не имею четкого представления ни о преобразованиях. и места достаточно, чтобы понять идею.

Мой текущий вершинный шейдер довольно прост:

  varying vec2 vUv;
  varying vec3 vPosition;
  varying vec3 vNormal;
  varying vec3 vViewDirection;

   void main() {
       vUv = uv;
       vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
       vPosition = (modelMatrix *
           vec4(position,1.0)).xyz;
       gl_Position = projectionMatrix * mvPosition;
      vec3 transformedNormal = normalMatrix *  vec3( normal );
      vNormal = normalize( transformedNormal );
      vViewDirection = normalize(mvPosition.xyz);
   }

Как мне получить что-то вроде vDeltaUV, которое дает расстояние между пикселями экрана в единицах UV?

Ограничения: я работаю в WebGL внутри three.js.

Вот пример одного изображения, где пользователь приблизил перспективу к моей текстуре: Нахождение размера пикселя экрана в UV-координатах для использования фрагментным шейдером

Вот тот же пример, но в уменьшенном масштабе; особенность выше — едва заметная диагональная линия рядом с центром (см. координаты, чтобы получить представление о масштабе). Я хочу, чтобы эта строка отображалась путем рендеринга всех пикселей с самым красным цветом соответствующего массива текстов.

Нахождение размера пикселя экрана в UV-координатах для использования фрагментным шейдером

Дополнение (относительно комментария ЖЖ)... Нет, я не думаю, что мипмэппинг сделает то, что я хочу, по двум причинам.

Во-первых, я на самом деле не накладываю текстуру; то есть я делаю что-то вроде этого:

   gl_FragColor = texture2D(mappingtexture,  texture2d(vec2(inputtexture.g,inputtexture.r))

Пользователь динамически создает текстуру отображения, что позволяет мне изменять карту искусственных цветов в реальном времени. Я думаю, что это действительно очень элегантное решение для моего приложения.

Во-вторых, я не хочу рисовать СРЕДНЕЕ значение соседних пикселей (т. е. сглаживание), я хочу максимальное ЭКСТРЕМАЛЬНОЕ значение соседних пикселей (т. е. что-то более похожее на поиск краев). «Экстремальность» в данном случае технически определяется моей кодировкой значений цвета g/r во входной текстуре.

Решение: Благодаря ответу ниже у меня теперь есть рабочее решение.

В моем коде javascript мне пришлось добавить:

  extensions: {derivatives: true}

к моему объявлению ShaderMaterial. Затем в моем фрагментном шейдере:

   float dUdx = dFdx(vUv.x); // Difference in U between this pixel and the one to the right.
  float dUdy = dFdy(vUv.x); // Difference in U between this pixel and the one to the above.
  float dU = sqrt(dUdx*dUdx + dUdy*dUdy);
  float pixel_ratio = (dU*(uInputTextureResolution));

Это позволяет мне делать такие вещи:

   float x = ... the u coordinate in pixels in the input texture
   float y = ... the v coordinate in pixels in the input texture
   vec4 inc = get_encoded_adc_value(x,y);

   // Extremum mapping:
   if (pixel_ratio>2.0) {
    inc = most_extreme_value(inc, get_encoded_adc_value(x+1.0, y));
   }
   if (pixel_ratio>3.0) {
    inc = most_extreme_value(inc, get_encoded_adc_value(x-1.0, y));    
  }

Эффект слабенький, но точно есть! Линии выскакивают намного четче.

Спасибо за помощь!

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
917
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не можете сделать это в вершинном шейдере, так как это этап предварительной растеризации, следовательно, выходное разрешение не зависит, но во фрагментном шейдере вы можете использовать dFdx, dFdyи ширина с помощью расширения GL_OES_standard_derivatives (которое доступно практически везде) для оценки площади выборки.

Если вы не обновляете текстуру в реальном времени, более простым и эффективным решением будет создание для нее пользовательских мип-уровней на ЦП.

Это выглядит интересно. Я посмотрю, есть ли какие-либо учебники по этим функциям. Текстуры действительно генерируются динамически, поэтому в приложении реального времени это занимает много времени. Даже если бы они у меня были, мне все равно нужен был бы надежный способ выбора текстуры для использования.

Nathaniel Tagg 29.07.2019 16:22

Графический процессор уже делает это за вас, вот что такое мип-маппинг, выбирая мип-уровень, наиболее близкий к соотношению тексель/экран-пиксель 1:1. Использование вашего подхода (например, не использование предложенного метода создания пользовательских мип-карт) быстрее только в том случае, если ваша текстура генерируется каждый кадр, а ваши уровни масштабирования довольно малы (например, минимизация 2-4), в любом другом случае мип-карты будут быть намного быстрее, и если процессор станет узким местом, вы также можете перенести эту нагрузку на графический процессор.

LJᛃ 29.07.2019 17:16

@LJ Я так не думаю; добавление выше

Nathaniel Tagg 29.07.2019 17:51

Другие вопросы по теме