Three.js - CanvasRenderer not rendering Mesh with multiple materials - javascript

I have a problem with CanvasRenderer rendering a Mesh that has multiple materials applied to a BoxBufferGeometry. It renders a Mesh with no materials applied. This is only problem with CanvasRenderer, when I use the same Mesh with WebGLRenderer all works as expected.
Here's an example code:
// three.js: multiple materials on a single mesh
var renderer, scene, camera, mesh;
init();
render();
function init() {
// renderer
renderer = new THREE.CanvasRenderer( { alpha: true } );
renderer.setSize( window.innerWidth / 2, window.innerHeight );
document.body.appendChild( renderer.domElement );
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera( 40, (window.innerWidth / 2) / window.innerHeight, 1, 1000 );
camera.position.set( 15, 20, 30 );
camera.lookAt(scene.position);
scene.add( camera );
// ambient
scene.add( new THREE.AmbientLight( 0xffffff, 0.1 ) );
// light
camera.add( new THREE.PointLight( 0xffffff, 1 ) );
// geometry
var geometry = new THREE.BoxBufferGeometry( 10, 10, 10 );
// materials
var material0 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
var material1 = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var material2 = new THREE.MeshBasicMaterial({ color: 0x0000ff });
var material3 = new THREE.MeshBasicMaterial({ color: 0xffff00 });
var material4 = new THREE.MeshBasicMaterial({ color: 0x00ffff });
var material5 = new THREE.MeshBasicMaterial({ color: 0xff00ff });
var materials = [ material0, material1, material2, material3, material4, material5 ];
// mesh
mesh = new THREE.Mesh( geometry, materials );
scene.add( mesh );
}
function render() {
requestAnimationFrame(render);
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
renderer.render( scene, camera );
}
I've also made this fiddle
Where you can see exactly what I'm talking about. In the fiddle there's a Mesh(cube) that has all 6 groups(sides) in different material(color), and that same Mesh is rendered with WebGLRenderer(left) and CanvasRenderer(right).
Can someone with more experience help me understand this.
Am I doing something wrong?
Is there some limitation with CanvasRenderer that disables it to render such a Mesh, and if so, how would I achieve this effect in some other way?
Is this a bug, and should I report it as an issue on three.js repository?
Thanks for your help!
Note:
I'm new to Three.js, so I apologize if I made some obvious mistake.
CanvasRenderer is crucial for me as I use phantom.js to capture some screenshots.
Three.js r93

CanvasRenderer does not appear to support BufferGeometry and multi-materials.
A work-around is to use Geometry, instead.
var geometry = new THREE.BoxGeometry( 10, 10, 10 );
three.js r.93

Related

Changing the location of an object on the canvas, using three js

I need to place a number of objects on the canvas, using three js. I'm getting stuck at the point of trying to change the location of the objects. My code is as below:
var scene = new THREE.Scene();
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 geometry = new THREE.BoxGeometry( 2, 1, 1 );
//geometry.position.x = 1;
//geometry.position.y = 1;
//geometry.position.z = 1;
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
//scene.children[1].position.set(0, 0, 0);
var cube = new THREE.Mesh(geometry, material);
scene.add( cube );
camera.position.z = 5;
renderer.render( scene, camera );
I've commented out the two different ways I tried to achieve this (both failed). Can anyone suggest a solution?
You have to set position to a mesh, not a geometry:
var geometry = new THREE.BoxGeometry( 2, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh(geometry, material);
cube.position.set(1, 1, 1);
scene.add( cube );

MeshPhongMaterial doesn't appear

I am a beginner in THREE.js, I want to create a sphere which I will use to create globe with texture but I'm stuck when creating MeshPhongMaterial it appears nothing. Otherwise when I'm using MeshBasicMaterial it appears,
And this is my code
var mainScene, camera, aspect, renderer;
mainScene = new THREE.Scene();
aspect = window.innerWidth / window.innerHeight;
camera = new THREE.PerspectiveCamera(40, aspect, 0.1, 100);
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
var canvasContainer = document.getElementById("canvasContainer");
canvasContainer.appendChild(renderer.domElement);
var mesh = new THREE.Mesh(
new THREE.SphereGeometry(0.5,32,32),
new THREE.MeshPhongMaterial({
color: 0x00ff00,
wireframe: true
})
);
mainScene.add( mesh );
camera.position.z = 5;
var render = function(){
requestAnimationFrame(render);
renderer.render(mainScene, camera);
}
render();
I don't know what's wrong with this code and should I use MeshPhongMaterial to do it?
Thank you
MeshPhongMaterial requires scene lights.
Here is one way, but look at the three.js examples.
// ambient
scene.add( new THREE.AmbientLight( 0xffffff, 0.1 ) );
// light
var light = new THREE.PointLight( 0xffffff, 1 );
camera.add( light );
scene.add( camera ); // required because the camera has a child
three.js r.84

Three.JS - Remove yellow box when using EdgesGeometry, LineSegments, and BoxHelper

Three.js Version: 82
I'm looking at this example here: https://threejs.org/examples/#webgl_helpers
Notice that there are yellow boxes around the models. I was using version 79 and was using THREE.EdgesHelper to outline my 3D objects I made in Blender, but THREE.EdgesHelper was replaced by THREE.EdgesGeometry. I wanted to see an example of this, and the only one I could find is linked above.
I dove into the line and BoxHelper objects, but I didn't notice anything that would allow me to get rid of those yellow boxes.
JSFiddle: https://jsfiddle.net/4nbjvmpe/
Here is the code from the JSFiddle:
HTML
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
CSS
body {
background-color: #000;
margin: 0px;
overflow: hidden;
}
JavaScript
var mesh, renderer, scene, camera, controls;
init();
animate();
function init() {
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 20, 20, 20 );
// controls
controls = new THREE.OrbitControls( camera );
// ambient
scene.add( new THREE.AmbientLight( 0x222222 ) );
// light
var light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 20, 20, 0 );
scene.add( light );
// geometry
var geometry = new THREE.SphereGeometry( 5, 12, 8 );
// material
var material = new THREE.MeshPhongMaterial( {
color: 0x00ffff,
shading: THREE.FlatShading,
transparent: true,
opacity: 0.7,
} );
// mesh
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
// CUSTOM
// This is where I create the outline mesh.
var group = new THREE.Group();
scene.add( group );
group.updateMatrixWorld(true);
var edges = new THREE.EdgesGeometry(geometry);
var line = new THREE.LineSegments(edges);
group.add(line);
line.material.depthTest = true;
line.material.opacity = 0.25;
line.material.transparent = false;
this.outlineMesh = new THREE.BoxHelper(line);
scene.add(this.outlineMesh);
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
Simply comment this.outlineMesh = new THREE.BoxHelper(line); and scene.add(this.outlineMesh);. you will get want you want.

Loading PLY files without faces - Three.js

I'm working on a Web Service which main funcionality resolves around displaying binary .ply files. To open and visualize the point cloud I'm using PLYLoader from Three.js. I used it to present example files from the internet and it worked. But when I'm trying to attach my .ply file it doesn't. I'm using Three.js because I need my display to be optimal, my files are at least 70mb.
Example .ply file here:
https://onedrive.live.com/redir?resid=7DDB287362EDFD5A!761&authkey=!AOHxkZk-6etH--0&ithint=file%2cply
I noticed that the .ply files that i have are a bit different from .ply files i displayed before. In my files there are no faces only points.
So basically my question is "Is it possible to display point cloud using Three.js? or should I use other library? If this is possible can someone help me with configuring my code to work properly?
Here it is my script in which I'm supporting .ply files:
var cameraControls;
var container = document.getElementById("three");
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, container.offsetWidth / container.offsetHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( container.offsetWidth, container.offsetHeight );
document.getElementById("three").appendChild( renderer.domElement );
cameraControls = new THREE.OrbitControls( camera, renderer.domElement );
cameraControls.target.set( 0, 0, 0 );
cameraControls.addEventListener( 'change', render );
var geometry = new THREE.BoxGeometry( 3, 3, 3 );
var material = new THREE.MeshPhongMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
var loader = new THREE.PLYLoader();
loader.load( 'resources/cube.ply', function ( geometry ) {
geometry.computeFaceNormals();
var material = new THREE.MeshStandardMaterial( { color: 0x0055ff } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.y = - 0.25;
mesh.rotation.x = - Math.PI / 2;
mesh.scale.multiplyScalar( 1 );
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add( mesh );
} );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
var light = new THREE.AmbientLight( 0x404040 ); // soft white light
scene.add( light );
directionalLight.position.set( 0, 1, 0 );
scene.add( directionalLight );
camera.position.z = 5;
function render() {
requestAnimationFrame( render );
renderer.render( scene, camera );
}
render();
Use THREE.MeshNormalMaterial. It loads the textures with MeshNormalMaterial for some odd reason
Use PointMaterials and Points
const loader = new PLYLoader();
loader.load('00000012.ply', function (geometry) {
var material = new THREE.PointsMaterial( { size: 0.005 } );
material.vertexColors = true //if has colors
var mesh = new THREE.Points(geometry, material)
scene.add(mesh)
} );

Issue with custom geometry and face normal

I'm quite new to ThreeJS and I have a small issue (probably wrong usage). I'm trying to create a custom geometry and define the faces normals by myself.
I create one normal in one direction and the other one in the opposite direction, as my Mesh is not 2 sided I expect to see only one of the face, however I can see both of them... Any Idea of what I'm doing wrong ?
Thanks!
<body>
<script src="../build/Three.js"></script>
<script src="js/Stats.js"></script>
<script>
var container, stats;
var camera, scene, renderer;
container = document.createElement( 'div' );
document.body.appendChild( container );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
camera.up.x = 0;
camera.up.y = 0;
camera.up.z = 1;
camera.position.x = 300;
camera.position.y = -1000;
camera.position.z = 1000;
camera.lookAt(new THREE.Vector3(300, 250, 0));
scene.add( camera );
var light, geometry, material;
scene.add( new THREE.AmbientLight( 0x404040 ) );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 1, 0 );
scene.add( light );
material = new THREE.MeshBasicMaterial( { color: 0xFFFF00, wireframe: false, transparent: false, opacity: 1 } );
geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(0,0,0));
geometry.vertices.push(new THREE.Vector3(600,0,0));
geometry.vertices.push(new THREE.Vector3(0,-500,0));
geometry.vertices.push(new THREE.Vector3(600,-500,0));
var face;
face = new THREE.Face3(0,2,1);
face.normal.set(0,0,-1);
geometry.faces.push(face);
face = new THREE.Face3(2,3,1);
face.normal.set(0,0,1);
geometry.faces.push(face);
geometry.computeCentroids();
//geometry.computeFaceNormals();
//geometry.computeTangents();
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
renderer.render( scene, camera );
</script>
</body>
WebGLRenderer uses the vertex order in which you created the face for defining the orientation instead of the normal. Try doing this:
face = new THREE.Face3(2,1,3);

Categories