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().
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>
I am having issues trying to set the default view of a panoramic image inside spherebuffergeometry. I have a mesh that makes use of this geometry and the material is an equirectangle panorama image. During runtime, the default view of the image is somewhere towards the right. I want the initial angle to be at the bottom of the camera. I tried changing the Phi angle and theta angle parameters of spherebuffergeometry. While I am able to move the default horizontal angle by changing Phi angle, the panoramic image looks weird when I change the theta angle.
I took the first two snapshots when phi angle was 0 and 100 respectively and theta angle was 0. I took the last snapshot when phi angle was 100 and theta angle was 1.
Any help would be appreciated.
Thanks
sphereBufferGeometry = new THREE.SphereGeometry(100,100,100,0,Math.PI*2,0,Math.PI); sphereBufferGeometry.scale( 1, 1, -1 );
var material = new THREE.MeshBasicMaterial( {
map: new THREE.TextureLoader().load([image] )
});
mesh = new THREE.Mesh( sphereBufferGeometry, material );
I have tried this as well.
init();
var scene,renderer,camera;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100);
var light = new THREE.PointLight(0xffffff, 0.8);
var light2 = new THREE.DirectionalLight( 0xffddcc, 1 );
light.position.set( 1, 0.75, 0.5 );
scene.add( light2 );
var sphereBufferGeometry = new THREE.SphereGeometry(100, 100, 100, 0, Math.PI * 2, 0, Math.PI);
sphereBufferGeometry.scale(1, 1, -1);
var material = new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load('https://threejs.org/examples/textures/2294472375_24a3b8ef46_o.jpg')
});
var mesh = new THREE.Mesh(sphereBufferGeometry, material);
mesh.rotation.x=1.6;
scene.add(camera);
scene.add(light);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({
antialias: true,
preserveDrawingBuffer: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
var orbitControls = new THREE.OrbitControls(camera, renderer.domElement);
camera.position.set(0, 0, 0.001);
orbitControls.update();
var container = document.getElementById('container');
var canvas = renderer.domElement;
canvas.setAttribute("class", "frame");
container.appendChild(canvas);
document.body.appendChild(container);
animate();
}
function animate()
{
requestAnimationFrame(animate);
renderer.render( scene, camera );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/105/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<div id="container"></div>
. As you can see, I've rotated the mesh so that the default view is looking at the floor.. if we click and drag the mouse upwards such that the window in the view is horizontal and then click and drag left or right, orbit controls don't seem to work properly in that it doesn't give a proper panoramic experience.. I would like to know how can this be fixed
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 using three.js where I'm showing a static background image and having a renderer animate shapes on top of it. The reason for doing this is to freely rotate the shapes' renderer without affecting the image. The problem is that the background sits behind the renderer so my question is, is it possible to make the renderer's "background" transparent (allowing the shapes to still show) in order to fully see the background image?
Things I've tried:
Setting opacity on renderer's domElement
Setting transparency for rgba with renderer's setClearColor method
Here's a simplified fiddle and you'll see that the square (thus renderer) is covering the background.
var square = new THREE.Shape();
square.moveTo(0, 0);
square.lineTo(0, length);
square.lineTo(length, length);
square.lineTo(length, 0);
square.lineTo(0, 0);
var geometry = new THREE.ShapeGeometry(square);
var material = new THREE.MeshBasicMaterial({
color: 'rgb(59, 89, 152)',
opacity: 1,
transparent: true
});
var mesh = new THREE.Mesh(geometry, material);
mesh.position.x = 50;
mesh.position.y = 50;
scene.add(mesh);
// and the camera
scene.add(camera);
renderer.render( scene, camera );
You need to set the webGLRenderer alpha parameter.
var renderer = new THREE.WebGLRenderer( { alpha: true } );
You can leave the clear color at the default value.
renderer.setClearColor( 0x000000, 0 ); // the default
Updated fiddles: http://jsfiddle.net/7McS2/3/ or http://jsfiddle.net/7McS2/4/
three.jr r.63
I have this code below and can´t seem to load the model.
loader = new THREE.JSONLoader(true);
loader.load("modelo.js" , function ( geometry, materials) {
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
scene.add( mesh );
} );
The entire code is below. If i take the out the line "loader.load(...)" it works fine and loads a small cube rotating as in the example from the tutorial in threejs.org, but when i try to load my model it doesn´t load anything. I watch a lot of examples and make this in different ways but it just doesn´t load.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.CubeGeometry(1,1,1);
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
loader = new THREE.JSONLoader(true);
loader.load("modelo.js" , function ( geometry, materials) {
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
scene.add( mesh );
} );
var render = function () {
requestAnimationFrame(render);
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
renderer.render(scene, camera);
};
render();
Good day, I've tested your code with r61 of the Three.js library. It works fine, here's my suggestions.
First try adding a light source to your scene. If for example your background is black and you load a model (even with a texture) that is unlit, it will be black on black. So:
var ambientLight = new THREE.AmbientLight(0xBBBBBB);
scene.add(ambientLight);
If that doesn't work have a look at some of the material values in the modelo.js file specifically the colorDiffuse value in the model's json is set to black (or matches your scenes background color). Did you at anytime have this in Maya? No matter, you've said you have tried a few models so that's a long shot anyway, but if it helps check out this post:
Loading Maya model with Three.js
Next, are you running this locally? If so are you running it in Chrome and have you set the chrome.exe --allow-file-access-from-files flag. If not try it in Firefox, it should just work.
Oh also check that (a) your camera isn't too close. Maybe move it back to say:
camera.position.z = 100;
or (b) your mesh is big enough to see:
mesh.scale.set(100, 100, 100);
That should do it, good luck