Aframe gltf-model demo with envmap - aframe

It's very convenient to load GLTF- model in aframe, but no case is found that contains envmap texture. I'd like to see that the official can provide the same case as three official. pmremGenerator.fromEquirectangular(texture) function is used to make gltf model produce real reflection effect
https://threejs.org/examples/#webgl_loader_gltf
https://threejs.org/examples/#webgl_materials_envmaps_hdr

One way would be creating a custom component, which will:
wait until the model is loaded
traverse through the object's children
if they have a material property - apply the envMap
The envmap needs to be a CubeTexture - which adds another level of complication, when you want to use a panorama. You can use a the WebGLRenderTargetCube - It's an object which provides a texture from a Cube Camera 'watching' the panorama.
Overall The component code could look like this:
// create the 'cubecamera' objct
var targetCube = new THREE.WebGLRenderTargetCube(512, 512);
var renderer = this.el.sceneEl.renderer;
// wait until the model is loaded
this.el.addEventListener("model-loaded", e => {
let mesh = this.el.getObject3D("mesh");
// load the texture
var texture = new THREE.TextureLoader().load( URL,
function() {
// create a cube texture from the panorama
var cubeTex = targetCube.fromEquirectangularTexture(renderer, texture);
mesh.traverse(function(node) {
// if a node has a material attribute - it can have a envMap
if (node.material) {
node.material.envMap = cubeTex.texture;
node.material.envMap.intensity = 3;
node.material.needsUpdate = true;
}
});
}
Check it out in this glitch.

I was having the same issue and i found that cube-env-map from a-frame-extras works like a charm.
View component on GitHub
Its docs describe it as:
Applies a CubeTexture as the envMap of an entity, without otherwise
modifying the preset materials
And the code is super simple:
yarn add aframe-extras
import 'aframe-extras'
<a-entity
gltf-model="src: url('/path/to/file.glb')"
cube-env-map="path: /cubeMapFolder/;
extension: jpg;
reflectivity: 0.9;">
</a-entity>

In THREE demo, I remember that WebGLRenderTargetCube was used to produce envmap, but recently it was found thatPMREMGenerator was basically used to generate envmap texture with mipmap. It also supports HDR image format, making gltf model better than JPG texture.
I don't know how these JS modules PMREMGenerator and RGBELoader are used together with the components of Aframe. Can someone provide such an example in Aframe ,Thanks
That's the same High dynamic range (RGBE) Image-based Lighting (IBL) using run-time generated pre-filtered roughness mipmaps (PMREM)

Related

Change opacity of glb 3D model with aframe

I am trying to make a web app where I can use world tracking to view a 3D model. I am trying to change the opacity of the model using the material property of the a-entity tag, however it does not seem to be working. any idea on how to change the opacity of my 3D object in order to make it translucent?
<a-entity
id="model"
gltf-model="#3dmodel"
class="cantap"
geometry="primitive: box"
scale="0.5 0.5 0.5"
material="transparent: true; opacity 0.1"
animation-mixer="clip: idle; loop: repeat"
hold-drag two-finger-spin pinch-scale>
</a-entity>
GLTF models come with their own materials included in the model file. These are handled by THREE.js rather than AFrame, so in order to access their properties you have to search through the elements object3D, using something like this:
this.el.object3D.traverse((child) => {
if (child.type === 'Mesh') {
const material = child.material;
// Do stuff with the material
material.opacity = 0.1;
}
})
See the THREE.js documentation on Materials and Object3D for more detail.
Also, I noticed you have both a geometry primitive and a gltf-model on that entity. Not sure how well those two things can co-exist, if you want both a box and the model you should probably make one a child of the other.
E Purwanto's answer above works for me with an addition of setting transparency true:
this.el.object3D.traverse((child) => {
if (child.type === 'Mesh') {
const material = child.material;
// Do stuff with the material
material.transparent = true; // enable to modify opacity correctly
material.opacity = 0.1;
}
})

How to use a collada model with aframe-v1.1.0.min

I have been using a-frame since 2018 to show my scenographies to the directors I work for. I used the colladas files for my objects and everything was working great and my textures were
as I wanted. But since the webxr (aframe-v1.1.0.min) appeared it is no longer possible to use
collada I have tried the Gltf files but it is too heavy and not satisfactory. So I wanted to know how to put collada back into the a-frame scipts. I tried: "collada-model-legacy.js"
with "ColladaLoader.js" in another folder but it doesn't work. Do you have a solution?
Thank you
You can use any of the loaders from the three.js repository - also the ColladaLoader.
You could create a wrapper component, which will use threejs loader and add the model to the scene:
AFRAME.registerComponent("foo", {
init: function() {
const el = this.el;
// create a loader
const loader = new THREE.ColladaLoader();
// load the model
loader.load("MODEL_URL", function(model) {
el.object3D.add(collada.scene);
})
}
})
A simple example could be this component (check it out with static and animated collada models here)

Aframe 1.0.4 - setting scene.environment does not update materials

So I saw an old post here:
https://discourse.threejs.org/t/is-there-a-way-to-increase-scene-environment-map-exposure-without-affecting-unlit-materials/13458/4
That says... "If you apply the env map to Scene.environment, it is automatically used as the environment map for all physical materials in the scene (assumed the material’s envmap is not set)."
So tried this using an Aframe component on the scene:
AFRAME.registerComponent('setenvironment', {
init: function () {
var sceneEl = this.el;
var loader = new THREE.CubeTextureLoader();
loader.setPath('./');
var textureCube = loader.load([
'./images/py.png', './images/pz.png',
'./images/nx.png', './images/ny.png',
'./images/px.png', './images/nz.png'
]);
textureCube.encoding = THREE.sRGBEncoding;
sceneEl.object3D.environment = textureCube;
}
});
The environment attribute is successfully set, but the other objects materials still have envMap set to null and the environment lighting does not take effect on the materials.
Any ideas?
aframe 1.0.4 uses three.js revision 111dev. The scene's environment property was introduced in revision 112 (source).
If you use the aframe master build - it seems to be working properly (as its based on three.js r119).
Otherwise, you'll have to iterate through the meshes, and set the material.envMap property manually.

Animating a series of PNG images in a-frame / AR.JS

I am currently experimenting with A-Frame and AR.js for a project I'm working on. I was wondering if it's possible to animate a series of PNG files eg. img-1.png, img-2.png, and so on in a-frame without individually adding animation for each frame?
I'm aware of an A-frame GIF component but GIFs are harder to maintain and can only output limited colors (and also trouble with opacity).
Any insights/help would be appreciated. Thanks!
How about a component, which loads up the .pngs as textures, and swaps them in a fixed interval:
AFRAME.registerComponent("slideshow", {
init: function() {
load up and store the images
var loader = new THREE.TextureLoader()
this.array = []
this.array.push(loader.load("one.png"))
this.array.push(loader.load("two.png"))
Instead of doing this one by one, you could do this in a loop ("img-" + i + ".png").
Also you could provide a list using the schema.
Wait until the entity is loaded:
this.el.addEventListener('loaded', e => {
let mesh = this.getObject3D('mesh')
let material = mesh.material
swap the material.map texture in the tick() or within an interval:
let i = 0
setInterval(e => {
// if we're at the last element - swap to the first one
if (i >= this.array.length) i = 0
this.material.map = this.array[i++]
this.material.needsUpdate = true
and it should be working like in this fiddle, when attached to an entity:
<a-box slideshow></a-box>
Why this.array ? For example you can easily access it in the remove() function and dispose the textures to free up memory.
Why not just do setAttribute('material', 'src', 'img-' + i + '.png') ?
I believe with more images it may by highly inefficcient.

How do I use the setting "Park (Day)" for the environment under Lighting from the gltf viewer to A-Frame?

I'm trying to load a gltf model (link) to A-frame, but it appears dark, I've checked it using the link and the difference is that in the gltf viewer, under lighting, there's a field called environment which is set to "Park (Day)".
with environment set to: None
with environment set to: Park (Day)
How do I apply this setting to my model in A-Frame?
The other difference is the gammeOutput property which I have already fixed with "colorManagement: true" in the a-scene renderer.
Currently using version 0.9.0 of A-Frame
If you see an image being reflected by the model, it's an environment map. Its used when you want your object to reflect its surroundings or any other environment.
You can set it on primitives with either envMap (cubemap) or sphericalEnvMap (360 image) property:
<a-sphere material="roughness:0; sphericalEnvMap: #myImage>
Check it out in this fiddle.
With models, you'd need to dig in a bit deeper. You'd need to traverse the model, and set each mesh envMap property:
let texture = THREE.TextureLoader()
const mesh = element.getObject3D('mesh');
const envMap = texture;
if (!mesh) return;
mesh.traverse(function (node) {
if (node.material && 'envMap' in node.material) {
node.material.envMap = envMap;
node.material.needsUpdate = true;
}
});

Resources