I'm trying to apply a different image on each face of a cube, on the inside.
I have a working example here: http://codepen.io/anon/pen/mymOKe
I load the images like this:
var material = [
new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('http://placehold.it/512x512', {}, function(){ webGLRenderer.render(scene, camera); })
}),
new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('http://placehold.it/512x512', {}, function(){ webGLRenderer.render(scene, camera); })
}),
new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('http://placehold.it/512x512', {}, function(){ webGLRenderer.render(scene, camera); })
}),
new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('http://placehold.it/512x512', {}, function(){ webGLRenderer.render(scene, camera); })
}),
new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('http://placehold.it/512x512', {}, function(){ webGLRenderer.render(scene, camera); })
}),
new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('http://placehold.it/512x512', {}, function(){ webGLRenderer.render(scene, camera); })
})
];
var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, new THREE.MeshFaceMaterial(material));
mesh.doubleSided = true;
And it doesn't work. In the code it starts at line 82.
At line 107 there is a commented part to build the cube with colors instead of textures, and that works.
What you need is to define THREE.BackSide in your material. For example:
var material = new THREE.MeshBasicMaterial({ map: texture, side: THREE.BackSide });
EDIT
Updated your code:
http://codepen.io/anon/pen/OVLVVr?editors=001
Look at Three.js and loading a cross-domain image for an explanation.
Also the code:
var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, new THREE.MeshFaceMaterial(material));
should be:
var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, material);
Related
I am trying to have my camera pan around a skybox using mouse movement. I am using three.js and OrbitControls.js. Please take a look at my code snippets below.
<!DOCTYPE html>
<html>
<head>
<meta charset=UTF-8 />
<link rel="stylesheet" type="text/css" href="styles.css" />
</head>
<body>
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three#0.121.1/build/three.module.js';
import { DRACOLoader } from 'https://cdn.jsdelivr.net/npm/three#0.121.1/examples/jsm/loaders/DRACOLoader.js';
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three#0.121.1/examples/jsm/controls/OrbitControls.js';
let scene, camera, renderer;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(55,window.innerWidth/window.innerHeight,45,30000);
camera.position.set(-900,-200,-900);
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);
let controls = new OrbitControls(camera, renderer.domElement)
controls.dispose();
controls.update();
document.addEventListener('mousemove', onDocumentMouseMove, false);
function onDocumentMouseMove(event) {
// Manually fire the event in OrbitControls
controls.handleMouseMoveRotate(event);
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
controls.update();
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
let materialArray = [];
let texture_ft = new THREE.TextureLoader().load( 'front.png');
let texture_bk = new THREE.TextureLoader().load( 'back.png');
let texture_up = new THREE.TextureLoader().load( 'up.png');
let texture_dn = new THREE.TextureLoader().load( 'down.png');
let texture_rt = new THREE.TextureLoader().load( 'right.png');
let texture_lf = new THREE.TextureLoader().load( 'left.png');
materialArray.push(new THREE.MeshBasicMaterial( { map: texture_ft }));
materialArray.push(new THREE.MeshBasicMaterial( { map: texture_bk }));
materialArray.push(new THREE.MeshBasicMaterial( { map: texture_up }));
materialArray.push(new THREE.MeshBasicMaterial( { map: texture_dn }));
materialArray.push(new THREE.MeshBasicMaterial( { map: texture_rt }));
materialArray.push(new THREE.MeshBasicMaterial( { map: texture_lf }));
for (let i = 0; i < 6; i++)
materialArray[i].side = THREE.BackSide;
let skyboxGeo = new THREE.BoxGeometry( 10000, 10000, 10000);
let skybox = new THREE.Mesh( skyboxGeo, materialArray );
scene.add( skybox );
animate();
}
function animate() {
renderer.render(scene,camera);
requestAnimationFrame(animate);
}
init();
</script>
</body>
</html>
I have updated OrbitControl.js as such:
this.handleMouseMoveRotate = function ( event ) {
rotateEnd.set( event.clientX, event.clientY );
rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
const element = scope.domElement;
rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
rotateStart.copy( rotateEnd );
scope.update();
}
However, I am receiving the error:
236(index):36 Uncaught TypeError: controls.handleMouseMoveRotate is not a function at HTMLDocument.onDocumentMouseMove ((index):36:10)
I know mouse movement is being detected as I see it firing as I move across the screen. What am I doing wrong?
Edit: I've updated the index.html file to point to a local copy of OrbitControls (with the edit I made)
You're right, I forgot to change that back to a local version. However, now I receive:
Uncaught TypeError: Failed to resolve module specifier "three". Relative references must start with either "/", "./", or "../".
This is a problem with Javascript scoping. You're declaring controls inside of init(), so it's not available inside onDocumentMouseMove().
let scene;
function init() {
let controls = new OrbitControls();
scene = new Scene();
}
function onDocumentMouseMove() {
// Controls does not exist here
controls.dosomething();
// But scene does exist
scene.add(xxyyzz);
}
Just declare the variable up one level to increase its scope, like you do with scene, camera, renderer. Then it should be accessible within your functions.
I have a .obj and .mtl which load textures from .tga files. This all seems to work / look fine in 3D modeling software, but when loaded with three.js (THREE.WebGLRenderer({ antialias: true })) some of the object's children, (specifically between the knees and the calves, but not, for example, the pockets and legs), seem to have a transparent jagged gap / empty triangles.
(Tried turning on antialiasing, changing the overdraw value, turning off transparency, etc.)
Loader function:
threejsHelper.helpers.loadObject('objects/pants/MaleBaggyPants.obj', 'objects/pants/MaleBaggyPants.mtl', {
blinn1SG: (new THREE.MeshPhongMaterial({ color: 0xffffff, transparent: false, opacity: 1.0, overdraw: 0.5, map: threejsHelper.helpers.loadTexture(app.manager, 'objects/pants/button.tga') })),
blinn2SG: (new THREE.MeshPhongMaterial({ color: 0xffffff, transparent: false, opacity: 1.0, overdraw: 0.5, map: threejsHelper.helpers.loadTexture(app.manager, 'objects/pants/back.tga') })),
blinn4SG: (new THREE.MeshPhongMaterial({ color: 0xffffff, transparent: false, opacity: 1.0, overdraw: 0.5, map: threejsHelper.helpers.loadTexture(app.manager, 'objects/pants/front.tga') })),
blinn5SG: (new THREE.MeshPhongMaterial({ color: 0xffffff, transparent: false, opacity: 1.0, overdraw: 0.5, map: threejsHelper.helpers.loadTexture(app.manager, 'objects/pants/pocket.tga') })),
blinn6SG: (new THREE.MeshPhongMaterial({ color: 0xffffff, transparent: false, opacity: 1.0, overdraw: 0.5, map: threejsHelper.helpers.loadTexture(app.manager, 'objects/pants/back.tga') })),
blinn7SG: (new THREE.MeshPhongMaterial({ color: 0xffffff, transparent: false, opacity: 1.0, overdraw: 0.5, map: threejsHelper.helpers.loadTexture(app.manager, 'objects/pants/front.tga') }))
}, function (object) {
object.rotation.x = (-90*Math.PI/180);
object.rotation.z = (-90*Math.PI/180);
app.scene.add(object);
app.ready = true;
});
Helper functions:
...
loadTexture: function (manager, path) {
var texture;
if (path.split('.').pop() == 'tga') {
var loader = new THREE.TGALoader();
texture = loader.load(path);
} else {
texture = new THREE.Texture();
var loader = new THREE.ImageLoader(manager);
loader.load(path, function (image) {
texture.image = image;
texture.needsUpdate = true;
});
}
return texture;
},
loadMaterial: function (mtlPath, textures, complete) {
var loader = new THREE.MTLLoader();
loader.load(mtlPath, function (materials) {
materials.preload();
if (!!materials.materials) {
for (var key in materials.materials) {
if (key in textures) {
materials.materials[key] = textures[key];
}
}
}
complete(materials);
});
},
loadObject: function (objPath, mtlPath, textures, complete) {
app.helpers.loadMaterial(mtlPath, textures, function (materials) {
var loader = new THREE.OBJLoader();
loader.setMaterials(materials);
loader.load(objPath, function (object) {
complete(object);
});
});
},
...
You seem to have extra vertices along the seem on both the objects which I think will screw with the triangulation.
Remove these vertices that are not needed and I'm 99% sure it will fix your problem.
I also noticed the model is at a very small scale.
I had the same problem. Some triangle didn't properly render on Threejs while it properly rendered on my OpenGL app.
I solved this trouble by using Uint32Array instead of Uint16Array to define the index of the geometry. I just put this line of code and everything worked like a charm.
const indices = new Uint32Array(faceDict.index);
I have a Problem with different textures on a cube. It only takes 1 texture with the following code...
var texture = new THREE.TextureLoader();
var texture1 = texture.load('texture1.jpg');
var texture2 = texture.load('texture2.jpg');
var texture3 = texture.load('texture3.jpg');
var texture4 = texture.load('texture4.jpg');
var texture5 = texture.load('texture5.jpg');
var texture6 = texture.load('texture6.jpg');
var geometry = new THREE.BoxBufferGeometry(height,width,length);
var material = new THREE.MeshBasicMaterial( { map: texture1,
map: texture2,map: texture3,map: texture4,map: texture5,
map: texture6 } );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
Try this:
var geometry = new THREE.BoxBufferGeometry(height,width,length);
var materials = [
new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('texture1.jpg')
}),
new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('texture2.jpg')
}),
new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('texture3.jpg')
}),
new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('texture4.jpg')
}),
new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('texture5.jpg')
}),
new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('texture6.jpg')
})
];
mesh = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materials));
scene.add(mesh);
Read the article:
http://architects.dzone.com/articles/combining-threejs-and
It seems however thay after kinetic.js v. 5-> this solution doesn't work anymore.
Has anyone been able to find a workaround?
Best regards and thank you
Jens
Three.js used canvas element
so used jquery to get the canvas used by kineti.js stage as shown in following code.
<script>
var camera, scene, renderer, geometry, material, mesh;
var stage, layer3D, layerGUI;
var animating = true;
function init() {
stage = new Kinetic.Stage({container: "container", width: 700, height: 700});
layer3D = new Kinetic.Layer();
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, 600 / 600, 1, 10000);
camera.position.z = 1000;
scene.add(camera);
geometry = new THREE.CubeGeometry(200, 200, 200);
material = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true });
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
stage.add(layer3D);
var canvas= layer3D.getCanvas();
canvas = $("#container canvas").get(0);
console.log( canvas );
console.log( layer3D );
renderer = new THREE.CanvasRenderer({ canvas: canvas });
renderer.setSize(700, 700);
var group = new Kinetic.Group({ draggable: true });
layerGUI = new Kinetic.Layer();
layerGUI.add(group);
stage.add(layerGUI);
render();
}
function animate() {
// note: three.js includes requestAnimationFrame shim
requestAnimationFrame(animate);
render();
}
function render() {
if (animating) {
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
}
renderer.render(scene, camera);
layerGUI.draw();
}
$(function () {
init();
animate();
});
</script>
Here canvas = $("#container canvas").get(0); is used to fetch the canvas of kinetic.js container.
I am trying to use two or more point clouds, but it just does not work - there are colr/transparency artifacts. How to fix, please?
My code so far looks like this:
var geometry = new THREE.Geometry ();
...
var material = new THREE.PointCloudMaterial ({
var material = new THREE.PointCloudMaterial ({
size: 60,
//size: 20, sizeAttenuation: false,
map: texture,
vertexColors: THREE.VertexColors, transparent: true
});
var particles = new THREE.PointCloud (geometry, material);
particles.sortParticles = true;
Try it live at jsbin