The secret life of Material Entities

The secret life of Material Entities.

Material entities in Vircadia are quite powerful but still, not very often used, I think in part it is because of some of it’s quirks, like the fact that you can not (yet) apply the same material entity to more than one object, but really I think the main reason is that it just seems so complicated and nerdy.
It really isn’t, complicated that is, it is a bit nerdy though, with all those property names and stuff but luckily you don’t have to remember all that stuff, I will provide some examples you can use and modify to your liking.

What are material Entities?

  • Material entities can be used to apply materials to models, avatars or shapes by making the material entity a child of the object.

  • For models and avatars, you can select which submesh and/or material slots you want to override.

  • You can override the material as a whole, replacing the original. or only override selected properties and keep the others as original by setting a property to fallthrough.

  • Material entities have a priority property, many material entities can be applied to the same mesh, but only the one with the highest priority will show, unless fallthrough is used in which case that property will “fall through” to the next highest material property.
    The properties of the material is JSON formated text and supplyed in the MaterialURL field, this can be either a link to external file or “MaterialData” in wich case it will look in the “MaterialData” field for the JSON formatted data.

  • The material data can contain multiple named materials that you can access by appending the name in the MaterialURL field, if the data only contains one material this can be omitted.

Why would you use material entities?

  • Applying custom shaders to avatars and entities (and shapes but here userdata can be used instead).

  • Quickly test different materials, no need to export a model 10 times to get it looking just right. Just live edit the material in-world.

  • Special effects using 3d projected mode or UV offset animation.

  • Changing some properties of a material on a model, like making glass double sided and transparent, or making part of a model render unlit.

  • Linked materials, in the sense that many objects can reference the same JSON file so changes to that file will show on all the objects.

  • Setting material properties that are usually not possible in models, like setting emission higher than 1 to get a bloom effect.

  • Simply putting materials on shapes.

How do I use material entities?

To make a material entity you can click create->material, if you don’t put anything in the Material URL field yo get an empty material with the material URL set to MaterialData, But it’s blank so now you have to know which properties to type in there :thinking:

You can look here: Entities - Vircadia API Docs to see the available properties, but honestly it’s just easier to load an existing material and modify it’s properties from there, here’s a material entity with the most basic properties already filled out:
http://silverfish-freestuff.s3.amazonaws.com/Materials/Examples/basicMaterialEntity.json
That should be a good starting point.
I usually prefer putting the data in the material data field of the entity instead of in an external file, but if you like to have it all in one central file or you use the same material on a lot of objects it may be better reference an external JSON file.

Note: importing JSON files.

JSON files are used somewhat ubiquitous in Vircadia for all sorts of stuff so you sort of have to know what is in it to know how to use it but for the most part, they represent an entity, or a collection of entities with all of their properties and relative relations, like this sippy Bird:
https://silverfish-freestuff.s3.eu-north-1.amazonaws.com/Misc/SippyBird/SippyBird_Green.json
that will load a fbx mode with animation and two materials in 3D projected mode parented to specific bone.
To load a JSON like this you can:

  1. Simply drag the link onto the interface window.

  2. use the create menu to load from url or file:

  3. use the main menu->edit:
    import_menuI

  4. Load it via script, If you know how to do that you probably find this guide really basic :SMILE

To use the material you need to parent it to a shape or model, first select the material entity, hold shift and select the target entity and then press ctrl+P, the material entity will change from a little ball into an material icon
material_icon

Now, it you select the material entity again and select the material tab in the create menu you can edit the properties of the material and how it applies to the target, importantly, you need to select which submeshes and/or materials you want to override.

Note: Parenting in VR mode.

To parent an entity in VR mode you open the list view in the create menu and enable multi select mode:

Now you can select first the material, then the target entity and in the edit menu, select:
Parent Entities to the last Selected

Well, this is all getting awfully long so let me just leave you with a few more examples, That’s how I usually figure stuff out so maybe it works for you too:

Note: this may not all be correct.

I did not properly test or fact-check all of my claims in this post so if you find an error or outright lie :cry: , let me know or, even better, update the information yourself

Happy Materializing…

5 Likes

With the release of 2021.1.3 we have some new features for materials with this PR.

In a nutshell, It is now possible to use webEntities or imageEntities as input for materials,
where you would normally put an URL to a texture in a material entity or shader,
you can instead put the UUID of a web, or, image entity.

Another new addition is the option to use the UUID of a material entity as "materialData", this is
another way of putting one material on many different meshes, similar to using an external material data JSON file but with the advantage that you can modify the “master” material entity in-world and have all the linked materials change.

Web content on meshes.


Get the example above here: webOnTV.json

I think this is one of the best use cases, It works exactly the same as any other material so follow the
instructions above.

To have it show web content copy the UUID of the web entity you want to show to the "albedoMap"property and set "unlit": true.
(You can also put the UUID in emissiveMap and keep unlit false, whatever you think looks best).

Remember that, like any other texture, how it looks depends on the UV map of the model so make sure it is unwrapped to suit your need.

Now if all is well, the web content should now show on the mesh part / material slot you selected but
you may notice it is mirrored on the Y axis, and maybe looking a bit bland because technical reasons :man_shrugging:
The mirroring is an easy fix, just set the material position Y to 1,
and the material scale Y to -1 like so:

As for texture looking a bit washed out, that is apparently due to some differences in the color space used in web entities, if you use an image entity as input, this is not a problem.
To overcome that I made a simple shader that applies gamma correction to the image, as well as taking care of the scaling/offset. The only downside to using this is that users that does not have Procedual shaders enabled will not see it (unless you use it on a shape entity)
The webOnTV.json example uses a normal material entity for one stack of TV’s and the custom shader for the other.

:exclamation: Web entities stop updating if they are not in your field of view.

So any material that references a web entity will “freeze” if the web entity is not within your view frustum. the web entity can be set to invisible or hidden inside a mesh but don’t make it too small, otherwise it may be culled very easily.

:exclamation: Aspect matters.

the aspect ratio as well as the “source resolution” of the web entity transfers to the “texture” so if your UV map is unwrapped to fit a 1:1 texture, you should also make the web entity 1:1.

Web content on Avatars.

This is exactly the same as for normal meshes, however, for avatars, both the web entity and the material should be avatar entities, otherwise you will loose them when changing domain or reloading. Sadly, loading avatar entities from JSON seems to be broken so you sort of have to create the entities as avatar entities by script.
This example will show on your avatar but has to be reloaded each time.

EDIT:
To overcome the avatar entity loading issue I made a script that add menu items (in Edit) to
load .json as avatar entities from file or url: AvatarEntitiesImporter.js

Web Content on Shapes.

For putting web content on Shapes using a custom shader like this is a good option because you don’t need a material entity, and it shows regardless of the users “enable procedural shaders” setting.

Put this in the userData of a shape, replacing [UUID of web entity] with the UUID of an existing web entity:

{
  "ProceduralEntity": {
    "version": 1,
    "shaderUrl": "https://vircadia-shders.glitch.me/showWebOnShape.fs",
    "channels": [
      "[UUID of web entity]"
    ],
    "uniforms": {
      "scale": [
        -4,
        3
      ],
      "position": [
        2,
        0
      ],
      "gamma": 2.2
    }
  }
}

The scale and position here is set to fit a quad, mess with that to fit other shapes.

:exclamation: Flat cube.

The UV map of the built in shapes is largely undocumented and sometimes weird, for example, the Quad shape is not unwrapped 1:1 as you might expect because it is in fact, just a cube, flattened in the Y axis so it has the same cross shape UV that is common for cubes.

Things to explore further:

  • Modify the shader to include a CRT effect or maybe a LED billboard effect, so far the math of this has me beaten :frowning_face:

  • How to easily host a looping video, the browser will play webm directly but how to make it loop?

  • Extract color information from the shader so we can have the screen illuminate the environment
    like we used to in the cinema.

  • How relay keyboard/game controller input to the web entity without having it focused. Also, in-world virtual joystick/gamepad/buttons that sends input to the web entity?

  • loading avatar entities needs fixing.

Other examples.

HexBird shows a gif on all sides of a hexagon shape.
Jetpac rezzes a TV, a ZX spectrum, and a web entity with playable Jetpac, you need to have the web entity focused to play the game.

2 Likes

Oooooo! This is so cool… thanks for sharing it… I have to digest it soon!

1 Like

For showing a looping video something like this seems to work nicely:

<!DOCTYPE HTML>
<html>
  <body>
    <video
      src = "https://upload.wikimedia.org/wikipedia/commons/transcoded/c/c0/Big_Buck_Bunny_4K.webm/Big_Buck_Bunny_4K.webm.240p.vp9.webm"
           type="video/webm"
           autoplay
           loop 
           muted
    </video>
  <style>
    video {
        min-width: 100%; 
        min-height: 100%; 
        height: auto;
        width: auto;
        object-fit: contained // fill or use "cover" to avoid distortion
        position: absolute;
    }
    body {
      background-color: #000000;
    }
  </style>
  </body>
</html>

You can remix my glitch and replace the video url or maybe use github pages, but note that it will not play mp4 videos, .ogv and .webm works well

2 Likes