Изменение текстуры и цвета объекта коллады Three.js

Недавно я получил пример three.js с официального сайта, работающий с моими объектами collada (.dae) с использованием файла ColladaLoader.js. Теперь мой вопрос: как мне изменить атрибут цвета загруженного объекта коллады и добавить пользовательскую текстуру ?? Я пытался добавить текстуру, пока безуспешно.

Вот мой код (немного измененный по сравнению с исходным примером):

function load_model(el) {

            if ( ! Detector.webgl ) Detector.addGetWebGLMessage();

            var container, stats;

            var camera, scene, renderer, objects;
            var particleLight, pointLight;
            var dae, skin;

            var loader = new THREE.ColladaLoader();
            loader.options.convertUpAxis = true;
            loader.load( '/site_media/models/model.dae', function ( collada ) {
                dae = collada.scene;
                skin = collada.skins[ 0 ];

                dae.scale.x = dae.scale.y = dae.scale.z = 0.90;
                dae.updateMatrix();

                init(el);
                animate();

            } );

            function init(el) {

                container = document.createElement( 'div' );
                el.append( container );

                camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
                camera.position.set( 2, 2, 3 );

                scene = new THREE.Scene();


                scene.add( dae );

                particleLight = new THREE.Mesh( new THREE.SphereGeometry( 4, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0xffffff } ) );
                scene.add( particleLight );

                // Lights

                scene.add( new THREE.AmbientLight( 0xcccccc ) );

                var directionalLight = new THREE.DirectionalLight(/*Math.random() * 0xffffff*/0xeeeeee );
                directionalLight.position.x = Math.random() - 0.5;
                directionalLight.position.y = Math.random() - 0.5;
                directionalLight.position.z = Math.random() - 0.5;
                directionalLight.position.normalize();
                scene.add( directionalLight );

                // pointLight = new THREE.PointLight( 0xffffff, 4 );
                // pointLight.position = particleLight.position;
                // scene.add( pointLight );

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


                container.appendChild( renderer.domElement );

                stats = new Stats();
                stats.domElement.style.position = 'absolute';
                stats.domElement.style.top = '0px';
                container.appendChild( stats.domElement );

                //

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

            }

            function onWindowResize() {

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

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

            }

            //

            var t = 0;
            var clock = new THREE.Clock();

            function animate() {

                var delta = clock.getDelta();

                requestAnimationFrame( animate );

                if ( t > 1 ) t = 0;

                if ( skin ) {

                    // guess this can be done smarter...

                    // (Indeed, there are way more frames than needed and interpolation is not used at all
                    //  could be something like - one morph per each skinning pose keyframe, or even less,
                    //  animation could be resampled, morphing interpolation handles sparse keyframes quite well.
                    //  Simple animation cycles like this look ok with 10-15 frames instead of 100 ;)

                    for ( var i = 0; i < skin.morphTargetInfluences.length; i++ ) {

                        skin.morphTargetInfluences[ i ] = 0;

                    }

                    skin.morphTargetInfluences[ Math.floor( t * 30 ) ] = 1;

                    t += delta;

                }

                render();
                stats.update();

            }

            function render() {

                var timer = Date.now() * 0.0005;

                camera.position.x = Math.cos( timer ) * 10;
                camera.position.y = 2;
                camera.position.z = Math.sin( timer ) * 10;

                camera.lookAt( scene.position );

                particleLight.position.x = Math.sin( timer * 4 ) * 3009;
                particleLight.position.y = Math.cos( timer * 5 ) * 4000;
                particleLight.position.z = Math.cos( timer * 4 ) * 3009;

                renderer.render( scene, camera );

            }


}

person psychok7    schedule 22.02.2013    source источник
comment
Возможный дубликат Как настроить материалы в THREE.js при загрузке моделей Collada (dae)?   -  person Damjan Pavlica    schedule 31.12.2016


Ответы (3)


С помощью такой функции вы можете рекурсивно переопределить материалы сцены коллады. Он проходит через всю иерархию и назначает материал.

var setMaterial = function(node, material) {
  node.material = material;
  if (node.children) {
    for (var i = 0; i < node.children.length; i++) {
      setMaterial(node.children[i], material);
    }
  }
}

Используйте его как setMaterial(dae, new THREE.MeshBasicMaterial({color: 0xff0000}));

Вероятно, вы могли бы адаптировать это, чтобы изменить существующие свойства материала, а не назначать новые, если это необходимо.

person yaku    schedule 22.02.2013
comment
Вы должны вызывать функцию внутри обратного вызова loader.load, чтобы вы назначали новые материалы после загрузки коллады. На самом деле вы можете сделать это в любое время после загрузки коллады, если вам нужно динамически менять материалы. А сама функция может идти куда угодно. - person yaku; 22.02.2013
comment
да, это работает для цвета. может ли это работать и для текстуры? если да, то как? - person psychok7; 22.02.2013
comment
Существует множество примеров создания материалов с текстурной картой. webgl_materials.html в папке примера — хорошая отправная точка. - person yaku; 22.02.2013
comment
я получаю WebGL: INVALID_VALUE: texImage2D: недопустимое изображение. Интересно, потому что мой объект довольно сложный, и я надеялся, что текстура обойдет его автоматически, или мне придется делать это вручную? - person psychok7; 22.02.2013
comment
Я обнаружил, что мне нужно добавить сцену в загрузчик. Пример кода. loader.load(// URL-адрес ресурса 'test/object.dae', // Функция при загрузке ресурса function (collada) { setMaterial(collada.scene, new THREE.MeshBasicMaterial({color: 0xff0000})); scene.add (collada.scene);}, - person Thomas Turner; 08.11.2015

После многих проблем мы написали небольшой хак в ColladaLoader.js, взяв идею @gaitat, которая в основном заменяет старый путь к текстурам из изображений, передавая некоторые новые в массиве и используя регулярные выражения для разбора xml для .png или .jpg под тегом изображения. Не уверен, что есть более простой способ, но, поскольку поддержка была ограничена, нам пришлось как-то придумывать исправление.

function parse( doc, imageReplace, callBack, url ) {

    COLLADA = doc;
    callBack = callBack || readyCallbackFunc;

    if ( url !== undefined ) {

        var parts = url.split( '/' );
        parts.pop();
        baseUrl = ( parts.length < 1 ? '.' : parts.join( '/' ) ) + '/';

    }

    parseAsset();
    setUpConversion();
    images = parseLib( "//dae:library_images/dae:image", _Image, "image" );

    for(var i in imageReplace) {
        var iR = imageReplace[i];

        for(var i in images) {
            var image = images[i];

            var patt=new RegExp('[a-zA-Z0-9\-\_]*\/'+iR.name,'g');

            //if(image.id==iR.id)
            if(patt.test(image.init_from))
                image.init_from = iR.new_image; 
        }//for
    }

    materials = parseLib( "//dae:library_materials/dae:material", Material, "material" );
    effects = parseLib( "//dae:library_effects/dae:effect", Effect, "effect" );
    geometries = parseLib( "//dae:library_geometries/dae:geometry", Geometry, "geometry" );
    cameras = parseLib( ".//dae:library_cameras/dae:camera", Camera, "camera" );
    controllers = parseLib( "//dae:library_controllers/dae:controller", Controller, "controller" );
    animations = parseLib( "//dae:library_animations/dae:animation", Animation, "animation" );
    visualScenes = parseLib( ".//dae:library_visual_scenes/dae:visual_scene", VisualScene, "visual_scene" );

    morphs = [];
    skins = [];

    daeScene = parseScene();
    scene = new THREE.Object3D();

    for ( var i = 0; i < daeScene.nodes.length; i ++ ) {

        scene.add( createSceneGraph( daeScene.nodes[ i ] ) );

    }

// unit conversion
scene.position.multiplyScalar(colladaUnit);
scene.scale.multiplyScalar(colladaUnit);

    createAnimations();

    var result = {

        scene: scene,
        morphs: morphs,
        skins: skins,
        animations: animData,
        dae: {
            images: images,
            materials: materials,
            cameras: cameras,
            effects: effects,
            geometries: geometries,
            controllers: controllers,
            animations: animations,
            visualScenes: visualScenes,
            scene: daeScene
        }

    };

    if ( callBack ) {

        callBack( result );

    }

    return result;

};
person psychok7    schedule 26.02.2013

Одна вещь, которую вы можете сделать, это изменить вашу модель коллады (файл dae), найти там ссылку на текстуру и изменить ее по своему вкусу.

person gaitat    schedule 22.02.2013
comment
нужно динамическое решение - person psychok7; 22.02.2013