threejs_playGnd icon indicating copy to clipboard operation
threejs_playGnd copied to clipboard

Cross-domain image for texture

Open chimanaco opened this issue 10 years ago • 10 comments

Hi, first of all thank you so much for creating _three.js playGnd. I definitely started to play with three.js thanks to this.

Let me ask you about texture with a cross-domain image. I want to load images from Instagram and use it for textures for geometries. However, I haven't done yet.

On _three.js playGnd, I can see a texture by the following code.

map = THREE.ImageUtils.loadTexture('../texturez/proxy.php?url=http://distilleryimage6.ak.instagram.com/77a4df402ebf11e38c1322000a1fb036_7.jpg'); geometry = new THREE.CubeGeometry(200, 200, 200); material = new THREE.MeshLambertMaterial({shading: THREE.FlatShading, color: 0xdcdcdc, map: map}); mesh = new THREE.Mesh(geometry, material); map.wrapS = map.wrapT = THREE.RepeatWrapping; map.repeat.set( 1, 1 ); scene.add(mesh);

I use proxy.php you mentioned in Stack Overflow.

cross-domain image for three.js (canvas/webGL), proxy? - Stack Overflow http://stackoverflow.com/questions/17710414/cross-domain-image-for-three-js-canvas-webgl-proxy

In addition, I also set access control using express.js.

app.all("/", function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With"); res.header("Access-Control-Allow-Methods", "GET, PUT, POST"); return next(); });

I downloaded _three.js playGnd code from Github and had a look at, but I haven't found a solution. Did you do anything else on _three.js playGnd but use proxy.php?

Thanks in advance.

chimanaco avatar Oct 12 '13 09:10 chimanaco

Forgot to mention:

  • Three.js r58
  • Googel Chrome 30.0.1599.69
  • Mac OS 10.8.4

chimanaco avatar Oct 12 '13 19:10 chimanaco

@nbriz mentions this in his short tutorial with Creator's Project

Basically you just need to prepend your link with ../texturez/proxy.php?url=:

map = THREE.ImageUtils.loadTexture('../texturez/proxy.php?url=http://distilleryimage6.ak.instagram.com/77a4df402ebf11e38c1322000a1fb036_7')

if you build your objects in the editor this will also pre-fill it. screen shot 2013-10-13 at 8 08 50 pm

yyolk avatar Oct 14 '13 01:10 yyolk

Thank you for comment. I meant that I can see a texture from a cross-domain image on playGnd editor, but I can' t outside the editor. Therefore, I want to ask how the editor can solve the cross domain policy problem when loading images.

chimanaco avatar Oct 15 '13 06:10 chimanaco

Basically you just need to prepend your link with ../texturez/proxy.php?url=:

map = THREE.ImageUtils.loadTexture('../texturez/proxy.php?url=http://distilleryimage6.ak.instagram.com/77a4df402ebf11e38c1322000a1fb036_7')

since proxy.php is a script running on the server hosting the page… it doesnt run into cross-domain policy issues

yyolk avatar Oct 15 '13 06:10 yyolk

@chimanaco it's always a hack to get images on other hosts as textures, it's technically against the rules ( for security reasons or whatever... don't totally understand why ). Like @yyolk mentioned the work-around is using a proxy like the one i posted on stackoverflow, here's the script i'm using:

            <?php
    // PHP Proxy
    // Responds to both HTTP GET and POST requests
    //
    // Author: Abdul Qabiz
    // March 31st, 2006
    //

    // Get the url of to be proxied
    // Is it a POST or a GET?
    $url = ($_POST['url']) ? $_POST['url'] : $_GET['url'];
    $headers = ($_POST['headers']) ? $_POST['headers'] : $_GET['headers'];
    $mimeType =($_POST['mimeType']) ? $_POST['mimeType'] : $_GET['mimeType'];


    //Start the Curl session
    $session = curl_init($url);

    // If it's a POST, put the POST data in the body
    if ($_POST['url']) {
        $postvars = '';
        while ($element = current($_POST)) {
            $postvars .= key($_POST).'='.$element.'&';
            next($_POST);
        }
        curl_setopt ($session, CURLOPT_POST, true);
        curl_setopt ($session, CURLOPT_POSTFIELDS, $postvars);
    }

    // Don't return HTTP headers. Do return the contents of the call
    curl_setopt($session, CURLOPT_HEADER, ($headers == "true") ? true : false);

    curl_setopt($session, CURLOPT_FOLLOWLOCATION, true); 
    //curl_setopt($ch, CURLOPT_TIMEOUT, 4); 
    curl_setopt($session, CURLOPT_RETURNTRANSFER, true);

    // Make the call
    $response = curl_exec($session);

    if ($mimeType != "")
    {
        // The web service returns XML. Set the Content-Type appropriately
        header("Content-Type: ".$mimeType);
    }

    echo $response;

    curl_close($session);

    ?>

keep in mind, that ../texturez/proxy.php?= implies that u have a folder on ur server called "texturez" with a file called "proxy.php" ... so u need to make sure to save the code above as "proxy.php" onto ur own server, otherwise ur referencing a file that doesn't exist

nbriz avatar Oct 15 '13 15:10 nbriz

Thank you guys for all help. Yes, I tried above things. I uploaded the following files on my server and tried them.

  • proxy.php (same as one on playGnd. I put it in the same directory as index.html)
  • index.html (copied from playGnd editor and modified a directory for proxy.php)
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      body {
        background-color: #ffffff;
        margin: 0;
        overflow: hidden;
      }
    </style>
  </head>
  <body>

    <script src="http://brangerbriz.net/labs/threejs_playGnd/js/three.min.js"></script>
    <script src="http://brangerbriz.net/labs/threejs_playGnd/js/Detector.js"></script>
    <script>

      if ( ! Detector.webgl ) Detector.addGetWebGLMessage();

      var camera, scene, renderer;
      var geometry, material, mesh;

      function setup() {

        var W = window.innerWidth, H = window.innerHeight;
        renderer = new THREE.WebGLRenderer();
        renderer.setSize( W, H );
        document.body.appendChild( renderer.domElement );

        camera = new THREE.PerspectiveCamera( 50, W/H, 1, 10000 );
        camera.position.z = 500;

        scene = new THREE.Scene();


        // paste your code from the geometryGUI here
        map = THREE.ImageUtils.loadTexture('proxy.php?url=http://distilleryimage6.ak.instagram.com/77a4df402ebf11e38c1322000a1fb036_7.jpg');
        geometry = new THREE.CubeGeometry(200, 200, 200);
        material = new THREE.MeshBasicMaterial({shading: THREE.FlatShading, color: 0xdcdcdc, map: map});
        mesh = new THREE.Mesh(geometry, material);
        map.wrapS = map.wrapT = THREE.RepeatWrapping;
        map.repeat.set( 1, 1 );
        scene.add(mesh);
      }

      function draw() {

        requestAnimationFrame( draw );

        // experiment with code from the snippets menu here

        renderer.render( scene, camera );

      }

      setup();
      draw();

    </script>

  </body>
</html>

But I couldn't make it, that's why I asked if there is something I have to do except loading a image though proxy.php.

I guess my problem is on my server or somewhere or just a simple mistake. :(

chimanaco avatar Oct 15 '13 16:10 chimanaco

Now I can get images on other hosts as textures. The way using proxy.php doesn't work for me (I still don't know why), but the way using corsproxy.com works. This is the second answer for one @nbriz posted on stackoverflow. Although I wish I could make it with proxy.php because I don't have to be dependent on someone's website, what I'm making is just a demo, so it's okay right now. I will try to use proxy.php again.

Then the code I'm using looks like the following.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      body {
        background-color: #ffffff;
        margin: 0;
        overflow: hidden;
      }
    </style>
  </head>
  <body>

    <script src="three.min.js"></script>
    <script src="Detector.js"></script>
    <script>

      if ( ! Detector.webgl ) Detector.addGetWebGLMessage();

      var camera, scene, renderer;
      var geometry, material, mesh;
      var canvas, context;
      var imgW = 612;
      var imgH = 612;

      function setup() {

        var W = window.innerWidth, H = window.innerHeight;
        renderer = new THREE.WebGLRenderer();
        renderer.setSize( W, H );
        document.body.appendChild( renderer.domElement );

        camera = new THREE.PerspectiveCamera( 50, W/H, 1, 10000 );
        camera.position.z = 1500;

        scene = new THREE.Scene();

        canvas = document.createElement("canvas");
        canvas.width = imgW;
        canvas.height = imgH;
        context = canvas.getContext("2d");

        var img = new Image();
        img.crossOrigin = '';

        var texture = new THREE.Texture(canvas);

        img.onload = function() {
            context.drawImage(img, 0, 0);
            texture.needsUpdate = true;
            scene.add(mesh);
        };
        img.src = 'http://www.corsproxy.com/distilleryimage6.ak.instagram.com/77a4df402ebf11e38c1322000a1fb036_7.jpg';

        geometry = new THREE.CubeGeometry(imgW, imgH, imgW);
        material = new THREE.MeshBasicMaterial({shading: THREE.FlatShading, color: 0xdcdcdc, map: texture});
        mesh = new THREE.Mesh(geometry, material);

      }

      function draw() {
        requestAnimationFrame( draw );

        // experiment with code from the snippets menu here

        renderer.render( scene, camera );

      }

      setup();
      draw();

    </script>
  </body>
</html>

Thanks for taking time, @yyolk @nbriz !

chimanaco avatar Oct 21 '13 05:10 chimanaco

thnx for sharing @chimanaco, nice to have options :)

nbriz avatar Oct 22 '13 16:10 nbriz

On a side-note; imgur also works, similar to corsproxy

yyolk avatar Oct 26 '13 19:10 yyolk

@yyolk looks nice! Thank you for sharing!

chimanaco avatar Oct 28 '13 15:10 chimanaco