Lighting effect looks weird with mesh Lambert material - three.js

I have a problem using Mesh Lambert Material with Three.js, I have a plane with different height points, but when trying to apply light the higher points are the ones that look darker, and it should be the other way around, my code looks like the following:
var geometry = new THREE.PlaneBufferGeometry(7500, 7500, worldWidth - 1, worldDepth -1);
geometry.computeFaceNormals();
geometry.applyMatrix(new THREE.Matrix4().makeRotationX(- Math.PI / 2));
texture = THREE.ImageUtils.loadTexture('img/grass.png');
mesh = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ map: texture }));
scene.add(mesh);
var pointLight = new THREE.PointLight(0xffffff, 100, 0);
pointLight.position.set(5, 50, 5);
scene.add(pointLight);
And the result looks like the following:
Thank you so much in advance.

In your call to
THREE.PointLight(0xffffff, 100, 0);
you are specifying intensity to be 100 when the normal range is 0.0 - 1.0 so your scene comes out over-lit.

Related

How to create a half Cylinder in Three js?

I´m very new to three js and I want to create a half Cylinder as roof.
var geometry = new THREE.CylinderGeometry(100,100,150);
var material = new THREE.MeshNormalMaterial();
var cylinder = new THREE.Mesh( geometry, material);
scene.add(cylinder);
This is the Basic Cylinder but unfortunately I couldn´t find an specific answer to a half cylinder yet.
Is it possible to create this with vertices?
The last 2 params of CylinderGeometry constructor allows this. For example:
var geometry = new THREE.CylinderGeometry(100,100,150, 8, 1, false, 0, Math.PI);
0 is the start angle and Math.PI is the end angle; i.e. half of a circle.

THREEJS After using the subdivision modifier on a sphere the shape is no longer solid, how can I make it back into a solid object?

I am creating a cylinder and then using the subdivision modifier to round the edges. After I apply this the shape is no longer solid. Could anyone point me in the right direction for how to make it a solid color again. I tried merging the vertices but that didn't seem to do anything. Thanks!
var geometry = new THREE.CylinderGeometry(0.4, 0.4, .5, 100);
var material = new THREE.MeshLambertMaterial( {color: 0xeef007, shading: THREE.SmoothShading} );
var modifier = new THREE.SubdivisionModifier( .5 );
geometry.mergeVertices();
modifier.modify( geometry );
var cyl = new THREE.Mesh( geometry, material );
minifig.add( cyl );
screenshot
I'm assuming by "solid" you mean not flat-shaded. Recompute the normals:
modifier.modify( geometry );
geometry.computeFaceNormals();
geometry.computeVertexNormals();

How to add a texture to one side of a cube without THREE.MultiMaterial to reduce draw calls

So lets say theres a cube with 2 materials.I'm using MultiMaterial but maybe thats not the correct approach because its showing 6 draw calls instead of 2. I'm worried about performance when it scales up.
http://codepen.io/glued/pen/JXmvzm
This is just an example, I know about FaceColors but would like to mix a meshBasicMaterial with another Material, say, with a texture.
var greenMaterial = new THREE.MeshBasicMaterial({ color: 0xc4f288 })
var orangeMaterial = new THREE.MeshBasicMaterial({ color: 0xf4511e })
var mats = [
orangeMaterial,
greenMaterial,
orangeMaterial,
orangeMaterial,
greenMaterial,
orangeMaterial
]
let box = new THREE.Mesh(geometry, new THREE.MultiMaterial( mats ))
If i used vertexColors: FaceColors and a texture:
new MeshBasicMaterial({ vertexColors: FaceColors, map:someTexture }))
how would i designate the texture for a specific face only?
I figured it out by creating a material with a texture and removing the UVs on the geometry faces that i'm not using
the texture is 128x256, See the codepen as i'm using a 2d canvas to generate
texture.repeat.y = 0.5
texture.offset.y = 0.5
let geometry = new THREE.BoxGeometry(50, 50, 50)
function assignUvAndColor(geo, i, color = 0x00cbff){
geo.faceVertexUvs[0][i] = new Array(3).fill(new THREE.Vector2(0, -1))
geo.faces[i].color.setHex(color)
}
const greenColor = 0xacffd3
assignUvAndColor(geometry, 3, greenColor)
assignUvAndColor(geometry, 2, greenColor)
assignUvAndColor(geometry, 0, greenColor)
assignUvAndColor(geometry, 1, greenColor)
assignUvAndColor(geometry, 4)
assignUvAndColor(geometry, 5)
assignUvAndColor(geometry, 6)
assignUvAndColor(geometry, 7)
let material = new THREE.MeshBasicMaterial({ map: texture, vertexColors: THREE.FaceColors })
let box = new THREE.Mesh(geometry, material)
http://codepen.io/glued/pen/grBEmo?editors=0010
multimaterial will always do N drawcalls where N = length of its material array
(see renderer implementation)
it does not even try to check whether some of its materials are duplicite in reference - so in your examples you have multimaterial with 6 materials = 6 drawcalls
you will have to change the geometry face material index or abandon using multimaterial and divide your geometry manually

Merge two planes with texture into one mesh

I want to merge two meshes in threejs. I want to create a geometry of two planes that are intersecting each other perpendicular. Both of the planes must have the same texture.
I've tried the following.
Currently this error occurs: THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.
var texture = THREE.ImageUtils.loadTexture('/img/foo.png');
var material = new THREE.MeshPhongMaterial( { map: texture, side: THREE.DoubleSide, transparent: true });
var m_plane_1 = new THREE.PlaneGeometry( 128, 128);
var m_plane_2 = new THREE.PlaneGeometry(128, 128);
var plane_1 = new THREE.Mesh(m_plane_1, material);
var plane_2 = new THREE.Mesh(m_plane_2, material);
plane_2.rotation.y = Math.PI / 2;
var combined = new THREE.Geometry();
combined.merge(plane_1); // does not work
//combined.merge(plane_1.geometry, plane_1.matrix); // this does not work
//combined.merge(m_plane_1.geometry, m_plane_1.matrix); // this does not work
scene.add(combined);
I've tried to read the source code for merge() but could not come to any conclusion. I've read stackoverflow threads but their approach does not work for me.
How can I solve this?
You want to get the intersection of the geometries. Then you can apply whatever texture you want to that new geometry.
To get the intersection, you should use Chandler Prall's Constructive Solid Geometry code: http://evanw.github.io/csg.js/
There are several ways to merge two geometries, but probably the simplest way to achieve what you want is to use the following pattern:
var geometry = new THREE.PlaneGeometry( 128, 128 );
var geometry2 = new THREE.PlaneGeometry( 128, 128 );
geometry2.applyMatrix( new THREE.Matrix4().makeRotationY( Math.PI / 2 ) );
geometry.merge( geometry2 );
three.js r.69
Try this:
plane_1.updateMatrix();
//Now the function merge
combined.merge(plane_1.geometry, plane_1.matrix);
//combined.merge(plane_1); // does not work
//combined.merge(plane_1.geometry, plane_1.matrix); // this does not work
//combined.merge(m_plane_1.geometry, m_plane_1.matrix); // this does not work

Non-radial texture mapping over a ring geometry in WebGL using Three.js

I am trying to simulate image deformation effects using textures over 2D geomtries using the ThreeJS library. I want to apply a texture image over a hollow circle (basically, a ring built by the THREE.RingGeometry function) and obtain the results shown at this image:
Following I show the results I am obtaining in my scene both for the solid ring and its wireframed version:
The problem is that, as you see, the texture is been applied in a radial way, from the center of the ring to the outside. However, what I really need is to apply the texture image on a concentric circle way, as shown in the first image of this question.
The idea is to produce a deformed version of the original texture over a ring shape. I would like to know how this effect can be programmatically achieved through Three.js in such a way that the destination shape can be any arbitrary 2D geometry .
Following, there is the relevant code I am using to draw my scene:
var texture = THREE.ImageUtils.loadTexture('./images/texture.png');
var wireRing = new THREE.Mesh(new THREE.RingGeometry(10, 20, 50, 5, 0, Math.PI * 2), new THREE.MeshBasicMaterial({map: texture, wireframe: true}));
wireRing.position.set(-25, 50, 0);
scene.add(wireRing);
var ring = new THREE.Mesh(new THREE.RingGeometry(10, 20, 50, 5, 0, Math.PI * 2), new THREE.MeshBasicMaterial({map: texture}));
ring.position.set(25, 50, 0);
scene.add(ring);
You just need to change the UV mapping in RingGeometry like so:
uvs.push( new THREE.Vector2( o / thetaSegments, i / phiSegments ) );
Also, if you want to rotate the texture around the ring, you instantiate the RingGeometry by varying the thetaStart parameter:
var geometry = new THREE.RingGeometry( 10, 20, 50, 5, thetaStart, Math.PI * 2 );
three.js r.67

Resources