Использование WebGLRenderer с параметром logarithmicDepthBufferset, установленным в true, вместе с ShaderMaterial - PullRequest
0 голосов
/ 20 ноября 2018

Я использую следующие ShaderMaterial для своих объектов в сцене.Код ниже работает.Однако, если я установлю для параметра WebGLRenderer logarithmicDepthBuffer значение true, определенный ниже материал будет отображаться неправильно.

new THREE.ShaderMaterial({
    uniforms: {
      color1: {
        value: new THREE.Color('#3a0000')
      },
      color2: {
        value: new THREE.Color('#ffa9b0')
      }
    },
    vertexShader: `
    varying vec3 vNormal;
    void main(void){
      vNormal      = normalMatrix * normalize(normal);
      gl_Position  = projectionMatrix * modelViewMatrix * vec4(position,1.0);
    }`,

    fragmentShader: `
    uniform vec3 color1;
    uniform vec3 color2;
    varying vec3 vNormal;
    void main(void){
      vec3 view_nv  = normalize(vNormal);
      vec3 nv_color = view_nv * 0.5 + 0.5;
      vec3 c = mix(color1, color2, nv_color.r);
      gl_FragColor  = vec4(c, 1.0);
    }`,
    side: THREE.DoubleSide,
  });

После поиска решения этой проблемы я нашел следующий SO ответ .Резюмируя, решение состоит в том, чтобы добавить 4 фрагмента кода к vertexShader и fragmentShader.

Где именно мне нужно интегрировать предоставленные фрагменты кода, то есть Vertex shaderbody и фрагмент шейдера body?

Я пробовал разные "позиции", но всегда получал ошибки WebGL.

THREE.WebGLProgram: shader error: 0 gl.VALIDATE_STATUS false gl.getProgramInfoLog Must have a compiled vertex shader attached. ERROR: 0:63: 'EPSILON' : undeclared identifier 

UPDATE добавленная игровая площадка: https://codepen.io/anon/pen/gQoaye

Если вы добавите опцию logarithmicDepthBuffer в конструктор, вы увидите, что ShaderMaterial больше не будет работать.

var renderer = new THREE.WebGLRenderer(logarithmicDepthBuffer:true);

Ответы [ 2 ]

0 голосов
/ 25 ноября 2018

Где именно я должен интегрировать предоставленные фрагменты кода, то есть тело вершинного шейдера и тело шейдера фрагмента?

В вершинном шейдере вы должны определить EPSILON.
После добавления фрагментов кода logdepthbuf_pars_vertex.glsl и logdepthbuf_vertex.glsl , конечный вершинный шейдер будет:

#ifdef USE_LOGDEPTHBUF
#define EPSILON 1e-6
#ifdef USE_LOGDEPTHBUF_EXT
varying float vFragDepth;
#endif
uniform float logDepthBufFC;
#endif

varying vec3 vNormal;

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

#ifdef USE_LOGDEPTHBUF
    gl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;
#ifdef USE_LOGDEPTHBUF_EXT
    vFragDepth = 1.0 + gl_Position.w;
#else
    gl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;
#endif
#endif
}

После добавления фрагментов кода, окончательный фрагментшейдер:

#ifdef USE_LOGDEPTHBUF
uniform float logDepthBufFC;
#ifdef USE_LOGDEPTHBUF_EXT
#extension GL_EXT_frag_depth : enable
varying float vFragDepth;
#endif
#endif

uniform vec3 color1;
uniform vec3 color2;
varying vec3 vNormal;
void main(void){
    vec3 view_nv  = normalize(vNormal);
    vec3 nv_color = view_nv * 0.5 + 0.5;
    vec3 c = mix(color1, color2, nv_color.r);
    gl_FragColor  = vec4(c, 1.0);

#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)
    gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;
#endif
} 

См. пример:

(function onLoad() {
  var container, camera, scene, renderer, orbitControls;
  
  function createModel() {

    var material = new THREE.ShaderMaterial({
    uniforms: {
      color1: {
        value: new THREE.Color('#3a0000')
      },
      color2: {
        value: new THREE.Color('#ffa9b0')
      }
    },
    vertexShader: `
    #ifdef USE_LOGDEPTHBUF
    #define EPSILON 1e-6
    #ifdef USE_LOGDEPTHBUF_EXT
    varying float vFragDepth;
    #endif
    uniform float logDepthBufFC;
    #endif

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

    #ifdef USE_LOGDEPTHBUF
        gl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;
    #ifdef USE_LOGDEPTHBUF_EXT
        vFragDepth = 1.0 + gl_Position.w;
    #else
        gl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;
    #endif
    #endif
    }`,

    fragmentShader: `
    #ifdef USE_LOGDEPTHBUF
    #ifdef USE_LOGDEPTHBUF_EXT
    #extension GL_EXT_frag_depth : enable
    varying float vFragDepth;
    #endif
    uniform float logDepthBufFC;
    #endif

    uniform vec3 color1;
    uniform vec3 color2;
    varying vec3 vNormal;
    void main(void){
        vec3 view_nv  = normalize(vNormal);
        vec3 nv_color = view_nv * 0.5 + 0.5;
        vec3 c = mix(color1, color2, nv_color.r);
        gl_FragColor  = vec4(c, 1.0);
        
    #if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)
        gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;
    #endif
    }`,
    side: THREE.DoubleSide,
  });

    //var material = new THREE.MeshPhongMaterial({color:'#b090b0'});
    var geometry = new THREE.BoxGeometry( 1, 1, 1 );
    var mesh = new THREE.Mesh(geometry, material);

    scene.add(mesh);
  }

  function init() {
    container = document.getElementById('container');
    
    renderer = new THREE.WebGLRenderer({
      antialias: true,
      logarithmicDepthBuffer: true
    });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    container.appendChild(renderer.domElement);

    camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100);
    camera.position.set(0, 1, -2);

    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xffffff);
    scene.add(camera);
    window.onresize = resize;

    orbitControls = new THREE.OrbitControls(camera);
    
    var helper = new THREE.GridHelper(100, 100);
    helper.material.opacity = 0.25;
    helper.material.transparent = true;
    scene.add(helper);

    var axis = new THREE.AxesHelper(1000);
    scene.add(axis);

    createModel();
  }

  function resize() {  
    var aspect = window.innerWidth / window.innerHeight;
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = aspect;
    camera.updateProjectionMatrix();
  }

  function animate() {
    requestAnimationFrame(animate);
    orbitControls.update();
    render();
  }

  function render() {
    renderer.render(scene, camera);
  }
  
  init();
  animate();
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<div id="container"></div>
0 голосов
/ 20 ноября 2018

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

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

Попробуйте определить EPSILON, например, используя макрос в самом шейдере:

#define EPSILON 1e-6

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

...