Three.js 不渲染纹理

Posted

技术标签:

【中文标题】Three.js 不渲染纹理【英文标题】:Three.js not rendering texture 【发布时间】:2017-09-06 20:52:30 【问题描述】:

我是 three.js 的新手,我觉得我的场景已经接近完成,但是当我渲染时,我只是得到空白的画布元素,我的控制台中没有错误。为什么我的代码没有渲染我的纹理?我已经非常接近地关注了文档,而且我刚刚挂断了这篇文章。谢谢您的帮助。这是我的js:

`var 相机、场景、渲染器、纹理、雾; var 网格、几何、材质、缓冲区;

        var start_time = Date.now();

        init();
        animate();

        function init() 

            var container = $('#clouds');

            // Bg gradient

            var canvas = document.createElement( 'canvas' );
            canvas.width = 32;
            canvas.height = window.innerHeight;

            var context = canvas.getContext( '2d' );

            var gradient = context.createLinearGradient( 0, 0, 0, canvas.height );
            gradient.addColorStop(0, "#1e4877");
            gradient.addColorStop(0.5, "#4584b4");

            context.fillStyle = gradient;
            context.fillRect(0, 0, canvas.width, canvas.height);

            container.css('background', 'url(' + canvas.toDataURL('image/png') + ')');
            container.css('background-size', '32px 100%');

            //

            camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 1, 3000 );
            camera.position.z = 6000;

            scene = new THREE.Scene();

            geometry = new THREE.Geometry();

            var texture = new THREE.TextureLoader().load( '/media/cloud-element.png', animate);
            THREE.LinearMipMapNearestFilter;
            THREE.LinearMipMapLinearFilter;

            var fog = new THREE.Fog( 0x4584b4, - 100, 3000 );

            material = new THREE.ShaderMaterial( 

                uniforms: 

                    "map":  type: "t", value: texture ,
                    "fogColor" :  type: "c", value: fog.color ,
                    "fogNear" :  type: "f", value: fog.near ,
                    "fogFar" :  type: "f", value: fog.far ,

                ,
                depthWrite: false,
                depthTest: false,
                transparent: true,
                color: 0xf2f2f2

             );

            var plane = new THREE.Mesh( new THREE.PlaneGeometry( 64, 64 ) );

            for ( var i = 0; i < 8000; i++ ) 

                plane.position.x = Math.random() * 1000 - 500;
                plane.position.y = - Math.random() * Math.random() * 200 - 15;
                plane.position.z = i;
                plane.rotation.z = Math.random() * Math.PI;
                plane.scale.x = plane.scale.y = Math.random() * Math.random() * 1.5 + 0.5;

                THREE.GeometryUtils.merge(geometry, plane);
            

            mesh = new THREE.Mesh( geometry, material );
            scene.add( mesh );

            mesh = new THREE.Mesh( geometry, material );
            mesh.position.z = - 8000;
            scene.add( mesh );

            renderer = new THREE.WebGLRenderer();
            renderer.setSize( window.innerWidth, window.innerHeight );

            container.append( renderer.domElement );

            window.addEventListener( 'resize', onWindowResize, false );

        

        function onWindowResize( event ) 

            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();

            renderer.setSize( window.innerWidth, window.innerHeight );

        

        function animate() 

            requestAnimationFrame( animate );

            var position = ( ( Date.now() - start_time ) * 0.03 ) % 8000;

            camera.position.x += (camera.position.x ) * 0.01;
            camera.position.y += (camera.position.y ) * 0.01;
            camera.position.z = - position + 8000;

            renderer.render( scene, camera );

        

    `

【问题讨论】:

你能解释一下这个var plane = new THREE.Mesh( new THREE.PlaneGeometry( 64, 64 ) );和这个new THREE.BufferGeometry(geometry, plane);吗? 这似乎是一些应该被删除的试验和错误中的剩余代码。原来有geometry.merge(geometry, plane);,但是当我添加这个时,我出现以下错误angular.js:14110 TypeError: Cannot read property '0' of undefined 【参考方案1】:

您可能应该首先解决几个警告。 color 不是 THREE.ShaderMaterial 的属性。 THREE.GeometryUtils.merge(geometry, plane); 已移动成为Geometry 上的 API。等等等等。

我已将您的代码剥离为一个可以在此处运行的简单 sn-p(因为我们无权访问您的纹理文件)。

我的变化完全失去了收获:

我删除了您的初始画布。您可以稍后替换它。请注意,我将 alpha: true 添加到WebGLRenderer 参数中。这允许渲染器画布后面的任何内容显示出来。 我知道你在用new THREE.Mesh( new THREE.Plane(...) ) 做什么。只创建一堆平面网格可能更容易,尽管这也会创建一堆绘制调用。 我用基本颜色替换了您的着色器定义,只是为了让它工作。如果更新后的代码没有给您任何“啊哈时刻”,我们可以解决您的纹理问题。我确实想指出,您可能不需要为此使用着色器。 THREE.MeshBasicMaterial 有一个 map 属性,它可以接受 THREE.Texture(由 THREE.TextureLoader 提供)。 请注意我是如何处理将几何图形合并在一起的。更新平面的转换属性不会更新其顶点,这是merge 使用的。相反,我创建了一个临时的THREE.Geometry 对象来保存您的顶点,然后我将您的平面更新的变换矩阵应用于它们。这会“烘焙”变换并允许 merge 接收重新定位的顶点。

除此之外,几乎相同。请查看并在您的代码中尝试这些技术。如果您的纹理仍有问题,请发表评论,我们会重新审视它们。

var camera, scene, renderer, texture, fog;
var mesh, geometry, material, buffer;

var start_time = Date.now();

init();
animate();

function init() 

  var container = $('#clouds');

  camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 3000);
  camera.position.z = 6000;

  scene = new THREE.Scene();

  geometry = new THREE.Geometry();

  material = new THREE.MeshBasicMaterial(color: 0xf2f2f2, opacity: 0.5, transparent: true);

  var plane = new THREE.Mesh( new THREE.PlaneGeometry(64, 64) ),
    tempGeometry = new THREE.Geometry();

  for (var i = 0; i < 8000; i++) 

    plane.position.x = Math.random() * 1000 - 500;
    plane.position.y = -Math.random() * Math.random() * 200 - 15;
    plane.position.z = i;
    plane.rotation.z = Math.random() * Math.PI;
    plane.scale.x = plane.scale.y = Math.random() * Math.random() * 1.5 + 0.5;
    // Warning: THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.
    //THREE.GeometryUtils.merge(geometry, plane);
    plane.updateMatrix();
    tempGeometry.copy(plane.geometry);
    tempGeometry.applyMatrix(plane.matrix);
    geometry.merge(tempGeometry);
  

  mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  mesh = new THREE.Mesh(geometry, material);
  mesh.position.z = -8000;
  scene.add(mesh);

  renderer = new THREE.WebGLRenderer( alpha: true );
  renderer.setSize(window.innerWidth, window.innerHeight);

  container.append(renderer.domElement);

  window.addEventListener('resize', onWindowResize, false);



function onWindowResize(event) 

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);



function animate() 

  requestAnimationFrame(animate);

  var position = ((Date.now() - start_time) * 0.03) % 8000;

  camera.position.x += (camera.position.x) * 0.01;
  camera.position.y += (camera.position.y) * 0.01;
  camera.position.z = -position + 8000;

  renderer.render(scene, camera);

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://threejs.org/build/three.js"></script>
<div id="clouds" style="background: lightBlue;"></div>

【讨论】:

是的!这真太了不起了!我终于自己完成了它,但是我的内存占用很大,并且也收到了合并通知。谢谢泰语的回答也为 THREE.js 的工作原理提供了超级信息。 很好地让它工作。 :) THREE.Geometry 不是处理几何图形的最节省内存的方法,尽管它是一个很好的易于使用的起点。作为提高效率的下一步,请查看THREE.BufferGeometry 和(特别是对于您的重复几何形状的情况)THREE.ImstancedBufferGeometry。祝你好运!

以上是关于Three.js 不渲染纹理的主要内容,如果未能解决你的问题,请参考以下文章

Three.js使用WebGLRenderTarget进行离屏渲染(后期处理)

Three.js 画布纹理幂为 2 但被裁剪

THREE.js - 大型int作为Uniform

使用vue学习three.js之加载和使用纹理-使用canvas画布上的绘画作为纹理渲染到方块上,使用动态绘画纹理

three.js 中挤出形状的奇怪工件和空纹理

Three.js 立方体,每个面都有不同的纹理