0

I have an OBJ file generated dynamically by a server on a separate domain. It has some materials and texture JPG files.

I load this OBJ file with a simple php proxy (fileProxy.php):

<?php
 header('Access-Control-Allow-Origin: *');
 header("Access-Control-Allow-Credentials: true"); 
 header('Access-Control-Allow-Headers: X-Requested-With');
 header('Access-Control-Allow-Headers: Content-Type');
 header('Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT'); // http://stackoverflow.com/a/7605119/578667
 header('Access-Control-Max-Age: 86400');

//Check if this is an image. if So print coorect header.
if (strpos($_REQUEST['fileToProxy'],'jpg') !== false) {

     header('Content-Type: image/jpeg');

}


$proxyFile = (isset($_REQUEST['fileToProxy'])? $_REQUEST['fileToProxy'] : null);

if ( isset($proxyFile)){
  // the files sent to us aren't properly url encoded
  $proxyFile = str_replace(' ', '+', $proxyFile);

  $content = file_get_contents($proxyFile);

  print($content);
}
else {
  echo "ERROR: no file to proxy";
}



?>

Loading the OBJ files works like a charm

BUT, i cant load the JPG textures embeded in the MTL file. Single colored shaders all work fine, but loading images i get errors.

I get the following error in chrome:

Uncaught SecurityError: Failed to execute 'texImage2D' on 'WebGLRenderingContext': the cross-origin image at http://ec2-54-201-204-177.us-west-2.compute.amazonaws.com/fileProxy.php?fil…est-2.compute.amazonaws.com/3DModels/435639/DonutFullBread.jpg&timtest=115 may not be loaded.

The address of the texture file is fed correctly into my proxy: http://ec2-54-201-204-177.us-west-2.compute.amazonaws.com/fileProxy.php?fileToProxy=http://ec2-54-201-204-177.us-west-2.compute.amazonaws.com/3DModels/435639/DonutFullBread.jpg&timtest=115

Now after checking my Network monitor, i realise that the Jpg Image is successfully downloaded and the correct CORS headers are all in place. But webgl/three.js still spits out the errors and does not display my model.

SO this seems like a WEBGL bug. But i get security erros in all browsers. I have tested this on my localhost and on my server. Same problem.

Any solutions?

UPDATE Here's how i load the OBJ/MTL files with three.js: (Only cross domain textures fail)

var loader = new THREE.OBJMTLLoader( manager);

///////////////////LOAD MDOEL////////////////////
 loader.load( 'http://ec2-54-201-204-177.us-west-2.compute.amazonaws.com/fileProxy.php?fileToProxy=' + obj.file, 'http://ec2-54-201-204-177.us-west-2.compute.amazonaws.com/fileProxy.php?fileToProxy=' + obj.material, function ( object ) {                                              
//if loaded, do some stuff here.                                                   
}
loadedmodel.add(object);

That's all I do really. The Materials and textures are phrased correctly by the loader. I dont have to set any materials up.

Aaron Isaac
  • 63
  • 3
  • 6

4 Answers4

4

I just want to put this here for other people. I had a very similar problem when i was trying to load images from static google map images. So here is what i did

THREE.ImageUtils.crossOrigin = "anonymous";

Just before the actual texure is being loaded. Now this got it working and i could load the images without a problem.

niksad8
  • 41
  • 3
3

I know this is old, but I just spent a few hours troubleshooting the same issue, so I thought I'd post an answer here for any future users that run into this. The solution is quite simple, but unfortunately it is not documented anywhere that I could see. I discovered it by pure dumb luck.

var loader = new THREE.OBJMTLLoader( manager);
loader.crossOrigin = ''; //  <-- this is all you need to add!

///////////////////LOAD MDOEL////////////////////
loader.load( 'http://obj_url.com', 'http://mtl_url.com', function ( object ) {                                              
    //if loaded, do some stuff here.                                                   
}
loadedmodel.add(object);

If it's not clear in the code above, the only thing you need to do is to add the line loader.crossOrigin = ''; after declaring the OBJMTLLoader.

I hope this helps someone in the future!

Vince
  • 3,207
  • 1
  • 17
  • 28
1

You need to set the crossorigin property explicitly for the image. Copying from one of my own examples:

images[id].image = new Image();

images[id].image.crossOrigin = "anonymous";

images[id].image.onload = function() {/* WebGL texture load of file here */}

images[id].image.src = "http://ec2-54-201-204-177.us-west-2.compute.amazonaws.com/fileProxy.php?fileToProxy=http://ec2-54-201-204-177.us-west-2.compute.amazonaws.com/3DModels/435639/DonutFullBread.jpg&timtest=115"

I loaded the image that you have mentioned above, and it works correctly for me in the browser as a texture.

Prabindh
  • 3,356
  • 2
  • 23
  • 25
  • Pardon my ignorance. But how will i go about doing this? The address always changes because these textures are generated dynamically. Also, if i just apply a standard lambert material with a texture from my proxy it works fine. The problem happens when the texture is applied through the OBJ/MTL loader i think. – Aaron Isaac Feb 23 '14 at 11:33
  • The code I specified runs on the client side (Javascript on the client browser). Wherever you are loading the image with Javascript, you need to specify this property for the image. – Prabindh Feb 23 '14 at 11:37
  • The texture its self is specified within the MTL file. How do i define the cross orgin properties for the texture, in this case? Thanks very much for your help. – Aaron Isaac Feb 23 '14 at 11:47
  • How are you loading the OBJ on the client side using Three.js ? – Prabindh Feb 23 '14 at 11:55
  • Have you tried adding "THREE.ImageUtils.crossOrigin = "";" before the three.js calls for loading ? – Prabindh Feb 23 '14 at 12:33
0

I often joke about my projects blowing up because I forgot a semicolon. Well, this time it is no joke. Someone actually forgot a semicolon in the latest revision of ThreeJS. I dug into MTLLoader.js (which is referenced by OBJMTLLoader.js) and found that this line (near the bottom of the MTLLoader prototype constructor) had a semicolon missing:

materialCreator.crossOrigin = this.crossOrigin

That'll kill any cross-site sharing for all materials. I added the semicolon back in...

materialCreator.crossOrigin = this.crossOrigin;

...and all was well with the world again.