I am rendering a sphere via three.js and when I apply a texture it works just fine.
However, the equation I'm using to make markers isn't something I can play around with.
How can I rotate a texture on a sphere so that I can align the image according to the marker positions? specifically in the x direction.
Problem...Markers should be over Kagoshima, Japan and Hong Kong, China
Should Be....and No I did not solve it...this is what it should look like not how it is now
var geometry = new THREE.SphereGeometry(200, 40, 30);
shader = Shaders['earth'];
uniforms = THREE.UniformsUtils.clone(shader.uniforms);
uniforms['texture'].texture = THREE.ImageUtils.loadTexture('/images/world5.png');
texture.wrapS = THREE.RepeatWrapping; // This causes globe not to load
texture.offset.x = radians / ( 2 * Math.PI ); // causes globe not to load
material = new THREE.MeshShaderMaterial({
uniforms: uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
});
mesh = new THREE.Mesh(geometry, material);
mesh.matrixAutoUpdate = false;
scene.addObject(mesh);
To shift the texture a certain number of radians of longitude, use this pattern:
texture.wrapS = THREE.RepeatWrapping; // You do not need to set `.wrapT` in this case
texture.offset.x = radians / ( 2 * Math.PI );
three.js r.58
To shift texture have a look at this question, this is another solution that worked for me.
Related
I have quite a large plane with a set displacement map and scale which I do not want to be changed. I simply want the loaded texture to apply to that mesh without it having to scale up so largely.
Currently, a floor texture doesn't look like a floor as it has been upscaled to suit the large plane.
How would I be able to scale down the texture and multiply it across the plane so it looks more like actual terrain?
const tilesNormalMap = textureLoader.load(
"./textures/Stylized_Stone_Floor_005_normal.jpg"
);
function createGround() {
let disMap = new THREE.TextureLoader().load("./models/Heightmap.png");
disMap.wrapS = disMap.wrapT = THREE.RepeatWrapping;
disMap.repeat.set(4, 2);
const groundMat = new THREE.MeshStandardMaterial({
map: tilesBaseColor,
normalMap: tilesNormalMap,
displacementMap: disMap,
displacementScale: 2
});
const groundGeo = new THREE.PlaneGeometry(300, 300, 800, 800);
let groundMesh = new THREE.Mesh(groundGeo, groundMat);
scene.add(groundMesh);
groundMesh.rotation.x = -Math.PI / 2;
groundMesh.position.y -= 1.5;
I tried using the .repeat method as shown below but i can't figure out how this would be implemented
tilesBaseColor.repeat.set(0.9, 0.9);
tilesBaseColor.offset.set(0.001, 0.001);
a photo of the current ground texture
enter image description here
First of all what you want to achieve does currently not work with three.js since it's only possible to a have a single uv transform for all textures (except for light and ao map). And map has priority in your case so you can't have different repeat settings for the displacement map. Related issue at GitHub: https://github.com/mrdoob/three.js/issues/9457
Currently, a floor texture doesn't look like a floor as it has been upscaled to suit the large plane. How would I be able to scale down the texture and multiply it across the plane so it looks more like actual terrain?
In this case, you have to use repeat values great 1 otherwise you zoom into the texture. Do it like in the following live example:
let camera, scene, renderer;
init().then(render);
async function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 1;
scene = new THREE.Scene();
const loader = new THREE.TextureLoader();
const texture = await loader.loadAsync('https://threejs.org/examples/textures/uv_grid_opengl.jpg');
// repeat settings
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(2, 2);
const geometry = new THREE.PlaneGeometry();
const material = new THREE.MeshBasicMaterial({map: texture});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function render() {
renderer.render(scene, camera);
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.148/build/three.min.js"></script>
Is there a way in three.js to turn a cube mesh shape into a diamond shape doing something like rotating the axis of the scale and then scaling it? I'm trying to create a flat-ish diamond shape, something like x50,y50,x10. If not, then what's the best way to create a diamond mesh, or a triangle mesh shape?
If you just turn the cube on its end and scale x you'll still have a (now imbalanced) rectangle shape, but if you turn it on it's end, reorient the axis of scale somehow so it's stretching across the middle from point to point, now you could just squeeze the cube with scale x, and you'd have a nice diamond shape with a thin waist.
For clarification, here's a pic of the mesh shape I am trying to make, ideally the diamond shape on the left, but the triangle shape will do also.
So, is there some way to rotate the axis of the scale? Is that what new THREE.Matrix4().makeTranslation is for? How do I use that in this context?
See plunker of my attempt here. Clearly my cube.scale.x = 0.5; code is not working and needs the axis of transform to be shifted.
Here's the js:
cube = new THREE.Mesh( geometry, material );
cube.rotation.z = Math.PI / 4 ;
cube.position.y = 35;
cube.scale.x = 0.5;
scene.add( cube );
If you want to convert your cube or box into a diamond shape, then the easiest method is to transform your geometry using a pattern like this one:
var geometry = new THREE.BoxGeometry( 100, 100, 20 );
geometry.applyMatrix( new THREE.Matrix4().makeRotationZ( Math.PI / 4 ) );
geometry.applyMatrix( new THREE.Matrix4().makeScale( 1, 2, 1 ) ); // optional
Once you create your mesh, you still have the option of further scaling the mesh, itself.
mesh = new THREE.Mesh( geometry, material );
mesh.scale.set( sz, sy, sz );
scene.add( mesh );
three.js r.71
What you need to do is to create a hierarchy of objects, the inner object will rotate around the z-axis and the outer object will scale on the x-axis.
mesh = new THREE.Mesh(geometry, material);
mesh.rotation.z = Math.PI / 4; // rotate by 45 degrees
var group = new THREE.Group();
group.add( mesh );
group.scale.x = 0.5; // scale by 0.5
scene.add( group );
Here is a fiddle: http://jsfiddle.net/3gxqboer/
I have a sphere and light source (basically sun and earth). On the sphere, I'm using a greyscale heightmap for terrain texture so I am using three.js's ShaderTerrain.js. I'm also using a directional light source. My code:
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
lightCamera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
controls = new THREE.OrbitControls( camera, renderer.domElement );
lightControls = new THREE.TrackballControls(lightCamera, renderer.domElement);
light = new THREE.DirectionalLight(0xffffff, 1.5);
light.position.set(0,0,20);
lightCamera.position.z = 225;
lightCamera.add(light);
camera.add(lightCamera);
scene.add(camera);
var terrainShader = THREE.ShaderTerrain[ "terrain" ];
uniformsTerrain = THREE.UniformsUtils.clone(terrainShader.uniforms);
// displacement is heightmap (greyscale image)
uniformsTerrain[ "tDisplacement" ].value = THREE.ImageUtils.loadTexture('heightmap.jpg');
uniformsTerrain[ "uDisplacementScale" ].value = 15;
// diffuse is texture overlay
uniformsTerrain[ "tDiffuse1" ].value = THREE.ImageUtils.loadTexture('earth.jpg');
uniformsTerrain[ "enableDiffuse1" ].value = true;
var material = new THREE.ShaderMaterial({
uniforms: uniformsTerrain,
vertexShader: terrainShader.vertexShader,
fragmentShader: terrainShader.fragmentShader,
lights: true,
fog: false
});
var geometry = new THREE.SphereGeometry(100,100,100);
geometry.computeTangents();
scene.add(new THREE.Mesh(geometry, material));
With this code, the sphere is created just fine with the raised texture and everything.
The problem is that when I rotate the sphere, the light source doesn't appear to stay fixed. It rotates with the sphere and you end up with dark spots (rather than the light always coming from the front and keeping what the users sees illuminated).
If I create a simple sphere instead, like so:
geometry = new THREE.SphereGeometry(100,100,100);
material = new THREE.MeshLambertMaterial({color: 0x00ee00, wireframe: true, transparent: true, needsUpdate: true});
sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
Everything works perfectly. The light source stays fixed while the sphere/camera rotates.
I've also tried code that simply rotates the (first) sphere (the one using the ShaderMaterial) and not the camera (attaching a function to the mousemove event and simply doing a sphere.rotation.x/y with the mouse position). This doesn't work either; When the sphere rotates, there are still shadows that appear to the user.
Not sure what I'm missing here.
Here's a jsfiddle: http://jsfiddle.net/Z5sS5/1/. Left click/drag to spin everything (camera + light), right click/drag to spin only the light. To see it working, keep basicSphere() uncommented. To see it not working, comment basicSphere() and uncomment terrainSphere().
I currently have a cube that I'm trying to rotate on a corner. I need it to spin on the corner like the photo below.
http://www.flickr.com/photos/fiu/2198328580/
I'm new to Three.js, so I'm sorry if this is a dumb question.
Here's the code for what I currently have
var geometry= new THREE.CubeGeometry (200,200,200, 4, 4, 4);
// material
var material = new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('inc/cube.jpg'), overdraw: true
});
cube = new THREE.Mesh( geometry, material );
cube.overdraw = true;
cube.position.y = 80;
cube.position.x = 5;
cube.position.z = 6;
cube.rotation.z = 14.9;
cube.rotation.y = 0 ;
cube.rotation.x = 0 ;
scene.add(cube);
On another note.... since I have the cube.jpg texture on the cube, if I have the values for the THREE.CubeGeometry set to (200,200,200) without the 4's, the texture warps... Anyone know how to stop the warping?
This is what I'm using to render:
renderer = new THREE.CanvasRenderer();
renderer.setClearColorHex(0xffffff, 0);
renderer.setSize( window.innerWidth, window.innerHeight ); container.appendChild( renderer.domElement );
It seems to work across most browsers, but if I use the WebGL renderer, it gives me issues with the Opacity of the Canvas.
To see the Project as it stands right now, its at http://fiudevspace.com/spincube
Conceptually all you need is to rotate the cube 45 degrees on a different axis from the 45 degrees you have already rotated - I do not use THREE as it would get between me and my solution more than it helps - remember the rule of thumb on object rotations : first translate the center of the object back to the origin (if not already there) then rotate about each axis you need, then finally translate the object back into position (reverse of previous translation) - hope this helps
I'm trying to create a long corridor with a repeating texture. How do I add a repeating texture and rotate a object (in this case a plane) at right angles to create the corridor wall's and ceiling?
var texture, material, plane;
texture = THREE.ImageUtils.loadTexture( "../img/texture.jpg" );
texture.wrapT = THREE.RepeatWrapping; // This doesn't seem to work;
material = new THREE.MeshLambertMaterial({ map : texture });
plane = new THREE.Mesh(new THREE.PlaneGeometry(400, 3500), material);
plane.doubleSided = true;
plane.position.x = 100;
plane.rotation.z = 2; // Not sure what this number represents.
scene.add(plane);
For an example of a repeating texture, check out the source of the example at:
http://stemkoski.github.com/Three.js/Texture-Repeat.html
I recommend the following changes to your code:
var texture, material, plane;
texture = THREE.ImageUtils.loadTexture( "../img/texture.jpg" );
// assuming you want the texture to repeat in both directions:
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
// how many times to repeat in each direction; the default is (1,1),
// which is probably why your example wasn't working
texture.repeat.set( 4, 4 );
material = new THREE.MeshLambertMaterial({ map : texture });
plane = new THREE.Mesh(new THREE.PlaneGeometry(400, 3500), material);
plane.material.side = THREE.DoubleSide;
plane.position.x = 100;
// rotation.z is rotation around the z-axis, measured in radians (rather than degrees)
// Math.PI = 180 degrees, Math.PI / 2 = 90 degrees, etc.
plane.rotation.z = Math.PI / 2;
scene.add(plane);
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!
I was looking for the same thing and you've just used the property THREE.DoubleSide on the wrong object. You should use it on the material rather than on the mesh itself:
material.side = THREE.DoubleSide;
...nothing more !
Update 2019: Imageutil.loadTexture is deprecated,
Use THREE.TextureLoader() instead
new THREE.TextureLoader().load(
WOOD,
//use texture as material Double Side
texture => {
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.offset.x = 90/(2*Math.PI);
var woodMaterial = new THREE.MeshPhongMaterial({
map: texture,
side: THREE.DoubleSide
});
// Add Ground
groundMesh = new THREE.Mesh(
new THREE.PlaneGeometry(GRID_SIZE, GRID_SIZE, 32),
woodMaterial
);
//rotate
groundMesh.rotation.x = Math.PI / 2;
this.scene.add(groundMesh);
}
);