Skip to content
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

Merged
merged 12 commits into from
Jan 30, 2023

Conversation

netpro2k
Copy link
Contributor

@netpro2k netpro2k commented Jan 25, 2023

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 for uv-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

Copy link
Contributor

@johnshaughnessy johnshaughnessy left a 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 object3Ds. 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();
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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...

Copy link
Contributor Author

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.

src/bit-components.js Outdated Show resolved Hide resolved
exitedObject3DQuery(world).forEach(removeFromMap);
entities.forEach(removeObjFromMap);
exitedObject3DQuery(world).forEach(removeObjFromMap);
exitedMaterialQuery(world).forEach(removeFromMatMap);
Copy link
Contributor

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 eids. Is that correct?

Copy link
Contributor Author

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.
Copy link
Contributor

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?

Copy link
Contributor Author

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);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

smart

Copy link
Contributor Author

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 => {
Copy link
Contributor

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]) => { ?

src/inflators/model.tsx Show resolved Hide resolved
const components = obj.userData.gltfExtensions?.MOZ_hubs_components;
if (components) inflateComponents(world, eid, components, idx2eid);

mapMaterials(obj, function (mat: Material) {
Copy link
Contributor

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,

Copy link
Contributor Author

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.

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;
Copy link
Contributor

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?

Copy link
Contributor Author

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) {
Copy link
Contributor

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)

Copy link
Contributor Author

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);
}
});
Copy link
Contributor

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?

Copy link
Contributor Author

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)) {

@netpro2k netpro2k merged commit e5f7385 into master Jan 30, 2023
@netpro2k netpro2k deleted the material-components branch January 30, 2023 21:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants