Table extra fields in js object
edubart opened this issue · 5 comments
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)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').textContentbut 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?
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)
endThen 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.
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.
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 fengari-lua/fengari-interop#44