2017-01-20 10 views
1

я добавил эффект свечения в 3d самолета трекере:Three.js ShaderMaterial работает только на некоторых графических процессорах

enter image description here

Эффект питается от THREE.ShaderMaterial. Эффект работает только на некоторых ПК. На других ПК эффект не отображается, но ошибок нет, и все остальное работает. Я пытался использовать несколько компьютеров и операционных систем, и, похоже, это проблема, связанная с оборудованием, а не проблема с ОС.

Код для glow эффекта выглядит следующим образом:

private _createGlow(radius: number, segments: number) { 

    let material = new THREE.ShaderMaterial({ 
     uniforms: { 
      "c": { type: "f", value: 0.01 }, 
      "p": { type: "f", value: 6 }, 
      glowColor: { type: "c", value: new THREE.Color(0x002296) }, 
      viewVector: { type: "v3", value: this._camera.position } 
     }, 
     vertexShader: ` 
     uniform vec3 viewVector; 
     uniform float c; 
     uniform float p; 
     varying float intensity; 
     void main() 
     { 
      vec3 vNormal = normalize(normalMatrix * normal); 
      vec3 vNormel = normalize(normalMatrix * viewVector); 
      intensity = pow(c - dot(vNormal, vNormel), p); 

      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 
     }`, 
     fragmentShader: ` 
     uniform vec3 glowColor; 
     varying float intensity; 
     void main() 
     { 
      vec3 glow = glowColor * intensity; 
      gl_FragColor = vec4(glow, 1.0); 
     }`, 
     side: THREE.FrontSide, 
     blending: THREE.AdditiveBlending, 
     transparent: true 
    }); 

    let geometry = new THREE.SphereGeometry(radius, segments, segments); 
    let mesh = new THREE.Mesh(geometry, material); 
    mesh.scale.multiplyScalar(1.2); 
    return mesh; 
} 

Код для создания сцены выглядит следующим образом:

this._scene = new THREE.Scene(); 
this._scene.add(this._universe); 
this._scene.add(this._glow); 
this._scene.add(this._atmosphere1); 
this._scene.add(this._atmosphere2); 
this._scene.add(this._earth); 
this._scene.add(this._light); 
this._scene.add(new THREE.AmbientLight(0x333333, 0.9)); 

Является ли это проблемой драйверов GPU или что-то подобное? Как я могу это исправить? Благодаря!

+0

'vertexShader' и' fragmentShader' уже включены в вопрос. –

ответ

1

В вашем вопросе есть много неизвестных. Поскольку у нас нет доступа ко всем системам, на которых вы протестировали код, мы не можем просто взять ваш код, «исправить» и дать вам рабочий фрагмент назад.

Что вы можете сделать, однако, это то, что повсеместно полезно при 3D-программировании, а именно дифференциальная отладка - деление и покорение.

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

  • Culling - ваша сетка может быть неправильно забито во время рендеринга
  • Глубина провал - ваша сетка может быть провалив тест глубины (не видно из кода, почему это могло быть)
  • Окружающая форма (normalMatrix и т. Д.) Может быть неправильно инициализирована.

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

Сначала сделайте шейдер, который выводит только белый цвет (или glowColor), и отключите отбраковывание и протестируйте его - вы видите свою сферу?

  • Да - проверка глубины;
  • Нет - проверка глубины виновата.

Включить отбраковку - вы видите сферу?

  • Да - отбраковка в порядке (возможно, вы могли видеть задние лица модели);
  • Нет - ваши лица выбраны неправильно.

Далее идет отладка нормальных векторов - передача нормалей в пиксельный шейдер и вывод их в виде цветов фрагментов. Вы можете закодировать их, используя (n * 0.5) + 0.5, чтобы получить «нормальную карту» мира в пространстве. Это выглядит хорошо?

  • Да - обычная форма, скорее всего, правильная;
  • Нет - это может быть ошибка в three.js.

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

Последний вопрос: что произойдет, если GPU делит на 0?

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

Мое предположение, почему ваш код не работает, так это то, что pow(c - dot(vNormal, vNormel), p) возвращает NaN, когда база отрицательна. У разных GPU, вероятно, есть разные способы справиться с NaN, некоторые менее очевидны, чем другие.

Вкратце: вы должны прочитать все это. Этот метод намного полезнее результата.