V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yuxi521
V2EX  ›  程序员

求助帖.Three.js

  •  
  •   yuxi521 · 2020-10-18 12:33:48 +08:00 · 3158 次点击
    这是一个创建于 1504 天前的主题,其中的信息可能已经有所发展或是发生改变。

    后端 boy 因业务需求不得不学习 Three.js.将三维模型加载到 web 浏览器展示即可.

    操作路线:

    1 下载官方 demo,打开,运行正常,可见效果
    2 网上下载.obj  .mtl 文件替换官方例子,打开,可见效果 试了二个
    3 建模师提供的 obj 文件,使用电脑 3d 可打开,证明模型文件没问题,用 three.js 打开,看不到效果图,f12 也没报错信息,猜测:1 加载出错?2 灯光角度大小问题导致我看不到模型?
    4 贴上控制台信息
    Using OBJLoader2 version: 3.2.0
    verify.html?_ijt=9h2s3381ah9lvusnfe2lvi6sk7:233 Starting initialisation phase...
    verify.html?_ijt=9h2s3381ah9lvusnfe2lvi6sk7:183 Progress: Loading: verificationCubes
    OBJLoader2.js:342 Parsing arrayBuffer...
    OBJLoader2Parser.js:324 OBJLoader.Parser configuration:
    	materialNames:
    		- attr_0
    		- defaultMaterial
    		- defaultVertexColorMaterial
    		- defaultLineMaterial
    		- defaultPointMaterial
    	materialPerSmoothingGroup: false
    	useOAsMesh: true
    	useIndices: false
    	disregardNormals: false
    	callbacks.onProgress: onProgress
    	callbacks.onAssetAvailable: defaultOnAssetAvailable
    	callbacks.onError: onError
    OBJLoader2Parser.js:1109 Global output object count: 1
    OBJLoader2Parser.js:1116 Overall counts: 
    	Vertices: 1806
    	Faces: 1806
    	Multiple definitions: 0
    OBJLoader2Parser.js:389 OBJLoader2Parser.execute: 23.46533203125 ms
    OBJLoader2.js:358 OBJLoader parse: verificationCubes: 24.51318359375 ms
    verify.html?_ijt=9h2s3381ah9lvusnfe2lvi6sk7:162 Loading complete: verificationCubes
    verify.html?_ijt=9h2s3381ah9lvusnfe2lvi6sk7:183 Progress: 
    

    现在不知道怎么办才好.初步的想法就是可以加载成功就行.后期再去完善其他.求大佬指点

    17 条回复    2020-10-19 15:28:32 +08:00
    misdake
        1
    misdake  
       2020-10-18 12:47:07 +08:00   ❤️ 1
    可以尝试一下导入到官方 editor 里看看效果: https://threejs.org/editor/
    如果能看到,说明 threejs 本身应该是支持的,但是可能是你的项目中的物体位置(比如三角形不在视野内)、相机(比如 clearcolor 黑色,物体也是黑色导致看不出来)或者灯光(比如物体本应不黑但是没有光照导致是黑的)有什么问题。
    如果看不到,说明导出的 obj 或 mtl 格式可能有某种不兼容(但不报错)的情况(比如材质透明了或者没设置上)。
    xiaoming1992
        2
    xiaoming1992  
       2020-10-18 12:54:14 +08:00 via Android   ❤️ 1
    你要注意,还有以下几种可能,会导致看不到模型:

    1. 模型的实际位置离摄像机很远,在摄像机的视野外
    2. 模型在 threejs 中的单位太小(例如 0.0001,只能看到一个小点,你肉眼看不到)或太大(摄像机视野内恰好只能看到模型的缝隙)
    3. 模型不在原点,且摄像头看向了其他方向

    以上情况我都实际碰见过的,所以要求导出模型时规范些
    xiaoming1992
        3
    xiaoming1992  
       2020-10-18 13:00:26 +08:00 via Android   ❤️ 1
    还有感觉 threejs 的问题可以发到官方论坛,一方面那里的人都是做这个的,另一方面官方论坛的气氛特别好,特别热心,基本很少有提问不被解答的,而 v2 接触过 threejs 的相对应该比较少吧。 以前经常逛的,现在不做这方面了才逛得少了
    beginor
        4
    beginor  
       2020-10-18 14:22:27 +08:00 via Android   ❤️ 1
    控制台信息应该是没有错误的, 但是仅凭这些信息很难诊断出具体的原因。

    如果有可能的话可以把网页脚本和文件都放在互联网上,这样大家才能更容易帮到你。
    beginor
        5
    beginor  
       2020-10-18 14:27:42 +08:00 via Android   ❤️ 1
    发错了, 应该是有错,因为出现了 onError
    hgjian
        6
    hgjian  
       2020-10-18 15:33:45 +08:00 via Android   ❤️ 1
    你可以看看 360 开源的框架哦:
    https://spritejs.org
    lhx880619
        7
    lhx880619  
       2020-10-18 16:29:38 +08:00 via Android   ❤️ 1
    现在建议直接 gltf 模型了 另外 BabylonJS 也是个不错的选择 对于没有 3d 基础的 感觉你还有很长的路走。。。
    yuxi521
        8
    yuxi521  
    OP
       2020-10-18 16:47:30 +08:00
    @lhx880619 仅仅是加载下模型展示出来 也不知道难度,公司没这方面技术的同事,领导就派我上了,哎
    tangchi695
        9
    tangchi695  
       2020-10-18 16:54:44 +08:00
    @lhx880619 没基础你让人用 Babylon😂
    tangchi695
        10
    tangchi695  
       2020-10-18 16:59:07 +08:00
    加载自己的模型看不到,先给灯光,再缩放模型,放大到 10 倍 100 倍率,或者缩小,或者加一个 axeshelper 定位看看在哪儿,加载器加载的回调里打印下结果,看看加载的结果是什么,成功和错误的回调都要打印。
    alw
        11
    alw  
       2020-10-19 08:39:02 +08:00
    1.windows10 自带 3d 查看器,可以直接双击打开看模型。
    2. 调灯光,否则有可能是黑色,黑色物体混在黑色背景,看个毛线。
    用这句统一变成不受光影响的基本色试试:
    `scene.overrideMaterial = new THREE.MeshBasicMaterial( { color: 'green' } );`

    3. 调摄像头坐标,模型太大,摄像头有可能有物体内部,或者超出了摄像头的可视范围。
    建议先用 3D 模型建一个 长宽高各一米的立方体来测试,验证以上三点之后,再调试设计师的模型,主要是搞清模型大小,摄像头应该放哪个位置等问题。
    LyleRockkk
        12
    LyleRockkk  
       2020-10-19 09:19:59 +08:00
    能不能贴一下加载模型的 js 代码,obj 格式的加载都不用过多设置,模型没问题多半是相机设置的有问题,画面中看不到模型
    yuxi521
        13
    yuxi521  
    OP
       2020-10-19 10:18:29 +08:00
    @LyleRockkk
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <title>three.js webgl - 2/OBJLoader verification</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">

    <style>
    body {
    font-family: Monospace;
    background-color: #F5F5F5;
    color: #fff;
    margin: 0 0 0 0;
    padding: 0 0 0 0;
    border: none;
    cursor: default;
    }
    #info {
    color: #fff;
    position: absolute;
    top: 10px;
    width: 100%;
    text-align: center;
    z-index: 100;
    display:block;
    }
    #info a {
    color: #f00;
    font-weight: bold;
    text-decoration: underline;
    cursor: pointer
    }
    #glFullscreen {
    width: 100%;
    height: 100vh;
    min-width: 640px;
    min-height: 360px;
    position: relative;
    overflow: hidden;
    z-index: 0;
    }
    #example {
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    background-color: #555555;
    }
    #feedback {
    color: darkorange;
    }
    #dat {
    user-select: none;
    position: absolute;
    left: 0;
    top: 0;
    z-Index: 200;
    }
    </style>
    </head>

    <body>
    <div id="glFullscreen">
    <canvas id="example"></canvas>
    </div>
    <div id="dat">

    </div>
    <div id="info">
    <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - OBJLoader2/OBJLoader verification
    <div id="feedback"></div>
    </div>

    <script type="module">

    'use strict';

    import {
    AmbientLight,
    DirectionalLight,
    GridHelper,
    PerspectiveCamera,
    Scene,
    Vector3,
    WebGLRenderer
    } from "../../../../build/three.module.js";

    import { TrackballControls } from "../../../jsm/controls/TrackballControls.js";

    import { MTLLoader } from "../../../jsm/loaders/MTLLoader.js";
    import { MtlObjBridge } from "../../../jsm/loaders/obj2/bridge/MtlObjBridge.js";
    import { OBJLoader } from "../../../jsm/loaders/OBJLoader.js";
    import { OBJLoader2 } from "../../../jsm/loaders/OBJLoader2.js";

    const OBJLoaderVerify = function ( elementToBindTo ) {
    this.renderer = null;
    this.canvas = elementToBindTo;
    this.aspectRatio = 1;
    this.recalcAspectRatio();

    this.scene = null;
    this.cameraDefaults = {
    posCamera: new Vector3( 0.0, 175.0, 500.0 ),
    posCameraTarget: new Vector3( 0, 0, 0 ),
    near: 0.1,
    far: 10000,
    fov: 45
    };
    this.camera = null;
    this.cameraTarget = this.cameraDefaults.posCameraTarget;

    this.controls = null;
    };

    OBJLoaderVerify.prototype = {

    constructor: OBJLoaderVerify,

    initGL: function () {
    this.renderer = new WebGLRenderer( {
    canvas: this.canvas,
    antialias: true,
    autoClear: true
    } );
    this.renderer.setClearColor( 0x050505 );

    this.scene = new Scene();

    this.camera = new PerspectiveCamera( this.cameraDefaults.fov, this.aspectRatio, this.cameraDefaults.near, this.cameraDefaults.far );
    this.resetCamera();
    this.controls = new TrackballControls( this.camera, this.renderer.domElement );

    let ambientLight = new AmbientLight( 0x404040 );
    let directionalLight1 = new DirectionalLight( 0xC0C090 );
    let directionalLight2 = new DirectionalLight( 0xC0C090 );

    directionalLight1.position.set( -100, -50, 100 );
    directionalLight2.position.set( 100, 50, -100 );

    this.scene.add( directionalLight1 );
    this.scene.add( directionalLight2 );
    this.scene.add( ambientLight );

    let helper = new GridHelper( 1200, 60, 0xFF4444, 0x404040 );
    this.scene.add( helper );
    },

    initContent: function () {
    let modelName = 'verificationCubes';
    this._reportProgress( { detail: { text: 'Loading: ' + modelName } } );

    let objLoader = new OBJLoader();

    let objLoader2 = new OBJLoader2();
    objLoader2.setModelName( modelName );
    objLoader2.setLogging( true, false );
    objLoader2.setUseOAsMesh( true );

    let scope = this;
    let callbackOnLoad = function ( object3d ) {
    scope.scene.add( object3d );
    console.log( 'Loading complete: ' + modelName );
    scope._reportProgress( { detail: { text: '' } } );
    };
    let onLoadMtl = function ( mtlParseResult ) {
    objLoader.setMaterials( mtlParseResult );
    objLoader.load( './mod1.obj', function ( object ) {
    object.position.y = -100;
    scope.scene.add( object );
    } );

    objLoader2.addMaterials( MtlObjBridge.addMaterialsFromMtlLoader( mtlParseResult ) );
    objLoader2.load( './mod1.obj', callbackOnLoad, null, null, null );
    };

    let mtlLoader = new MTLLoader();
    mtlLoader.load( './mod1.mtl', onLoadMtl );
    },

    _reportProgress: function( event ) {
    let output = ( event.detail !== undefined && event.detail !== null && event.detail.text !== undefined && event.detail.text !== null ) ? event.detail.text : '';
    console.log( 'Progress: ' + output );
    document.getElementById( 'feedback' ).innerHTML = output;
    },

    resizeDisplayGL: function () {
    this.controls.handleResize();

    this.recalcAspectRatio();
    this.renderer.setSize( this.canvas.offsetWidth, this.canvas.offsetHeight, false );

    this.updateCamera();
    },

    recalcAspectRatio: function () {
    this.aspectRatio = ( this.canvas.offsetHeight === 0 ) ? 1 : this.canvas.offsetWidth / this.canvas.offsetHeight;
    },

    resetCamera: function () {
    this.camera.position.copy( this.cameraDefaults.posCamera );
    this.cameraTarget.copy( this.cameraDefaults.posCameraTarget );

    this.updateCamera();
    },

    updateCamera: function () {
    this.camera.aspect = this.aspectRatio;
    this.camera.lookAt( this.cameraTarget );
    this.camera.updateProjectionMatrix();
    },

    render: function () {
    if ( ! this.renderer.autoClear ) this.renderer.clear();
    this.controls.update();
    this.renderer.render( this.scene, this.camera );
    }
    };

    let app = new OBJLoaderVerify( document.getElementById( 'example' ) );

    let resizeWindow = function () {
    app.resizeDisplayGL();
    };

    let render = function () {
    requestAnimationFrame( render );
    app.render();
    };

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

    console.log( 'Starting initialisation phase...' );
    app.initGL();
    app.resizeDisplayGL();
    app.initContent();

    render();

    </script>
    </body>
    </html>
    nsjs
        14
    nsjs  
       2020-10-19 14:31:09 +08:00
    微软自带的能打开并不能说明模型没有问题,每个模型解析器的实现都不一样的,微软的那个实现比较弱
    各家的东西都或多或少有些不兼容的情况的
    obj 在 3dmax 里导出的时候也有很多选项的,你得反复测试不同的组合

    threejs 的解析不出来你可以试试别家的,babylonjs 和 cesium 都可以解析 obj 模型文件,这 2 个都是 js 库
    桌面软件的话你可以下载一个 blender 试试能不能加载
    nsjs
        15
    nsjs  
       2020-10-19 14:35:08 +08:00
    看了你加载的代码,你是设置了相机位置并且看向原点的
    obj 格式是不含相机信息的,我觉得最有可能的就是模型没有归到原点
    你可以问问建模的人
    nsjs
        16
    nsjs  
       2020-10-19 14:38:53 +08:00
    然后是你的相机位置离中心 500 米开外,模型如果只有 1 米不到的大小看不见很正常
    还有建模软件里单位设置得设置成米,否则有缩放的
    GressJoe
        17
    GressJoe  
       2020-10-19 15:28:32 +08:00
    obj 用文本编辑器打开看看坐标是多大数量级的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2473 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 02:20 · PVG 10:20 · LAX 18:20 · JFK 21:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.