Modifying the appearance of a Three.js collada object with new textures and colors

After successfully implementing a three.js example from the official site with my collada objects (.dae) using ColladaLoader.js, I am now wondering how to change the color attribute of the loaded collada object and add a custom texture. So far, my attempts at adding the texture have been unsuccessful.

Below is the code, slightly modified from the original example:

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 );

            }


}

Answer №1

If you want to recursively change the materials of your collada scene, you can utilize this handy function. It will traverse through the entire hierarchy and apply the specified material.

const applyMaterial = (node, newMaterial) => {
  node.material = newMaterial;
  if (node.children) {
    for (let i = 0; i < node.children.length; i++) {
      applyMaterial(node.children[i], newMaterial);
    }
  }
}

To use it, simply call

applyMaterial(dae, new THREE.MeshBasicMaterial({color: 0xff0000}));

If necessary, you could modify this function to adjust existing material properties instead of assigning a completely new one.

Answer №2

Following numerous challenges, we implemented a clever workaround in ColladaLoader.js inspired by @gaitat. This solution involves replacing the original texture paths with new ones stored in an array and utilizing regular expressions to extract image file types like .png or .jpg from the XML. Given the limited support available, we had to devise this fix to address the issue.

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;

};

Answer №3

An option available to you is adjusting your collada model (dae file) by identifying the texture reference and customizing it as desired.

Answer №4

if ( checkUrlValidity( url ) ) {
    var urlParts = splitURL( url );
    removeLastPartOfURL( urlParts );
    setBaseUrl( urlParts );

}

parseAsset();
setUpConversion();
loadImagesFromLibrary( "//dae:library_images/dae:image", _Image, "image" );

for(var index in imageReplaceArray) {
    var replaceImage = imageReplaceArray[index];

    for(var position in imageArray) {
        var img = imageArray[position];

        var pattern = createRegExp('[a-zA-Z0-9\-\_]*\/'+replaceImage.name,'g');

        //if(img.id==replaceImage.id)
        if(pattern.test(img.init_from))
            img.init_from = replaceImage.new_image; 
    }//for
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing Vuex state within Vue-Router route definitions

My Vuex store setup in main.js looks like this: import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) //initialize the store const store = new Vuex.Store({ state: { globalError: '', user: { ...

Avoid consistently updating information

I am experiencing a strange issue in my project. I have 2 tabs, and in one tab, there are checkboxes and a submit button. The user selects items from the checkboxes, and upon clicking the button, they should see their selections in the other tab. This fu ...

"Encountered issues during compiling: X ERROR found at line 9 in the Header.js file, spanning from characters

An error occurred while compiling the module. The following message was displayed: Module not found: Error: Can't resolve '@mui/icons-material/Search' in 'C:\Users\pande\Documents\slack-clone\src\component ...

Developing UIs in React that change dynamically according to the radio button chosen

Problem Statement I am currently developing a web application feature that computes the heat insulation factor for a specific area. You can view the live demonstration on Codesandbox <a href="https://codesandbox.io/p/github/cloudmako09/btu-calc/main?im ...

Retrieve JSON information using AJAX

As I am new to JSON and Ajax, the question I have may seem basic. When I try to display data from my JSON object containing 'name', 'task', 'date', and 'status' using Ajax, it does not show up on my page. Below is m ...

What is the best way to utilize the ajax factory method in order to establish a $scoped variable?

One issue I frequently encounter in my controllers is a repetitive piece of code: // Get first product from list Product.get_details( id ) .success(function ( data ) { // Setup product details $scope.active_product = data; }); To avoid this ...

Every time I invoke a module, non-global variables are utilized

Within a module.exports file, I am facing an issue where the variables are shared among different instances of the module. Instead, I want each call to the module to have its own set of values for cycle number, original data, new product, etc., similar to ...

Automatically populate input field values into a textarea using a separator with jQuery

There are multiple input fields to fill out: <input type="text" placeholder="name"> <input type="text" placeholder="age"> <input type="text" placeholder="gender"> <input type="text" placeholder="interest"> As I enter information i ...

The animation in Rive feels sluggish when navigating to a page with animation in Blazor WASM, despite implementing dispose methods

After attempting to display river animation on the index page using Blazor WASM (basic template), I encountered some performance issues. When navigating back and forth between the Counter page and the index page, I noticed that after around 20 clicks, the ...

Texture JSONLoader is loaded and processed this data

I created a textured shape in Blender and exported it. When I loaded it using a json loader, everything looked fine except for the colors. The geometry was good, I could see the texture on the shape, but all I saw was black and white. Can anyone help me fi ...

Guide on Implementing Right-to-Left (RTL) Support in Material UI React

Currently, I am in the process of developing an application designed for LTR usage, but I am interested in adding RTL support as well. The application itself is built on top of Material UI React. By using CSS Flex Box, I have managed to rotate the applicat ...

"Filtering a JSON File Based on Button Data Attributes: A Step-by-

I am working with a set of buttons that have specific data-map attributes as shown below: <button class="btn btn-default mapper" data-map="2015-11-13">Monday</button> <button class="btn btn-default mapper" data-map="2015-11-14">Tuesday&l ...

How to style the first dropdown value in AngularJS to appear bold?

Is there a way to style only the first value in a dropdown list as bold without using jQuery? Here is the code for the dropdown: <div class="col-xs-3"> <select-box id="ad-version-select" options="curItem.stats.version" model="state.version" i ...

Angular's observable function is not providing a complete response

In my Angular component, I have a function that is called from a template. This function returns an Observable of type string, but unfortunately it only returns the `data` variable. How can I modify it to return `dateNew[0] + " de " + data + " de "+ dateNe ...

Seeking the method to obtain the response URL using XMLHttpRequest?

I'm having trouble with a page (url) that I request via XMLHttpRequest. Instead of getting a response from the requested url, the request is being directed to another page. requesting --- > page.php getting response from > directedpage.php ...

Tips for assigning the result of a Fetch API call to a variable

Hello everyone! I'm currently working on a project that requires me to retrieve the latitude or longitude of a location using the Google Maps API. However, I am facing an issue with returning values using the Fetch API and its promises. I have succe ...

What is the best way to connect a Jquery plugin to a table within a partial view following an ajax request?

I have a main view that utilizes a partial view to display items in a table format. Main View (Enclosed within a div, it references the Partial View) <div id="divList"> @Html.Action("_list") </div> Partial View (Displaying a list of it ...

Determining the orientation of an image in JavaScript

Currently, I am attempting to determine the orientation of images using JavaScript in order to apply a specific class to them. This process seems to be functioning correctly on Firefox, but is presenting challenges on other browsers. It appears to work bet ...

What is the best way to access query string values using JavaScript?

Is it possible to retrieve query string values without using a plugin in jQuery? If the answer is yes, how can this be accomplished? If not, are there any plugins available that can help with this task? ...

Numerous instances of Codemirror

I have the ability to generate and exhibit multiple dynamic codemirror instances, however, I am having trouble referencing them using the code snippet below. I suspect that the problem lies in creating a dynamic function name (not entirely sure how to ac ...