fengari-lua / fengari

🌙 φεγγάρι - The Lua VM written in JS ES6 for Node and the browser
MIT License
1.8k stars 64 forks source link

Table extra fields in js object #155

Closed edubart closed 5 years ago

edubart commented 5 years ago

I am trying to port this example of three.js to Fengari: https://threejs.org/examples/?q=shader#webgl_shader

However I am getting these errors and the example does not work:

THREE.ShaderMaterial: 'apply' is not a property of this material.
THREE.ShaderMaterial: 'invoke' is not a property of this material.
THREE.ShaderMaterial: 'get' is not a property of this material.
THREE.ShaderMaterial: 'has' is not a property of this material.

Looks like when I create a table the js objects will always have these fields and make Three.js error. How do I fix this?

For reference my ported code of the example is this:

  local js = require 'js'
  local THREE = js.global.THREE
  local document, window, new = js.global.document, js.global.window, js.new
  local container, camera, scene, renderer, uniforms
  local function onWindowResize()
    renderer:setSize(window.innerWidth, window.innerHeight)
  end
  local function init()
    container = document:getElementById('container')
    camera = new(THREE.OrthographicCamera, -1, 1, 1, -1, 0, 1)
    scene = new(THREE.Scene)
    local geometry = new(THREE.PlaneBufferGeometry, 2, 2)
    uniforms = {
      time = { value = 1.0 }
    }
    local material = new(THREE.ShaderMaterial, {
      uniforms= uniforms,
      vertexShader= document:getElementById('vertexShader').textContent,
      fragmentShader= document:getElementById('fragmentShader').textContent
    })
    local mesh = new(THREE.Mesh, geometry, material)
    scene:add(mesh)
    renderer = new(THREE.WebGLRenderer)
    renderer:setPixelRatio(window.devicePixelRatio)
    container:appendChild(renderer.domElement)
    onWindowResize()
    window:addEventListener('resize', onWindowResize, false)
  end
  local function animate(_, timestamp)
    timestamp = timestamp or 0
    window:requestAnimationFrame(animate)
    uniforms.time.value = timestamp / 1000
    renderer:render(scene, camera)
  end
  init()
  animate(nil, 1)
edubart commented 5 years ago

I've found a workaround, doing this:

    local material = new(THREE.ShaderMaterial)
    material.uniforms= uniforms
    material.vertexShader= document:getElementById('vertexShader').textContent
    material.fragmentShader= document:getElementById('fragmentShader').textContent

but I still want to know how to make the other way work. And now I am having another issue the animation is static, unlike the pure js example the line uniforms.time.value = timestamp / 1000 does not seems to work, I think its because maybe the lua object is not linked with the js object? If so how could I make it work?

edubart commented 5 years ago

I have found a solution for both problems by creating a JS object explicitly:

  local object = function(t)
    return js.new(function(o)
      for k,v in pairs(t) do
        o[k] = v
      end
    end)
  end

Then instead of using plain tables I use:

    uniforms = object{
      time = object{ value = 1.0 }
    }
    local material = new(THREE.ShaderMaterial, object{
      uniforms= uniforms,
      vertexShader= document:getElementById('vertexShader').textContent,
      fragmentShader= document:getElementById('fragmentShader').textContent
    })

Took me a while to try this, I think a function for creating JS objects similar to this one could be implemented in fengari-interop or at least this behavior could be documented for new users trying to use fengari with other JS libs.

catwell commented 5 years ago

I agree, we all have helpers like this (see mine), they could be in interop.

daurnimator commented 5 years ago

However I am getting these errors and the example does not work:

THREE.ShaderMaterial: 'apply' is not a property of this material.
THREE.ShaderMaterial: 'invoke' is not a property of this material.
THREE.ShaderMaterial: 'get' is not a property of this material.
THREE.ShaderMaterial: 'has' is not a property of this material.

Looks like when I create a table the js objects will always have these fields and make Three.js error. How do I fix this?

Lua tables are not exposed as JS objects, but as Map-like objects with get/set methods. As you've discovered, you'll need to convert your table to a JS object, or alternatively use js.createproxy.

daurnimator commented 5 years ago

I agree, we all have helpers like this (see mine), they could be in interop.

I'm going to close this issue as a duplicate of https://github.com/fengari-lua/fengari-interop/issues/44