Three.js Materials are reversed depending on direction of view - javascript

I am using Three.js to model a home. The idea is that I can show the home to an architect and discuss it further. The project is supposed to be walkable, so I put together it all on this site. If you visit the site to view the code, use arrow keys to move horizontally relative to the grass, use W/S to move up/down, and A/D to yaw view.
https://bsdillon.github.io/cs200_Spring2020/ThreeJs/solarhouse.html
I was able to make panels (cubes actually) and put textures on them. Everything looks great except that the walls look different depending on the direction of view. See the image below. I added a red line and yellow triangle to help make the geometry more obvious. The image on the left shows the external view of a panel with a clapboard exterior and an open doorway on the left. The image on the right shows the same panel viewed from inside the structure. You can see that from inside the door is still on the left (it should appear on the right) and the stick frame interior also appears to be reversed.
I never noticed this before, but it appears to be the standard for the way I set up these panels. Apparently I'm doing something wrong. The question is how can I show the texture so that the views will be consistent.
var materialArray = new Object();//I set up an object I set up to store materials
function makeMaterial2(filename, repeatX, repeatY)//a method for creating materials from an image file
{
var m = new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( filename ), transparent: true, opacity: 0.9, color: 0xffffff });
return m;
}
//two examples of the material creation I implemented
materialArray["rDoor"] = makeMaterial2("doorRight.png",false,false);
materialArray["crDoor"] = makeMaterial2("doorRightClapboard.png",false,false);
function drawPanel2(x,y,z,x2,y2,z2,str)//this funciton creates a cube with the material in question
{
var cubegeometry = new THREE.BoxGeometry(Math.abs(x-x2),Math.abs(y-y2),Math.abs(z-z2));
var cube = new THREE.Mesh(cubegeometry, materialArray[str]);
cube.position.set((x+x2)/2,(y+y2)/2,(z+z2)/2);
return cube;
}
//adding the panels to the scene with the materials
scene.add(drawPanel2(-10,level,front,0,level+height,front,"rDoor"));
scene.add(drawPanel2(-10,level,front+margin,0,level+height,front+margin,"crDoor"));

You are using a simple BoxGeometry that has standard UV texture coodinates. A texture mapped on this geometry will look the same from all sides (see box example). However, you want that the open space of the door is at the same position. You could do one of the following to achieve that:
Apply different materials and textures to different sides of the box. The 6 sides of BoxGeometry are already indexed for multi material usage.
a) You'll have to flip a texture in an image editing software and save it separately. Load these multiple textures.
b) Clone the texture and set texture.wrapS = THREE.RepeatWrapping; texture.repeat.x = - 1; to flip it (How to flip a Three.js texture horizontally).
Create an array of 6 materials each with its according texture and pass it to the Mesh.
Change the UV texture coordinates of BoxGeometry, such that one side will show the texture flipped.
Your boxes are flat. 4 sides aren't visible. Instead of a BoxGeometry, you could also create a PlaneGeometry. Set material.side: THREE.DoubleSide such that the plane will be visible from both sides. Following this approach, you'll have to rework your drawPanel2 method, because you can't just flatten one side of the geometry, but you have to rotate the plane according the intended orientation of the panel.

Related

Three.js - Simple custom texture box looks different on the sides than on the up / down faces. Why it happens and how to match them

In three.js when using a single texture for a box the side faces look different than the top and bottom faces.
Why does this happen? and how can I make the textures of the 6 faces look similar?
The following is the part of the code related to texture
var corkTexture = new THREE.ImageUtils.loadTexture( 'img/cork-256.png' );
corkTexture.wrapS = corkTexture.wrapT = THREE.MirroredRepeatWrapping;
corkTexture.repeat.set( 10, 10 );
corkTexture.offset.set(0.5, 0.5);
var corkMaterial = new THREE.MeshBasicMaterial( { map: corkTexture } );
In this url you can see the complete code and the result
http://heyplay.org/animation/index.html
Thanks.
Using a default BoxGeometry, your texture will be transformed to fit across the whole surface. This means that for a square texture, a square surface will look correct, but a short surface will have a squished texture, and a tall surface will have a stretched texture.
Consider you have a box that is 10w×10h×10d. If you apply a square texture to the box, all sides will look the same. But if your box is 10w×2h×10d, then the top and bottom will look correct, but the short sides will have a squished texture, like the problem you're seeing.
You can get the sides of a short box to look similar (and it helps that you have a repeating texture) by adjusting the UV values for either the top or bottom vertices of all four side faces.
Take a look at Geometry.faceVertexUvs. This is where the UV information is stored. Identify which vertices are the ones you want to update, and then change the values of the associated UVs. (Deciding what values to use is beyond the scope of this question, but I recommend doing so based on the aspect ratio of the face vs. the texture.)

How to incorporate a "moving" background in THREE.js

I cam across this site: https://travisscott.com/
As you can see, when you move the camera, the gradient background has different 360 degree shading.
What part of THREE.js would something like this be part of?
Can someone point me in the right direction?
As #gaitat said in their comment above- the background is a cube map wrapped in a sphere. This is just a normal three.js material with a texture map applied. Here is the code from the page cleaned up to be readable:
var backgroundSphere = new THREE.Mesh(
new THREE.SphereGeometry(30,10,10),
new THREE.MeshBasicMaterial({
map: (new THREE.TextureLoader).load("assets/images/textures/pano.jpg"),
side: c.DoubleSide
})
);
The shiny material on the model is achieved using the same environment map:
var shinyMaterial = new THREE.MeshStandardMaterial({
color: 16777215,
metalness: 1,
roughness: -1,
envMap: <A loaded cube texture (the same as the pano image above)>,
side: c.DoubleSide,
shading: c.FlatShading
});
There is more information on loading a cube texture in the three.js docs: https://threejs.org/docs/#api/textures/CubeTexture
Page is using: three.js [r79] from what I can see.
Here's the process.
Create the asset - Get a 360 panorama image from some source. Photoshop it to make it blurred.
Create sphere in your Threejs setup. Make its scale 10x heigher than the main model scale
Apply MeshLambertMaterial to it with face sides to be BackSided
Load the 360 image that you edited in your scene
Apply the image as emissiveMap. Make sure that the emissive color is set to white.
Render

IntersectObjects - THREE.Line - Three.js

I have a THREE.Line object that is used to orchestrate a custom grid. Now the problem I am having is when using a raycast to intersectObjects when the users mouse might goes over this grid, the intercept only succeeds if the users mouse goes "directly" over any of the grid lines.
Please see the attached photo:
So ultimately what I am am trying to accomplish is, how can the fill in the space between the lines with an "invisible" face or even shape so that when the users mouse goes over this grid, I can trigger an action. Here is currently what I am doing:
var response = this.buildGridGeometry(modelStep,modelSize,gridtype);
var geometry = response['geometry'];
geometry.computeBoundingBox();
// # Setup the material
var material = new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } );
// # Draw each individual line
var line = new THREE.Line( geometry, material, THREE.LinePieces );
Any suggestions?
The easiest solution would be to create a custom Geometry with the same shape as the grid, then make it's initial position, rotation and scale match with the grid (if it isn't already). After that you can add the custom Geometry as a child to the grid so that it moves correspondingly. Last step is to make the custom Geometry mesh invisible by setting its property .visible = false;.
Now you just need to use the raycasters intersectsObject() on the custom Geometry mesh instead, and when it does intersect, you know that the grid is intersected aswell.

Three.js disable lighting

I want to disable lighting entirely in three.js, and render a 3D object. Currently, since lighting is active in some form, the object appears completely black. I have no calls to any sort of lighting currently in my program, and I have been unable to find a solution with searching.
Edit: Code
var white = 0xFFFFFF;
var facemat = new THREE.MeshBasicMaterial( { color: white, opacity: 1.0, shading: THREE.FlatShading } );
vrmlLoader.addEventListener('load', function ( event ) {
var object = event.content;
object.material = facemat;
scene.add(object);
});
vrmlLoader.load("ship.wrl");
My questions for this particular post have mostly been answered. If I am to ask more I will drive this post off topic.
Shading / lighting take care of drawing an object in such a way that you can perceive its depth. In your example picture, shading is disabled - there is no depth, the object is the same everywhere - you cannot differentiate parts of it.
Now, it should be pretty obvious that you can't draw stuff without colour - just like you can't draw on a piece of paper without pencils or any other tool. What you are seeing is simply your object drawn with black colour. What you want to see is your object drawn in white, which is almost the same but if you do that currently, you'll see nothing since your background is white!
Anyway, after those clarifications, here is a how-to:
Change the background colour of your renderer to white:
renderer.setClearColor(0, 1)
Change the colour of your object by changing its material:
object.material = new THREE.MeshBasicMaterial(0xFFFFFF)

I'm doing something wrong with SpotLights and shadows in Three.js

I have a really simple scene which has one .dae mesh in it, and a 7000*7000 plane underneath the mesh. I'd like it to be lit by a high SpotLight, so the mesh throws a shadow on the ground. But, something seems to be broken! No matter how high I put the SpotLight, it never lights up the plane! Also, it lights the mesh up only a little, while it is in a small square (perimeter).
You can see the situation here:
As soon as I move the mesh (a monster) around, it wont be lit anymore.
This is how I instantiate the light:
// create a spotlight
self.spotLight = new THREE.SpotLight();
// set its position
self.spotLight.position.y = 1000; //I recon it needs to be relatively high so it lights up everything
self.spotLight.position.x = 0; //(0, 0) are the coordinates where the mesh is spawned, and are the center of the plane
self.spotLight.position.z = 0;
self.spotLight.castShadow = true;
This is how the plane is made:
//The plane.
self.plane = new THREE.Mesh(new THREE.PlaneGeometry(self.groundSize, self.groundSize), new THREE.MeshLambertMaterial({color: 0x5C8A00}));
self.plane.receiveShadow = true;
self.plane.position.x = 0;
self.plane.position.y = -26;
self.plane.position.z = 0;
Also, here's another picture, this time, I've added a lot of PointLights:
You can see how the shadow still disappears!
Now, what am I doing wrong here? AFAIK, light should disperse equally in all directions! And also, there is another problem, I seem to be unable to add multiple SpotLights on the scene! Everything slows down completely if I do so - is this intended? Maybe it's because I enabled shadows on all of them...
#Neil, the same thing happens in your code as well!
I have created a jsfiddle showing a plane with Lambert material and a rotating cube that is casting a shadow, maybe you can see what is different to yours.
edit
Try playing about with some of the params, I can stop the clipping on my demo with:
spotLight.shadowCameraFov = 70;
update demo and moving demo

Categories