Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

User uploaded textures in three.js

Here you will find a jsFiddle adaptation of the problem.

I would like to create a 3d web application in which the user is able to select an image file on their local machine:

<input id="userImage" type="file"/>

When a file is selected, the image is loaded as a parameter in a THREE.ShaderMaterial object. A glsl shader is applied to the image and the result is rendered to a container in the browser:

$("#userImage").change(function(){
    var texture = THREE.ImageUtils.loadTexture( $("#userImage").val() );
    texture.image.crossOrigin = "anonymous";
    shader.uniforms.input.value = texture;
    shader.uniforms.input.needsUpdate = true;
});

Unfortunately, this results in the following error:

Cross-origin image load denied by Cross-Origin Resource Sharing policy.

I am aware there are issues with trying to access cross-origin resources in WebGL, but at the same time I see the following work around is offered in the official specification for WebGL:

The following ECMAScript example demonstrates how to issue a CORS request for an image coming from another domain. The image is fetched from the server without any credentials, i.e., cookies.

var gl = ...;
var image = new Image();

// The onload handler should be set to a function which uploads the HTMLImageElement
// using texImage2D or texSubImage2D.
image.onload = ...;

image.crossOrigin = "anonymous";

image.src = "http://other-domain.com/image.jpg";

In my code you see I've specified the crossOrigin parameter for the image object, but I still receive the error. Where does my example differ from the specification? Is it even possible to use local resources in WebGL as one would with resources hosted on another server? Barring that, are there any other work arounds I should consider to accomplish the task?

like image 484
16807 Avatar asked Dec 19 '13 23:12

16807


2 Answers

The solution actually turns out to be commonly used to preview local images prior to, say, uploading them a server. The image you are trying to render is converted to a data url where restrictions about cross origin policies do not apply. The corrected code is located here. What follows is the meat of it:

userImage = $("#userImage")[0];
if (userImage.files && userImage.files[0]) {
    var reader = new FileReader();

    reader.onload = function (e) {
        image.src = e.target.result;
    };

    reader.readAsDataURL(userImage.files[0]);
}
like image 74
16807 Avatar answered Sep 29 '22 21:09

16807


I also had this problem, but I had almost exact code only I was using

var map = THREE.ImageUtils.loadTexture( e.target.result );

So I had to replace that code with

var image = document.createElement( 'img' );
var texture = new THREE.Texture( image );
image.onload = function()  {
    texture.needsUpdate = true;
};

and that solved the problem..

like image 25
pera Avatar answered Sep 29 '22 22:09

pera