-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Material Components (uv-scroll, video-texture-target, video-texture-source) #5911
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work! Left some comments. I'll be curious if/when we ever bump into an invalidated assumption about entities always being associated with object3D
s. Even if down the road we decide again material entities, it's encouraging to me to see that we can "just" have entities and component data and it's fine
@@ -113,6 +115,7 @@ export class App { | |||
this.store = store; | |||
// TODO: Create accessor / update methods for these maps / set | |||
this.world.eid2obj = new Map(); | |||
this.world.eid2mat = new Map(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I (wrongly) assumed that the networking system would be making use of eid2obj
, but this doesn't seem to be the case. I'd love to see a NetworkedUVScroll
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the way I would network sync a lot of the animation type stuff is just using serverTime instead. But your point stands it should be completely trivial to network stuff about material entities too, they are not special.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Network IDs would need to be assigned (deterministically) to materials in setNetworkedData...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah that makes sense. That makes things a bit more tricky but still seems doable.
exitedObject3DQuery(world).forEach(removeFromMap); | ||
entities.forEach(removeObjFromMap); | ||
exitedObject3DQuery(world).forEach(removeObjFromMap); | ||
exitedMaterialQuery(world).forEach(removeFromMatMap); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Checking my understanding...)
It is OK not to call o.material ? o.material.eid ? removeEntity(world, o.material.eid)
in the traverseSome
above, because the various cleanup
functions are going to call disposeMaterial
as needed. We don't risk missing any material eid
s. Is that correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the idea yeah. I don't think it would be appropriate to remove a material entity just because an Mesh pointing at that material was removed. We specifically dispose of materials when we are done with them through various different means. All of them should always call disposeMaterial
, which will call removeEntity
, and then it will be removed from the map here.
migrateLegacyComponents(world); | ||
uvScrollQuery(world).forEach(function (eid) { | ||
const map = (world.eid2mat.get(eid)! as MeshBasicMaterial).map; | ||
if (!map) return; // This would not exactly be expected to happen but is not a "bug" either. There is just no work to do in this case. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused why this wouldn't be a bug. Is it valid to attach a UVScroll (material) component to something that isn't a material? Alternatively, is it valid to have a material eid
that is not in eid2mat
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. It must be on a material, and the material will be in the map (hence the !). What is not guaranteed, and I don't think inherently a bug is that a material can choose to not have a map. In practice you would not do this in a GLTF file, but I could see cases where we would be UV scrolling something and changing its map. Maybe turning it off? Not sure. Maybe that is not a real usecase.
} | ||
mapMaterials(obj, function (m) { | ||
disposables.add(m); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
smart
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, in making sure we were calling disposeMaterial
here it became clear that we didn't need to be so verbose. Also it was actually a bug before because we weren't calling dispose on the material itself.
components: { [componentName: string]: any }, | ||
idx2eid: Map<number, EntityID> | ||
) { | ||
Object.keys(components).forEach(name => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Object.entries(components).forEach(([name, props]) => {
?
const components = obj.userData.gltfExtensions?.MOZ_hubs_components; | ||
if (components) inflateComponents(world, eid, components, idx2eid); | ||
|
||
mapMaterials(obj, function (mat: Material) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this check if the object was replaced by an inflator?
mapMaterials( world.eid2obj.get(eid) || obj,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The materials in the GLTF file certainly would not be on an object created by an inflator. If obj
is a Mesh
(only thing that can have materials from the GLTFLoader) and swapped, that's a bug, and we throw an exception below.
src/bit-systems/video-texture.ts
Outdated
const data = sourceDataMap.get(eid); | ||
if (data && world.time.elapsed > data.lastUpdated + 1000 / VideoTextureSource.fps[eid]) { | ||
updateRenderTarget(world, data.renderTarget, data.camera); | ||
data.lastUpdated = world.time.elapsed; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does video-texture.ts set renderTarget.needsUpdate = false
after updateRenderTarget
whereas that does not happen here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was just an additional property I sloppily stuck on renderTarget
in the camera-tool system. This system does not use that, though the purpose of that in camera-tool system was to only update the render target when the material preview is visible, which we should actually do here too...
|
||
function noop() {} | ||
|
||
export function updateRenderTarget(world: HubsWorld, renderTarget: WebGLRenderTarget, camera: EntityID) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is tricky. (Not new)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think it will become less tricky if we schedule it in the right spot relative to normal rendering. It might actually already be the case that the bone visibility stuff is no longer needed but I didn't want to revisit that now.
} else if (source && entityExists(world, source)) { | ||
bindMaterial(world, eid); | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if the source
entity goes away, and this VideoTextureTarget.source[eid]
pointed to it? Do we need to check for that and set VideoTextureTarget.source[eid] = 0
, is this handled already, or is this not possible / unnecessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be handled just above if (!source || !entityExists(world, source)) {
This PR adds support for "material components". We allow adding hubs components to materials in GLTF files. So far we only used this for
video-texture-source
(and intended to go back and use it foruv-scroll
). Previously we had no good way of implementing this, since components could only be on AFRAME entities, and entities could only be Object3Ds. This PR turns Materials into entities as well, so components can be added to them.I am still slightly uneasy about the concept of making materials entitles (and the number of entities this adds), but it feels nice to actually be able to implement this correctly. If we discover we really do not end up creating more material components then we can consider special casing these instead, similar to what we did before.
Part of implementing video-texture-source was factoring out the code for updating render targets used in the camera tool system. Ideally we should probably refactor that to actually use video-texture-target and video-texture-source components. The code in this function was also simplified a bit resolving some (but not all) of the TODOs.
This also incidentally fixes issues that were present resolving node references in components (these are the first components we have implemented that use them).
part of #5899