RenderTarget as new texture returns 只有一个黑白纹理

RenderTarget as new texture returns only a black and white texture

RenderTarget as new texture 第 2 部分:如果我给一个平面一个着色器并将一个纹理传输到它并且渲染工作正常。然后我看到一个带有传递给着色器的纹理的平面,太棒了

但是如果我尝试通过 renderTarget 将此结果作为新纹理输出,我会得到黑白纹理

谁知道为什么?

var camera, controls, scene, renderer, container, aspect;

var textureCamera
var textureScene;
    
function main() {
init();
animate();
}

function init() {

    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setPixelRatio( window.devicePixelRatio ); 
    renderer.shadowMap.enabled = true; 
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    renderer.setClearColor( 0x000000 );  
    container = document.getElementById('container');
    renderer.setSize(container.clientWidth, container.clientHeight);
    container.appendChild( renderer.domElement );

    aspect = container.clientWidth / container.clientHeight; 
    scene = new THREE.Scene();
    scene.background = new THREE.Color( 0x000000 );
    
    camera = new THREE.PerspectiveCamera( 60, container.clientWidth / container.clientHeight, 1, 1000000 );
    camera.position.set(0, 0, 200);

    controls = new THREE.OrbitControls( camera, renderer.domElement );
    controls.enableZoom = true;
    controls.enabled = true;
    controls.target.set(0, 0, 0);
    
    //-------------

    const loader = new THREE.TextureLoader();
    var texture = loader.load("pz.png");   //fine 
    //texture = generateTexture(); //returns a black and white texture 
    const geometry = new THREE.PlaneGeometry( 50, 50 );
    const material = customShader(texture);
    const plane = new THREE.Mesh( geometry, material); 
    scene.add( plane );

}//-------End init----------


function animate() {

    requestAnimationFrame( animate );  
    render();
    
}//-------End animate----------

function render() {
    
    //renderer.render(textureScene, textureCamera);   //for test, it works correct 

    camera.updateMatrixWorld();
    camera.updateProjectionMatrix(); 
    renderer.render(scene, camera); 

}//-------End render----------


function generateTexture() {

    var resolution = 2000;
    textureScene = new THREE.Scene();
    textureScene.background = new THREE.Color(0xFFFFFF);

    var textureOptions = { 
        format: THREE.RGBFormat,
        magFilter: THREE.LinearFilter,
        minFilter: THREE.LinearFilter,
    };

    var renderTarget = new THREE.WebGLRenderTarget(resolution, resolution, textureOptions);
    textureCamera = new THREE.PerspectiveCamera(60, 1, 0.1, 100000.0);
        
    textureCamera.position.set(0, 0, 200);
    textureCamera.lookAt(0, 0, 0);

    const loader = new THREE.TextureLoader();
    var texture = loader.load("pz.png");
    const geometry = new THREE.PlaneGeometry( 50, 50 );
    const material = customShader(texture);
    const plane = new THREE.Mesh( geometry, material); 
    textureScene.add( plane );

    renderer.setRenderTarget( renderTarget );
    renderer.clear(); 
    renderer.render( textureScene, textureCamera );
    
    renderer.setRenderTarget(null);
    return renderTarget.texture;
}


function customShader(texture){

    var Vertex =`
    varying vec2 vUv;
    void main() {
        vUv = uv;
        vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
        gl_Position = projectionMatrix * modelViewPosition;
    }`;
    
    var Fragment =`

    uniform sampler2D tex;
    varying vec2 vUv;
    void main() {
        vec4 color = texture2D(tex, vUv);
        gl_FragColor = color;
    }`;
    
    var uniforms = {   
        tex: { value: texture }
    };  
            
    return Shader = new THREE.ShaderMaterial({              
        uniforms: uniforms,         
        vertexShader: Vertex,
        fragmentShader: Fragment,   
        //transparent: true,
        side: THREE.DoubleSide,
    }); 

}

问题是您必须等到纹理实际加载后才能渲染到渲染目标。我已经更新了您的代码,因此它使用 async/await 语法来解决问题。尤其是看看 ​​generateTexture() 是如何改变的。

let camera, scene, renderer;

init().then(animate);

async function init() {

  renderer = new THREE.WebGLRenderer();
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  renderer.setClearColor(0x000000);
  document.body.appendChild(renderer.domElement);

  const aspect = window.innerWidth / window.innerHeight;
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0x000000);

  camera = new THREE.PerspectiveCamera(60, aspect, 1, 1000000);
  camera.position.set(0, 0, 200);

  const controls = new THREE.OrbitControls(camera, renderer.domElement);

  //-------------

  const texture = await generateTexture();
  const geometry = new THREE.PlaneGeometry(50, 50);
  const material = customShader(texture);
  const plane = new THREE.Mesh(geometry, material);
  scene.add(plane);

} //-------End init----------


function animate() {

  requestAnimationFrame(animate);
  render();

} //-------End animate----------

function render() {

  renderer.render(scene, camera);

} //-------End render----------


async function generateTexture() {

  const resolution = 2000;
  const textureScene = new THREE.Scene();
  textureScene.background = new THREE.Color(0xFFFFFF);

  const renderTarget = new THREE.WebGLRenderTarget(resolution, resolution);
  const textureCamera = new THREE.PerspectiveCamera(60, 1, 0.1, 100000.0);

  textureCamera.position.set(0, 0, 200);
  textureCamera.lookAt(0, 0, 0);

  const loader = new THREE.TextureLoader();
  const texture = await loader.loadAsync("https://threejs.org/examples/textures/uv_grid_opengl.jpg");
  const geometry = new THREE.PlaneGeometry(50, 50);
  const material = customShader(texture);
  const plane = new THREE.Mesh(geometry, material);
  textureScene.add(plane);

  renderer.setRenderTarget(renderTarget);
  renderer.clear();
  renderer.render(textureScene, textureCamera);

  renderer.setRenderTarget(null);
  return renderTarget.texture;
}


function customShader(texture) {

  const Vertex = `
    varying vec2 vUv;
    void main() {
        vUv = uv;
        vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
        gl_Position = projectionMatrix * modelViewPosition;
    }`;

  const Fragment = `

    uniform sampler2D tex;
    varying vec2 vUv;
    void main() {
        vec4 color = texture2D(tex, vUv);
        gl_FragColor = color;
    }`;

  const uniforms = {
    tex: {
      value: texture
    }
  };

  return Shader = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: Vertex,
    fragmentShader: Fragment
  });

}
body {
      margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three@0.138.3/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.138.3/examples/js/controls/OrbitControls.js"></script>

通过上面的代码,我在第二个场景中将土星环记录为纹理,然后将其投影到主场景中的球体上。结果和我想象的一模一样。但是,包含所有内容的整个代码非常广泛。土星背后环上的阴影、土星纹理和散射大气也是如此。投射在土星和光环上的阴影取决于土星在太阳周围的位置。整个事情都在不断更新。 如第一张图片所示,土星上环影的代码并不太大。我以前从未做过 fiddle。如果有人对代码感兴趣,我很高兴被告知如何在此处集成可执行代码。