I have a simple square plate made in Blender.
I'm trying to add a simple texture to this object. I tried so many tutorials and code I found on the net, I just cant make it happen
my code is
<html>
<style>
body{
margin: 0;
overflow: hidden;
}
</style>
<canvas id="myCanvas"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/93/three.min.js"></script>
<script src="http://threejs.org/examples/js/loaders/MTLLoader.js"></script>
<script src="http://threejs.org/examples/js/loaders/OBJLoader.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="UnpackDepthRGBAShader.js"></script>
<script src="ShadowMapViewer.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45 ,window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 5, 14);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setClearColor(0xededed);
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var loader = new THREE.TextureLoader();
var texture = loader.load( "./2.jpg" );
// it's necessary to apply these settings in order to correctly display the texture on a shape geometry
//texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 0.05, 0.05 );
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
var keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30, 100%, 75%)'), 1.0);
keyLight.position.set(-100, 0, 100);
var fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240, 100%, 75%)'), 0.75);
fillLight.position.set(100, 0, 100);
var backLight = new THREE.DirectionalLight(0xffffff, 1.0);
backLight.position.set(100, 0, -100).normalize();
var manager = new THREE.LoadingManager();
manager.onProgress = function ( item, loaded, total ) {
console.log( item, loaded, total );
};
var textureLoader = new THREE.TextureLoader( manager );
var textureOBJ = textureLoader.load( './1.jpg' );
var onProgress = function ( xhr ) {
if ( xhr.lengthComputable ) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log( Math.round(percentComplete, 2) + '% downloaded' );
}
};
var onError = function ( xhr ) {
console.log(xhr);
};
var roundedRectShape = new THREE.Shape();
( function roundedRect( ctx, x, y, width, height, radius ) {
ctx.moveTo( x, y + radius );
ctx.lineTo( x, y + height - radius );
ctx.quadraticCurveTo( x, y + height, x + radius, y + height );
ctx.lineTo( x + width - radius, y + height );
ctx.quadraticCurveTo( x + width, y + height, x + width, y + height - radius );
ctx.lineTo( x + width, y + radius );
ctx.quadraticCurveTo( x + width, y, x + width - radius, y );
ctx.lineTo( x + radius, y );
ctx.quadraticCurveTo( x, y, x, y + radius );
} )( roundedRectShape, 0, 0, 18.5, 18.5, 2 );
addShape( roundedRectShape, 0x008000, -1.41, 0.5, 1, Math.PI / -2, 0, 0, 0.1 );
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
var loader = new THREE.OBJLoader( manager );
loader.load( './3.obj', function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.map = textureOBJ;
}
} );
object.position.y = -0.01;
object.position.x = 0;
object.position.z = 0;
scene.add( object );
}, onProgress, onError );
controls.update();
var animate = function () {
requestAnimationFrame( animate );
renderer.render(scene, camera);
};
animate();
function addShape( shape, color, x, y, z, rx, ry, rz, s ) {
var geometry = new THREE.ShapeBufferGeometry( shape );
var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( { side: THREE.DoubleSide, map: texture } ) );
mesh.position.set( x, y, z );
mesh.rotation.set( rx, ry, rz );
mesh.scale.set( s, s, s );
scene.add( mesh );
}
</script>
I'm trying to add this simple png as the texture. anyone can help?
plate - example -> http://37.59.53.90:8080/test1.html
I've managed to create a cup with texture -> http://37.59.53.90:8080/test.html
It looks like you're using THREE.TextureLoader incorrectly.
The texture loader's load() method takes two arguments;
- the URL of the image to be loaded, and
- a callback
The callback is invoked when the texture has loaded and is ready for use.
You should restructure your code so that the texture returned in the load() methods callback can be applied to your object.
To illustrate this, a quick solution to get textures loading and displaying on your object might look like this:
var loader = new THREE.OBJLoader( manager );
// Use a callback, in a similar way to your THREE.OBJLoader
new THREE.TextureLoader( manager ).load( './1.jpg' , function(texture) {
loader.load( './3.obj', function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
// Assign the loaded texture from the enclosing THREE.TextureLoader to the child material
child.material.map = texture;
}
});
object.position.y = -0.01;
object.position.x = 0;
object.position.z = 0;
scene.add( object );
}, onProgress, onError );
})
Related
I am looking for a way to draw several objects with unique textures. I came across this old question about instancedMesh where someone got the multiple instances with different textures but on desktop, textures have weird artifacts. Initially I thought something must be wrong with that demo but everything seems fine to me, I also tried to use mix functions in place of conditionals but textures still have artifacts.
I have been looking for different ways to draw multiple unique geometries so merging geometries isn't an option, but most results I get are for multiple objects with merged geometry. Would be great if someone can offer some guidance.
var camera, scene, renderer, stats;
var mesh;
var amount = parseInt( window.location.search.substr( 1 ) ) || 10;
var count = Math.pow( amount, 3 );
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2( 1, 1 );
var rotationTheta = 0.1;
var rotationMatrix = new THREE.Matrix4().makeRotationY( rotationTheta );
var instanceMatrix = new THREE.Matrix4();
var matrix = new THREE.Matrix4();
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( amount, amount, amount );
camera.lookAt( 0, 0, 0 );
scene = new THREE.Scene();
var light = new THREE.HemisphereLight( 0xffffff, 0x000088 );
light.position.set( - 1, 1.5, 1 );
scene.add( light );
var light = new THREE.HemisphereLight( 0xffffff, 0x880000, 0.5 );
light.position.set( - 1, - 1.5, - 1 );
scene.add( light );
var geometry = new THREE.BoxBufferGeometry( .5, .5, .5, 1, 1, 1 );
var material = [
new THREE.MeshStandardMaterial( { map: new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/square-outline-textured.png' ) } ),
new THREE.MeshStandardMaterial( { map: new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/golfball.jpg' ) } ),
new THREE.MeshStandardMaterial( { map: new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/metal.jpg' ) } ),
new THREE.MeshStandardMaterial( { map: new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/roughness_map.jpg' ) } ),
new THREE.MeshStandardMaterial( { map: new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/tri_pattern.jpg' ) } ),
new THREE.MeshStandardMaterial( { map: new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/water.jpg' ) } ),
];
material.forEach((m,side)=>{
if ( side!=2 ) return;
m.onBeforeCompile = ( shader ) => {
shader.uniforms.textures = { 'type': 'tv', value: [
new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/crate.gif' ),
new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/equirectangular.png' ),
new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/colors.png' )
] };
shader.vertexShader = shader.vertexShader.replace(
'#define STANDARD',
`#define STANDARD
varying vec3 vTint;
varying float vTextureIndex;`
).replace(
'#include <common>',
`#include <common>
attribute vec3 tint;
attribute float textureIndex;`
).replace(
'#include <project_vertex>',
`#include <project_vertex>
vTint = tint;
vTextureIndex=textureIndex;`
);
shader.fragmentShader = shader.fragmentShader.replace(
'#define STANDARD',
`#define STANDARD
uniform sampler2D textures[3];
varying vec3 vTint;
varying float vTextureIndex;`
)
.replace(
'#include <fog_fragment>',
`#include <fog_fragment>
int texIdx = int(vTextureIndex);
vec4 col;
if (texIdx == 0) {
col = texture2D(textures[0], vUv );
} else if ( texIdx==1) {
col = texture2D(textures[1], vUv );
} else if ( texIdx==2) {
col = texture2D(textures[2], vUv );
}
gl_FragColor = col;
// gl_FragColor.rgb *= vTint;`
)
;
}
});
mesh = new THREE.InstancedMesh( geometry, material, count );
var i = 0;
var offset = ( amount - 1 ) / 2;
var transform = new THREE.Object3D();
var textures = [];
for ( var x = 0; x < amount; x ++ ) {
for ( var y = 0; y < amount; y ++ ) {
for ( var z = 0; z < amount; z ++ ) {
transform.position.set( offset - x, offset - y, offset - z );
transform.updateMatrix();
mesh.setMatrixAt( i ++, transform.matrix );
textures.push(Math.random()<0.3 ? 0 : (Math.random()<0.5 ? 1 : 2));
}
}
}
geometry.setAttribute( 'textureIndex',
new THREE.InstancedBufferAttribute( new Float32Array(textures), 1 ) );
scene.add( mesh );
renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
new THREE.OrbitControls( camera, renderer.domElement );
stats = new Stats();
document.body.appendChild( stats.dom );
window.addEventListener( 'resize', onWindowResize, false );
document.addEventListener( 'mousemove', onMouseMove, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onMouseMove( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
raycaster.setFromCamera( mouse, camera );
var intersection = raycaster.intersectObject( mesh );
// console.log('intersection', intersection.length);
if ( intersection.length > 0 ) {
mesh.getMatrixAt( intersection[ 0 ].instanceId, instanceMatrix );
matrix.multiplyMatrices( instanceMatrix, rotationMatrix );
mesh.setMatrixAt( intersection[ 0 ].instanceId, matrix );
mesh.instanceMatrix.needsUpdate = true;
}
renderer.render( scene, camera );
stats.update();
}
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/libs/stats.min.js"></script>
<script src="https://threejs.org/examples/js/libs/dat.gui.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
I believe your issue comes from converting a float to an int, and then using that to create branches. This bug shows up only in a few GPUs, not all of them. I got it to work by keeping vTextureIndex as float, sampling all 3 textures and multiplying each by 1 if the textureIndex matches, or multiplying by 0 if the textureIndex does not match.
I basically replaced these lines:
int texIdx = int(vTextureIndex);
vec4 col;
if (texIdx == 0) {
col = texture2D(textures[0], vUv );
} else if ( texIdx==1) {
col = texture2D(textures[1], vUv );
} else if ( texIdx==2) {
col = texture2D(textures[2], vUv );
}
with this approach:
float x = vTextureIndex;
vec4 col;
col = texture2D(textures[0], vUv ) * step(-0.1, x) * step(x, 0.1);
col += texture2D(textures[1], vUv ) * step(0.9, x) * step(x, 1.1);
col += texture2D(textures[2], vUv ) * step(1.9, x) * step(x, 2.1);
If textureIndex is 0, the first texture is multiplied by 1, the others by 0
If textureIndex is 1, the second texture is multiplied by 1, the others by 0
If textureIndex is 2, the third texture is multiplied by 1, the others by 0
var camera, scene, renderer, stats;
var mesh;
var amount = parseInt( window.location.search.substr( 1 ) ) || 10;
var count = Math.pow( amount, 3 );
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2( 1, 1 );
var rotationTheta = 0.1;
var rotationMatrix = new THREE.Matrix4().makeRotationY( rotationTheta );
var instanceMatrix = new THREE.Matrix4();
var matrix = new THREE.Matrix4();
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( amount, amount, amount );
camera.lookAt( 0, 0, 0 );
scene = new THREE.Scene();
var light = new THREE.HemisphereLight( 0xffffff, 0x666666 );
light.position.set( - 1, 1.5, 1 );
scene.add( light );
var light = new THREE.HemisphereLight( 0xffffff, 0x666666, 0.5 );
light.position.set( - 1, - 1.5, - 1 );
scene.add( light );
var geometry = new THREE.BoxBufferGeometry( .5, .5, .5, 1, 1, 1 );
var material = [
new THREE.MeshStandardMaterial({color: 0xff9900}),
new THREE.MeshStandardMaterial({color: 0xff0099}),
new THREE.MeshStandardMaterial( { map: new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/metal.jpg' ) } ),
new THREE.MeshStandardMaterial({color: 0x9900ff}),
new THREE.MeshStandardMaterial({color: 0x0099ff}),
new THREE.MeshStandardMaterial({color: 0x99ff00}),
];
material.forEach((m,side)=>{
if ( side!=2 ) return;
m.onBeforeCompile = ( shader ) => {
shader.uniforms.textures = { 'type': 'tv', value: [
new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/crate.gif' ),
new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/sprite0.png' ),
new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/sprite.png' )
] };
shader.vertexShader = shader.vertexShader.replace(
'#define STANDARD',
`#define STANDARD
varying vec3 vTint;
varying float vTextureIndex;`
).replace(
'#include <common>',
`#include <common>
attribute vec3 tint;
attribute float textureIndex;`
).replace(
'#include <project_vertex>',
`#include <project_vertex>
vTint = tint;
vTextureIndex=textureIndex;`
);
shader.fragmentShader = shader.fragmentShader.replace(
'#define STANDARD',
`#define STANDARD
uniform sampler2D textures[3];
varying vec3 vTint;
varying float vTextureIndex;`
)
.replace(
'#include <fog_fragment>',
`#include <fog_fragment>
float x = vTextureIndex;
vec4 col;
col = texture2D(textures[0], vUv ) * step(-0.1, x) * step(x, 0.1);
col += texture2D(textures[1], vUv ) * step(0.9, x) * step(x, 1.1);
col += texture2D(textures[2], vUv ) * step(1.9, x) * step(x, 2.1);
gl_FragColor = col;
`
)
;
}
});
mesh = new THREE.InstancedMesh( geometry, material, count );
var i = 0;
var offset = ( amount - 1 ) / 2;
var transform = new THREE.Object3D();
var textures = [];
for ( var x = 0; x < amount; x ++ ) {
for ( var y = 0; y < amount; y ++ ) {
for ( var z = 0; z < amount; z ++ ) {
transform.position.set( offset - x, offset - y, offset - z );
transform.updateMatrix();
mesh.setMatrixAt( i ++, transform.matrix );
textures.push(Math.random()<0.3 ? 0 : (Math.random()<0.5 ? 1 : 2));
}
}
}
geometry.setAttribute( 'textureIndex',
new THREE.InstancedBufferAttribute( new Float32Array(textures), 1 ) );
scene.add( mesh );
renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
new THREE.OrbitControls( camera, renderer.domElement );
stats = new Stats();
document.body.appendChild( stats.dom );
window.addEventListener( 'resize', onWindowResize, false );
document.addEventListener( 'mousemove', onMouseMove, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onMouseMove( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
raycaster.setFromCamera( mouse, camera );
var intersection = raycaster.intersectObject( mesh );
// console.log('intersection', intersection.length);
if ( intersection.length > 0 ) {
mesh.getMatrixAt( intersection[ 0 ].instanceId, instanceMatrix );
matrix.multiplyMatrices( instanceMatrix, rotationMatrix );
mesh.setMatrixAt( intersection[ 0 ].instanceId, matrix );
mesh.instanceMatrix.needsUpdate = true;
}
renderer.render( scene, camera );
stats.update();
}
<script src="https://cdn.jsdelivr.net/npm/three#0.140.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.140.0/examples/js/libs/stats.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.140.0/examples/js/controls/OrbitControls.js"></script>
I am having trouble getting the MTLLoader to work correctly. I have already been able to use the OBJLoader by itself to load the 3d object and I have a camera that works properly too in my scene. When I try and use the MTLLoader with the OBJLoader the object loads but it breaks my other three.js code. I get these errors:
three.js:24415 Uncaught TypeError: Cannot set property 'value' of undefined
at initMaterial (three.js:24415)
at setProgram (three.js:24493)
at WebGLRenderer.renderBufferDirect (three.js:23552)
at renderObject (three.js:24269)
at renderObjects (three.js:24239)
at WebGLRenderer.render (three.js:24037)
at render (demo2.html:480)
The object loads and it looks like some textures load but the textures don't look right, the camera breaks. I have been having trouble with this and could really use some guidance.
Here is my MTLLoader code by itself
var mesh = null;
var mtlLoader = new THREE.MTLLoader();
mtlLoader.load( 'dapHouseGood5.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.load( 'dapHouseGood5.obj', function ( object ) {
mesh = object;
scene.add( mesh );
} );
Here is the rest of my three.js code for reference
<script>
/* global THREE */
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const renderer2 = new THREE.WebGLRenderer({canvas});
var kitchenCameraActive = false;
document.getElementById("roomSelect").addEventListener("change", changeIt);
function changeIt(e) {
document.getElementById(e.target.value).click();
console.log(e);
}
var fov = 45;
var aspect = 2; // the canvas default
var near = 0.1;
var far = 100;
var camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(-97.570, 5.878, -5.289);
camera.rotation.set(0,0,0);
const controls = new THREE.OrbitControls(camera, canvas);
controls.target.set(0, 5, 0);
controls.update();
document.getElementById("kitchen").addEventListener("click", changeCamera);
document.getElementById("bathroom").addEventListener("click", changeCamera);
document.getElementById("deck").addEventListener("click", changeCamera);
document.getElementById("livingRoom").addEventListener("click", changeCamera);
document.getElementById("bedRoom").addEventListener("click", changeCamera);
document.getElementById("walkway").addEventListener("click", changeCamera);
document.getElementById("sideHouse").addEventListener("click", changeCamera);
document.getElementById("frontPorch").addEventListener("click", changeCamera);
document.getElementById("garageDoor").addEventListener("click", changeCamera);
document.getElementById("insideGarage").addEventListener("click", changeCamera);
function changeCamera(e) {
camera.rotation.set(e.toElement.attributes[5].nodeValue,
e.toElement.attributes[6].nodeValue, e.toElement.attributes[7].nodeValue);
camera.fov = e.toElement.attributes[4].nodeValue;
camera.position.set(e.toElement.attributes[1].nodeValue,
e.toElement.attributes[2].nodeValue, e.toElement.attributes[3].nodeValue);
camera.updateProjectionMatrix();
if (e.target.id == "walkway" || e.target.id == "frontPorch" || e.target.id ==
"garageDoor" || e.target.id == "insideGarage")
{
controls.target.set(0, 5, 0);
controls.update();
}
if(e.target.id == "kitchen"){
controls.target.set(7, 6, 7);
}
if(e.target.id == "bathroom"){
controls.target.set(-9,15,-7);
}
if(e.target.id == "deck"){
controls.target.set(31, 7, 1);
}
if(e.target.id == "livingRoom"){
controls.target.set(-12.5, 1.5, -18.5);
}
if(e.target.id == "bedRoom"){
controls.target.set(-15.7, 14, -21);
}
if(e.target.id == "insideGarage"){
controls.target.set(24.405, 6.733, -6.425);
}
controls.update();
console.log(e);
}
const scene = new THREE.Scene();
scene.background = new THREE.Color('black');
{
const planeSize = 40;
}
{
const skyColor = 0xB1E1FF; // light blue
const groundColor = 0xB97A20; // brownish orange
const intensity = 1;
const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
scene.add(light);
}
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(5, 10, 2);
scene.add(light);
scene.add(light.target);
}
var mesh = null;
var mtlLoader = new THREE.MTLLoader();
mtlLoader.load( 'dapHouseGood5.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.load( 'dapHouseGood5.obj', function ( object ) {
mesh = object;
scene.add( mesh );
} );
} );
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function onPositionChange(o) {
console.log("position changed in object");
console.log(o);
console.log('camera_default: '+camera.position.x+', '+camera.position.y+',
'+camera.position.z);
console.log('camera_default: '+camera.rotation.x+', '+camera.rotation.y+',
'+camera.rotation.z);
console.log(camera.fov);
console.log('quaternion_default: '+camera.quaternion.x+', '+
camera.quaternion.y+', '+camera.quaternion.z+', '+camera.quaternion.w);
}
controls.addEventListener('change', onPositionChange);
var mouse = new THREE.Vector2();
var raycaster, mouse = { x : 0, y : 0};
init();
function init () {
//Usual setup code here.
raycaster = new THREE.Raycaster();
renderer.domElement.addEventListener( 'click', raycast, false );
}
function raycast ( e ) {
//1. sets the mouse position with a coordinate system where the center
// of the screen is the origin
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
//2. set the picking ray from the camera position and mouse coordinates
raycaster.setFromCamera( mouse, camera );
//var mouse3D = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, -(
event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
//raycaster.setFromCamera( mouse3D, camera );
//3. compute intersections
var intersects = raycaster.intersectObjects( scene.children, true );
for ( var i = 0; i < intersects.length; i++ ) {
console.log( intersects[ i ].object.name );
}
}
}
main();
</script>
I am trying to load a ctm model in my scene but I have the following error :
geometry.computeOffsets is not a function
I have divided my code in 2 files : 1 html file and 1 js file that contain the code to create the scene and load the ctm model.
My html file is as below:
<!DOCTYPE html>
<head>
<title>Basic template</title>
<style>canvas { width: 100%; height: 100% }</style>
<script src="../lib/three.min.js"></script>
<script src="../lib/Detector.js"></script>
<script src="../lib/Coordinates.js"></script>
<script src="../lib/OrbitAndPanControls.js"></script>
<script src="../lib/TrackballControls.js"></script>
<script src="../lib/stats.min.js"></script>
<script src="js/loaders/ctm/lzma.js"></script>
<script src="js/loaders/ctm/ctm.js"></script>
<script src="js/loaders/ctm/CTMLoader.js"></script>
</head>
<body>
<script src="js/loaders/ctm/ctm_loader_house.js"></script>
</body>
And my javascriptfile ctm_loader_house.js:
var camera, scene,s, renderer;
var cameraControls;
var clock = new THREE.Clock();
// LOADER
function callbackModel( geometry, s, material, x, y, z, rx, ry ) {
var mesh = new THREE.Mesh( geometry, material );
mesh.position.set( x, y, z );
mesh.scale.set( s, s, s );
mesh.rotation.x = rx;
mesh.rotation.z = ry;
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add( mesh );
}
function init() {
// SCENE
scene = new THREE.Scene();
// LIGHTS
scene.add( new THREE.AmbientLight( 0x222222 ) );
var light = new THREE.DirectionalLight( 0xFFFFFF, 1.0 );
light.position.set( 200, 400, 500 );
scene.add( light );
light = new THREE.DirectionalLight( 0xFFFFFF, 1.0 );
light.position.set( -400, 200, -300 );
scene.add( light );
//CAMERA
var canvasWidth = window.innerWidth;
var canvasHeight = window.innerHeight;
camera = new THREE.PerspectiveCamera( 20, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.z = 800;
// RENDERER
renderer = new THREE.WebGLRenderer();
renderer.setSize( canvasWidth, canvasHeight );
document.body.appendChild( renderer.domElement );
cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement);
cameraControls.target.set( 0, 0, 0 );
// LOADER
function checkTime() {
var c = 0,
var s = Date.now();
c ++;s= Date.now();
if ( c === 3 ) {
var e = Date.now();
console.log( "Total parse time: " + (e-s) + " ms" );
}
}
var loader = new THREE.CTMLoader();
loader.load( "models/ctm/ModernGlass-House_simplify.ctm", function( geometry ) {
var material1 = new THREE.MeshLambertMaterial( { color: 0xffffff } );
//callbackModel( geometry, scale , material, position x,position y,position z, rotation x, rotation y )
callbackModel( geometry, 0.1, material1, 0, 0, 0, -1.57, 1.57 );
checkTime();
}, { useWorker: true } );
//AXIS
Coordinates.drawGround({size:10000});
Coordinates.drawGrid({size:1000,scale:0.01});
Coordinates.drawGrid({size:1000,scale:0.01, orientation:"y"});
Coordinates.drawGrid({size:1000,scale:0.01, orientation:"z"});
}
function render() {
var delta = clock.getDelta();
requestAnimationFrame(render);
cameraControls.update(delta);
renderer.render(scene, camera);
}
init();
render();
Any help is much appreciated.
Thanks #WestLangley, I got it working. Here is the code.
var camera, scene,s, controls, renderer;
var cameraControls;
var clock = new THREE.Clock();
function callbackModel( geometry, s, material, x, y, z, rx, ry ) {
var mesh = new THREE.Mesh( geometry, material );
mesh.position.set( x, y, z );
mesh.scale.set( s, s, s );
mesh.rotation.x = rx;
mesh.rotation.z = ry;
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add( mesh );
}
function init() {
// SCENE
scene = new THREE.Scene();
// LIGHTS
scene.add( new THREE.AmbientLight( 0x222222 ) );
var light = new THREE.DirectionalLight( 0xFFFFFF, 1.0 );
light.position.set( 200, 400, 500 );
scene.add( light );
light = new THREE.DirectionalLight( 0xFFFFFF, 1.0 );
light.position.set( -400, 200, -300 );
scene.add( light );
//CAMERA
var canvasWidth = window.innerWidth;
var canvasHeight = window.innerHeight;
camera = new THREE.PerspectiveCamera( 20, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.z = 800;
controls = new THREE.OrbitControls( camera );
// RENDERER
renderer = new THREE.WebGLRenderer();
renderer.setSize( canvasWidth, canvasHeight );
document.body.appendChild( renderer.domElement );
// LOADER
var c = 0, s = Date.now();
function checkTime() {
c ++;s= Date.now();
if ( c === 3 ) {
var e = Date.now();
console.log( "Total parse time: " + (e-s) + " ms" );
}
}
var loader = new THREE.CTMLoader();
loader.load( "models/ctm/ModernGlass-House_simplify.ctm", function( geometry ) {
var material1 = new THREE.MeshLambertMaterial( { color: 0xffffff } );
//callbackModel( geometry, scale , material, position x,position y,position z, rotation x, rotation y )
callbackModel( geometry, 0.1, material1, 0, 0, 0, -1.57, 1.57 );
checkTime();
}, { useWorker: true } );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
render();
}
function render() {
renderer.render( scene, camera );
}
init();
animate();
First to say, I do not speak English well.
Anyway, Let's get something straight.
I want to modify mesh(cube) size when i scroll the mouse wheel to zoomin or zoomout.
I hope to increase mesh(cube) size when zoom in and Opposite case, too.
my code is below.
<script src="../lib/Three.js/build/Three.js"></script>
<script src="http://code.jquery.com/jquery.min.js"></script>
<script>
var CANVAS_WIDTH = 400,
CANVAS_HEIGHT = 300;
var renderer = null, //웹지엘 또는 2D
scene = null, //씬 객체
camera = null; //카메라 객체
var capture = false,
start = [],
angleX = 0,
angleY = 0,
zoom = 1.0;
function initWebGL()
{
setupRenderer();
setupScene();
setupCamera();
var myColor = new THREE.Color( 0xff0000 );
myColor.setRGB(0.0, 1.0, 0.0);
var alpha = 1.0;
renderer.setClearColor(myColor, alpha);
(function animLoop(){
//camera zoom in and zomm out
renderer.render(scene, camera);
requestAnimationFrame( animLoop );
})();
/**
mouse event code for screen control about zoom, rotate
**/
$(document).ready(function() {
console.log($("#my-canvas").length);
$("#my-canvas").on("mousedown", function(e) {
capture = true;
start = [e.pageX, e.pageY];
console.log("start:" + start);
});
$("#my-canvas").on("mouseup", function(e) {
console.log(e.type);
capture = false;
console.log("end capture");
});
$("#my-canvas").mousemove(function(e) {
console.log(e.type);
if (capture)
{
var x = (e.pageX - start[0]);
var y = (e.pageY - start[1]);
//시작위치 업데이트
start[0] = e.pageX;
start[1] = e.pageY;
angleX += x;
angleY += y;
//console.log()
}
});
});
$(document).ready(function(evt) {
$("#my-canvas").on("mousewheel", function (e) {
adjustZoom(window.event.wheelData);
}).on("DOMMouseScroll", function (e) {
//파이어폭스
adjustZoom(e.originalEvent.detail * -1.0);
});
});
function adjustZoom(delta) {
if(delta > 0)
{
zoom += 0.1;
} else {
zoom -= 0.1;
if(zoom < 0.01) { zoom = 0.1;}
}
}
}
function setupRenderer()
{
renderer = new THREE.WebGLRenderer({canvas: document.createElement( 'canvas')});
renderer.setSize( CANVAS_WIDTH, CANVAS_HEIGHT );
$(renderer.domElement).attr('id','my-canvas');
//캔버스 엘리먼트를 추가하는 곳
document.body.appendChild( renderer.domElement );
}
function setupScene()
{
scene = new THREE.Scene();
addMesh();
addLight();
}
function setupCamera()
{
camera = new THREE.PerspectiveCamera(
35, //시야
CANVAS_WIDTH / CANVAS_HEIGHT, //종횡비
.1, //전방 절단면
10000 //후방 절단면
);
camera.position.set(-15, 10, 10);
camera.lookAt( scene.position );
scene.add( camera );
}
function addMesh()
{
var cube = new THREE.Mesh(
new THREE.CubeGeometry( 5, 7, 5 ),
new THREE.MeshLambertMaterial( { color: 0x0000FF} )
);
scene.add(cube);
}
function addLight()
{
var light = new THREE.PointLight( 0xFFFFFF );
light.position.set( 20, 20, 20 );
scene.add(light);
}
</script>
You wish to modify the scale value of the object. This can be done for each axis.
Each mesh object has a scale value as a vector.
So this would
mesh.scale.set( 2, 1, 1 )
Or in your case
cube.scale.set();
You can also access it this way,
cube.scale.x = 2.0;
Though the cube object is stored locally, you might want to set the globally and alter this value with the mouse action.
Hope that well.
As a note, the question provides a bit too much of the script, shorter and faster to the point is better.
My problem is the following : The mousehover actions works on the cubes even if the mouse is not directly over the cubes, it works if it is on an Y axis over or under the cubes, out of the scene. Can someone explain me why and how to fix it?
<!DOCTYPE html>
<html lang="fr" xml:lang="fr" xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>
<script src="lib/Three.js" type="text/javascript"></script>
<script src="lib/Detector.js"></script>
<script src="lib/stats.min.js" type="text/javascript"></script>
<script src="lib/THREEx/THREEx.WindowResize.js"></script>
<script src="lib/THREEx/THREEx.FUllScreen.js"></script>
<script src="lib/TrackballControls.js"></script>
<style type="text/css">
body
{
color: #ffffff;
text-align:center;
background-color: gray;
margin: 0px;
}
#center
{
color: #fff;
position: absolute;
top: 50px; width: 100%;
padding: 5px;
z-index:100;
}
#center h1
{
font-size:60px;
}
#container
{
position:absolute;
bottom:0;
}
</style>
</head>
<body>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<div id="container"></div>
</body>
<script>
// MAIN
console.log("Main.js");
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
// global variables
var container, scene, camera, renderer, stats, controls;
// custom variables
var t = THREE;
var cube;
// to keep track of the mouse position
var projector, INTERSECTED, mouse = { x: 0, y: 0 },
// an array to store our particles in
particles = [];
init();
animate();
function init()
{
// scene
scene = new THREE.Scene();
// camera
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
scene.add(camera);
camera.position.set(0,0,800);
camera.lookAt(scene.position);
// renderer
renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
// container
container = document.getElementById('container');
container.appendChild( renderer.domElement );
// stats
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.bottom = '0px';
stats.domElement.style.zIndex = 100;
container.appendChild( stats.domElement );
// events
THREEx.WindowResize(renderer, camera);
THREEx.FullScreen.bindKey({ charCode : 'm'.charCodeAt(0) });
// initialize object to perform world/screen calculations
projector = new THREE.Projector();
// CUSTOM
// Cubes
x = window.innerWidth / 5;
y = window.innerHeight / 10;
console.log(window.innerWidth);
console.log(window.innerHeight);
var geometry = new t.CubeGeometry(125,125,125);
var material = new t.MeshBasicMaterial({color:0xCCCCCC});
cube = new t.Mesh(geometry, material);
cube.name = "cube";
scene.add(cube);
cube.position.set(-x,-y,0);
x = window.innerWidth;
y = window.innerHeight / 10;
var geometry2 = new t.CubeGeometry(125,125,125);
var material2 = new t.MeshBasicMaterial({color:0xCCCCCC});
cube2 = new t.Mesh(geometry2, material2);
scene.add(cube2);
cube2.name = "cube2";
cube2.position.set(0,-y,0);
x = window.innerWidth / 5;
y = window.innerHeight / 10;
var geometry3 = new t.CubeGeometry(125,125,125);
var material3 = new t.MeshBasicMaterial({color:0xCCCCCC});
cube3 = new t.Mesh(geometry3, material3);
cube3.name = "cube3";
scene.add(cube3);
cube3.position.set(x,-y,0);
// particles
makeParticles();
// Mouse events
document.addEventListener( 'mousemove', onMouseMove, false );
document.addEventListener( 'mousedown', onMouseDown, false );
}
// called when the mouse moves
function onMouseMove( event )
{
// store the mouseX and mouseY position
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
function onMouseDown( event )
{
event.preventDefault();
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
var intersects = ray.intersectObjects( scene.children );
if ( intersects.length > 0 )
{
console.log(INTERSECTED.name);
if(INTERSECTED.name == "cube")
{
page("real");
}
}
}
function animate()
{
cube.rotation.y +=0.005;
cube.rotation.x -=0.005;
cube2.rotation.y +=0.005;
cube2.rotation.x -=0.005;
cube3.rotation.y +=0.005;
cube3.rotation.x -=0.005;
//textMesh.rotation.y +=0.005;
requestAnimationFrame( animate );
render();
update();
}
// creates a random field of Particle objects
function makeParticles()
{
var particle, material;
// we're gonna move from z position -1000 (far away)
// to 1000 (where the camera is) and add a random particle at every pos.
for ( var zpos= -1000; zpos < 1000; zpos+=20 )
{
// we make a particle material and pass through the
// colour and custom particle render function we defined.
material = new THREE.ParticleCanvasMaterial( { program: particleRender } );
// make the particle
particle = new THREE.Particle(material);
// give it a random x and y position between -500 and 500
particle.position.x = Math.random() * 1000 - 500;
particle.position.y = Math.random() * 1000 - 500;
// set its z position
particle.position.z = zpos;
// scale it up a bit
particle.scale.x = particle.scale.y = 10;
// add it to the scene
scene.add( particle );
// and to the array of particles.
particles.push(particle);
}
}
// there isn't a built in circle particle renderer
// so we have to define our own.
function particleRender( context )
{
// we get passed a reference to the canvas context
context.beginPath();
// and we just have to draw our shape at 0,0 - in this
// case an arc from 0 to 2Pi radians or 360º - a full circle!
context.arc( 0, 0, 0.2, 2, Math.PI * 4, true );
context.fillStyle = "white";
context.fill();
};
// moves all the particles dependent on mouse position
function updateParticles()
{
// iterate through every particle
for(var i=0; i<particles.length; i++)
{
particle = particles[i];
// and move it forward dependent on the mouseY position.
particle.position.z += 250 * 0.02;
// if the particle is too close move it to the back
if(particle.position.z>1000) particle.position.z-=2000;
}
}
function render()
{
renderer.render( scene, camera );
}
function update()
{
updateParticles();
stats.update();
// find intersections
// create a Ray with origin at the mouse position
// and direction into the scene (camera direction)
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
// create an array containing all objects in the scene with which the ray intersects
var intersects = ray.intersectObjects( scene.children );
// INTERSECTED = the object in the scene currently closest to the camera
// and intersected by the Ray projected from the mouse position
// if there is one (or more) intersections
if ( intersects.length > 0 )
{
// if the closest object intersected is not the currently stored intersection object
if ( intersects[ 0 ].object != INTERSECTED)
{
// restore previous intersection object (if it exists) to its original scale
if ( INTERSECTED )
{
INTERSECTED.scale.x = INTERSECTED.currentscale.x;
INTERSECTED.scale.y = INTERSECTED.currentscale.y;
INTERSECTED.scale.z = INTERSECTED.currentscale.z;
}
// store reference to closest object as current intersection object
INTERSECTED = intersects[ 0 ].object;
// store scale of closest object (for later restoration)
scalex = INTERSECTED.scale.x;
scaley = INTERSECTED.scale.y;
scalez = INTERSECTED.scale.z;
INTERSECTED.currentscale = { x : scalex , y : scaley, z : scalez };
// set a new scale for closest object
INTERSECTED.scale.x = INTERSECTED.scale.y = INTERSECTED.scale.z = 1.5;
}
}
else // there are no intersections
{
// restore previous intersection object (if it exists) to its original scale
if ( INTERSECTED )
{
INTERSECTED.scale.x = INTERSECTED.currentscale.x;
INTERSECTED.scale.y = INTERSECTED.currentscale.y;
INTERSECTED.scale.z = INTERSECTED.currentscale.z;
}
// remove previous intersection object reference
// by setting current intersection object to "nothing"
INTERSECTED = null;
}
}
// Pour charger une page dynamiquement
function page(page){
$("body").animate({opacity:0},1000, function(){
$("body").empty();
$("body").load(page +'.html');
$("body").animate({opacity:1},1000, function(){
});
});
}
</script>
</html>
Is there an offset between the window top left corner and the canvas top left corner?
If so, you have to calculate the offset (top and left) and subtract the values from the event.client values.
Try this :
// now get the space between top left browser window corner
var absoluteOffsetLeft = 0;
var absoluteOffsetTop = 0;
var obj = <your HTML object containing the canvas>;
// taken from http://www.quirksmode.org/js/findpos.html
if (obj.offsetParent) {
do {
absoluteOffsetLeft += obj.offsetLeft;
absoluteOffsetTop += obj.offsetTop;
} while (obj = obj.offsetParent);
} else {
console.log("Method offsetParent not supported");
}
// YOUR mouse move event handler - also take the innerWidth and Height from the canvas
function onMouseMove( event ) {
// store the mouseX and mouseY position
mouse.x = ( (event.clientX - absoluteOffsetLeft) / canvas.innerWidth ) * 2 - 1;
mouse.y = - ( (event.clientY - absoluteOffsetTop) / canvas.innerHeight ) * 2 + 1;
}