I am creating this 3d graph that represents a network of people. The nodes in the network are the names of people and between them lines are drawn whi9ch represents a connection. The purpose of this network is that people can turn it around and look through it to see what their network looks like, however, when I turn the camera around the network, the 3d text that I creat3ed with textgeometry is stuck to the same position and unformtunately therefore unreadable for the user when they want to look at the network from a different side. I know that this question has been asked several times before and I have read most of the answers on here, but I still cannot get it to work.
The problem that I encounter mostly is that when I try to do something like this:
nodeRenderer.lookAt(camera.position);
I get a problem that the camera is not defined. The camera is added to the scene, however this happens in a different .js document. This is where the scene gets created and the camera gets added (/ngraph.three/index.js):
var THREE = require('./lib/three');
module.exports = function (graph, settings) {
var merge = require('ngraph.merge');
settings = merge(settings, {
interactive: true
});
var beforeFrameRender;
var isStable = false;
var disposed = false;
var layout = createLayout(settings);
var renderer = createRenderer(settings);
var camera = createCamera(settings);
var scene = settings.scene || new THREE.Scene();
(...)
function renderNode(nodeId) {
nodeRenderer(nodeUI[nodeId]);
}
(...)
function initNode(node) {
var ui = nodeUIBuilder(node);
if (!ui) return;
// augment it with position data:
ui.pos = layout.getNodePosition(node.id);
// and store for subsequent use:
nodeUI[node.id] = ui;
scene.add(ui);
}
(...)
function createCamera(settings) {
if (settings.camera) {
return settings.camera;
}
var container = renderer.domElement;
var camera = new THREE.PerspectiveCamera(75, container.clientWidth/container.clientHeight, 0.1, 3000);
camera.position.z = 400;
return camera;
}
And this is where the nodes get created (ngraph.three/lib/defaults.js):
var THREE = require('./three');
module.exports.createNodeUI = createNodeUI;
module.exports.createLinkUI = createLinkUI;
module.exports.nodeRenderer = nodeRenderer;
module.exports.linkRenderer = linkRenderer;
function createNodeUI(node) {
var nodeMaterial = new THREE.MeshFaceMaterial( [
new THREE.MeshPhongMaterial( { color: 0x00cccc, shading: THREE.FlatShading } ), // front
new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.SmoothShading } ) // side
] );
var nodeGeometry = new THREE.TextGeometry( node.data, { size: 5, height: 2, curveSegments: 6, font: "helvetiker", weight: "normal", style: "normal" });
var nodeDirection = new THREE.Quaternion (THREE.Camera.Quaternion);
return new THREE.Mesh(nodeGeometry, nodeMaterial);
}
function createLinkUI(link) {
var linkGeometry = new THREE.Geometry();
linkGeometry.vertices.push(new THREE.Vector3(0, 0, 0));
linkGeometry.vertices.push(new THREE.Vector3(0, 0, 0));
var linkMaterial = new THREE.LineBasicMaterial({ color: 0x00cccc });
return new THREE.Line(linkGeometry, linkMaterial);
}
(...)
function nodeRenderer(node) {
node.position.x = node.pos.x;
node.position.y = node.pos.y;
node.position.z = node.pos.z;
}
(...)
I tried ui.quaternion = camera.quaternion; in /ngraph.three/index.js, but this didn't do anything, and I've tried nodeUI.lookAt(camera.position); but this gave an error: TypeError: nodeUI.lookAt is not a function.
PS: I'm using Three.js Rev. 68, Ngraph and node.js.
I can only guess since a lot of code is missing but your createNodeUI returns a THREE.Mesh which is a subclass of Object3D which has the function .lookAt(vector) to align its local z-axis to the given vector.
And you said you receive this Error : TypeError: nodeUI.lookAt is not a function that looks like you re trying to call .lookAt of the array and not of the node itself.
so try nodeUI[node.id].lookAt(camera.position)
Related
I am working on a geometric visualization using Trois.js. My goal is to color the nodes of the mesh according to their values. For that, i have already created the nodes and i would first like to import the values from a file.dat, then assign the nodes with these values, in order to change the colors of the nodes according to their assigned values.
Here is the code.js I am using to create the nodes:
jsonURL = "/resources/datasets/Mesh.json";
var colors = ['#898ec1', '#9193bd', '#9999ba', '#a19eb7', '#a8a4b4', '#aea9b1', '#b5afae', '#bbb5ac', '#c1bbaa', '#c7c0a9', '#cdc6a8', '#d2cca8', '#d8d2a8', '#ded8a9', '#e3ddab', '#e8e3ae', '#ede9b2', '#f2efb9', '#f7f4c2', '#fcface', '#fff5d1', '#ffeac2', '#ffe0b3', '#fdd6a6', '#fbcc99', '#f7c38c', '#f3b980', '#efb075', '#eaa76a', '#e49e61', '#de9558', '#d88d4f', '#d18448', '#c97c41', '#c1753b', '#b86d37', '#b06733', '#a66030', '#9c5a2e', '#92542e'];
$.getJSON(jsonURL , function setPoints(dataset) {
var timestamp=1565715018;
for (i=0; i<dataset.humidity.length;i++){
if (dataset.humidity[i].time == timestamp){
for (ii=0; i<dataset.humidity[i].data.length;ii++)
{
var dotPz = dataset.humidity[i].data[ii].x;
var dotPx = dataset.humidity[i].data[ii].y;
var dotPy = dataset.humidity[i].data[ii].z;
var dotGeometry = new THREE.Geometry();
dotGeometry.vertices.push(new THREE.Vector3( dotPx, dotPy, dotPz));
var dotMaterial = new THREE.PointsMaterial( {
size: 0.0002,
color: "#ffffff",
blending: THREE.AdditiveBlending,
transparent: true,
depthTest: false,
sizeAttenuation: true,
} );
scene.add(new THREE.Points(dotGeometry, dotMaterial));
}
};
}
});
Does anyone know how to assign nodes with values imported from a file.dat? Any ideas would be very helpful!
Thank you
I'm attempting to display a list of renderer/scene/camera "groups" on the same html page. I ran into problems when trying to implement a render loop on all of them, using requestAnimationFrame. I am, however, unable to successfully render even a single frame by looping over the list.
calling renderer.render on each of the "groups" in the same function that I instantiate them in works fine. I refactored the code to allow calling render on each of the renderers outside of said function, and my blue spheres disappear;
I have some elements...
<div class="1"></div>
<div class="2"></div>
<div class="3"></div>
<div class="4"></div>
that I add some threeJs things to
$(document).ready(function(){
addResizeandCenterListener(window, $("#container"), 4/3);
addResizeListener($("#container"), $(".playerhalf"), 2/1);
for (let item of [".1", ".2", ".3", ".4", ".5", ".6", ".7", ".8"]) {
var threeDetails = addThreeRendererToElem($(item), item);
var scene = threeDetails["scene"];
addClickListenerToElem($(item), scene);
}
});
threeList = [];
//this adds a renderer/scene/camera to the element "elem"
function addThreeRendererToElem(elem, name){
var width = elem.innerWidth();
var height = elem.innerHeight();
var scene = newScene();
scene.name = name;
addDefaultLight(scene);
addBlueBall(scene);
var camera = addDefaultCamera(scene, width, height);
var renderer = newRenderer(width, height);
elem[0].appendChild(renderer.domElement);
//this works fine regardless of how many renderer/scene/camera groups I have placed in the DOM
//renderer.render(scene, camera);
var threeDict = {"renderer":renderer, "scene":scene, "camera":camera}
threeList.push(threeDict)
//this does not work, even if I only place a single renderer/scene camera group in the DOM
renderList();
}
function renderList() {
var tlist = threeList;
for (var i = 0; i< tlist;i++) {
var threeDict = tlist[i];
threeDict["renderer"].render(threeDict["scene"],
threeDict["camera"]);
}
}
function newScene(){
scene = new THREE.Scene();
return scene;
}
function newCamera(w, h){
camera = new THREE.PerspectiveCamera(45, w / h, 0.1, 100);
return camera;
}
function newRenderer(w, h){
renderer = new THREE.WebGLRenderer({alpha:true, antialias:true});
renderer.setSize(w, h);
return renderer;
}
function addObjectToScene(obj, scene){
scene.add(obj);
}
function ballObj(color){
var ballGeometry = new THREE.SphereGeometry(3, 16, 16);
var ballMaterial = new THREE.MeshPhongMaterial({color: 0x33aaff});
var ball = new THREE.Mesh(ballGeometry, ballMaterial);
return ball;
}
function spotLightObj(){
var spot = new THREE.SpotLight(0xffffff);
return spot;
}
function addDefaultCamera(scene, width, height){
var camera = newCamera(width, height);
camera.position.set(1,1,20);
camera.lookAt(scene.position);
return camera;
}
function addDefaultLight(scene){
var spot = spotLightObj();
spot.position.set(1, 10, 4);
addObjectToScene(spot, scene);
}
function addBlueBall(scene){
var hexcolor = "0x33aaff";
bball = ballObj(hexcolor);
addObjectToScene(bball, scene);
}
I expect to see some blue spheres, like when I am calling render from inside addThreeRendererToElem, but I don't. Instead, the canvases are all blank. The canvases are in the correct places on the web page, inspecting threeList in the console shows that all the objects are indeed there. There are no error messages.
Incorrect ending condition on your for-loop inside the renderList function.
You are missing .length. Should be:
function renderList() {
var tlist = threeList;
for ( var i = 0; i < tlist.length; i++ ) {
var threeDict = tlist[i];
threeDict["renderer"].render( threeDict["scene"], threeDict["camera"] );
}
}
I create a car use THREE.ExtrudeGeometry, and following is my code :
function setExtMaterial(drawFunc,options,meshMaterial){
var geom = new THREE.ExtrudeGeometry(drawFunc(),options);
var shape = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial]);
return shape;
}
function drawShap1(){
var shape = new THREE.Shape();
shape.moveTo(10,10);
shape.splineThru([
new THREE.Vector2(10.2,11.8),
new THREE.Vector2(12,12)
])
shape.lineTo(18,12);
shape.splineThru([
new THREE.Vector2(19.8,11.8),
new THREE.Vector2(20,10)
])
shape.lineTo(20,4);
shape.lineTo(10,4);
shape.lineTo(10,10);
return shape;
}
var options1 = {
amount:25,
bevelThickness:1,
bevelSize:1,
beveSegments:60,
steps:60,
curveSegments:60
}
var mesh2 = new THREE.MeshPhongMaterial({
color:new THREE.Color('#FAF808')
});
var carBody = setExtMaterial(drawShap1,options1,mesh2);
carBody.position.set(-10,-3,15);
carBody.rotation.y = Math.PI/2;
car.add(carBody);
console.log(carBody)
Now I use console.log('carBody') to see what print ,and result is:
Group {uuid: "896051F5-8F4E-43C8-8EFE-B9FC4A07B7DE", name: "", type:
"Group", parent: Object3D, children: Array1…}
The carBody is Group ?!
And now I use subtract():
function subtract(obj1,obj2,mesh,target){
var o1BSP = new ThreeBSP(obj1);
var o2BSP = new ThreeBSP(obj2);
var r = o1BSP.subtract(o2BSP);
var result = r.toMesh(mesh);
result.geometry.computeFaceNormals();
result.geometry.computeVertexNormals();
target.add(result);
}
var windowFront = new THREE.Mesh(new THREE.CubeGeometry(1,5,9),mesh1);
windowFront.position.set(16,6,0);
subtract(carBody,windowFront,mesh2,car);
And when I use threeBSP's subtract() chrome point out this information:
And I look at ThreeBSP.js's code ,it seems that just Geometry and Mesh can use subtract() to create like this door:
How to use subtract() on the element that we create with THREE.ExtrudeGeometry. Any help is greatly appreciated.
I am trying create a simple three.js app, but I'm getting stuck on some of the nuances of javascript. I don't really know how to explain the problem without an example:
var Model = function() {
THREE.Object3D.call(this);
this.loadedMesh = null;
this.meshIsLoaded = false;
};
Model.prototype = {
constructor: Model,
load: function(path, mtlName, objName) {
var onProgress = function(xhr) {...};
var onError = function(err) {...};
THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader());
mtlLoader.setPath(path);
mtlLoader.load(mtlName, function(materials) {
materials.preload();
objLoader.setMaterials(materials);
objLoader.setPath(path);
objLoader.load(objName, function(object) {
object.position.set(0, -5, 10);
object.scale.set(5, 5, 5);
object.rotation.y = Math.PI; // 180 degrees
scene.add(object);
this.loadedMesh = object;
this.meshIsLoaded = true;
});
}, onProgress, onError);
}
};
This wrapper should be a container for a three model. The loading works fine, but when I try and save the Model into a variable, none of the internal members are altered outside of the Model scope.
var spaceman = new Model();
spaceman.load("ACES/", "acesjustforroomshow.mtl", "acesjustforroomshow.obj");
...
function update() {
if (spaceman.meshIsLoaded)
spaceman.loadedMesh.rotation.x += 0.1;
}
It's weird because if I debug the app and wait until the model is loaded, I can hover over the internal members and they are populated. When I hover over the spaceman object, the values for loadedMesh and meshIsLoaded remain the default.
Is there some aspect of prototyping that I'm not understanding here?
My guess is that the issue is the this variable. Within the callback function you're passing to objLoader.load, it may no longer be set to your object. If I'm right, either of the below fixes should work:
Using bind:
objLoader.load(objName, function(object) {
object.position.set(0, -5, 10);
object.scale.set(5, 5, 5);
object.rotation.y = Math.PI; // 180 degrees
scene.add(object);
this.loadedMesh = object;
this.meshIsLoaded = true;
}.bind(this));
Capturing this in another variable:
var that = this;
objLoader.load(objName, function(object) {
object.position.set(0, -5, 10);
object.scale.set(5, 5, 5);
object.rotation.y = Math.PI; // 180 degrees
scene.add(object);
that.loadedMesh = object;
that.meshIsLoaded = true;
});
I am making a flame using the THREE.js and spark.js, but when I render the world I can't see the flame and the world is empty. I saw the console for the error but there is no error regarding this. I tried a lot but can't find out the actual error. Here is the code.
threexSparks = new THREEx.Sparks({
maxParticles : 400,
counter : new SPARKS.SteadyCounter(300)
});
//threexSparks.position.x = 1000;
// setup the emitter
//var emitter = threexSparks.emitter();
var counter = new SPARKS.SteadyCounter(500);
var emitter = new SPARKS.Emitter(counter);
var initColorSize = function() {
this.initialize = function(emitter, particle) {
particle.target.color().setHSV(0.3, 0.9, 0.4);
particle.target.size(150);
};
};
emitter.addInitializer(new initColorSize());
emitter.addInitializer(new SPARKS.Position(new SPARKS.PointZone(new THREE.Vector3(1000, 0, 0))));
emitter.addInitializer(new SPARKS.Lifetime(0, 0.8));
emitter.addInitializer(new SPARKS.Velocity(new SPARKS.PointZone(new THREE.Vector3(0, 250, 00))));
emitter.addAction(new SPARKS.Age());
emitter.addAction(new SPARKS.Move());
emitter.addAction(new SPARKS.RandomDrift(1000, 0, 1000));
emitter.addAction(new SPARKS.Accelerate(0, -200, 0));
Thanks
Tere is strange problems with particles and WebGL render. It will be good if you're using CanvasRender. But for WebGL not.
Also in your code you forgot about creating threejs objects for particles. Sparks.js allows only interface for particles. But you need to create particles itself.
You can look at my jsfiddle example. there I use modified version of sparks.js library. Changes just to be able to override VectorPool behaviour.
http://jsfiddle.net/YeJ4X/35/
Main part there is:
var particleCount = 1800,
particles = new THREE.Geometry(), //store particle vertices
pMaterial = new THREE.ParticleBasicMaterial({
size: 10,
map: txture, //in jsfiddle i create texture from canvas
transparent: true
});
var particleSystem = new THREE.ParticleSystem(particles, pMaterial); //threejs particle system
//initialize our particles (and set that are dirty). sparkjs initialize it later for us
for(var p = 0; p < particleCount; p++) {
v = new THREE.Vector3(numMax,numMax,numMax);
v.isDirty=true;
particles.vertices.push(v);
}
SPARKS.VectorPool.__pools = particles.vertices; //initialize vectors pool
And there is my new vector pool for sparksjs
SPARKS.VectorPool = {
__pools: [],
get: function() {
var ret = _.find(this.__pools, function(v){return v.isDirty});
ret.isDirty=false;
return ret;
},
release: function(v) {
v.isDirty=true;
v.set(numMax,numMax,numMax);
}
};
Of course you must care about count of partices that are used in sparks.js and precreated by hands.
My sparkjs fork is here: https://github.com/elephanter/sparks.js there I fix problem with lastest tweenjs and add other little changes I described before.