Cloning a rigged mesh and dealing with skinned materials Ask Question

I have a scene with multiple rigged meshes uploaded from a .json file. To create independent meshes I use .copy(). I want all these meshes to have different materials, every material must have different color.

Loader:

jsonLoader.load("models/player.json", function (geometry, materials) {
    materials.forEach(function (material) {
        material.skinning = true;
        material.side = THREE.FrontSide;
    });
    meshes.player = new THREE.SkinnedMesh(geometry, materials);
    meshes.player.castShadow = true;
    meshes.player.receiveShadow = true;
    meshes.player.scale.set(0.5,0.5,0.5);
});

Than clone it:

mesh = meshes.player.clone();
mesh.material[0] = meshes.player.material[0].clone();
mesh.material[0].color.setHex( randomColor );

But it works very weird: if I add to the scene one mesh with random color and than add second mesh with the other color, the first mesh changes it’s color to the color of the second mesh.

All my materials use skinning, every mesh must have it’s own skeleton. I found this page on GitHub, maybe I have the same issue. But I still don’t realise how skeleton affects material.

Cannot import Blender 2.79 JSON using THREE.js Ask Question

I am creating a 3D graph visualization in an Angular project using 3D Force Graph and need to use 3D models designed using Blender as nodes in the graph. I have tried the following code, but the imported object using three.js returns undefined, and the following warning is generated multiple times.

Offscreen-For-WebGL-0000014E33B8D990]RENDER WARNING: Render count or primcount is 0.

The code is as follows:

var self = this;
var loader = new THREE.JSONLoader();
var house = loader.load("assets/model/house.json",
    function ( obj ) {
      // After object is loaded      
      console.log("house -- "+house);     // returns undefined
      self.showGraph(gData,house,themeNum);
      console.log("graph drawn");
    },
    // onProgress callback
    function ( xhr ) {
      console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );
    },
    // onError callback
    function ( err ) {
      console.error( 'An error occurred -- '+err );
    }
);
    
// function to draw the graph -- to be executed on 3D model load
showGraph(gData:any, house:any, themeNum: any){
    const Graph = ForceGraph3D()
      (document.getElementById('3d-graph'))
      .nodeThreeObject(({ group }) => new THREE.Mesh(
        [
          new THREE.BoxGeometry(Math.random() * 20, Math.random() * 20, Math.random() * 20),          
          house,
          new THREE.CylinderGeometry(Math.random() * 10, Math.random() * 10, Math.random() * 20),
          new THREE.DodecahedronGeometry(Math.random() * 10),
          new THREE.SphereGeometry(Math.random() * 10),
          new THREE.TorusGeometry(Math.random() * 10, Math.random() * 2),
          new THREE.TorusKnotGeometry(Math.random() * 10, Math.random() * 2)
        ][group],
        new THREE.MeshLambertMaterial({
          color: this.themes[themeNum][group],
          transparent: true,
          opacity: 0.75
        })
      ))
        .nodeAutoColorBy('group')  
        .onNodeClick(node => {    
          this.attach3DNodeClickEvent(node);
        })      
        .graphData(gData); 
  }

three.js Cannot read property 'center' of undefined Ask Question

I’m trying to load a 3D model of a cube onto a 3D Force Directed Graph using GLTFLoader in three.js. The project is built using Angular.

The model is loaded, showing GLTFLoader: 23.507080078125ms but the object is not displayed. It further gives an error showing,

ERROR TypeError: Cannot read property 'center' of undefined
at Sphere.copy (three.module.js:5347)
at Mesh.raycast (three.module.js:14240)
at intersectObject (three.js:42091)
at Raycaster.intersectObjects (three.js:42164)
at animate (3d-force-graph.module.js:386)
at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:398)
at Object.onInvokeTask (core.es5.js:4136)
at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:397)
at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.runTask (zone.js:165)
at ZoneTask.invoke (zone.js:460)
at timer (zone.js:1732)

The code to load the model is as below:

    var manager = new THREE.LoadingManager();
    var loader = new GLTFLoader(manager);
    loader.load(
      // resource URL
      'assets/model/cube.gltf',
      // called when the resource is loaded
      function ( gltf ) {           
        gltf.scene.traverse( function ( child ) {
          if ( child.isMesh ) {
            child.material = gltf.materials;
          }
        } );               
        var cube = gltf.scene; // Object        
        self.showGraph(gData,cube,themeNum);
        console.log("graph drawn");
      },
      // called when loading is in progresses
      function ( xhr ) {    
        console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );    
      },
      // called when loading has errors
      function ( error ) {    
        console.log( 'An error happened -- ' + error );    
      }
    );
    
// function to draw the graph -- to be executed on 3D model load
showGraph(gData:any, cube:any, themeNum: any){
    const Graph = ForceGraph3D()
      (document.getElementById('3d-graph'))
      .nodeThreeObject(({ group }) => new THREE.Mesh(
        [
          new THREE.BoxGeometry(Math.random() * 20, Math.random() * 20, Math.random() * 20),          
          cube,
          new THREE.CylinderGeometry(Math.random() * 10, Math.random() * 10, Math.random() * 20),
          new THREE.DodecahedronGeometry(Math.random() * 10),
          new THREE.SphereGeometry(Math.random() * 10),
          new THREE.TorusGeometry(Math.random() * 10, Math.random() * 2),
          new THREE.TorusKnotGeometry(Math.random() * 10, Math.random() * 2)
        ][group],
        new THREE.MeshLambertMaterial({
          color: this.themes[themeNum][group],
          transparent: true,
          opacity: 0.75
        })
      ))
        .nodeAutoColorBy('group')  
        .onNodeClick(node => {    
          this.attach3DNodeClickEvent(node);
        })      
        .graphData(gData); 
  }

Three.js – Simple custom texture box looks different on the sides than on the up / down faces. Why it happens and how to match them Ask Question

In three.js when using a single texture for a box the side faces look different than the top and bottom faces.

Why does this happen? and how can I make the textures of the 6 faces look similar?

The following is the part of the code related to texture

var corkTexture = new THREE.ImageUtils.loadTexture( 'img/cork-256.png' );
corkTexture.wrapS = corkTexture.wrapT = THREE.MirroredRepeatWrapping;
corkTexture.repeat.set( 10, 10 );
corkTexture.offset.set(0.5, 0.5);
var corkMaterial = new THREE.MeshBasicMaterial( { map: corkTexture } );

In this url you can see the complete code and the result

http://heyplay.org/animation/index.html

Thanks.

Threejs, why render setSize function is being executed before the code which is before it? Ask Question

Hello I have one doubt:

Today I tryed to change canvas’ size dinamically. I would like to get the size of the Plane loaded and put its size into the canvas’s size, to adapt canvas to whatever plane’s size is.

First, debugging the program I see that the first canvas 800×600 is being created, which is correct:

enter image description here

Second I thougt it would be linear and go to the load function to get the model from local sotrage, however it went to the renderer.setSize()

enter image description here

Then the same two steps are done for the second canvas:

enter image description here

enter image description here

Then, in the fifth and sixth steps we load the model into the canvas:

enter image description here

enter image description here

Here I show you the full code, first the file being discussed, then other important files:

InitCanvas.js

// this class handles the load and the canva for a nrrd
// Using programming based on prototype: https://javascript.info/class
// This class should be improved:
//   - Canvas Width and height

InitCanvas = function (IdDiv, Filename) {


    this.IdDiv = IdDiv;
    this.Filename = Filename
}

InitCanvas.prototype = {

    constructor: InitCanvas,

    init: function () {

        this.container = document.getElementById(this.IdDiv);

        // this should be changed.
        debugger;
        this.container.innerHeight = 600;
        this.container.innerWidth = 800;

        //These statenments should be changed to improve the image position
        this.camera = new THREE.PerspectiveCamera(60, this.container.innerWidth / this.container.innerHeight, 0.01, 1e10);
        this.camera.position.z = 300;

        let scene = new THREE.Scene();
        scene.add(this.camera);

        // light

        let dirLight = new THREE.DirectionalLight(0xffffff);
        dirLight.position.set(200, 200, 1000).normalize();

        this.camera.add(dirLight);
        this.camera.add(dirLight.target);


        // read file

        let loader = new THREE.NRRDLoader();
        loader.load(this.Filename, function (volume) {

            //z plane
            let sliceZ = volume.extractSlice('z', Math.floor(volume.RASDimensions[2] / 4));

            debugger;
            this.container.innerWidth = sliceZ.iLength;
            this.container.innerHeight = sliceZ.jLength;

            sliceZ.mesh.material.color.setRGB(0,1,1);


            console.log('Our slice is: ', sliceZ);

            scene.add(sliceZ.mesh);
        }.bind(this));


        this.scene = scene;

        // renderer

        this.renderer = new THREE.WebGLRenderer({alpha: true});
        this.renderer.setPixelRatio(this.container.devicePixelRatio);
        debugger;
        this.renderer.setSize(this.container.innerWidth, this.container.innerHeight);

        // add canvas in container
        this.container.appendChild(this.renderer.domElement);

    },

    animate: function () {

        this.renderer.render(this.scene, this.camera);
    }

}

logic.js

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

// global variables for this scripts
let OriginalImg,
    SegmentImg;

var mouse = new THREE.Vector2();
var raycaster = new THREE.Raycaster();
var mousePressed = false;
var clickCount = 0;


init();
animate();


// initilize the page
function init() {
    let filename = "models/nrrd/columna01.nrrd"; // change your nrrd file
    let idDiv = 'original';
    OriginalImg = new InitCanvas(idDiv, filename);
    OriginalImg.init();
    console.log(OriginalImg);

    filename = "models/nrrd/columnasegmentado01.nrrd"; // change your nrrd file
    idDiv = 'segment';
    SegmentImg = new InitCanvas(idDiv, filename);
    SegmentImg.init();
}

let originalCanvas = document.getElementById('original');
originalCanvas.addEventListener('mousedown', onDocumentMouseDown, false);
originalCanvas.addEventListener('mouseup', onDocumentMouseUp, false);


function onDocumentMouseDown(event) {
    mousePressed = true;

    clickCount++;

    mouse.x = ( ( event.clientX - OriginalImg.renderer.domElement.offsetLeft ) / OriginalImg.renderer.domElement.clientWidth ) * 2 - 1;
    mouse.y = - ( ( event.clientY - OriginalImg.renderer.domElement.offsetTop ) / OriginalImg.renderer.domElement.clientHeight ) * 2 + 1

    console.log('Mouse x position is: ', mouse.x, 'the click number was: ', clickCount);
    console.log('Mouse Y position is: ', mouse.y);

    raycaster.setFromCamera(mouse.clone(), OriginalImg.camera);
    var objects = raycaster.intersectObjects(OriginalImg.scene.children);

    console.log(objects);
}

function onDocumentMouseUp(event) {
    mousePressed = false
}


function animate() {


    requestAnimationFrame(animate);
    OriginalImg.animate();
    SegmentImg.animate();


}   

index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Prototype: three.js without react.js</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <link rel="stylesheet" href="css/styles.css">

        <!-- load the libraries and js -->
        <script src="js/libs/three.js"></script>

        <script src="js/Volume.js"></script>
        <script src="js/VolumeSlice.js"></script>
        <script src="js/loaders/NRRDLoader.js"></script>

        <script src="js/Detector.js"></script>
        <script src="js/libs/stats.min.js"></script>
        <script src="js/libs/gunzip.min.js"></script>
        <script src="js/libs/dat.gui.min.js"></script>

        <script src="js/InitCanvas.js"></script>


    </head>

    <body>
        <div id="info">
            <h1>Prototype: three.js without react.js</h1> 
        </div>

        <!-- two canvas -->
        <div class="row">
            <div class="column" id="original">
            </div>

            <div class="column" id="segment">

            </div>
          </div> 

        <script src="js/logic.js"></script>

    </body>
</html>

styles.css

body {
    font-family: Monospace;
    margin: 0px;
    overflow: hidden;
}

#info {
    color: rgb(137, 145, 192);
    position: absolute;
    top: 10px;
    width: 100%;
    text-align: center;
    z-index: 5;
    display:block;
}

.column {
    float: left;
    width: 50%;
}

/* Clear floats after the columns */
.row:after {
    content: "";
    display: table;
    clear: both;
}

canvas {
    width: 200px;
    height: 200px;
    margin: 100px;
    padding: 0px;
    position: static; /* fixed or static */
    top: 100px;
    left: 100px;
}

In addition other external resources being used are, NRRDLoader:

https://github.com/mrdoob/three.js/blob/dev/examples/js/loaders/NRRDLoader.js

Volume.js

https://github.com/mrdoob/three.js/blob/dev/examples/js/Volume.js

VolumeSlice.js

https://github.com/mrdoob/three.js/blob/dev/examples/js/VolumeSlice.js

Could you help me please?

Terrain intersection perfomance Ask Question

I create var geometry = new THREE.PlaneGeometry(512,512,255,255); then parse jpg heightmap and change verticles’ positions to receive deformed plane. Than I cast ray from the sky to the ground in the animate() function to get intersection point:

var raycaster = new THREE.Raycaster( new THREE.Vector3(player.x, 100, player.z), new THREE.Vector3(0, -1, 0) );
var intersects = raycaster.intersectObject( ground, true );
if(intersects.length == 1) {
    mesh.position.set(intersects[0].point.x, intersects[0].point.y, intersects[0].point.z);
}

But FPS become very low (<20). I also tried to get y-position through the height map, but texture is only 256 x 256, so if I want to make mesh follow the terrain the y-coordinate is jerking.

javascript add texture on the floor from computer onclick Ask Question

I am trying to put a texture on my floor using <input type="file" onchange=function()> but always I see just black texture. Don’t know, how to put my .jpg file from computer as a texture on my floor. Any help?

here is my code

javascript:

  function preview_image(event) {
    var reader = new FileReader();
    reader.onload = function() {
      var floorTexture = THREE.ImageUtils.loadTexture(reader);
      floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
      floorTexture.repeat.set(10, 10);
      var floorMaterial = new THREE.MeshBasicMaterial({
        map: floorTexture,
        side: THREE.DoubleSide
      });
      var floorGeometry = new THREE.PlaneGeometry(100, 100, 10, 10);
      var floor = new THREE.Mesh(floorGeometry, floorMaterial);
      floor.position.set(0, 0, 0);
      floor.rotation.set(0, 0, 0);
      scene.add(floor);

      var output = floorTexture;
      output.src = reader.result;
    }
    reader.readAsDataURL(event.target.files[0]);
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.min.js"></script>
<input type="file" accept="image/jpeg, image/png" onchange="preview_image(event)" /> <img id="output_image" />

How to make webGL distort the HTML under it? [closed] Ask Question

I was playing around with this example: https://threejs.org/examples/?q=glitch#webgl_postprocessing_glitch.

I have a local copy of the example and made the Three.js renderer an overlay by giving it z-index of 999 and passing {alpha: true} to the renderer to make it transparent. Then I pasted a normal html webpage under it with a bunch of h1 and background-color set to red. So the webpage is positioned right under the canvas. The problem when i do this is that the glitch effects just end up being a bunch of horizontal white lines.

Is it possible for webGL to distort the html view under it?

Three.js — Cannot assign material to a object Ask Question

I am a noob in three.js and I just got started recently. Here’s my problem, I try to assign a material to an object, but it doesn’t work.

var objloader=new THREE.OBJLoader();
var material=new THREE.MeshNormalMaterial();
objloader.load('man.obj', function(object) {
    object.position.y=-30;
    object.material= material;
    scene.add(object);
    render();
});

Threejs, div innerWidth and innerHeight changes by its own after setting it with plane's width and height? Ask Question

Hello I have one doubt.

I am trying to set the innerWidth and innerHeight of the div, the container whichs has inside the canvas, with the following code, the important code is the inner loader.load function, which get executed when we have the plane finished loading in the page.

// this class handles the load and the canva for a nrrd
// Using programming based on prototype: https://javascript.info/class
// This class should be improved:
//   - Canvas Width and height

InitCanvas = function (IdDiv, Filename) {


    this.IdDiv = IdDiv;
    this.Filename = Filename
}

InitCanvas.prototype = {

    constructor: InitCanvas,

    init: function () {

        this.container = document.getElementById(this.IdDiv);

        // this should be changed.
        debugger;
        this.container.innerHeight = 600;
        this.container.innerWidth = 800;

        //These statenments should be changed to improve the image position
        this.camera = new THREE.PerspectiveCamera(60, this.container.innerWidth / this.container.innerHeight, 0.01, 1e10);
        this.camera.position.z = 300;

        let scene = new THREE.Scene();
        scene.add(this.camera);

        // light

        let dirLight = new THREE.DirectionalLight(0xffffff);
        dirLight.position.set(200, 200, 1000).normalize();

        this.camera.add(dirLight);
        this.camera.add(dirLight.target);


        // read file

        let loader = new THREE.NRRDLoader();
        loader.load(this.Filename, function (volume) {

            //z plane
            let sliceZ = volume.extractSlice('z', Math.floor(volume.RASDimensions[2] / 4));

            debugger;
            this.container.innerWidth = sliceZ.iLength;
            this.container.innerHeight = sliceZ.jLength;

            sliceZ.mesh.material.color.setRGB(0,1,1);


            console.log('Our slice is: ', sliceZ);

            scene.add(sliceZ.mesh);
        this.scene = scene;

        // renderer

        this.renderer = new THREE.WebGLRenderer({alpha: true});
        this.renderer.setPixelRatio(this.container.devicePixelRatio);
        debugger;
        this.container.appendChild(this.renderer.domElement);
        }.bind(this));





    },

    animate: function () {

        this.renderer.render(this.scene, this.camera);
    }

}

As you see I am binding this in the loader.load asynchronous call, because we would like to access this.container into it, which is a property in the class InitCanvas.

Then we are getting the width and height of the plane which has just finished loading, with the sentences:

 this.container.innerWidth = sliceZ.iLength;
 this.container.innerHeight = sliceZ.jLength;

And I have seen using the web debugger that it does load the plane’s width and height into the container, into the div:

enter image description here

We see that the this.container.innerWidth is being changed with 3128 and this.container.innerHeight is being changed with 1760.

However, then we see that after plane’s rendering the container div is 300×150:

enter image description here

How is this possible?

In addition, why our web console reports us:

Uncaught TypeError: Cannot read property 'render' of undefined
    at InitCanvas.animate (InitCanvas.js:79)
    at animate (logic.js:63)

I think, it is because we do have access to this.renderer into loader.load function because of we have a bind(this), however in the animate() function, the InitCanvas’ class scope has been lost.

How could we fix it?

Thank you for your help!

Additional code which would be relevant:

logic.js

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

// global variables for this scripts
let OriginalImg,
    SegmentImg;

var mouse = new THREE.Vector2();
var raycaster = new THREE.Raycaster();
var mousePressed = false;
var clickCount = 0;


init();
animate();


// initilize the page
function init() {
    let filename = "models/nrrd/columna01.nrrd"; // change your nrrd file
    let idDiv = 'original';
    OriginalImg = new InitCanvas(idDiv, filename);
    OriginalImg.init();
    console.log(OriginalImg);

    filename = "models/nrrd/columnasegmentado01.nrrd"; // change your nrrd file
    idDiv = 'segment';
    SegmentImg = new InitCanvas(idDiv, filename);
    SegmentImg.init();
}

let originalCanvas = document.getElementById('original');
originalCanvas.addEventListener('mousedown', onDocumentMouseDown, false);
originalCanvas.addEventListener('mouseup', onDocumentMouseUp, false);


function onDocumentMouseDown(event) {
    mousePressed = true;

    clickCount++;

    mouse.x = ( ( event.clientX - OriginalImg.renderer.domElement.offsetLeft ) / OriginalImg.renderer.domElement.clientWidth ) * 2 - 1;
    mouse.y = - ( ( event.clientY - OriginalImg.renderer.domElement.offsetTop ) / OriginalImg.renderer.domElement.clientHeight ) * 2 + 1

    console.log('Mouse x position is: ', mouse.x, 'the click number was: ', clickCount);
    console.log('Mouse Y position is: ', mouse.y);

    raycaster.setFromCamera(mouse.clone(), OriginalImg.camera);
    var objects = raycaster.intersectObjects(OriginalImg.scene.children);

    console.log(objects);
}

function onDocumentMouseUp(event) {
    mousePressed = false
}


function animate() {


    requestAnimationFrame(animate);
    OriginalImg.animate();
    SegmentImg.animate();


}   

index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Prototype: three.js without react.js</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <link rel="stylesheet" href="css/styles.css">

        <!-- load the libraries and js -->
        <script src="js/libs/three.js"></script>

        <script src="js/Volume.js"></script>
        <script src="js/VolumeSlice.js"></script>
        <script src="js/loaders/NRRDLoader.js"></script>

        <script src="js/Detector.js"></script>
        <script src="js/libs/stats.min.js"></script>
        <script src="js/libs/gunzip.min.js"></script>
        <script src="js/libs/dat.gui.min.js"></script>

        <script src="js/InitCanvas.js"></script>


    </head>

    <body>
        <div id="info">
            <h1>Prototype: three.js without react.js</h1> 
        </div>

        <!-- two canvas -->
        <div class="row">
            <div class="column" id="original">
            </div>

            <div class="column" id="segment">

            </div>
          </div> 

        <script src="js/logic.js"></script>

    </body>
</html>

styles.css

body {
    font-family: Monospace;
    margin: 0px;
    overflow: hidden;
}

#info {
    color: rgb(137, 145, 192);
    position: absolute;
    top: 10px;
    width: 100%;
    text-align: center;
    z-index: 5;
    display:block;
}

.column {
    float: left;
    width: 50%;
}

/* Clear floats after the columns */
.row:after {
    content: "";
    display: table;
    clear: both;
}

canvas {
    width: 200px;
    height: 200px;
    margin: 100px;
    padding: 0px;
    position: static; /* fixed or static */
    top: 100px;
    left: 100px;
}

EDIT: I have done what @Mugen87 tell us and it makes the canvas have the loaded model’s width and height. However I did not expect that the model was offset from top left canvas part. It is being displayer on bottom right corner, and as there is no scrollbar it hiders most of it.

enter image description here

enter image description here

How could we add a scrollbar to the page to be able to see the canvas well?

Also here I post the code which resizes the canvas as @Mugen87 suggested:

 let loader = new THREE.NRRDLoader();
        loader.load(this.Filename, function (volume) {

            //z plane
            let sliceZ = volume.extractSlice('z', Math.floor(volume.RASDimensions[2] / 4));

            debugger;
            this.container.innerWidth = sliceZ.iLength;
            this.container.innerHeight = sliceZ.jLength;
            this.renderer.setSize(this.container.innerWidth, this.container.innerHeight);

            sliceZ.mesh.material.color.setRGB(0,1,1);


            console.log('Our slice is: ', sliceZ);

            scene.add(sliceZ.mesh);
        }.bind(this));