I try to create the planet Earth with three.js. I used a texture on a MeshBasicMaterial and it worked perfectly, but when I change the material to a MeshPhongMaterial it just doesn't render the map anymore.
I want to change the material because I want to add a bump Map too.
Here's my code:
let renderer;
const earthGeometry = new THREE.SphereGeometry(5, 50, 50);
const earthMaterial = new THREE.MeshPhongMaterial({
map: new THREE.TextureLoader().load("../img/globe.jpg"),
// bumpMap: new THREE.TextureLoader().load("../img/earthbump.jpg"),
// bumpScale: 0.3,
});
const sphere = new THREE.Mesh(earthGeometry, earthMaterial);
scene.add(sphere);
And there's not a single problem in the console so I don't know what to do.
I'm also using svelte and vite, maybe it can come from here.
I used a texture on a MeshBasicMaterial and it worked perfectly, but when I change the material to a MeshPhongMaterial it just doesn't render the map anymore.
If it does work with MeshBasicMaterial but not with MeshPhongMaterial, you most likely have no lights in your scene. Try it with this basic setup:
const ambientLight = new THREE.AmbientLight( 0xffffff, 0.4 );
scene.add( ambientLight );
const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.8 );
directionalLight.position.set( 100, 100, 0 );
scene.add( directionalLight );
Related
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
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
I'm working on a tutorial for Three.js and in an example, it presents the concepts of shadows that can be utilized through methods such as: castShadow, receiveShadow and by setting shadowMapenabled to true.
However the example code is for Three.js r69. As of the date of this question, Three.js is at r75 and this code for casting shadows does not work.
Additionally the current Three.js documentation has no information on shadowMapenabled nor shadowMap.enabled or the other methods mentioned.
Suggestions on how to resolve this?
Some of the shadow map properties have been renamed in the recent versions, but they basically work the same.
Setting up the renderer for shadow maps (and choosing the more computational expensive shadow map type):
var renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
Setting up the light (notice how it also works with THREE.PointLight):
var light = new THREE.PointLight( 0xffffff, 1, 100 );
light.position.set( 0, 12, 0 );
light.castShadow = true; // default false
light.shadow.mapSize.width = 1024; // default 512
light.shadow.mapSize.height = 1024; // default 512
light.shadow.camera.near = 2; // default 0.5
light.shadow.camera.far = 100; // default 500
//light.shadow.camera.left = 500 // Not sure about this one +
// right, top and bottom, Do they still do anything?
scene.add( light );
You get notified of all these API changes if you check your console when trying to use the properties specified in the current documention.
Creating you objects that casts and receives shadows is same as before:
//Creating box
var boxGeometry = new THREE.BoxGeometry( 1, 1, 1 );
var boxMaterial = new THREE.MeshPhongMaterial( { color: 0xdddddd, specular: 0x999999, shininess: 15, shading: THREE.FlatShading } );
var box = new THREE.Mesh( boxGeometry, boxMaterial );
box.castShadow = true;
scene.add( box );
creating plane
var planeGeometry = new THREE.PlaneGeometry( 20, 20, 32, 32 );
var planeMaterial = new THREE.MeshPhongMaterial( { color: 0x00dddd, specular: 0x009900, shininess: 10, shading: THREE.FlatShading } )
var plane = new THREE.Mesh( planeGeometry, planeMaterial );
plane.receiveShadow = true;
scene.add( plane );
Placing the plane under the box and it will receive a shadow.
Here is a working codepen example
EDIT
In the current version of THREE.js, the scene needs to be rendered at least twice for the shadows to show.
THREE.js r75.
Here is a the simple code for shadow in three.js .Also included the shadow camera helper
var light = new THREE.SpotLight( 0xFFAA55 );
light.castShadow = true;
light.position.set( 1, 3, 5 );
light.shadowCameraNear = 0.5;
scene.add( light );
helper = new THREE.CameraHelper( light.shadow.camera );
scene.add( helper );
code
I'm creating a skydome in three.js like this:
var geometry = new THREE.SphereGeometry( 40, 32, 15, 1*Math.PI/2, 2*Math.PI, Math.PI, Math.PI);
var material = new THREE.MeshBasicMaterial( { color: 0xddddff } );
mesh = new THREE.Mesh( geometry, material );
mesh.material.side = THREE.DoubleSide;
scene.add( mesh );
This does draw half of a sphere but it also colors the part that I expected to be open (it colors the surface of my mesh that I need the skydome for). How do I solve this problem?
The thing is that even if you draw half a sphere, I doubt it will put UVs correctly, so I very recommend you to make your own skydome using custom mesh.
For skydome you can use mesh.material.side = THREE.BackSide instead of .DoubleSide, btw, unless you stay on the surface all the time.
I wasn't drawing the sphere correctly:
var geometry = new THREE.SphereGeometry( 50, 60, 60, Math.PI, Math.PI, 3*Math.PI/2);
var material = new THREE.MeshBasicMaterial( { color: 0xddddff } );
mesh = new THREE.Mesh( geometry, material );
mesh.material.side = THREE.DoubleSide;
scene.add( mesh );
PRoblem: i'm trying to create (just for fun) a simple poker card (with a card back and a card front).
I have two different images, for back and front.
I easily created a Plane geometry with a single texture for both sides, but i really don't know how to assign a texture for a side and the other texture for the other side...
i tried this (without success :( ):
var textureBack = new THREE.ImageUtils.loadTexture( 'images/cardBack.png' );
var textureFront = new THREE.ImageUtils.loadTexture( 'images/cardFront.png' );
var material1 = new THREE.MeshBasicMaterial( { map: textureBack } );
var material2 = new THREE.MeshBasicMaterial( { map: textureFront } );
var geometry = new THREE.PlaneGeometry( 90, 110, 1, 1 );
geometry.faces[ 0 ].materials.push( material1 );
geometry.faces[ 1 ].materials.push( material2 );
var card = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial());
any help, please? :)
Was searching for solution without duplicating all my geometry.
Here you go ladies and gentlemen...
var materials = [new THREE.MeshBasicMaterial({map: texture, side: THREE.FrontSide}),
new THREE.MeshBasicMaterial({map: textureBack, side: THREE.BackSide})];
var geometry = new THREE.PlaneGeometry(width, height);
for (var i = 0, len = geometry.faces.length; i < len; i++) {
var face = geometry.faces[i].clone();
face.materialIndex = 1;
geometry.faces.push(face);
geometry.faceVertexUvs[0].push(geometry.faceVertexUvs[0][i].slice(0));
}
scene.add(new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materials)));
BOOM a Two Faced Plane for ya, the loop will also work with geometries with more faces, replicating each face and applying the BackSide texture to it.
Enjoy!
You need to place two plane geometries back-to-back.
First, create a geometry for the front.
var geometry1 = new THREE.PlaneGeometry( 90, 110, 1, 1 );
Now create another geometry for the back.
var geometry2 = new THREE.PlaneGeometry( 90, 110, 1, 1 );
Spin it 180 degrees.
geometry2.applyMatrix( new THREE.Matrix4().makeRotationY( Math.PI ) );
After you load the materials, create the meshes, and add them as children of a "card" object.
// textures
var textureFront = new THREE.ImageUtils.loadTexture('images/cardFront.png' );
var textureBack = new THREE.ImageUtils.loadTexture('images/cardBack.png' );
// material
var material1 = new THREE.MeshBasicMaterial( { color: 0xffffff, map: textureFront } );
var material2 = new THREE.MeshBasicMaterial( { color: 0xffffff, map: textureBack } );
// card
card = new THREE.Object3D();
scene.add( card );
// mesh
mesh1 = new THREE.Mesh( geometry1, material1 );
card.add( mesh1 );
mesh2 = new THREE.Mesh( geometry2, material2 );
card.add( mesh2 );
You'll have an easier time with this if you use WebGLRenderer.
Fiddle: http://jsfiddle.net/mdAb7/11/
Updated to three.js r.69