Error in mesh if returned from a method

My first three.js app body { margin: 0; } canvas { width: 100%; height: 100% }

/*

I create a method to build a mesh then returned to be used, it gives an error, "Cannot read property ‘visible’ of null’ in three.js file
am I doing something wrong???

*/

    var scene = new THREE.Scene();
    scene.background = new THREE.Color(0xffffff);
    var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    var renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    var texture = new THREE.TextureLoader().load('https://cdn.pixabay.com/photo/2017/08/31/14/51/emotions-2700972_960_720.jpg');
    var material = new THREE.MeshBasicMaterial({
        map: texture,
        wireframe: true
    });
    var geometry = new THREE.BoxGeometry(2.65, 2.65, 2.65);
    var cube = new THREE.Mesh(geometry, material);
    cylind = cylinder({
        r1: .4,
        r2: 1,
        h: 2,
        sh: 20,
        sv: 10,
        cup: false,
     //   textura: 'https://cdn.pixabay.com/photo/2017/08/31/14/51/emotions-2700972_960_720.jpg'
    });
      ob = new THREE.Group();
    ob.add(cube); 
    scene.add(ob);
   setTimeout(()=>{

// if I add it here it shows "Cannot read property ‘visible’ of null’ "
// ob.add(cylind);

    },5000);
    controls = new THREE.DeviceOrientationControls(ob);
    camera.position.z = 5;
    var animate = function() {
        requestAnimationFrame(animate);
        controls.update();
        renderer.render(scene, camera);
    };

    animate();
    
    
 function cylinder(parameters) {
     this.ret="mesh";
this.geo;
this.mesh;
this.r1 = 1;
this.r2 = 1;
this.h = 1;
this.sh = 10;
this.sv = 10;
this.cup = false;
this.buffer = true;
this.mat = null;
this.textura = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTtrzfNmlas9LW_v3P7uUomsyklfGTuJCKpvcnXGfGy3axhOQSC';
if (parameters.r1 != undefined) this.r1 = parameters.r1;
if (parameters.r2 != undefined) this.r2 = parameters.r2;
if (parameters.h != undefined) this.h = parameters.h;
if (parameters.sh != undefined) this.sh = parameters.sh;
if (parameters.sv != undefined) this.sv = parameters.sv;
if (parameters.cup != undefined) this.cup = parameters.cup;
if (parameters.buffer != undefined) this.buffer = parameters.buffer;

 if (this.buffer) this.geo = new THREE.CylinderBufferGeometry(this.r1, this.r2, this.h, this.sh, this.sv);
else this.geo = new THREE.CylinderGeometry(this.r1, this.r2, this.h, this.sh, this.sv)
if(parameters.ret!=undefined) this.ret=parameters.ret;
if(this.ret==="geometry") return geo;

if (parameters.textura == undefined && parameters.mat == undefined){

        loader = new THREE.TextureLoader();

     loader.load(this.textura,
        function(texture) {
            this.mat = new THREE.MeshBasicMaterial({
                   map: texture
            });
            this.mesh = new THREE.Mesh(this.geo, this.mat);
            
            // if I add it from right here not shows errors, 
            ob.add(this.mesh);// 
            
            return this.mesh;
        })    

}

if (parameters.textura != undefined && mat == undefined) {
    this.textura = parameters.textura;
     loader = new THREE.TextureLoader();
    loader.load(this.textura,
        function(texture) {
            this.mat = new THREE.MeshBasicMaterial({
                //  color: 0x0faaf0
                map: texture
            });
            //doesn't take the material
            this.mesh = new THREE.Mesh(this.geo, this.mat);
            alert(this.textura+"\n\n"+texture);
            return this.mesh;
        });
}
if (parameters.mat != undefined) this.mat = parameters.mat;
this.mesh = new THREE.Mesh(this.geo, this.mat);
return this.mesh;

}

</script>

Consider using JSFiddle, Codepen, or Glitch rather than pasting large sections of code, as this will make it easier for you and others to find bugs quickly.

In this section:

if (this.buffer) this.geo = new THREE.CylinderBufferGeometry(this.r1, this.r2, this.h, this.sh, this.sv);
else this.geo = new THREE.CylinderGeometry(this.r1, this.r2, this.h, this.sh, this.sv)
if(parameters.ret!=undefined) this.ret=parameters.ret;
if(this.ret==="geometry") return geo;

… do you mean to return this.geo instead of geo?

You may find it easier to use scoped variables instead of this.foo, like so:

var geometry;
var mesh;

function doThing () {
  // ...
  mesh = foo.mesh;
  geometry = mesh.geometry;
  // ...
}

doThing();
console.log(mesh); // THREE.Mesh
1 Like

you’re right, should be this.geo,

the issue in this case is in when these statements are true…
if (parameters.textura == undefined && parameters.mat == undefined){…}

about JSFiddle is there a link for ‘all’ the threejs files?

I am new in all this and still learning,

I don’t know of a JSFiddle that includes all example files (it would be a bit large).

This sample (https://jsfiddle.net/s3rjfcc3/) shows the core library and demonstrates how to include other files from examples/js/* as needed.

Thanks for your advice and help, I made a jsfiddle HERE, if possible try it, at least with me it freeze it…

*not sure what the problem is…

I would avoid using this unless you are sure you understand how it works in JS - in the following part of your code:

         loader.load(this.textura,
            function(texture) {
                this.mat = new THREE.MeshBasicMaterial({
                       map: texture
                });
                this.mesh = new THREE.Mesh(this.geo, this.mat);
                
                // If added here to ob looks ok
                // the problem looks with the returned mesh
                
                ob.add(this.mesh);
                
                return this.mesh;
            })    

…There is no reason to use this. It does not mean the same thing as earlier in your code, so this.geo is undefined. Use variables as in the example above, and avoid using this.foo = bar unless you are writing a Class.

var geometry;
var mesh;

function doThing () {
  // ...
  mesh = foo.mesh;
  geometry = mesh.geometry;
  // ...
}

doThing();
console.log(mesh); // THREE.Mesh

Even easier, load textures this way:

if (parameters.textura == undefined && parameters.mat == undefined){
       loader = new THREE.TextureLoader();
       this.mat = mat = new THREE.MeshBasicMaterial({
         map: loader.load(this.textura)
       });
}

OK, I tried to clean a little bit my codes, but still the problem exist, what looks like the problem is in the material…

please can anyone test it, I am not sure if I am doing something wrong or could be a three bug,
thanks …

https://jsfiddle.net/jauregui/u87kyysj/3/

(what I want to do is make like a little library and put it in a separate js file, that’s why I want to return a mesh without accessing variables like scene or group from the main program).

You may want to review how callbacks work in JavaScript. In particular I recommend Eloquent JavaScript’s sections on Functions and Asynchronous Programming.

Essentially, your code does this:

var cylinder = function ( parameters ) {
  // ...

  loader = new THREE.TextureLoader();
  loader.load(textura, function(texture) {
    mat = new THREE.MeshBasicMaterial({map: texture});
    mesh = new THREE.Mesh(geo, mat);
    return mesh; // "first" return
  });

  // ...
  return mesh; // "second" return
}

By the time the texture loads, the “second” return (the only one that is in the original function - which is critical) has already happened. Returning a mesh from the texture callback does nothing, because it isn’t “in sync” with the original function.

One alternative is to put variables outside of your callbacks and modify them from within callbacks.

var cylinder = function ( parameters ) {
  mesh = new THREE.Mesh(geo, new THREE.MeshBasicMaterial({map: texture}));
  // ...
  loader = new THREE.TextureLoader();
  loader.load(textura, function(texture) {
    mesh.material.map = texture;
  });
  // ...
  return mesh;
}

Thanks for your help, you’r right,