How to display a locally selected image in three.js? - image

I always get a cross-origin-error. how can I circumvent this, or better yet, fix it?
I need the user to be able to pic a local image and let it be displayed in a PlaneGeometry.
my code:
this.reader.readAsDataURL(file);
this.reader.onloadend = function( ev ) {
var file = ev.target.result,
//geometry = new THREE.CubeGeometry(1, 1, 0.1),
geometry = new THREE.PlaneGeometry(1, 1, 1, 2),
texture = THREE.ImageUtils.loadTexture(file),
material = new THREE.MeshBasicMaterial({ map: texture }),
mesh = new THREE.Mesh(geometry, material);
mesh.name = "Marker" + mesh.id;
mesh.rotation.x = 90 * ( Math.PI / 180 );
Editor.addObject(mesh);
console.log(Editor.scene.children);
SignalHub.signals.updateScene.dispatch();
SignalHub.signals.markerAdded.dispatch();
The geometry shows up but it's blank!

Option 1
Use an img.
var image = document.createElement( 'img' );
image.src = dataurl;
var texture = new THREE.Texture( image );
texture.needsUpdate = true;
See here.
Option 2
Where is the html server from? If it is a local htm file, then you could instead serve it from a web server on the local machine (e.g. IIS / apache).
Whether the server is local or remote, you can upload the image to your web server when they have selected it and use a URL to retrieve it from the web server. This will satisfy the cross-origin policies.
Option 3
Convert the image into Base64 text
Store it in an external Javascript file
Link it to your project page
Load it into your texture
See here (SO answer) and here (details off-site).
Option 4
Create a shortcut for the browser such as:
c:// ... /chrome.exe --allow-file-access-from-files
Option 5
Use the .crossOrigin = '' property. It was not working, but I think it is now fixed. See here and here.

I made this example: http://develoteca.com/EjerciosOnline/Exampleplane/, you can load a local image
Greetings.

Related

object.updateWorldMatrix is not a function

As documentation of Three.js said, after changing the position of the camera, we must call the updateProjectionMatrix() method.
I'm doing the same. But it gives me an error like this:
TypeError: object.updateWorldMatrix is not a function
at Box3.expandByObject (three.module.js:6329)
at Box3.setFromObject (three.module.js:6233)
at index.js:66
at GLTFLoader.js:147
at GLTFLoader.js:1639
My goal is to put my loaded GLTF object, in the center of the screen.
And this is the code I'm using for it:
this.gltfLoader.load("/corolla.gltf", (object) => {
const box = new THREE.Box3().setFromObject(object);
const size = box.getSize(new THREE.Vector3()).length();
const center = box.getCenter(new THREE.Vector3());
// reset OrbitControl
this.controls.reset();
object.position.x += (object.position.x - center.x);
object.position.y += (object.position.y - center.y);
object.position.z += (object.position.z - center.z);
this.controls.maxDistance = size * 10;
this.camera.near = size / 100;
this.camera.far = size * 100;
this.camera.updateProjectionMatrix();
this.camera.position.copy(center);
this.camera.position.x += size / 2.0;
this.camera.position.y += size / 5.0;
this.camera.position.z += size / 2.0;
this.camera.lookAt(center);
this.gltf = object.scene;
this.scene.add(this.gltf);
},
this.manageLoading,
this.gltfLoadErr);
For the record, I'm using the last version of Three.js, it's 0.110.0;
It looks like the errors is occurring here:
const box = new THREE.Box3().setFromObject(object);
Where object is the object coming back from the call to GLTFLoader.load.
According to the docs, object is not an Object3D (which is what Box3.setFromObject expects).
Instead, object is a JSON structure containing information about the GLTF data. The three.js example suggests object.scene would be a renderable entity (if it exists).
Take a look at the code for the GLTFLoader example, here. Compare it against your implementation. You can also debug your code to see exactly what is object contains. Once you have a handle on that, if you're still having problems, come back and ask more questions!
Short solution:
var hollowCylinderGeom = new THREE.LatheBufferGeometry([
new THREE.Vector2(1, 0),
new THREE.Vector2(2, 0),
new THREE.Vector2(2, 2),
new THREE.Vector2(1, 2),
new THREE.Vector2(1, 0)
], 90).toNonIndexed();
var mesh = new THREE.Mesh(hollowCylinderGeom);
console.log(new THREE.Box3().setFromObject(mesh));

Three.js | Not able to add Dynamic Text Geometry to 3d mesh

I am working on a POC in which I have to customize a watch in 3d model.
I am using thee.js for doing webgl stuff. I was able to change strap color , dial color and load texture images on strap. But I am stuck when I try to add dynamic text on the the watch , I have to update text on watch's back dial as user types in Engrave Text text box . For this I tried https://github.com/jeromeetienne/threex.dynamictexture library , which works on a new geometry but I am not able to add it watch's existing model.
I have pushed all code in github : https://github.com/bhupendra1011/watch-3d-engrave , as I was not able to load external 3d models from my fiddle account {CORS issue}.
Demo of the POC can be seen here : https://bhupendra1011.github.io/watch-3d-engrave/index.html
Below is the code to add text on watch dial; For loading text click on use textures textbox in index.html
function engraveTextOnWatch(val = "IWC") {
dynamicTexture = new THREEx.DynamicTexture(512, 512);
dynamicTexture.context.font = "bolder 90px Verdana";
// watch back dial geometry & material where text needs to be engraved
var backDialGeometry = object3d.children[1].children[0].children[0].geometry;
var backDialMaterial = object3d.children[1].children[0].children[0].material;
// geometry to add dynamic text
var geometry = new THREE.CubeGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({
map: dynamicTexture.texture
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh); // adding mesh to scene , but this needs to be attache to watch's back dial geomtry
/* tried adding dynamicTexture to watch back dial material, but this is not working , text not appearing */
//backDialMaterial.map = dynamicTexture.texture;
dynamicTexture.texture.needsUpdate = true;
dynamicTexture.drawText(val, 2, 256, "orange");
}
Kindly let me know how can I add dynamic text on existing model.
Thanks.
I was able to reproduce your problem in Blender and it comes from your model's UV map.
I downloaded your model, opened it in Three.js editor and converted it to .obj to open it in blender to reproduve your problem
As you can see on the image, applying a texture is just as messy. You need to rework the model's uvmap to achieve the desired effect like so (I used a random image from your folder)
And while you're at it, you might want to consider optimizing your model, which is pretty heavy and could be simplified for faster load without losing visual quality (but it's entirely up to you, I'm just suggesting).
Here's the current model
Here's a quick possible replacement. Cylinder that's open on one end and beveled on the edge loop

Making portals with ThreeJS

Im trying to make portals with ThreeJS. I found this page Mini-Portals That explains how to make portals with OpenGL. So i tried to replicate the portal view function in TJS. Now this is my result:
The left portal(right camera) is normal camera and right portal(left camera) is the view matrix gotten from tutorial. As you can see the portal view on the right is quite weird.
The main issue here is that the scaling of the images is all wrong and the angle im seeing the images in portal is wrong. Currently its flat and show where i pointed the camera, but what i want is portal where the scaling is correct(image on portal is same scale as the world itself) and what is see in portal depends on the angle where im watching.
What am i doing wrong and what should i do to fix it?
For people who want a great Portal system with Three.js :
https://github.com/markotaht/Portals
Its been a while. But i have found a way to do what i needed. The 4th parameter in not needed. Basically i send camera, and my 2 portal objects(Meshes) to my function. Instead of using the matrix multiplication way(does not work in ThreeJS because ThreeJS does some weird stuff with it) I split the matrices into pieces. Then manually calculate the new position and rotation and construct the new matrix from it. And i set this new matrix as my cameras worldMatrix. Voila a working portal. Next step is oblique view fusrum, because we want our nearplane to be the portal otherwise we can have some objects between the camera and portal.
And the rendering procedure itself uses stencil buffer to render the portals correctly. If anyone needs, this will help you: https://th0mas.nl/2013/05/19/rendering-recursive-portals-with-opengl/
function portal_view(camera, src_portal, dst_portal, kordaja) {
src_portal.updateMatrixWorld()
dst_portal.updateMatrixWorld()
camera.updateMatrixWorld()
var camerapos = new THREE.Vector3();
var camerarot = new THREE.Quaternion();
var camerascale = new THREE.Vector3();
camera.matrix.decompose(camerapos,camerarot,camerascale);
var srcpos = new THREE.Vector3();
var srcquat = new THREE.Quaternion();
var srcscale = new THREE.Vector3();
src_portal.matrix.decompose(srcpos, srcquat, srcscale);
var destquat = new THREE.Quaternion();
var destpos = new THREE.Vector3();
var destscale = new THREE.Vector3();
dst_portal.matrix.decompose(destpos,destquat,destscale);
var diff = camerapos.clone().sub(srcpos);
var ydiff = src_portal.rotation.y - dst_portal.rotation.y - Math.PI;
diff.applyAxisAngle(new THREE.Vector3(0,1,0),-ydiff);
var newcampos = diff.add(destpos);
var yrotvec = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,1,0),-ydiff);
console.log(yrotvec)
srcquat = srcquat.multiply(destquat.inverse());
camerarot = camerarot.multiply(yrotvec);
var inverse_view_to_source = new THREE.Matrix4();
inverse_view_to_source.compose(newcampos,camerarot,camerascale);
return inverse_view_to_source;
}
NOTE:
I moved my answer to the answers so i can mark an answer.

Simple holes aren't rendered properly in Three.js

I have a simple rectangular wall and I like to place multiple window holes on it. It always works great for the first hole, but as soon as I add additional holes the polygon becomes messed up. See the images below to see what I'm talking about.
How can I draw holes properly in Three.js?
The right hole is not drawn properly.
After increasing the height of the right hole the entire wall mesh becomes halfcut.
Here is a sample code that causes above problem:
var shape = new THREE.Shape();
shape.moveTo(0, 0);
shape.lineTo(1, 0);
shape.lineTo(1, 1);
shape.lineTo(0, 1);
var windowHole = new THREE.Path();
windowHole.moveTo(0.14999999888241292, 0.7758620689655171)
windowHole.lineTo(0.4999999962747097, 0.7758620689655171)
windowHole.lineTo(0.4999999962747097, 0.3448275862068965)
windowHole.lineTo(0.14999999888241292, 0.3448275862068965)
shape.holes.push(windowHole);
windowHole = new THREE.Path();
windowHole.moveTo(0.5999999955296517, 0.7758620689655171)
windowHole.lineTo(0.7499999944120646, 0.7758620689655171)
windowHole.lineTo(0.7499999944120646, 0.6034482758620688)
windowHole.lineTo(0.5999999955296517, 0.6034482758620688)
shape.holes.push(windowHole);
var mesh = new THREE.Mesh(new THREE.ShapeGeometry(shape), this.material);
root.add(mesh);
The above code results in a warning:
Warning, unable to triangulate polygon!
at public_html/libs/three.js:27785
It turned out that this was a bug that is now fixed in version 66dev.
The bug was reported and discussed here:
https://github.com/mrdoob/three.js/issues/3386
The fixed version that I'm using now is developer built version 66dev committed at Jan 27th, 2014 here:
https://github.com/mrdoob/three.js/tree/dev/build
I assume this fix will be merged with the main three.js soon, but until then you can use the link above.
Some code might help. if possible link your code in jsfiddle...
just you need to change the order of the path creation... refer the link... http://jsfiddle.net/ebeit303/BuNb2/
var shape = new THREE.Shape();
shape.moveTo(-5, -5);
shape.lineTo(-5, 5);
shape.lineTo(5, 5);
shape.lineTo(5, -5);
shape.lineTo(-5, -5);
var windowHole = new THREE.Path();
windowHole.moveTo(-2,-2);
windowHole.lineTo(0,-2);
windowHole.lineTo(0,0);
windowHole.lineTo(-2,0);
windowHole.lineTo(-2,-2);
shape.holes.push(windowHole);
windowHole1 = new THREE.Path();
windowHole1.moveTo(3,3);
windowHole1.lineTo(4,3);
windowHole1.lineTo(4,4);
windowHole1.lineTo(3,4);
windowHole1.lineTo(3,3);
shape.holes.push(windowHole1);
var geometry = new THREE.ShapeGeometry( shape );
var material = new THREE.MeshBasicMaterial({color:0xffccff, side:2, overdraw:true} );
var mesh = new THREE.Mesh(geometry, material );
group.add(mesh);
Have a look on http://learningthreejs.com/data/constructive-solid-geometry-with-csg-js/. Whatever your codes are it will help you in doing it better. Substraction, addition, union, intersection everything is possible.

Super sample antialiasing with threejs

I want to render my scene at twice the resolution of my canvas and then downscale it before displaying it. How would I do that using threejs?
for me the best way to have a perfect AA with not too much work (see the code below)
ps :if you increase more than 2 its start to be too sharpen
renderer = new THREE.WebGLRenderer({antialiasing:true});
renderer.setPixelRatio( window.devicePixelRatio * 1.5 );
This is my solution. The source comments should explain what's going on. Setup (init):
var renderer;
var composer;
var renderModel;
var effectCopy;
renderer = new THREE.WebGLRenderer({canvas: canvas});
// Disable autoclear, we do this manually in our animation loop.
renderer.autoClear = false;
// Double resolution (twice the size of the canvas)
var sampleRatio = 2;
// This render pass will render the big result.
renderModel = new THREE.RenderPass(scene, camera);
// Shader to copy result from renderModel to the canvas
effectCopy = new THREE.ShaderPass(THREE.CopyShader);
effectCopy.renderToScreen = true;
// The composer will compose a result for the actual drawing canvas.
composer = new THREE.EffectComposer(renderer);
composer.setSize(canvasWidth * sampleRatio, canvasHeight * sampleRatio);
// Add passes to the composer.
composer.addPass(renderModel);
composer.addPass(effectCopy);
Change your animation loop to:
// Manually clear you canvas.
renderer.clear();
// Tell the composer to produce an image for us. It will provide our renderer with the result.
composer.render();
Note: EffectComposer, RenderPass, ShaderPass and CopyShader are not part of the default three.js file. You have to include them in addition to three.js. At the time of writing they can be found in the threejs project under the examples folder:
/examples/js/postprocessing/EffectComposer.js
/examples/js/postprocessing/RenderPass.js
/examples/js/postprocessing/ShaderPass.js
/examples/js/shaders/CopyShader.js
Here's how you might be able to work it out: In your three.js initialization code, when you create your renderer, make it double the dimensions of your primary canvas, and set it to render to a secondary, hidden canvas element that is twice as large as your primary canvas. Perform the necessary image manipulation on the secondary canvas, and then display the result on the primary canvas.

Resources