Three.js Unculled SkyBox - three.js

I am attempting to have my skybox not be affected by the camera.far parameter. I would like to cull all other scene objects with this just not the skybox.
When I set skyBox.frustumCulled = false; it makes no difference. skyBox being the mesh of course.
Is this done by adding another render pass? If so I would need 2 different cameras one with a really high far value to allow viewing of the skybox right? How can this be done efficiently?
For clarity here is the snippet from my terrain object code used for drawing the skybox:
shader = THREE.ShaderLib["cube"];
shader.uniforms["tCube"].value = this.cubetexture;
mat = new THREE.ShaderMaterial({
uniforms: shader.uniforms,
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader,
depthWrite: false,
side: THREE.BackSide
});
geo = new THREE.BufferGeometry().fromGeometry(new THREE.BoxGeometry(1024, 1024, 1024));
mesh = new THREE.Mesh(geo, mat);
mesh.rotation.y += 90;
mesh.scale.x = mesh.scale.y = mesh.scale.z = 50;
mesh.frustumCulled = false;
mesh.matrixAutoUpdate = false;
mesh.rotationAutoUpdate = false;
mesh.updateMatrix();
this.skybox = mesh;
scene.add(this.skybox);

You're adding a skybox in the 'main' scene. A better way to accomplish a skydome would be to create a new scene. this will be the 'background' to your 'main' scene. There's also a discussion about skydomes v.s. skyboxes, simply put, a box saves polys, a dome looks better. in this example i'll be using a dome/sphere.
var renderer = new THREE.WebGLRenderer( {alpha: true, antialias: true} );
var mainScene = new THREE.Scene();
var mainCamera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 20000 );
var skydome = {
scene: new THREE.Scene(),
camera: new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 20000 );
};
skydome.material = new THREE.MeshBasicMaterial({color: 0x0F0F0F}) //the material for the skydome, for sake of lazyness i took a MeshBasicMaterial.
skydome.mesh = new THREE.Mesh(new THREE.SphereGeometry(100, 20, 20), skydome.material);
skydome.scene.add(skydome.mesh);
now, during the render function you adjust only the rotation of the skydome camera, not the position.
var render = function(){
requestAnimationFrame( render );
skydome.camera.quaternion = mainCamera.quaternion;
renderer.render(skydome.scene, skydome.camera); //first render the skydome
renderer.render(mainScene, mainCamera);//then render the rest over the skydome
};
renderer.autoclear = false; //otherwise only the main scene will be rendered.

Related

Mixing Phong and PBR materials in three.js

I have an application that includes meshes rendered with MeshPhongMaterials. They work well with the full suite of lights available in three.js.
However, I want to combine them with imported GLB/GLTF models. In order to have the models lit, I believe I must use an environment map such as the following:
function _Environment() {
const env_scene = new THREE.Scene();
const roomMaterial = new THREE.MeshStandardMaterial( { side: THREE.BackSide } );
const room = new THREE.Mesh( new THREE.BoxGeometry(), roomMaterial );
room.position.set( 0, 0, 0 );
room.scale.set( 40, 40, 40 );
env_scene.add( room );
const env_alight = new THREE.AmbientLight(0xFFFFFF, .1);
env_scene.add(env_alight);
return env_scene;
}
function main() {
canvas = document.getElementById('c');
renderer = new THREE.WebGLRenderer({canvas: canvas, antialias: true});
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.outputEncoding = THREE.sRGBEncoding;
const aspect = 4/3; // the canvas default
camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(5, 0, 2);
camera.up.set(0,1,0);
camera.lookAt(new THREE.Vector3());
camera.updateProjectionMatrix()
const environment = new _Environment();
const pmremGenerator = new THREE.PMREMGenerator(renderer);
scene = new THREE.Scene();
scene.background = new THREE.Color(DefaultBackgroundColor);
scene.environment = pmremGenerator.fromScene(environment).texture;
dlight = new THREE.DirectionalLight(0xFFFFFF, .7);
dlight.position.set(5, 5, 10);
dlight.target.position.set(0, 0, 0);
scene.add(dlight);
scene.add(dlight.target);
alight = new THREE.AmbientLight(0xFFFFFF, .3);
scene.add(alight);
requestAnimationFrame(render);
}
However, it seems that the environment map causes the Phong materials to show up saturated and I cannot find a good combination of lights that work.
One can always convert everything to PBR, but am I missing something? Can Phong and PBR co-exist in a well lit, natural looking scene?

Three.js self transparency, object should not be see through

Codepen demonstrating the problem
https://codepen.io/anon/pen/GjJpYw?editors=0010
I have 2 meshes, one which contains 2 cubes, and the other which is 1 cube. The mesh with 2 cubes sandwiches the mesh with one cube (so the single cube is in the center). When I set all cubes to transparent but set the opacity of the center cube to 1, I would not expect to be able to see the back cube when looking through the front cube but I can.
I was wondering is there any easy way to fix this? This is a very simplified version of the problem I'm facing so I can't easily split the geometries. I also cannot just set transparent to false since ideally I would like to be able to have the middle cube partially transparent as well. Any suggestions?
var width = window.innerWidth;
var height = window.innerHeight;
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
var scene = new THREE.Scene();
var cubeGeometry = new THREE.CubeGeometry(100, 100, 100);
var cube = new THREE.Mesh(cubeGeometry);
cube.position.set(0, 25, -200);
var cube2 = new THREE.Mesh(cubeGeometry);
cube2.position.set(0, -25, 200);
cube.updateMatrix();
cube2.updateMatrix();
var singleGeometry = new THREE.Geometry();
singleGeometry.merge(cube.geometry, cube.matrix);
singleGeometry.merge(cube2.geometry, cube2.matrix);
var combinedMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, opacity: 0.5, transparent: true});
var mesh = new THREE.Mesh(singleGeometry, combinedMaterial);
var cubeGeometry = new THREE.CubeGeometry(200, 200, 200);
var cubeMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff, opacity: 0.8, transparent: true});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);
scene.add(mesh);
var camera = new THREE.PerspectiveCamera(60, width / height, 1, 1000);
camera.position.z = 500;
var controls = new THREE.OrbitControls(camera);
controls.addEventListener('change', render);
var pointLight = new THREE.PointLight(0xffffff);
pointLight.position.set(0, 300, 200);
scene.add(pointLight);
render();
animate();
function animate() {
requestAnimationFrame( animate );
controls.update();
}
function render() {
renderer.render( scene, camera );
}

ThreeJS Texture is pixelated when seen from distance

I was playing with webGL and ThreeJS, then I've got the following issue:
Textures with large images gets pixelated when seen from distance.
Check the example: http://jsfiddle.net/4qTR3/1/
Below is the code:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 10, 7000);
var light = new THREE.PointLight(0xffffff);
light.position.set(0, 150, 100);
scene.add(light);
var light2 = new THREE.AmbientLight(0x444444);
scene.add(light2);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.PlaneGeometry(500, 500, 10, 10);
//I use different textures in my project
var texture = new THREE.ImageUtils.loadTexture(TEST_IMAGE);
var textureBack = new THREE.ImageUtils.loadTexture(TEST_IMAGE);
textureBack.anisotropy = renderer.getMaxAnisotropy();
texture.anisotropy = renderer.getMaxAnisotropy();
//Filters
texture.magFilter = THREE.NearestFilter;
texture.minFilter = THREE.LinearMipMapLinearFilter;
textureBack.magFilter = THREE.NearestFilter;
textureBack.minFilter = THREE.LinearMipMapLinearFilter;
var materials = [
new THREE.MeshLambertMaterial({
transparent: true,
map: texture,
side: THREE.FrontSide
}),
new THREE.MeshLambertMaterial({
transparent: true,
map: textureBack,
side: THREE.BackSide
})];
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));
}
planeObject = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materials));
planeObject.overdraw = true;
planeObject.position.z = -5000;
scene.add(planeObject);
camera.position.z = 1000;
(function render() {
requestAnimationFrame(render);
planeObject.rotation.y += 0.02;
renderer.render(scene, camera);
})();
If the image of the texture has got text in it, the text becomes very pixelated with poor quality.
How can I fix this?
In order to not get pixelated you need to use mips but WebGL can't generate mips for non-power-of-2 textures. Your texture is 800x533, neither of those is a power of 2.
a couple of options
1) Scale the picture offline to powers of 2 like 512x512 or 1024x512
2) Scale the picture at runtime before making a texture.
Load the image yourself, once loaded make a canvas that is power-of-2. call drawImage(img, 0, 0, canvas.width, canvas.height) to scale the image into the canvas. Then load the canvas into a texture.
You also probably want to change your mag filtering from NearestFilter to LinearFilter.
Note: (1) is the better option. (2) takes time on the user's machine, uses more memory, and you have no guarantee what the quality of the scaling will be.
Example here.

Three.js not showing my texture

I need to make a ball with a texture on it. I'm very new at WebGL and Three.js. The problem is that I see a White Sphere but not the texture on it. As a new user I am not able to submit a picture.
The code part is this:
function init() {
canvas = document.getElementById( 'canvas' );
camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 1000;
scene = new THREE.Scene();
camera.lookAt (scene.position);
var llum = new THREE.DirectionalLight();
llum.intensity=50;
llum.position.x=camera.position.x;
llum.position.y=camera.position.y;
llum.position.z=camera.position.z;
llum.lookAt(scene.position);
scene.add(llum);
var texture = THREE.ImageUtils.loadTexture('ull.jpg');
texture.needsUpdate = true;
var material = new THREE.MeshBasicMaterial( texture );
var quality = 16, step = 1024 / quality;
var geom = new THREE.SphereGeometry(500,100,100);
mesh = new THREE.Mesh( geom, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer({ antialias: true});
renderer.setSize( window.innerWidth, window.innerHeight );
canvas.innerHTML = "";
//Afegim al canvas el que hem de renderitzar
canvas.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
window.addEventListener( 'resize', onWindowResize, false );
}
Thanks in advance.
It should be like this:
var material = new THREE.MeshBasicMaterial( { map: texture } );
Since this is the first page that shows up in Google search results I will post what was solution in my case. I draw texture on square but the square was actually rotated backward so camera saw back of the square without texture, after fixing rotation everything worked fine.
var geometry = new THREE.PlaneGeometry(FLOOR_SIZE, FLOOR_SIZE, 10, 10);
var loader = new THREE.TextureLoader();
loader.load('images/floor.jpg', function ( texture ) {
var material = new THREE.MeshBasicMaterial({
map: texture,
overdraw: 0.5
});
var floor = new THREE.Mesh( geometry, material );
// ROTATION THAT MADE SQUARE INVISIBLE WAS Math.PI/2
floor.rotation.x = -Math.PI/2;
floor.position.y = -0.1;
scene.add(floor);
});

How to change width of CubeGeometry with Three.js?

I have a cube geometry and a mesh, and i don't know how to change the width (or height... i can change x, y and z though).
Here's a snippet of what i have right now:
geometry = new THREE.CubeGeometry( 200, 200, 200 );
material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } );
mesh = new THREE.Mesh( geometry, material );
// WebGL renderer here
function render(){
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
renderer.render( scene, camera );
}
function changeStuff(){
mesh.geometry.width = 500; //Doesn't work.
mesh.width = 500; // Doesn't work.
geometry.width = 500; //Doesn't work.
mesh.position.x = 500// Works!!
render();
}
Thanks!
EDIT
Found a solution:
mesh.scale.x = 500;
Just to complete comment and solution from question (and have an answer present with example code):
// create a cube, 1 unit for width, height, depth
var geometry = new THREE.CubeGeometry(1,1,1);
// each cube side gets another color
var cubeMaterials = [
new THREE.MeshBasicMaterial({color:0x33AA55, transparent:true, opacity:0.8}),
new THREE.MeshBasicMaterial({color:0x55CC00, transparent:true, opacity:0.8}),
new THREE.MeshBasicMaterial({color:0x000000, transparent:true, opacity:0.8}),
new THREE.MeshBasicMaterial({color:0x000000, transparent:true, opacity:0.8}),
new THREE.MeshBasicMaterial({color:0x0000FF, transparent:true, opacity:0.8}),
new THREE.MeshBasicMaterial({color:0x5555AA, transparent:true, opacity:0.8}),
];
// create a MeshFaceMaterial, allows cube to have different materials on each face
var cubeMaterial = new THREE.MeshFaceMaterial(cubeMaterials);
var cube = new THREE.Mesh(geometry, cubeMaterial);
cube.position.set(0,0,0);
scene.add( cube );
cube.scale.x = 2.5; // SCALE
cube.scale.y = 2.5; // SCALE
cube.scale.z = 2.5; // SCALE
A slightly advanced, dynamic example (still the same scaling) implemented here:
You can dispose the geometry of cube and affect the new one like this :
let new_geometry = new THREE.CubeGeometry(500,200,200);
geometry.dispose();
cube.geometry = new_geometry;
Scale properties can be used to for changing width, height and and depth of cube.
//creating a cube
var geometry = new THREE.BoxGeometry(1,1,1);
var material = new THREE.MeshBasicMaterial({color:"white"});
var cube = new THREE.Mesh(geometry, material);
//changing size of cube which is created.
cube.scale.x = 30;
cube.scale.y = 30;
cube.scale.z = 30;

Resources