I am completely new to Three.JS and cant seem to get my head around getting a skybox to appear in my scene. I'm not getting any errors from my code, which has left me stumped. Any help would be greatly appreciated.
function createSky(){
var imageList = "CubeMap"
THREE.ImageUtils.crossOrigin = '';
var faces = ["HDR0001",
"HDR0002",
"HDR0003",
"HDR0004",
"HDR0005"];
var imgType = ".jpg";
var skyGeo = new THREE.CubeGeometry (500, 500, 500);
var matFacesArray = [];
for (var i = 0; i < 6; i++) {
matFacesArray.push( new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture( imageList + faces[i] + imgType ),
side: THREE.BackSide
}));
}
var sky = new THREE.MeshFaceMaterial ( matFacesArray );
var skyBox = new THREE.Mesh ( skyGeo, sky );
scene.add ( skyBox );
}
Where are you watching your log for warnings/errors?
Seems strange you are not getting any feedback since THREE.ImageUtils.loadTexture is deprecated, use TextureLoader.load instead, this warning should show up if you are using a somewhat later version of three js.
Also, what browser are you using? I find that Firefox is usually a bit more generous with showing textures than Chrome for example. This has to do with cross-origin image load and can be a problem when you try to run your code locally.
Related
I'm using Three.js in a website project for a construction company. They want some 360° photos (photospheres) that I made using my phone (Google pixel 5). They also want to show a 3D representation of one of their projects so using Three.js seems to be the best solution.
Here is what it looks like in Google Photos:
Google Photos screenshot
And what it looks like in Three.js:
Three.js screenshot
You can see the colors are really bad (contrast, white balance, idk) compared to the original version.
It's the first time I use Three.js so here is my code:
Scene:
async connectedCallback() {
// Scene
this.scene = new THREE.Scene();
// Background equirectangular texture
const background_img = this.getAttribute('background');
if (background_img) this.loadBackground(background_img);
// Camera
this.camera = new THREE.PerspectiveCamera(60, this.clientWidth / this.clientHeight, 1, 5000);
// Lights
// this.scene.add(new THREE.HemisphereLight(0xffeeb1, 0x080820, 0));
const spotLight = new THREE.SpotLight(0xffa95c, 5);
spotLight.position.set(20, 20, 20);
spotLight.castShadow = true;
spotLight.shadow.bias = -0.0001;
spotLight.shadow.mapSize.width = 1024 * 4;
spotLight.shadow.mapSize.height = 1024 * 4;
this.scene.add(spotLight);
// Renderer
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.toneMapping = THREE.ReinhardToneMapping;
this.renderer.toneMappingExposure = 2.3;
this.renderer.shadowMap.enabled = true;
this.renderer.setPixelRatio(devicePixelRatio);
this.renderer.setSize(this.clientWidth, this.clientHeight);
this.appendChild(this.renderer.domElement);
// Orbit controls
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.controls.autoRotate = true;
// Resize event
addEventListener('resize', e => this.resize());
// Load model
const url = this.getAttribute('model');
if (url) this.loadModel(url);
// Animate
this.resize();
this.animate();
// Resize again in .1s
setTimeout(() => this.resize(), 100);
// Init observer
new IntersectionObserver(entries => this.classList.toggle('visible', entries[0].isIntersecting), { threshold: 0.1 }).observe(this);
}
Background (photosphere):
loadBackground(src) {
const equirectangular = new THREE.TextureLoader().load(src);
equirectangular.mapping = THREE.EquirectangularReflectionMapping;
// Things Github Copilot suggested, removing it does not change colors so I thing it's not the problem
equirectangular.magFilter = THREE.LinearFilter;
equirectangular.minFilter = THREE.LinearMipMapLinearFilter;
equirectangular.format = THREE.RGBFormat;
equirectangular.encoding = THREE.sRGBEncoding;
equirectangular.anisotropy = 16;
this.scene.background = equirectangular;
}
As Marquizzo said in a comment:
You’re changing the renderer’s tone mapping and the exposure. It’s normal for the results to be different when you make modifications to the color output.
I kept saying the problem is not the lines Github Copilot suggested because I got the same result when removing those but I tried removing one line at a time and it turns out that this line was the problem:
equirectangular.format = THREE.RGBFormat;
Now my result is a bit dark compared to Google Photos's one but the colors are finally accurate! I still have a lot of things to learn haha.
Three.js screenshot after removing the problematic line
Thank you Marquizzo!
i wanted to ask if there is a simple solution to preload Textures and Images in ThreeJs.
I load them all into an array: myTextureArray.push(new THREE.ImageUtils.loadTexture('../textures/floor_red.jpg');
How can i check if and when all Textures are loaded successfully ?
Here is an older Version Link: http://museum.baraq.de/
Thanks for help!
There is a Loading Manager in Three.js you can use to keep track of your loaded Textures or Objects.
Example implementation:
var textureManager = new THREE.LoadingManager();
textureManager.onProgress = function ( item, loaded, total ) {
// this gets called after any item has been loaded
};
textureManager.onLoad = function () {
// all textures are loaded
// ...
};
var textureLoader = new THREE.ImageLoader( textureManager );
var myTextureArray = [];
var myTexture = new THREE.Texture();
myTextureArray.push( myTexture );
textureLoader.load( 'my/texture.jpg', function ( image ) {
myTexture.image = image;
} );
Tested in Three.js r71.
I want to use Three.js (OGL + JavaScript) to load an object from file. I have an working example without loading it (some basic elements rendered). But when I try to load object using JSONLoader.load(...), Firefox console shows error:
SyntaxError: missing formal parameter
The reference: http://threejs.org/docs/#Reference/Loaders/JSONLoader
The source code for my added fragment (loading object), which cause an error:
//loading an object
var loader = new THREE.JSONLoader(); //works so far
loader.load("./Project2/proj/grzyb.js",
function(geometry,
new THREE.MeshLambertMaterial( { map: texture, ambient: 0xbbbbbb } )
//for the line above, in Firefox console i get
//"SyntaxError: missing formal parameter"
){
var materials = new THREE.MeshFaceMaterial(
new THREE.MeshLambertMaterial( { map: texture, ambient: 0xbbbbbb } )
);
grzyb = new THREE.Mesh(geometry, materials);
grzyb.scale.set(5, 5, 5);
grzyb.position.set(2,2,2);
grzyb.receiveShadow = true;
grzyb.castShadow = true;
scene.add(grzyb);
}
);
You are trying to insert MeshLambertMaterial creation into a function header definition. Function header can only contain parameter names - not any actual code to create them.
Also it is not clear whether you want to use material coming from model file or your own material with texture that you loaded elsewhere (in the example there is no code that would set texture variable). Assuming you want to use materials from model, your code should look like this:
var loader = new THREE.JSONLoader(); //works so far
loader.load("./Project2/proj/grzyb.js",
function(geometry, materials) {
var material = new THREE.MeshFaceMaterial( materials );
grzyb = new THREE.Mesh(geometry, material);
grzyb.scale.set(5, 5, 5);
grzyb.position.set(2,2,2);
grzyb.receiveShadow = true;
grzyb.castShadow = true;
scene.add(grzyb);
}
);
if you want to use different material, then set material variable to anything you want. exmaple:
var texture = THREE.ImageUtils.LoadTexture( "../path/image.jpg" );
var material = new THREE.MeshBasicMaterial( { map:texture } );
var grzyb = new THREE.Mesh(geometry, material);
I'm using three.js to create a minecraft texture editor, similar to this. I'm just trying to get the basic click-and-paint functionality down, but I can't seem to figure it out. I currently have textures for each face of each cube and apply them by making shader materials with the following functions.
this.createBodyShaderTexture = function(part, update)
{
sides = ['left', 'right', 'top', 'bottom', 'front', 'back'];
images = [];
for (i = 0; i < sides.length; i++)
{
images[i] = 'img/'+part+'/'+sides[i]+'.png';
}
texCube = new THREE.ImageUtils.loadTextureCube(images);
texCube.magFilter = THREE.NearestFilter;
texCube.minFilter = THREE.LinearMipMapLinearFilter;
if (update)
{
texCube.needsUpdate = true;
console.log(texCube);
}
return texCube;
}
this.createBodyShaderMaterial = function(part, update)
{
shader = THREE.ShaderLib['cube'];
shader.uniforms['tCube'].value = this.createBodyShaderTexture(part, update);
shader.fragmentShader = document.getElementById("fshader").innerHTML;
shader.vertexShader = document.getElementById("vshader").innerHTML;
material = new THREE.ShaderMaterial({fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: shader.uniforms});
return material;
}
SkinApp.prototype.onClick =
function(event)
{
event.preventDefault();
this.change(); //makes texture file a simple red square for testing
this.avatar.remove(this.HEAD);
this.HEAD = new THREE.Mesh(new THREE.CubeGeometry(8, 8, 8), this.createBodyShaderMaterial('head', false));
this.HEAD.position.y = 10;
this.avatar.add(this.HEAD);
this.HEAD.material.needsUpdate = true;
this.HEAD.dynamic = true;
}
Then, when the user clicks any where on the mesh, the texture file itself is update using canvas. The update occurs, but the change isn't showing up in the browser unless the page is refreshed. I've found plenty of examples of how to change the texture image to a new file, but not on how to show changes in the same texture file during runtime, or even if it's possible. Is this possible, and if not what alternatives are there?
When you update a texture, whether its based on canvas, video or loaded externally, you need to set the following property on the texture to true:
If an object is created like this:
var canvas = document.createElement("canvas");
var canvasMap = new THREE.Texture(canvas)
var mat = new THREE.MeshPhongMaterial();
mat.map = canvasMap;
var mesh = new THREE.Mesh(geom,mat);
After the texture has been changed, set the following to true:
cube.material.map.needsUpdate = true;
And next time you render the scene it'll show the new texture.
Here is all the basics of what you have to know about "updating" stuff in three.js: https://threejs.org/docs/#manual/introduction/How-to-update-things
Hi I am trying to do what seems like simple shading with threejs. I am using the Up and Running book by O'reilly.
Everything was working fine, until I tried to do this:
var shader = THREE.ShaderLib["normal"];
var uniforms = THREE.UniformsUtils.clone(shader.uniforms);
uniforms["tNormal"].texture = normalMap;
uniforms["tDiffuse"].texture = surfaceMap;
uniforms["tSpecular"].texture = specularMap;
This keeps throwing this error:
TypeError: uniforms.normal is undefined
[Break On This Error]
uniforms["normal"].texture = normalMap;
I have been looking around online for a while and am not sure what syntax needs to change to solve this issue.
Any help is appreciated.
I think that should be like:
uniforms["tNormal"] = {
texture: normalMap
};
Same for tDiffuse, tSpecular.
I find that when running your code, after the lines:
var shader = THREE.ShaderLib["normal"];
var uniforms = THREE.UniformsUtils.clone(shader.uniforms);
uniforms is an object with one member: opacity. Thus uniforms["tNormal"] does not yet exist. As Olivia suggested, you could add these in using:
uniforms["tNormal"] = {
texture: normalMap
};
Your error and your code are different. The error reports undefined texture on:
uniforms["normal"].texture = normalMap;
The code you cited says you're using:
uniforms["tNormal"].texture = normalMap;.
I'm working on the same book examples, try this:
var shader = THREE.ShaderLib[ "normalmap" ];
var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
uniforms[ "tNormal" ].texture = normalMap;
uniforms[ "tDiffuse" ].texture = surfaceMap;
uniforms[ "tSpecular" ].texture = specularMap;
uniforms[ "enableDiffuse" ].value = true;
uniforms[ "enableSpecular" ].value = true;