Two material in the same place in three.js - javascript

I'm trying to put two materials in a plane, one over the other. I mean, I have a bricks background and over it I need to put another material whit other texture.

Use the following approach to apply more than a single material to a mesh. The idea is to define BufferGeometry.groups in a way such that the entire geometry (not just parts of it) is rendered with different materials.
var renderer, scene, camera;
init();
render();
function init() {
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setClearColor( 0x000000, 0.0 );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 15, 20, 30 );
scene.add( camera );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render );
controls.minDistance = 10;
controls.maxDistance = 50;
scene.add( new THREE.AmbientLight( 0xffffff, 0.1 ) );
var light = new THREE.PointLight( 0xffffff, 1 );
camera.add( light );
var geometry = new THREE.BoxBufferGeometry( 10, 10, 10 );
geometry.clearGroups();
geometry.addGroup( 0, Infinity, 0 );
geometry.addGroup( 0, Infinity, 1 );
// textures
var loader = new THREE.TextureLoader();
var map = loader.load( 'https://threejs.org/examples/textures/decal/decal-diffuse.png', render );
var normalMap = loader.load( 'https://threejs.org/examples/textures/decal/decal-normal.jpg', render );
var material1 = new THREE.MeshPhongMaterial( {
color: 0xffffff,
specular: 0x222222,
shininess: 100,
map: map,
normalMap: normalMap,
alphaTest: 0.5,
visible: true
} );
var material2 = new THREE.MeshNormalMaterial( {
opacity: 0.5,
transparent: true,
visible: true
} );
mesh = new THREE.Mesh( geometry, [ material1, material2 ] );
scene.add( mesh );
}
function render() {
renderer.render( scene, camera );
}
body {
margin: 0px;
}
canvs {
display: block;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.116.1/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.116.1/examples/js/controls/OrbitControls.js"></script>

Related

Three.js duplicates objects shape but uses new color with ColladaLoader and STLLoader

I need to load collada and STL models stored in files to the same scene. I do this with three.js framework with a standard ColladaLoader() and STLLoader() like in the linked examples.
The first object appears correctly, but the second repeats its shape in the color of the second object.
I don't understand why. Where can be the problem?
UPD
var sloader = new STLLoader();
sloader.load( 'models/m1.stl', function ( geometry ) {
var meshMaterial = new THREE.MeshPhongMaterial( { color: 0xAAAAAA, specular: 0x111111, shininess: 200 } );
if ( geometry.hasColors ) {
meshMaterial = new THREE.MeshPhongMaterial( { opacity: geometry.alpha, vertexColors: THREE.VertexColors } );
}
var mesh = new THREE.Mesh( geometry, meshMaterial );
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add( mesh );
});
var tmploader = new ColladaLoader();
tmploader.load('models/m2.dae',
function (geometry) {
var robot = geometry.scene;
var meshMaterial = new THREE.MeshPhongMaterial();
robot.traverse(function(child) {
if (child instanceof THREE.Mesh) {
child.material = meshMaterial;
}
});
//robot = new THREE.Mesh( geometry, meshMaterial );
scene.add(robot);
});
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 2000 );
camera.position.set( -10, 10, -10);
camera.lookAt( 0, 3, 0 );
scene = new THREE.Scene();
// lights
var light = new THREE.AmbientLight( 0x404040, 1.0 ); // soft white light
scene.add( light );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 1.0 );
directionalLight.position.set( 1, 1, -1 ).normalize();
scene.add( directionalLight );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

Grainy textures in a simple cube scene

I'm just starting to learn three.js and have been trying to set up a simple textured cube box in an isometric view. When I add edge lines to my cube it turns out to be quite grainy on a few of the edges.
I've tried moving the camera and aspect ratio a bit but to no avail.
var aspect = 100/100
var scene = new THREE.Scene();
var d = 100;
camera = new THREE.OrthographicCamera( - d * aspect, d * aspect, d, - d, 1, 500 );
camera.position.set( 80, 80, 80 ); // all components equal
camera.lookAt( scene.position ); // or the origin
var renderer = new THREE.WebGLRenderer( {alpha: true });
renderer.setSize( 100, 80 );
document.body.appendChild( renderer.domElement );
var geometry = new THREE.BoxGeometry( 65, 65, 65 );
var edges = new THREE.EdgesGeometry( geometry )
var line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( {color: 0x000000} ) );
var material = new THREE.MeshBasicMaterial( { color: 0xf0f0f5 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
scene.add( line );
var animate = function () {
requestAnimationFrame( animate );
renderer.render( scene, camera );
};
animate();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.min.js"></script>
The above gives me a nice grey cube with black edges but the edges appear grainy in my browser.
Picture below:
This is a Z-fighting issue, which can be solved by a polgon offset .polygonOffset.
The issue is caused because the lines and the surface have to same coordinates and depth.
Set the .polygonOffset, .polygonOffsetFactor and .polygonOffsetUnits property of that THREE.Material, which is set to the solid geometry.
This causes that the surfaces are slightly pushed to the back and the lines cover the surfaces:
e.g.
var material = new THREE.MeshBasicMaterial({
color: 0xf0f0f5,
polygonOffset: true,
polygonOffsetFactor: 1.0,
polygonOffsetUnits: -4.0
} );
var aspect = 100/100
var scene = new THREE.Scene();
var d = 100;
camera = new THREE.OrthographicCamera( - d * aspect, d * aspect, d, - d, 1, 500 );
camera.position.set( 80, 80, 80 ); // all components equal
camera.lookAt( scene.position ); // or the origin
var renderer = new THREE.WebGLRenderer( {alpha: true });
renderer.setSize( 100, 80 );
document.body.appendChild( renderer.domElement );
var geometry = new THREE.BoxGeometry( 65, 65, 65 );
var edges = new THREE.EdgesGeometry( geometry )
var line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( {color: 0x000000} ) );
var material = new THREE.MeshBasicMaterial({
color: 0xf0f0f5,
polygonOffset: true,
polygonOffsetFactor: 1.0,
polygonOffsetUnits: -4.0
} );
var cube = new THREE.Mesh( geometry, material );
scene.add( line );
scene.add( cube );
var animate = function () {
requestAnimationFrame( animate );
renderer.render( scene, camera );
};
animate();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.min.js"></script>

3D text not rendering in three.js scene

The text 'Hello three.js!' is not rendering in my scene. It worked fine when I was using BoxGeometry but I seem to missing something for TextBufferGeometry.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); // fov, aspect, near and far
camera.position.set(-15, 0, 25);
camera.lookAt( scene.position );
var loader = new THREE.FontLoader();
loader.load( 'fonts/helvetiker_regular.typeface.json', function ( font ) {
var material = new THREE.MeshPhongMaterial( { color: 0x0033ff, specular: 0x555555, shininess: 30 } );
var textGeo = new THREE.TextGeometry( 'Hello three.js!', {
font: font,
size: 80,
height: 5,
curveSegments: 12,
bevelEnabled: true,
material: 0,
extrudeMaterial: 1
} );
textGeo.computeBoundingBox();
textGeo.computeVertexNormals();
var mesh = new THREE.Mesh( textGeo, material );
scene.add(mesh);
} );
var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 1, 1 ).normalize();
scene.add(light);
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
renderer.render( scene, camera );
I can't make sense of three.js documenation for TextGeometry https://threejs.org/docs/#api/geometries/TextGeometry
I needed to move the render code inside the font loader callback.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); // fov, aspect, near and far
camera.position.set(-15, 0, 25);
camera.lookAt( scene.position );
var loader = new THREE.FontLoader();
loader.load( 'fonts/helvetiker_regular.typeface.json', function ( font ) {
var material = new THREE.MeshPhongMaterial( { color: 0x0033ff, specular: 0x555555, shininess: 30 } );
var geometry = new THREE.TextGeometry( 'Hello three.js!', {
font: font,
size: 80,
height: 5,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 10,
bevelSize: 8,
bevelSegments: 5
} );
var mesh = new THREE.Mesh( geometry, material );
scene.add(mesh);
var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 1, 1 ).normalize();
scene.add(light);
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
renderer.render( scene, camera );
} );

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.

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