three.js gltf model becomes grey and textureless, after changing texture - three.js

hey guys i am new to three.js and i am trying to change my texture using Meshmatcap material. however, i am facing an issue where i change the texture, my model texture and color would disappear after adding skinning: true , which is necessary for my model to retain size . is there any way to solve this issue? thanks in advance. currently using the model from https://sketchfab.com/3d-models/tyrannosaurus-rex-9d3a3e42c0054c35aa39c3ee07388d16
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>3d model</title>
</head>
<body>
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three#0.114/build/three.module.js';
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three#0.114/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/three#0.114/examples/jsm/loaders/GLTFLoader.js';
import { RGBELoader } from 'https://cdn.jsdelivr.net/npm/three#0.114/examples/jsm/loaders/RGBELoader.js';
var container, controls;
var camera, scene, renderer, mixer, clock;
var obj , material , texture , mesh
init();
animate();
function init() {
container = document.getElementById( 'test' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.01, 1000 );
camera.position.x = 0
camera.position.y = 2
camera.position.z = 10
scene = new THREE.Scene();
// scene.background = new THREE.Color(0xffffff);
var light = new THREE.HemisphereLight(0xffffff,0x000000,10);
scene.add(light);
clock = new THREE.Clock();
var loader = new GLTFLoader();
// Load a glTF resource
loader.load('scene.gltf', function ( gltf ) {
var textureLoader = new THREE.TextureLoader();
mesh = gltf.scene.children[0]
console.log(mesh)
var texture = textureLoader.load('blue1.jpg');
// texture.minFilter = THREE.LinearFilter;
var matcapMaterial = new THREE.MeshMatcapMaterial({ skinning: true ,normalMap: texture })
obj = scene.add( mesh );
obj.traverse((o) => {
if (o.isMesh) o.material = matcapMaterial
;
})
;
mixer = new THREE.AnimationMixer( mesh );
gltf.animations.forEach( ( clip ) => {
mixer.clipAction( clip ).play();
} );
} );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 0.8;
renderer.outputEncoding = THREE.sRGBEncoding;
container.appendChild( renderer.domElement );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function animate() {
requestAnimationFrame( animate );
var delta = clock.getDelta();
if ( mixer ) mixer.update( delta );
renderer.render( scene, camera );
}
</script>
<div id="test">
</div>
</body>
</html>

When replacing textures of glTF asset with manually loaded textures, you have to set the Texture.flipY property to false in order to accommodate the uv convention of glTF.
This circumstance is also mentioned in the documentation page of THREE.GLTFLoader.

Related

one OrbitControls with two scenes

I want to sync the mouse control of two .dae files (in two scenes side-by-side) with OrbitControls. I can control any one object individually with any one of my scenes but any attempt to control both objects in sync fails.
It seems like I can only have one OrbitControls instance. Any one of the following 'controls#' lines works on its own but as soon as I have both, only the first one is operative:
controls1 = new OrbitControls( camera1, renderer1.domElement );
controls2 = new OrbitControls( camera2, renderer2.domElement );
I am a chemistry prof, not a programmer.Any help is gratefully appreciated. Thanks!
<html lang="en">
<head>
<title>GD - 2 mols</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<h3> VB orbital visualizer: 2 molecules</h3>
<div id="molcontainer1"></div>
<div id="molcontainer2"></div>
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims#1.3.6/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "../three/build/three.module.js"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { ColladaLoader } from '../three/examples/jsm/loaders/ColladaLoader.js';
import { OrbitControls } from '../three/examples/jsm/controls/OrbitControls.js';
let molcontainer1, molcontainer2, camera1, camera2, scene1, scene2, renderer1, renderer2, mol1, mol2;
init();
//animate();
function init() {
molcontainer1 = document.getElementById( 'molcontainer1' );
molcontainer2 = document.getElementById( 'molcontainer2' );
//scene, camera, lighting, etc
scene1 = new THREE.Scene();
scene1.background = new THREE.Color( 0xbbffff );
scene2 = new THREE.Scene();
scene2.background = new THREE.Color( 0xffcccc );
camera1 = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 2000 );
camera1.position.set( 0.4, 0.4, 0.4 );
camera1.lookAt( 0, 0, 0 );
camera2 = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 2000 );
camera2.position.set( 0.4, 0.4, 0.4 );
camera2.lookAt( 0, 0, 0 );
const ambientLight1 = new THREE.AmbientLight( 0xffffff, 1 ); // was 0xcccccc
scene1.add( ambientLight1 );
const ambientLight2 = new THREE.AmbientLight( 0xffffff, 1 ); // was 0xcccccc
scene2.add( ambientLight2 );
const directionalLight1 = new THREE.DirectionalLight( 0xffffff, 0.8 );
directionalLight1.position.set( 1, 1, 1 ).normalize();
scene1.add( directionalLight1 );
const directionalLight2 = new THREE.DirectionalLight( 0xffffff, 0.8 );
directionalLight2.position.set( 1, 1, 1 ).normalize();
scene2.add( directionalLight2 );
renderer1 = new THREE.WebGLRenderer();
renderer1.outputEncoding = THREE.sRGBEncoding;
renderer1.setPixelRatio( window.devicePixelRatio );
renderer1.setSize( window.innerWidth/2, window.innerHeight/2 );
molcontainer1.appendChild( renderer1.domElement );
renderer2 = new THREE.WebGLRenderer();
renderer2.outputEncoding = THREE.sRGBEncoding;
renderer2.setPixelRatio( window.devicePixelRatio );
renderer2.setSize( window.innerWidth/2, window.innerHeight/2 );
molcontainer2.appendChild( renderer2.domElement );
// loading manager
const loadingManager = new THREE.LoadingManager( function () {
scene1.add( mol1 );
scene2.add( mol2 );
} );
// assign collada .dae file
const loader1 = new ColladaLoader( loadingManager );
loader1.load( './models/molecule.dae', function ( collada ) {
mol1 = collada.scene;
animate();
render();
} );
const loader2 = new ColladaLoader( loadingManager );
loader2.load( './models/CH2CHO.dae', function ( collada ) {
mol2 = collada.scene;
animate();
render();
} );
// 3d mouse controls
controls1 = new OrbitControls( camera1, renderer1.domElement );
controls2 = new OrbitControls( camera2, renderer2.domElement );
controls1.addEventListener( 'change', render );
controls2.addEventListener( 'change', render );
controls1.target.set( 0, 0, 0 );
controls2.target.set( 0, 0, 0 );
//controls.update();
window.addEventListener( 'resize', onWindowResize );
}
function animate() {
requestAnimationFrame( animate);
window.addEventListener( 'resize', onWindowResize ); // just added this
render();
}
function onWindowResize() {
camera1.aspect = window.innerWidth / window.innerHeight;
camera1.updateProjectionMatrix();
renderer1.setSize( window.innerWidth/2, window.innerHeight/2 );
camera2.aspect = window.innerWidth / window.innerHeight;
camera2.updateProjectionMatrix();
renderer2.setSize( window.innerWidth/2, window.innerHeight/2 );
render();
}
function render() {
renderer1.render( scene1, camera1 );
renderer2.render( scene2, camera2 );
//controls.update();
}
</script>
</body>
</html>```
You actually only need one camera and one OrbitControls to drive the two renderers and Scenes. The reason for this is that neither is intrinsically tied to the renderer or the Scene; the camera basically just tracks a group of variables that, on each frame, allow the renderer to compute its projection, and the OrbitControls only cares about the user's interaction with (a defined portion of) the page and the camera whose values it needs to mutate. (Note, as well, that neither a camera nor an OrbitControls takes any reference to a renderer or Scene when you initialize it, and most examples you see don't use Scene.Add() to add the camera to the scene graph.)
So, your code needs the following modifications.
First, wrap your molcontainer* divs inside of another div, and give it an ID of, say, molwrapper. This wrapper div will define the area on the page (comprising the two scenes) that will receive the user interaction for the OrbitControls. Use document.getElementById() to store a reference to molwrapper.
Next, remove all references to camera2 and rename camera1 to camera, and do the same with controls2 and controls1.
Finally, initialize controls (which used to be controls1) by passing it references to camera (which used to be camera1) and molwrapper.
I've posted a working example on CodePen.

How can I flip some normals of vertex geometry in three.js?

I have tested PCL triangluation introduced here:
And from the experiment I got a .vtk file.
And I tried to render it via web browser whith three.js on windows.
It is like below:
See! There are many holes. These holes are triangles that have opposite normal vectors.
What I need is flipping those normal vectors that are opposite than others.
This way I believe I would get clean mesh image as shown below:
How can I do this?
Do I work with three.js?
Had I better work with pcl library? - the triangluation?
This is the html I tested:
<!DOCTYPE html>
<html lang="en">
<head>
<!--title>four.js webgl - loaders - vtk loader</title-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<script type="module">
var console = (window.console = window.console || {});
import * as THREE from '../build/three.module.js';
import { TrackballControls } from './jsm/controls/TrackballControls.js';
import { VTKLoader } from './jsm/loaders/VTKLoader.js';
import { VertexNormalsHelper } from './jsm/helpers/VertexNormalsHelper.js';
let container, camera, controls, scene, renderer, vnh;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.01, 1e10);
camera.position.set( -1, 0, 0 );
scene = new THREE.Scene();
scene.add( camera );
// light
const hemiLight = new THREE.HemisphereLight( 0xffffff, 0x000000, 1 );
scene.add( hemiLight );
const dirLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
dirLight.position.set( 2, 2, 2 );
scene.add( dirLight );
const material = new THREE.MeshLambertMaterial( { color: 0xffffff } );
const loader = new VTKLoader();
loader.load( "models/vtk/point_cloud_mesh.vtk", function ( geometry )
//loader.load( "models/vtk/point_cloud_mesh_not_smoothed.vtk", function ( geometry )
{
//geometry.applyMatrix(new THREE.Matrix4().makeScale(-1, -1,-1));
//geometry.computeFaceNormals();
//var tmp;
//console.log(geometry.index.count);
//console.log(geometry.userData);
geometry.computeVertexNormals();
const mesh = new THREE.Mesh( geometry, material );
mesh.position.set( - 0.075, 0.005, 0 );
mesh.scale.multiplyScalar( 0.2 );
scene.add( mesh );
//vnh = new VertexNormalsHelper(mesh, 0.001, 0x00ff00, 1);
//scene.add( vnh );
} );
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container = document.createElement( 'div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
// controls
controls = new TrackballControls( camera, renderer.domElement );
controls.minDistance = .1;
controls.maxDistance = 0.5;
controls.rotateSpeed = 5.0;
window.addEventListener( 'resize', onWindowResize );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
controls.handleResize();
}
function animate() {
requestAnimationFrame( animate );
controls.update();
//if (vnh) vnh.update();
renderer.render( scene, camera );
}
</script>
</body>
</html>
Thanks to WestLangley , I finally got a expected result as shown below:
Thank you WestLangley and Stackoverflow!!
But the question still remains. WestLangley's suggestion helps but it wouldn't be the only one solution. As you see below, some of the normal vectors are facing into the body of my hand. I believe there would be a way to make all the normal vectors face out of the body of my hand. Answers to this question still wanted...

Change the color of 3D model using colorPicker three.js

I am trying to change the color of 3D object where intersected using color picker.I am trying with dat.gui.I want to change the color of 3d part where it gets clicked and change the selected from the colorPicker.I tried out some possible ways but it doesn't work out.Please,refer to the code I tried out. Help me out with some solution and draw my attention to where I am getting wrong. Thanks.
<!DOCTYPE html>
<html lang="en">
<head>
<title>color</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #000;
color: #fff;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="three.js"></script>
<script src="OrbitControls.js"></script>
<script src="Detector.js"></script>
<script src="stats.min.js"></script>
<script src="loaders/MTLLoader.js"></script>
<script src="loaders/OBJLoader.js"></script>
<script type='text/javascript' src='DAT.GUI.min.js'></script>
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container, stats;
var camera, controls, scene, renderer,effectController;
var raycaster;
var objects = [];
var selectedObject,selectedPos;
var rotation;
var pos,quat;
var INTERSECTED;
var guiColor;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 15;
controls = new THREE.OrbitControls( camera );
scene = new THREE.Scene();
scene.background = new THREE.Color( 0x555000 );
scene.add( camera );
// light
var dirLight = new THREE.DirectionalLight( 0xffffff );
dirLight.position.set( 200, 200, 1000 ).normalize();
camera.add( dirLight );
camera.add( dirLight.target );
var mtlLoader = new THREE.MTLLoader(); mtlLoader.setBaseUrl('assets/'); mtlLoader.setPath('assets/'); mtlLoader.load('anno.mtl', function (materials) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath('assets/');
objLoader.load('anno.obj', function (object) {
scene.add( object );
objects.push( object );
});
});
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
/* Controls */
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = false;
raycaster = new THREE.Raycaster();
gui = new dat.GUI();
parameters =
{
color: "#ff0000",
};
gui.add( parameters, 'reset' ).name("Reset");
guiColor = gui.addColor( parameters, 'color' ).name('Color');
container = document.createElement( 'div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
stats = new Stats();
container.appendChild( stats.dom );
window.addEventListener( 'resize', onWindowResize, false );
renderer.domElement.addEventListener("click", onclick, false);
}
var mouse = new THREE.Vector2();
function onclick(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(objects, true);
if (intersects.length > 0) {
INTERSECTED = intersects[0].object;
if ( INTERSECTED && INTERSECTED.material.emissive != null ){
guiColor.onChange(function(){
INTERSECTED.material.emissive.setHex(parameters.color)
});
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
stats.update();
}
</script>
</body>
</html>
I've create a little live demo with your code and a basic working solution. I'd like to highlight three important changes:
You can use the onChange() event handler in order to know when a certain dat.gui property has changed. The demo uses this feature to update the color of a selected object.
I have refactored your raycasting logic into something more simple. I've seen you've copied some code from the official three.js examples but the new code should be sufficient for your case. Besides, it's also better to update Material.color instead of Material.emissive.
If you set OrbitControls.enableDamping to true, you have to update the controls in your animation loop.
https://jsfiddle.net/btuzd23o/2/
three.js R103

GLTFLoader global variable undefined

i'm learning three js and try to animate an gltf object rotation in three.js r98. But I get a Console Error: Variable obj undefined, but the variable is declared on top before the init script, so it should be global right. I don't see why this shouldn't work. If I use scene.rotation.y += 0.01; it works. But this is not usefull if there are other object which should not rotate^^. the variable model has the same error. With MLTD Loader this works: Loop Rotation on any axis for a 3D obj Three js. Instead of gltf.scene i tried gltf.asset but with same error.
Many Thanks for help.
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>My first three.js app</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="js/three.js"></script>
<script src="js/GLTFLoader.js"></script>
<script src="js/WebGL.js"></script>
<script src="js/stats.min.js"></script>
<script src="js/dat.gui.min.js"></script>
<script>
if ( WEBGL.isWebGLAvailable() === false ) {
document.body.appendChild( WEBGL.getWebGLErrorMessage() );
}
var stats, clock, mixer;
var camera, scene, renderer, model;
var obj;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 100 );
camera.position.set( 0, 3, 10);
camera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xf0f0f0f );
scene.fog = new THREE.Fog( 0xe0e0e0, 20, 100 );
clock = new THREE.Clock();
// lights
var light = new THREE.HemisphereLight( 0xffffff, 0x444444 );
light.position.set( 0, 20, 0 );
scene.add( light );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 20, 10 );
scene.add( light );
// model
var loader = new THREE.GLTFLoader();
loader.load( 'logo1.gltf', function( gltf ) {
model = gltf.scene;
model.scale.set(1,1,1);
obj = model;
scene.add( model );
//createGUI( model, gltf.animations );
}, undefined, function( e ) {
console.error( e );
} );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.gammaOutput = true;
renderer.gammaFactor = 2.2;
container.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
// stats
// stats = new Stats();
//container.appendChild( stats.dom );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function animate() {
obj.rotation.y += 0.01;
requestAnimationFrame( animate );
renderer.render( scene, camera );
//stats.update();
}
</script>
</body>
</html>
The problem is that obj is only set when the onLoad() callback of GLTFLoader.load() fires. Since this happens in an asynchronous way, you should put the following line of code in your animate() function in order to solve the problem.
if ( obj ) obj.rotation.y += 0.01;

three.js set background image

How to create a static background image?
For default background:
scene = new THREE.Scene();
// ...
renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setClearColor( scene.fog.color, 1 );
How to set a image for scene.fog, or set opacity for clearcolor?
If you are trying to set a static background image (even if you rotate your main camera, the background doesn't change), you have to create 2 scenes and 2 cameras.
The first scene will be composed of a basic plane on which a texture is applied.
The second scene will have all your objects.
Here is a code that would do it :
<html>
<body>
<script src="Three.js"></script>
<script>
var color = 0x000000;
// Create your main scene
var scene = new THREE.Scene();
// Create your main camera
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// Create lights
var light = new THREE.PointLight(0xEEEEEE);
light.position.set(20, 0, 20);
scene.add(light);
var lightAmb = new THREE.AmbientLight(0x777777);
scene.add(lightAmb);
// Create your renderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Create a cube
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshLambertMaterial({
color: 0xff00ff,
ambient: 0x121212,
emissive: 0x121212
});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// Set up the main camera
camera.position.z = 5;
// Load the background texture
var texture = THREE.ImageUtils.loadTexture( '1.jpg' );
var backgroundMesh = new THREE.Mesh(
new THREE.PlaneGeometry(2, 2, 0),
new THREE.MeshBasicMaterial({
map: texture
}));
backgroundMesh .material.depthTest = false;
backgroundMesh .material.depthWrite = false;
// Create your background scene
var backgroundScene = new THREE.Scene();
var backgroundCamera = new THREE.Camera();
backgroundScene .add(backgroundCamera );
backgroundScene .add(backgroundMesh );
// Rendering function
var render = function () {
requestAnimationFrame(render);
// Update the color to set
if (color < 0xdddddd) color += 0x0000ff;
// Update the cube color
cube.material.color.setHex(color);
// Update the cube rotations
cube.rotation.x += 0.05;
cube.rotation.y += 0.02;
renderer.autoClear = false;
renderer.clear();
renderer.render(backgroundScene , backgroundCamera );
renderer.render(scene, camera);
};
render();
</script>
</body>
</html>
**Demo right here **
Hope this helps.
NOTE (2014/06/28): This code works with the latest release of Three.js: R67
Use Texture loader to load a any image as texture and then apply that to scene like this:
//Load background texture
const loader = new THREE.TextureLoader();
loader.load('https://images.pexels.com/photos/1205301/pexels-photo-1205301.jpeg' , function(texture)
{
scene.background = texture;
});
Result:
Demo:
See the Pen Flat Earth Three.JS by Hitesh Sahu (#hiteshsahu) on CodePen.
this run:
renderer = new THREE.WebGLRenderer({ antialias: false,alpha:true });
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor(0x000000, 0);
An background image can be set by setting the scene.background attribute of the THREE.Scene:
scene = new THREE.Scene();
bgTexture = loader.load("https://i.stack.imgur.com/vDUZz.jpg",
function ( texture ) {
var img = texture.image;
bgWidth= img.width;
bgHeight = img.height;
resize();
} );
scene.background = bgTexture;
bgTexture.wrapS = THREE.MirroredRepeatWrapping;
bgTexture.wrapT = THREE.MirroredRepeatWrapping;
The aspect ratio of the image can be adjusted to the aspect ratio of the canvas like this:
var aspect = window.innerWidth / window.innerHeight;
var texAspect = bgWidth / bgHeight;
var relAspect = aspect / texAspect;
bgTexture.repeat = new THREE.Vector2(
Math.max(relAspect, 1),
Math.max(1/relAspect,1) );
bgTexture.offset = new THREE.Vector2(
-Math.max(relAspect-1, 0)/2,
-Math.max(1/relAspect-1, 0)/2 );
See the code snippet:
(function onLoad() {
var container, loader, camera, scene, renderer, controls, bgTexture, bgWidth, bgHeight;
init();
animate();
function init() {
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 100);
camera.position.set(0, -4, -1.5);
loader = new THREE.TextureLoader();
loader.setCrossOrigin("");
scene = new THREE.Scene();
bgTexture = loader.load("https://raw.githubusercontent.com/Rabbid76/graphics-snippets/master/resource/texture/background.jpg",
function ( texture ) {
var img = texture.image;
bgWidth= img.width;
bgHeight = img.height;
resize();
}
);
scene.background = bgTexture;
bgTexture.wrapS = THREE.MirroredRepeatWrapping;
bgTexture.wrapT = THREE.MirroredRepeatWrapping;
scene.add(camera);
window.onresize = resize;
var ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
directionalLight.position.x = -0.75;
directionalLight.position.y = -0.5;
directionalLight.position.z = -1;
scene.add( directionalLight );
controls = new THREE.OrbitControls(camera, renderer.domElement);
createModel();
}
function createModel() {
var material = new THREE.MeshPhongMaterial({color:'#b090b0'});
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
}
function resize() {
var aspect = window.innerWidth / window.innerHeight;
var texAspect = bgWidth / bgHeight;
var relAspect = aspect / texAspect;
bgTexture.repeat = new THREE.Vector2( Math.max(relAspect, 1), Math.max(1/relAspect,1) );
bgTexture.offset = new THREE.Vector2( -Math.max(relAspect-1, 0)/2, -Math.max(1/relAspect-1, 0)/2 );
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = aspect;
camera.updateProjectionMatrix();
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
renderer.render(scene, camera);
}
})();
<script src="https://threejs.org/build/three.min.js"></script>
<!--script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.min.js"></script-->
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<div id="container"></div>
thank you ))
I found yet another solution:
<!DOCTYPE html>
<head>
<title>three.js webgl - orbit controls</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
color: #000;
font-family:Monospace;
font-size:13px;
text-align:center;
font-weight: bold;
background-image:url(./foto.jpg);
margin: 0px;
overflow: hidden;
}
#info {
color:#000;
position: absolute;
top: 0px; width: 100%;
padding: 5px;
}
a {
color: red;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="info">
three.js
</div>
<script src="./three.min.js"></script>
<script src="js/loaders/OBJLoader.js"></script>
<script src="js/controls/OrbitControls.js"></script>
<script src="js/Detector.js"></script>
<script src="js/libs/stats.min.js"></script>
<!--используем для вывода информации fps-->
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container, stats;
var camera, controls, scene, renderer;
var cross;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 0.1, 2000 );
camera.position.z = 100;
controls = new THREE.OrbitControls( camera );
controls.addEventListener( 'change', render );
scene = new THREE.Scene();
var manager = new THREE.LoadingManager();
manager.onProgress = function ( item, loaded, total ) {
console.log( item, loaded, total );
};
var texture = new THREE.Texture();
var loader = new THREE.ImageLoader( manager );
loader.load( './kos.jpg', function ( image ) {
texture.image = image;
texture.needsUpdate = true;
} );
// model
var loader = new THREE.OBJLoader( manager );
loader.load( './skull.obj', function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.map = texture;
}
} );
object.position.y = 10;
scene.add( object );
} );
// lights
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 1, 1, 1 );
scene.add( light );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( -1, -1, -1 );
scene.add( light );
light = new THREE.AmbientLight( 0xffffff );
scene.add( light );
renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
stats.domElement.style.zIndex = 100;
container.appendChild( stats.domElement );
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
render();
}
function animate() {
requestAnimationFrame( animate );
controls.update();
}
function render() {
renderer.render( scene, camera );
stats.update();
}
</script>
</body>
It seems rather late in the day to be adding any contribution to this thread but here is my 'hap'orth':
<head>
<meta charset=utf-8>
<title>Temple7</title>
<style>
body { margin: 0;
}
canvas { width: 100%; height: 100%;
background-image:url(Clouds.jpg);
}
</style>
</head>
This rather simplistic approach has its limitations. The .jpg image retains its pixel dimensions so that, for different sizes of the browser window one sees different amounts of the image. If the canvas size exceeds the size of the .jpg, then tiling occurs.

Resources