Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using clojurescript to render Three.js scene on HTML page

I'm trying to implement the Creating a scene example for three.js in clojurescript.

I'm not doing the animation and just want to display the static scene (a green block).

The problem appears to be in this function that is called to render the scene.

    (defn ^:export draw []
      (.render renderer scene camera)
    )

This is what is doing the calling from the HTML.

    %script{:type => "text/javascript"}
      three.demo.draw();

It sees and runs the draw function, for example, when I have it print out "HELLO" to the body of the document.

    (.write js/document "HELLO")

I have no idea what's wrong, everything else on the page is rendered.

In this HTML file, I have

<script src='https://raw.github.com/mrdoob/three.js/master/build/three.js'></script>
<script src='js/main.js' type='text/javascript'></script>
<script type='text/javascript'>goog.require('main')</script>

and

<script type='text/javascript'>
  three.demo.draw();
</script>

Below is the end of main.js, which is the Javascript created from the clojurescript file.

    goog.provide("three.demo");
    goog.require("cljs.core");
    goog.require("goog.dom");
    three.demo.scene = new THREE.Scene;
    three.demo.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1E3);
    three.demo.renderer = new THREE.WebGLRenderer;
    three.demo.renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(three.demo.renderer.domElement);
    three.demo.geometry = new THREE.CubeGeometry(1, 1, 1);
    three.demo.material = new THREE.MeshBasicMaterial(cljs.core.ObjMap.fromObject(["\ufdd0'color"], {"\ufdd0'color":255}));
    three.demo.cube = new THREE.Mesh(three.demo.geometry, three.demo.material);
    three.demo.scene.add(three.demo.cube);
    three.demo.camera.position.setZ(5);
    three.demo.draw = function draw() {
      three.demo.renderer.render(three.demo.scene, three.demo.camera);
      return document.write("HELLO")
    };
    goog.exportSymbol("three.demo.draw", three.demo.draw);

Under :cljsbuild in the project.clj file has

    :foreign-libs [{:file "https://raw.github.com/mrdoob/three.js/master/build/three.js"
                    :provides ["three"]}]

I tried :externs and :foreign-libs and neither seems to work.

like image 345
Kao Nashi Avatar asked Jan 23 '13 00:01

Kao Nashi


1 Answers

The direct translation of the Creating a scene code would be:

(defn ^:export example []
  (let [scene (js/THREE.Scene.)
        width (.-innerWidth js/window)
        height (.-innerHeight js/window)
        camera (js/THREE.PerspectiveCamera. 75 (/ width height) 0.1 1000 )
        renderer (js/THREE.CanvasRenderer.)
        geometry (js/THREE.CubeGeometry. 1 1 1)
        material (js/THREE.MeshBasicMaterial. (clj->js {:color 0x00ff00}))
        cube (js/THREE.Mesh. geometry material)
        render (fn cb []
                   (js/requestAnimationFrame cb) 
                   (set! (.-x (.-rotation cube))  (+ 0.1 (.-x (.-rotation cube))) )
                   (set! (.-y (.-rotation cube))  (+ 0.1 (.-y (.-rotation cube))) )
                   (.render renderer scene camera)
                 ) 
        ]
    (.setSize renderer width height)
    (.appendChild js/document.body (.-domElement renderer) )
    (.add scene cube)
    (set! (.-z (.-position camera))  5)
    (render)
    )
  )

This is not using :foreign-libs and :require; it uses the direct JS interop and assumes that three.js was previously loaded. It can be probably done in a nicer way, but this is a one-to-one translation that works.

like image 56
f3lix Avatar answered Sep 29 '22 14:09

f3lix