I don't find any good example to do that so any help would be very useful :)
I want achieve this type of light in ceiling of my house object in Three.js
rectLight = new THREE.RectAreaLight( 0xffffff, 500, 10, 10 );
rectLight.position.set( 5, 5, 0 );
rectLightHelper = new THREE.RectAreaLightHelper( rectLight );
scene.add( rectLightHelper );
I have Tried all the light type for example pointLight , DirectionalLight , SpotLight and in last i found this ReactAreaLight but still i don't achieve this type of light in my three.js scene.
You need to apply postprocessing. Try Effect Composer and BloomPass
//For adding additional effect an the top of rendering
function postprocessing() {
renderScene = new THREE.RenderPass(scene, camera);
effectFXAA = new THREE.ShaderPass(THREE.FXAAShader);
effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight);
var copyShader = new THREE.ShaderPass(THREE.CopyShader);
copyShader.renderToScreen = true;
bloomPass = new THREE.UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 0.5, 0.1, 0.85); //( resolution, strenght, radius, threshold));
composer = new THREE.EffectComposer(renderer);
composer.setSize(window.innerWidth, window.innerHeight);
composer.addPass(renderScene);
composer.addPass(effectFXAA);
composer.addPass(bloomPass);
composer.addPass(copyShader);
}
// start the render loop
function render() {
renderer.clear();
composer.render();
renderer.render(scene, camera);
composer.render();
}
Related
I have looked through stack overflow and google and I have found how to CENTER a text geometry but that is not what I want to do.
I have a scene that just has a block of text that says "Buy Here!". Using the documentation in the three.js website and examples here I was able to do that after some struggling. I had some trouble finding out how to refer to that mesh since I had created the geometry inside a function, and it took hours for me to know about setting a name for it as a string so it can be accessible from different parent/child levels.
What I am NOT able to do now is to offset the text by some arbitrary number of units. I tried shifting it down by 5 units. No matter how I try to do it it isn't working. I either manage to make the text geometry disappear OR my whole scene is black.
Here is my code...
I have the basic scene setup working properly and I'll include it here but feel free to skip since I'm pretty sure this has nothing to do with the issue...
import './style.css'
import * as THREE from 'three';
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three#0.117.0/examples/jsm/controls/OrbitControls.js';
import TWEEN from 'https://cdn.jsdelivr.net/npm/#tweenjs/tween.js#18.5.0/dist/tween.esm.js';
//BASIC SCENE SETUP
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
//LIGHTS (POINT AND AMBIENT)
const pointLight = new THREE.PointLight(0xFFFFFF);
pointLight.position.set(5, 5, 5);
const ambientLight = new THREE.AmbientLight(0xFFFFFF);
scene.add(pointLight, ambientLight);
//RESIZE WINDOW
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}, false);
//ORBIT CONTROLS
const controls = new OrbitControls(camera, renderer.domElement);
controls.minDistance = 5;
controls.maxDistance = 70;
controls.enablePan = false;
controls.enableRotate = false;
controls.enableZoom = false;
controls.target.set(0,0,-1);
camera.position.setZ(25);
window.addEventListener("click", (event) => {
onClick(event);
})
window.addEventListener("mousemove", onMouseMove);
var animate = function() {
requestAnimationFrame(animate);
controls.update();
render();
TWEEN.update();
};
function render() {
renderer.render(scene, camera);
}
animate();
and here is my code for the text object....
var loaderF = new THREE.FontLoader();
loaderF.load( 'https://threejs.org/examples/fonts/optimer_regular.typeface.json', function ( font ) {
var geometry = new THREE.TextGeometry( 'Buy Here!', {
font: font,
size: 2.3,
height: 0.1,
curveSegments: 15,
bevelEnabled: true,
bevelThickness: 0.5,
bevelSize: 0.31,
bevelSegments: 7
} );
geometry.center();
var material = new THREE.MeshLambertMaterial({color: 0x686868});
var mesh = new THREE.Mesh( geometry, material );
mesh.name = "bhText"
scene.add( mesh );
mesh.userData = { URL: "http://google.com"};
} );
Here's what I have tried.....
under "var geometry ({...});" I typed....
geometry.position.setX(-5);
but the text object disappears completely so I tried
geometry.position.setX = -5;
but there was no difference so i tried taking out
geometry.center();
but it had the same results.
So then I tried using
mesh.position.x = -5;
with AND without
geometry.center();
but again, they all just make my text object disappear.
So now I tried to set the position from outside the function by typing the following code OUTSIDE of everything that is contained in
loaderF.load ('https.....', function (font){var geometry = .....})
using the reference I learned....
scene.getObjectByName("bhText").position.x(-5);
but this makes my entire scene go blank (black). So I tried variations of like
scene.getObjectByName("bhText").position.x = -5;
scene.getObjectByName("bhText").position.setX(-5);
scene.getObjectByName("bhText").position.setX = -5;
mesh.position.setX = -5;// I was pretty sure this wasn't going to work since I wasn't
//using the mesh name specifically for when it's inside something
//I can't reach because of parent-child relations
and again trying each of those with AND without
geometry.center();
but they all made my scene go black.
I just wanna move it down a couple of units. Sheesh.
Could anyone be kind enough to tell me WHERE in my code I can set the position of the text geometry? Thank you please.
I just wanna move it down a couple of units.
In this case use mesh.position.y = - 5;. Changing the x coordinate will move the mesh to the left or right. Here is a complete live example based on your code:
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set( 0, 0, 10 );
const renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
const pointLight = new THREE.PointLight(0xFFFFFF);
pointLight.position.set(5, 5, 5);
const ambientLight = new THREE.AmbientLight(0xFFFFFF);
scene.add(pointLight, ambientLight);
const loader = new THREE.FontLoader();
loader.load('https://threejs.org/examples/fonts/optimer_regular.typeface.json', function(font) {
const geometry = new THREE.TextGeometry('Buy Here!', {
font: font,
size: 2,
height: 0.5
});
geometry.center();
const material = new THREE.MeshLambertMaterial({
color: 0x686868
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = - 1; // FIX
mesh.name = "bhText"
scene.add(mesh);
renderer.render(scene, camera);
});
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.130.1/build/three.min.js"></script>
I am working on 3D Modelling using Thrre.js , and have to display neat and clean product after reading a .DAE file but my product display is not well clean and good . Can anybody please help me , i have also given the light sources but still product shown are very dull .Actual product to be shown
My product image render screen shot , no leather is shown in product and also very dull
I am trying following Code :
<script>
var renderer, scene, camera, controls, light;
var geometry, material, mesh;
init();
animate();
function init() {
document.body.style.cssText = 'margin: 0; overflow: hidden' ;
renderer = new THREE.WebGLRenderer( { alpha: 1, antialias: true, clearColor: 0xffffff } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 50000 );
camera.position.set( 100, 100, 100 );
//camera.position.set(-15, 10, 15);
controls = new THREE.TrackballControls( camera, renderer.domElement );
scene.add(camera);
light = new THREE.AmbientLight(0xffffff, 10);
light.position.set(100,100, 100).normalize();
scene.add(light);
light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(10, 10, 10).normalize();
scene.add(light);
var pointlight = new THREE.PointLight(0xffffff, 1, 0);
pointlight.position.set(50, 100, 50)
camera.add(pointlight);
scene.add(pointlight);
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(10,10,10);
scene.add(spotLight);
var pointHelper = new THREE.PointLightHelper(pointlight, 0.1);
scene.add(pointHelper);
this.renderer.render(this.scene, this.camera);
geometry = new THREE.BoxGeometry( 10, 10, 10 );
material = new THREE.MeshLambertMaterial( { ambient: 0x333333, color: 0x888888, opacity: 0.000001, transparent: true } );
// material = new THREE.MeshLambertMaterial({ color: 0xffffff, vertexColors: THREE.FaceColors });
mesh = new THREE.Mesh( geometry, material );
mesh.name = 'basic template mesh';
mesh.visible = false;
scene.add( mesh );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
controls.update();
}``
Through this code , i got the very dull product.
Can Anyone Please help me to sort out this problem ?
You are using the wrong material. The MeshLambertMaterial is used for diffuse surfaces, those that do not have specular highlights (paper, raw wood, cloth). You need to use the MeshPhongMaterial which allows the specular highlights (white spots) in the chair.
In your model, you have two types of surface: leather and wood. Even though both of them have specular highlights, their shininess are different. You will have to define separate materials for both surfaces. But, since I see you have a single object, this can be difficult. You can define a single MeshPhongMaterial for both surfaces, but you will have to try several values in the parameters to get the desired effect.
I would like to animate a bezier curve in ThreeJS. The start, end and control points will update. Eventually I will need to have many curves animating at once. What's the most efficient way to do this?
If you run the code snippet below, you'll see that I'm creating the Bezier object, Geometry and Line each time the frame renders. I'm removing the previous line from the scene and then adding the new, updated line. Is there a better way? Perhaps updating only the geometry and not adding the line again?
var camera, scene, renderer, geometry, material, mesh;
init();
animate();
/**
Create the scene, camera, renderer
*/
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 500;
scene.add(camera);
addCurve();
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
/**
Add the initial bezier curve to the scene
*/
function addCurve() {
testPoint = 0;
curve = new THREE.CubicBezierCurve3(
new THREE.Vector3( testPoint, 0, 0 ),
new THREE.Vector3( -5, 150, 0 ),
new THREE.Vector3( 20, 150, 0 ),
new THREE.Vector3( 10, 0, 0 )
);
curveGeometry = new THREE.Geometry();
curveGeometry.vertices = curve.getPoints( 50 );
curveMaterial = new THREE.LineBasicMaterial( { color : 0xff0000 } );
curveLine = new THREE.Line( curveGeometry, curveMaterial );
scene.add(curveLine);
}
/**
On each frame render, remove the old line, create new curve, geometry and add the new line
*/
function updateCurve() {
testPoint ++;
scene.remove(curveLine);
curve = new THREE.CubicBezierCurve3(
new THREE.Vector3( testPoint, 0, 0 ),
new THREE.Vector3( -5, 150, 0 ),
new THREE.Vector3( 20, 150, 0 ),
new THREE.Vector3( 10, 0, 0 )
);
curveGeometry = new THREE.Geometry();
curveGeometry.vertices = curve.getPoints( 50 );
curveLine = new THREE.Line( curveGeometry, curveMaterial );
scene.add(curveLine);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
updateCurve();
renderer.render(scene, camera);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.min.js"></script>
Creating new lines per each frame is very exepnsive opertation.
What is that the best way to create animated curves?
Probably using shaders. But it can take much more time to implement, so if my next suggestions will be enough for you, just them.
Improve curve updating in your code
I tried not to change a lot of your code. Marked edited places with "// EDITED" comment. I added an array cause you said that there will be many curves.
Explanation
As #WestLangley said, try to avoid using new keyword inside animation loop.
CubicBezierCurve3 has v0, v1, v2 and v3 attributes. Those are THREE.Vector3`s that you provide from the beginning. .getPoints() uses them to return you vertices array. So you can simply change them and no new keyword is needed. See this line for more details.
Rather then recreating line, in your case you can simply update geometry. As you have a THREE.Line - your geometry only needs vertices. After changing vertices you should set geometry.verticesNeedUpdate = true or Three.js will ignore your changes.
var camera, scene, renderer, geometry, material, mesh, curves = [];
init();
animate();
/**
Create the scene, camera, renderer
*/
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 500;
scene.add(camera);
addCurve();
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
/**
Add the initial bezier curve to the scene
*/
function addCurve() {
testPoint = 0;
curve = new THREE.CubicBezierCurve3(
new THREE.Vector3( testPoint, 0, 0 ),
new THREE.Vector3( -5, 150, 0 ),
new THREE.Vector3( 20, 150, 0 ),
new THREE.Vector3( 10, 0, 0 )
);
curveGeometry = new THREE.Geometry();
curveGeometry.vertices = curve.getPoints( 50 );
curveMaterial = new THREE.LineBasicMaterial( { color : 0xff0000 } );
curveLine = new THREE.Line( curveGeometry, curveMaterial );
scene.add(curveLine);
// EDITED
curves.push(curveLine); // Add curve to curves array
curveLine.curve = curve; // Link curve object to this curveLine
}
/**
On each frame render, remove the old line, create new curve, geometry and add the new line
*/
function updateCurve() {
testPoint ++;
// EDITED
for (var i = 0, l = curves.length; i < l; i++) {
var curveLine = curves[i];
// Update x value of v0 vector
curveLine.curve.v0.x = testPoint;
// Update vertices
curveLine.geometry.vertices = curveLine.curve.getPoints( 50 );
// Let's three.js know that vertices are changed
curveLine.geometry.verticesNeedUpdate = true;
}
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
updateCurve();
renderer.render(scene, camera);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.min.js"></script>
I'm very new to Three.JS and 3D web dev in general what I'm trying to do is mimic this action: https://www.youtube.com/watch?v=HWSTxPc8npk&feature=youtu.be&t=7s Essentially this is a set of 3D planes and upon click the whole stack reacts and gives space around the one that's clicked.
For now, my base case is 3 planes and figuring first out if I can click the the middle one, how do I get the others to jump back smoothly as if they were pushed rather than instant appear and disappear as they do now on the click of a button.
The long term goal is to have a separate button for every plane so that on click, the selected plane will have padding around it and the rest of the planes in stack move accordingly.
I've looked into Tween.js, and CSS3D but pretty overwhelmed as a newbie. Any tutorials or tips would be greatly appreciated!
// Our Javascript will go here.
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
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.PlaneGeometry( 3, 3, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var plane = new THREE.Mesh( geometry, material );
plane.rotation.y = -.7;
var material2 = new THREE.MeshBasicMaterial( { color: 0x0000ff } );
var material3 = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
var plane2 = new THREE.Mesh(geometry, material2 );
plane2.rotation.y = -.7;
plane2.position.x = 1;
var plane3 = new THREE.Mesh(geometry, material3);
plane3.rotation.y = -.7;
plane3.position.x = -1;
scene.add( plane, plane2, plane3 );
camera.position.z = 5;
function render() {
requestAnimationFrame( render );
// cube.rotation.x += 0.1;
// cube.rotation.y += 0.1;
renderer.render( scene, camera );
}
render();
function clickFirst() {
TWEEN.removeAll();
var tween = new TWEEN.Tween(plane3.position).to({x: -2}, 1000).start();
tween.easing(TWEEN.Easing.Elastic.InOut);
render();
}
</script>
<button onclick="clickFirst();" style="background-color: white; z-index: 9999;">Click me</button>
First, you need to locate the 2 planes.
Second, you need to make the planes clickable:
https://threejs.org/examples/#webgl_interactive_cubes
https://github.com/josdirksen/learning-threejs/blob/master/chapter-09/02-selecting-objects.html
Third, you should use Tween.js for the transition.
after picking the right plane, make a tween for the other planes with a tween, all to move on the same Axis:
example:
createjs.Tween.get(plane3.position.z).to(
plane3.position.z + 100
, 1000, createjs.Ease.cubicOut)
If you will add some code here after starting to implement i would be able to help more.
I am trying to replicate the functionality of Google's Cardboard Demo "Exhibit" with three.js. I took the starting example straight from the Chrome Experiments web page and just dropped in code to draw a simple triangular pyramid in the init method:
function init() {
renderer = new THREE.WebGLRenderer();
element = renderer.domElement;
container = document.getElementById('example');
container.appendChild(element);
effect = new THREE.StereoEffect(renderer);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(90, 1, 0.001, 700);
camera.position.set(0, 0, 50);
scene.add(camera);
controls = new THREE.OrbitControls(camera, element);
controls.rotateUp(Math.PI / 4);
controls.noZoom = true;
controls.noPan = true;
var geometry = new THREE.CylinderGeometry( 0, 10, 30, 4, 1 );
var material = new THREE.MeshPhongMaterial( { color:0xffffff, shading: THREE.FlatShading } );
var mesh = new THREE.Mesh( geometry, material );
mesh.updateMatrix();
mesh.matrixAutoUpdate = false;
scene.add( mesh );
var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 1, 1, 1 );
scene.add( light );
light = new THREE.DirectionalLight( 0x002288 );
light.position.set( -1, -1, -1 );
scene.add( light );
light = new THREE.AmbientLight( 0x222222 );
scene.add( light );
function setOrientationControls(e) {
if (!e.alpha) {
return;
}
controls = new THREE.DeviceOrientationControls(camera);
controls.connect();
controls.update();
element.addEventListener('click', fullscreen, false);
window.removeEventListener('deviceorientation', setOrientationControls, true);
}
window.addEventListener('deviceorientation', setOrientationControls, true);
window.addEventListener('resize', resize, false);
setTimeout(resize, 1);
}
The OrbitControls method on desktop works perfectly: by dragging with the mouse, the screen orbits around the pyramid. On mobile using DeviceOrientationControls however, this effect is entirely lost and instead the camera moves freely at (0, 0, 0). I tried doing as a previous question suggested and replacing the camera with scene such that:
controls = new THREE.DeviceOrientationControls(scene);
however this does not work at all and nothing moves when the device is rotated. What do I need to change to replicate OrbitControls behavior with the motion captured by DeviceOrientationControls?
To create a deviceorientation orbit controler, like you see on this demo, http://novak.us/labs/UmDemo/; It involves modifying the existing OrbitControls.js.
The file changes can be seen in this commit on github: https://github.com/snovak/three.js/commit/f6542ab3d95b1c746ab4d39ab5d3253720830dd3
I've been meaning to do a pull request for months. Just haven't gotten around to it. Needs a bunch of clean up.
You can download my modified OrbitControls.js here (I haven't merged in months either, results may vary): https://raw.githubusercontent.com/snovak/three.js/master/examples/js/controls/OrbitControls.js
Below is how you would implement the modified OrbitControls in your own scripts:
this.controls = new THREE.OrbitControls( camera, document.getElementById('screen') ) ;
controls.tiltEnabled = true ; // default is false. You need to turn this on to control with the gyro sensor.
controls.minPolarAngle = Math.PI * 0.4; // radians
controls.maxPolarAngle = Math.PI * 0.6; // radians
controls.noZoom = true ;
// How far you can rotate on the horizontal axis, upper and lower limits.
// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
controls.minAzimuthAngle = - Math.PI * 0.1; // radians
controls.maxAzimuthAngle = Math.PI * 0.1; // radians
this.UMLogo = scene.children[1];
controls.target = UMLogo.position;
I hope that gets you where you want to be! :-)
To use the DeviceOrientationControls You must call controls.update() during your animation loop or the control will not update it's position based on device info.