地图不适用于加载的 Obj

Posted

技术标签:

【中文标题】地图不适用于加载的 Obj【英文标题】:Map not applying to loaded Obj 【发布时间】:2018-06-21 02:41:53 【问题描述】:

这是我上一个问题here 的后续。我只是想在这个 obj 的每一侧应用不同的纹理,但什么都没有出现。没有控制台错误,我相信我正在以正确的顺序应用。

这应该很简单,但过去一个小时我一直在努力解决这个问题。下面是一个代码示例:

(function onLoad() 
  var canvasElement;
  var width, height;
  var scene, camera;
  var renderer;
  var controls;

  var pivot;
  var bagMesh;
  var planeMesh;
  
  const objLoader = new THREE.OBJLoader2();
  const fileLoader = new THREE.FileLoader();
  const textureLoader = new THREE.TextureLoader();
 
  init();

  function init() 
    container = document.getElementById('container');
    initScene();
    addGridHelper();
    addCamera();
    addLighting();
    addRenderer();
    addOrbitControls();

    loadPlaneObj();
    
    // Logic
		var update = function() ;

		// Draw scene
		var render = function() 
			renderer.render(scene, camera);
		;

		// Run game logic (update, render, repeat)
		var gameLoop = function() 
			requestAnimationFrame(gameLoop);
			update();
			render();
		;
		gameLoop();
  

  /**** Basic Scene Setup ****/
  function initScene() 
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xd3d3d3);
    var axis = new THREE.AxesHelper();
    scene.add(axis);
  

  function addCamera() 
    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.set(3,3,3);
    scene.add(camera);
  

  function addGridHelper() 
    var planeGeometry = new THREE.PlaneGeometry(2000, 2000);
    planeGeometry.rotateX(-Math.PI / 2);

    var planeMaterial = new THREE.ShadowMaterial(
      opacity: 0.2
    );
    var plane = new THREE.Mesh(planeGeometry, planeMaterial);
    plane.position.y = -200;
    plane.receiveShadow = true;
    scene.add(plane);

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

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

  // *********** Lighting settings **********************
  function addLighting() 
    var light = new THREE.HemisphereLight(0xffffff, 0xffffff, 1);
    scene.add(light);
  

  // ************** Material settings **************
  function setMaterial(materialName) 
    // get the object from the scene
    var bagMesh = scene.getObjectByName('bag');
    var material;

    if (!materialName) 
      materialName = materials.material;
    

    if (bagMesh) 
      var colour = parseInt(materials.colour);
      switch (materialName) 
        case 'MeshBasicMaterial':
          material = new THREE.MeshBasicMaterial(
            color: colour
          );
          break;
        case 'MeshDepthMaterial':
          material = new THREE.MeshDepthMaterial();
          break;
        case 'MeshLambertMaterial':
          material = new THREE.MeshLambertMaterial(
            color: colour
          );
          break;
        case 'MeshNormalMaterial':
          material = new THREE.MeshNormalMaterial();
          break;
        case 'MeshPhongMaterial':
          material = new THREE.MeshPhongMaterial(
            color: colour
          );
          break;
        case 'MeshPhysicalMaterial':
          material = new THREE.MeshPhysicalMaterial(
            color: colour
          );
          break;
        case 'MeshStandardMaterial':
          material = new THREE.MeshStandardMaterial(
            color: colour
          );
          break;
        case 'MeshToonMaterial':
          material = new THREE.MeshToonMaterial(
            color: colour
          );
          break;
      
      bagMesh.children.forEach(function(c) 
        c.material = material;
      );
    
  

  function setMaterialColour(colour) 
    materials.colour = colour;
    setMaterial(null);
  
  // ************** End of materials ***************

  function addRenderer() 
    renderer = new THREE.WebGLRenderer(
      antialias: true
    );
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    container.appendChild(renderer.domElement);
  

  function addOrbitControls() 
    var controls = new THREE.OrbitControls(camera, renderer.domElement);
  

  function addPivot() 
    var cubeGeo = new THREE.BoxBufferGeometry(5, 5, 5);
    var cubeMat = new THREE.MeshBasicMaterial();
    pivot = new THREE.Mesh(cubeGeo, cubeMat);
    bagMesh.position.x -= 15;
    bagMesh.position.z -= 55;

    pivot.add(bagMesh);
    pivot.add(handle);
    scene.add(pivot);
  
  
  function loadPlaneObj() 
		loadObjWithMtl('PlaneWithMaterial', 
      'https://rawgit.com/Katana24/threejs-experimentation/material-test/models/PlaneWithMaterial.obj', 
      'https://rawgit.com/Katana24/threejs-experimentation/material-test/models/PlaneWithMaterial.mtl')
			.then(function(mesh) 
        loadTexture(
          'https://rawgit.com/Katana24/threejs-experimentation/material-test/img/1.jpg', scene, 0xff0000, THREE.FrontSide, mesh);
			);
	
  
  function loadObjWithMtl(modelName, modelUrl, mtlUrl) 
		return new Promise(function(resolve, reject) 
			var callbackOnLoad = function ( event )  resolve(event.detail.loaderRootNode); ;
			var onLoadMtl = function ( materials ) 
				objLoader.setModelName( modelName );
				objLoader.setMaterials( materials );
				objLoader.getLogger().setDebug( true );
				objLoader.load( modelUrl, callbackOnLoad, null, null, null, false );
			;
			objLoader.loadMtl(mtlUrl, null, onLoadMtl );
		);
	

	function loadTexture(imgPath, scene, color, side, mesh) 
		var loadedMesh = mesh;
	  textureLoader.load(imgPath,
			function (texture) 	
        var geometry = new THREE.Geometry().fromBufferGeometry( loadedMesh.children[0].geometry );
				mesh.children[0].material.map = texture;
				mesh.children[0].material.needsUpdate = true;
				scene.add(mesh);
			,
			undefined,
			function ( err ) 
				console.error( 'An error occurred...' );
			
		);
	
  
  function addPlaneToSceneSOAnswer(mesh) 
		var frontMaterial = new THREE.MeshBasicMaterial(  color : 0xff0000, side: THREE.FrontSide  );
		var backMaterial 	= new THREE.MeshBasicMaterial(  color : 0x00ff00, side: THREE.BackSide  );
		
		var geometry = new THREE.Geometry().fromBufferGeometry( mesh.children[0].geometry );
		var length = geometry.faces.length;
		geometry.faces.splice(14, 1);

		for (var i = 0; i < geometry.faces.length; i ++ ) 
			var face = geometry.faces[i];
			face.color.setHex(Math.random() * 0xffffff);
		
		mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( vertexColors: THREE.FaceColors, side: THREE.DoubleSide ) );
		mesh.material.side = THREE.FrontSide; 
		
		var mesh2 = new THREE.Mesh( geometry, mesh.material.clone() ); 
		mesh2.material.side = THREE.BackSide; 
		// mesh2.material.vertexColors = THREE.NoColors; 
		mesh2.material.vertexColors = [new THREE.Color(0xff0000), new THREE.Color(0x00ff00), new THREE.Color(0x0000ff)];

		mesh.add( mesh2 );
		scene.add(mesh);
	
)();
body 
  background: transparent;
  padding: 0;
  margin: 0;
  font-family: sans-serif;


#canvas 
  margin: 10px auto;
  width: 800px;
  height: 350px;
  margin-top: -44px;
<body>
  <div id="container"></div>
  <script src="https://threejs.org/build/three.js"></script>
  <script src="https://threejs.org/examples/js/libs/dat.gui.min.js"></script>
  <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
  <script src="https://threejs.org/examples/js/loaders/MTLLoader.js"></script>
  <script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/LoaderSupport.js"></script>
  <script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/OBJLoader2.js"></script>
</body>

那么我在这里做错了什么简单的事情?我认为问题出在这个函数上:

  function loadTexture(imgPath, scene, color, side, mesh) 
    var loadedMesh = mesh;
    textureLoader.load(imgPath,
      function (texture)   
        var geometry = new THREE.Geometry().fromBufferGeometry( loadedMesh.children[0].geometry );
        mesh.children[0].material.map = texture;
        mesh.children[0].material.needsUpdate = true;
        scene.add(mesh);
      ,
      undefined,
      function ( err ) 
        console.error( 'An error occurred...' );
      
    );
  

此函数获取网格,然后加载所需的纹理并将其应用于网格中的材质。然后它告诉材料更新。这是正确的方法吗?

这个答案here 实际上只有在设置完所有内容后才调用渲染,但我希望能够在运行时更改纹理、材质等。

我以为mesh.children[0].material.needsUpdate = true 会通知着色器程序更新...

谢谢

【问题讨论】:

【参考方案1】:

纹理加载正确,但显示不正确,因为搅拌器对象不提供任何纹理坐标:

# Blender v2.77 (sub 0) OBJ File: 'Plane.blend'
# www.blender.org
mtllib PlaneWithMaterial.mtl
o Plane
v -1.000000 0.000000 1.000000
v 1.000000 0.000000 1.000000
v -1.000000 0.000000 -1.000000
v 1.000000 0.000000 -1.000000
vn 0.0000 1.0000 0.0000
usemtl Material
s off
f 1//1 2//1 4//1 3//1

请改用以下对象:

# Blender v2.77 (sub 0) OBJ File: 'Plane.blend'
# www.blender.org
mtllib PlaneWithMaterial.mtl
o Plane

v -1.000000 0.000000 1.000000
v 1.000000 0.000000 1.000000
v -1.000000 0.000000 -1.000000
v 1.000000 0.000000 -1.000000

vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000

vn 0.0000 1.0000 0.0000

usemtl Material
s off
f 1/1/1 2/2/1 4/4/1 3/3/1

见代码sn-p:

(function onLoad() 
  var canvasElement;
  var width, height;
  var scene, camera;
  var renderer;
  var controls;

  var pivot;
  var bagMesh;
  var planeMesh;
  
  const objLoader = new THREE.OBJLoader2();
  const fileLoader = new THREE.FileLoader();
  const textureLoader = new THREE.TextureLoader();
  textureLoader.setCrossOrigin("");
 
  init();

  function init() 
    container = document.getElementById('container');
    initScene();
    addGridHelper();
    addCamera();
    addLighting();
    addRenderer();
    addOrbitControls();

    loadPlaneObj();
    
    // Logic
		var update = function() ;

		// Draw scene
		var render = function() 
			renderer.render(scene, camera);
		;
    
    function resize() 
      var aspect = window.innerWidth / window.innerHeight;
      renderer.setSize(window.innerWidth, window.innerHeight);
      camera.aspect = aspect;
      camera.updateProjectionMatrix();
    
    window.onresize = resize;

		// Run game logic (update, render, repeat)
		var gameLoop = function() 
			requestAnimationFrame(gameLoop);
			update();
			render();
		;
		gameLoop();
  

  /**** Basic Scene Setup ****/
  function initScene() 
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xd3d3d3);
    var axis = new THREE.AxesHelper();
    scene.add(axis);
  

  function addCamera() 
    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.set(1,1,1);
    scene.add(camera);
  

  function addGridHelper() 
    var planeGeometry = new THREE.PlaneGeometry(2000, 2000);
    planeGeometry.rotateX(-Math.PI / 2);

    var planeMaterial = new THREE.ShadowMaterial(
      opacity: 0.2
    );
    var plane = new THREE.Mesh(planeGeometry, planeMaterial);
    plane.position.y = -200;
    plane.receiveShadow = true;
    scene.add(plane);

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

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

  // *********** Lighting settings **********************
  function addLighting() 
    var light = new THREE.HemisphereLight(0xffffff, 0xffffff, 1);
    scene.add(light);
  

  // ************** Material settings **************
  function setMaterial(materialName) 
    // get the object from the scene
    var bagMesh = scene.getObjectByName('bag');
    var material;

    if (!materialName) 
      materialName = materials.material;
    

    if (bagMesh) 
      var colour = parseInt(materials.colour);
      switch (materialName) 
        case 'MeshBasicMaterial':
          material = new THREE.MeshBasicMaterial(
            color: colour
          );
          break;
        case 'MeshDepthMaterial':
          material = new THREE.MeshDepthMaterial();
          break;
        case 'MeshLambertMaterial':
          material = new THREE.MeshLambertMaterial(
            color: colour
          );
          break;
        case 'MeshNormalMaterial':
          material = new THREE.MeshNormalMaterial();
          break;
        case 'MeshPhongMaterial':
          material = new THREE.MeshPhongMaterial(
            color: colour
          );
          break;
        case 'MeshPhysicalMaterial':
          material = new THREE.MeshPhysicalMaterial(
            color: colour
          );
          break;
        case 'MeshStandardMaterial':
          material = new THREE.MeshStandardMaterial(
            color: colour
          );
          break;
        case 'MeshToonMaterial':
          material = new THREE.MeshToonMaterial(
            color: colour
          );
          break;
      
      bagMesh.children.forEach(function(c) 
        c.material = material;
      );
    
  

  function setMaterialColour(colour) 
    materials.colour = colour;
    setMaterial(null);
  
  // ************** End of materials ***************

  function addRenderer() 
    renderer = new THREE.WebGLRenderer(
      antialias: true
    );
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    container.appendChild(renderer.domElement);
  

  function addOrbitControls() 
    var controls = new THREE.OrbitControls(camera, renderer.domElement);
  

  function addPivot() 
    var cubeGeo = new THREE.BoxBufferGeometry(5, 5, 5);
    var cubeMat = new THREE.MeshBasicMaterial();
    pivot = new THREE.Mesh(cubeGeo, cubeMat);
    bagMesh.position.x -= 15;
    bagMesh.position.z -= 55;

    pivot.add(bagMesh);
    pivot.add(handle);
    scene.add(pivot);
  
  
  function loadPlaneObj() 
    makeTextFile = function (text) 
      var data = new Blob([text], type: 'text/plain');
      var textFile = window.URL.createObjectURL(data);
      return textFile;   
    
    var textbox_obj = document.getElementById('plane_obj');
    var obj_url = makeTextFile(textbox_obj.value);
    var textbox_mtl = document.getElementById('plane_mtl');
    var mtl_url = makeTextFile(textbox_mtl.value);

    loadObjWithMtl('plane1', 
      obj_url, mtl_url)
			.then(function(mesh) 
        loadTexture(
         'https://rawgit.com/Katana24/threejs-experimentation/material-test/img/1.jpg',
         scene, 0xff0000, THREE.FrontSide, mesh);
			);
	
  
  function loadObjWithMtl(modelName, modelUrl, mtlUrl) 
		return new Promise(function(resolve, reject) 
			var callbackOnLoad = function ( event )  resolve(event.detail.loaderRootNode); ;
			var onLoadMtl = function ( materials ) 
				objLoader.setModelName( modelName );
				objLoader.setMaterials( materials );
				objLoader.getLogger().setDebug( true );
				objLoader.load( modelUrl, callbackOnLoad, null, null, null, false );
			;
			objLoader.loadMtl(mtlUrl, null, onLoadMtl );
		);
	

	function loadTexture(imgPath, scene, color, side, mesh) 
		var loadedMesh = mesh;
	  textureLoader.load(imgPath,
			function (texture) 	
        var geometry = new THREE.Geometry().fromBufferGeometry( loadedMesh.children[0].geometry );
				mesh.children[0].material.map = texture;
				mesh.children[0].material.needsUpdate = true;
				scene.add(mesh);
			,
			undefined,
			function ( err ) 
				console.error( 'An error occurred...' );
			
		);
	
  
  function addPlaneToSceneSOAnswer(mesh) 
		var frontMaterial = new THREE.MeshBasicMaterial(  color : 0xff0000, side: THREE.FrontSide  );
		var backMaterial 	= new THREE.MeshBasicMaterial(  color : 0x00ff00, side: THREE.BackSide  );
		
		var geometry = new THREE.Geometry().fromBufferGeometry( mesh.children[0].geometry );
		var length = geometry.faces.length;
		geometry.faces.splice(14, 1);

		for (var i = 0; i < geometry.faces.length; i ++ ) 
			var face = geometry.faces[i];
			face.color.setHex(Math.random() * 0xffffff);
		
		mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( vertexColors: THREE.FaceColors, side: THREE.DoubleSide ) );
		mesh.material.side = THREE.FrontSide; 
		
		var mesh2 = new THREE.Mesh( geometry, mesh.material.clone() ); 
		mesh2.material.side = THREE.BackSide; 
		// mesh2.material.vertexColors = THREE.NoColors; 
		mesh2.material.vertexColors = [new THREE.Color(0xff0000), new THREE.Color(0x00ff00), new THREE.Color(0x0000ff)];

		mesh.add( mesh2 );
		scene.add(mesh);
	
)();
body 
  background: transparent;
  padding: 0;
  margin: 0;
  font-family: sans-serif;


#canvas 
  margin: 10px auto;
  width: 800px;
  height: 350px;
  margin-top: -44px;
<body>
  <div id="container"></div>
  <script src="https://threejs.org/build/three.js"></script>
  <script src="https://threejs.org/examples/js/libs/dat.gui.min.js"></script>
  <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
  <script src="https://threejs.org/examples/js/loaders/MTLLoader.js"></script>
  <script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/LoaderSupport.js"></script>
  <script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/OBJLoader2.js"></script>

  <textarea id="plane_obj" style="display:none;">
    # Blender v2.77 (sub 0) OBJ File: 'Plane.blend'
    # www.blender.org
    mtllib Plane.mtl
    o Plane
    
    v -1.000000 0.000000 1.000000
    v 1.000000 0.000000 1.000000
    v -1.000000 0.000000 -1.000000
    v 1.000000 0.000000 -1.000000
    
    vt 0.000000 0.000000
    vt 1.000000 0.000000
    vt 0.000000 1.000000
    vt 1.000000 1.000000
    
    vn 0.0000 1.0000 0.0000
    
    usemtl None
    s off
    f 1/1/1 2/2/1 4/4/1 3/3/1
  </textarea>

  <textarea id="plane_mtl" style="display:none;">
    # Blender MTL File: 'Plane.blend'
    # Material Count: 1
    
    newmtl None
    Ns 0
    Ka 0.000000 0.000000 0.000000
    Kd 0.8 0.8 0.8
    Ks 0.8 0.8 0.8
    d 1
    illum 2
  </textarea>

</body>

【讨论】:

非常感谢您的回答 我用您上面概述的内容替换了 obj 数据,但是当它遇到 loadTexture 函数并在传入的网格上查找几何时它会抱怨 - 结果网格没有任何子对象。 实际上这很奇怪 - 我将我的 jsfiddle 更新为你所拥有的并且它可以工作,但同样的动作在我的本地不起作用 - 仍然返回给孩子们..

以上是关于地图不适用于加载的 Obj的主要内容,如果未能解决你的问题,请参考以下文章

无法加载安卓谷歌地图 V2

vue使用maptalks地图+three加载video视频obj+mtl和gltf模型

百度echarts地图扩展动态加载geoCoord

Jquery 选择器不适用于动态 .get 加载的内容

加载功能不适用于href

TableView 重新加载不适用于 SwiftUI 中的 UIViewRepresentable