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.
Related
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)
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)
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.
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;
}
});
I have created a dice entity from six plane entities. However, when I click and drag the dice entity, instead of moving that dice, only one sided face gets dragged.
This can be tried hands on at link http://shrouded-chamber-73425.herokuapp.com/
Rather than creating a box from six planes, you should create one box and use a material that will render the dice faces for you. You can use three.js CubeTexture:
AFRAME.registerComponent('dice-texture', {
init: function () {
var box = this.el.getOrCreateObject3D('mesh');
var loader = new THREE.CubeTextureLoader();
loader.setPath('/images/diceTextures/');
var textureCube = loader.load([
'1.png', '2.png',
'3.png', '4.png',
'5.png', '6.png'
]);
box.material = new THREE.MeshStandardMaterial({envMap: textureCube);
}
});
<a-entity geometry="primitive: box" dice-texture></a-entity>
Then you can further optimize so that every box shares the same material so you aren't creating a new one each time.