KhronosGroup / glTF-Blender-IO

Blender glTF 2.0 importer and exporter
https://docs.blender.org/manual/en/latest/addons/import_export/scene_gltf2.html
Apache License 2.0
1.48k stars 316 forks source link

Manage KHR_materials_volume #1454

Closed julienduroure closed 2 years ago

julienduroure commented 3 years ago

Currently, KHR_materials_transmission is managed but not KHR_materials_volume nor KHR_materials_ior.

I'am not very familiar with these extensions, so let's discuss about it and how to implement it:

Without any order:

donmccurdy commented 3 years ago

At present, KHR_materials_volume only has an effect when combined with KHR_materials_transmission. In the future there may be other ways to use it for subsurface scattering and translucency effects, but that's a ways out yet. The following properties define a volume:

I believe we can infer that a material should export with KHR_materials_volume if it (1) has non-zero transmission, and (2) has enabled the "Screen Space Refraction" option:

Screen Shot 2021-08-23 at 10 51 09 AM

The extension requires thickness information. If "Refraction Depth" is not enabled, I think we'll have to use some kind of default, I'm not sure I understand what Blender is doing internally to show refraction when that is set to zero. When it is enabled, we could probably use its value. Note that thickness should be calculated in the local coordinate space of the object to which the material is attached (is this a problem?).

It may also be helpful to provide a Thickness socket on the glTF Settings node, like Occlusion. We can bake a thickness texture in Blender in very much the same way, but there's no way to use that thickness texture in Blender's renderers that I'm aware of, so we'd need another way to export the baked information.

I'm not sure what (if anything) to do with attenuationColor and attenuationDistance at this stage.

donmccurdy commented 3 years ago

I'm not sure what (if anything) to do with attenuationColor and attenuationDistance at this stage.

See comments in https://github.com/KhronosGroup/glTF/pull/1726#issuecomment-683820025, we can use the Principled Volume node in complement to the Principled BSDF, although I'm still not sure exactly which sockets to use. Note that SSS is a separate, upcoming, glTF extension.

Screen Shot 2021-08-23 at 8 43 54 PM
emackey commented 2 years ago

Lately I've been doing some experimenting with Blender and KHR_materials_volume. Here's my adaptation of the AttenuationTest Sample Model:

screenshot of attenuation test

Some notes:

emackey commented 2 years ago

One more note: Sadly, Eevee seems geared towards smoke as the realtime volumetric effect. Only Cycles can produce a sane image as shown above. Still I think it is well worth supporting these parameters.

emackey commented 2 years ago

And for the exporter: attenuationDistance = (density > 0.0) ? (1.0 / density) : None.

The importer should not have to worry about attenuationDistance being zero, that's illegal in glTF.

stmaccarelli commented 2 years ago

Hi guys. exporting KHR_materials_transmission without setting KHR_materials_volume properties is quite unuseful. A refracrive material that has zero thickness, is not refracting anything.

I wrote a "user extension" of Khronos glTF-Blender-IO exporter (following this example: https://github.com/KhronosGroup/glTF-Blender-IO/tree/master/example-addons/example_gltf_extension) that simply uses Blender's "refraction depth" property and exports that as thicknessFactor. Note that hte size unit in Blender is m(etres), I don't know what the unit of the thicknessFactor is in glTF, but to me it looks like m(etres) is acceptable, according to the objects in the scene.

this version of the addon doesn't export attenuationDistance, attenuationColor or thicknessMap, but I'm working on it.

Here's a GIST: https://gist.github.com/stmaccarelli/840bbc5f04c097a884787063e710db08

https://user-images.githubusercontent.com/1394193/141613442-6bbd5a43-b6c5-4643-997e-ab092f61d8ff.mp4

stmaccarelli commented 2 years ago

updated the GIST with KHR_materials_ior. exports IOR (index of refraction) from Blender Principled BSDF node. Most of the times we'll use the standard 1.45 index (water) but now if you want, you can simulate different materials (sapphire, water, glycerin, glass, etc)

donmccurdy commented 2 years ago

exporting KHR_materials_transmission without setting KHR_materials_volume properties is quite unuseful.

There's a range of uses for transmissive materials that don't require refraction: thin-walled glass that is fully transmissive but still reflective (unlike alpha blending), or rough transmissive materials like frosted glass. Certainly we'd like to support KHR_materials_volume as well, but that should be omitted at export if refraction is disabled.

I don't know what the unit of the thicknessFactor is in glTF

Meters, and affected by the scale of the mesh.

@stmaccarelli would you be willing to open a PR to add your changes here, similar to https://github.com/KhronosGroup/glTF-Blender-IO/pull/1094? I don't think it's necessary for all parameters to be supported initially, especially if some are harder to map from Blender's materials.

stmaccarelli commented 2 years ago

Hello @donmccurdy ,

There's a range of uses for transmissive materials that don't require refraction: thin-walled glass that is fully transmissive but still reflective

Yes, but it is quite uncommon in real life. The only stuff I can think about, with such features, is glass xmas balls, or soap balls.

or rough transmissive materials like frosted glass

This can take advantage from KHR_materials_volume params too, because a frosted glass ball refracts and distorts light too.

Certainly we'd like to support KHR_materials_volume as well, but that should be omitted at export if refraction is disabled.

Do you mean Blender screen space refraction setting in the renderer tab? Or refraction as material property? I think it can be done in either case. Right now my raw plugin has a checkbox, but a better Blender addons coder can do a better job

I don't know what the unit of the thicknessFactor is in glTF

Meters, and affected by the scale of the mesh.

So it should be the same as Blender

would you be willing to open a PR to add your changes here, similar to #1094? I don't think it's necessary for all parameters to be supported initially, especially if some are harder to map from Blender's materials.

I have a "final" version of my addon, I was working on thickness map, but it's quite difficult to me because blender doesn't natively supports it in its Principled BSDF or Glass Material
I'd like not to mess up with the exporter code (I should also study how it's made). My addon is coded as an extension of the Khronos plugin, following specs and guidelines I can't find anymore. maybe it was this https://github.com/KhronosGroup/glTF-Blender-IO/tree/master/example-addons/example_gltf_extension I'll try to submit it somehow.

emackey commented 2 years ago

There's a range of uses for transmissive materials that don't require refraction: thin-walled glass that is fully transmissive but still reflective

Yes, but it is quite uncommon in real life. The only stuff I can think about, with such features, is glass xmas balls, or soap balls.

It's much more common in lower-poly models, for example of house windows or car windows. Basically any situation where the model can only afford a single layer of polys to represent a pane of glass, can avoid using the full KHR_materials_volume extension, and avoid its associated costs.

Even so I'm eager to see a proper implementation of KHR_materials_volume in Blender, as obviously refraction can make a whole scene look a lot more sophisticated.

donmccurdy commented 2 years ago

but it's quite difficult to me because blender doesn't natively supports it in its Principled BSDF or Glass Material...

For baked Occlusion we've resorted to detecting an "Occlusion" slot on a custom "glTF Settings" node. Seems very reasonable to do the same thing with a "Thickness" slot here I think, unless/until Blender adds its own equivalent.

Do you mean Blender screen space refraction setting in the renderer tab? Or refraction as material property?

I was thinking of the material property – does that seem ok?

stmaccarelli commented 2 years ago

It's much more common in lower-poly models, for example of house windows or car windows. Basically any situation where the model can only afford a single layer of polys to represent a pane of glass, can avoid using the full KHR_materials_volume extension, and avoid its associated costs.

EDIT: I'm sorry, I was wrong. Yes, but in that case you won't need transmission at all... reflections is all you need, and you can achieve that with clearcoat, by just reflecting the environmental map.

declaring a model has KHR_materials_transmission is computationally expensive the same way if the volume thickness 1 meter, 10 meters or 0.001 meters, the renderer has to do the same operations, only on different numbers. JS renderers assign 0.001 arbitrary volume to transmissive materials, so for my aim, it's computationally the same as declaring 1.0 volume.

KHR_materials_volume applies to the same single layer of polys. You can even apply to a single quad, and tell the renderer, using KHR_materials_volume, that has to simulate light refraction as that quad would be a 0,5meters thick glass. plus, using IOR, you can even tell the renderer what material is that panel! it may refract like water, diamond, ice, etc...

stmaccarelli commented 2 years ago

For baked Occlusion we've resorted to detecting an "Occlusion" slot on a custom "glTF Settings" node. Seems very reasonable to do the same thing with a "Thickness" slot here I think, unless/until Blender adds its own equivalent.

I identified a slot that can be used as thickness, but that slot only accepts numbers, not textures. RIght now I featured all the properties of KHR_material_transmission, KHR_materials_volume and KHR_materials_ior just using Blender native slots. The only one I'm missing is a thickness map (texture)

I was thinking about using Blender's Principled BSDF MAterial's Subsurface Color node, because it supports textures too, but it's actually for a different purpose.

Let's also say that a Blender plugin has the ability to add items to Blender panels, so a "Khronos glTF extrensions" panel could be added with such extra stuff. But I don't know if I'd be able to code that in a reasonable amount of time, maybe someone more expert would be helpful.

stmaccarelli commented 2 years ago

anyways, I'll soonest cleanup my last plugin edits, and I'll post a new GIST code + demo screencast, and we'll discuss about everything. I?ll try to find some time tomorrow morning.

I also need to check if my code is now compatible with Blender 3.0 and the newer Khronos glTF exporter...

donmccurdy commented 2 years ago

Let's also say that a Blender plugin has the ability to add items to Blender panels, so a "Khronos glTF extrensions" panel could be added with such extra stuff.

Since this plugin is enabled in Blender by default, I don't think we can/should add new UI panels unfortunately. Using a "Thickness" socket on a custom "glTF Settings" node has been our workaround for that, and since it's already required for Occlusion maps I think it would make sense for a Thickness map.

Support for subsurface in glTF is on the roadmap, so we probably don't want to misappropriate that slot. :)

emackey commented 2 years ago

Yes, but in that case you won't need transmission at all...

Actually, I meant like this: https://sketchfab.com/3d-models/pony-cartoon-885d9f60b3a9429bb4077cfac5653cf9

And this: https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/ToyCar

KHR_materials_volume applies to the same single layer of polys

No, in the Extending Materials section, there's a note that says "A non-zero thickness switches from thin-walled to volumetric behavior. This requires a manifold/closed mesh." Later, in the properties section, it says "The doubleSided property has no effect on volume boundaries". So, this is intended for a single-sided mesh of polygons surrounding an enclosed volume of material. Behavior of a single layer of double-sided polygons will be unpredictable, especially in a path tracer where the volume boundary is only crossed once.

+1 for Don's comments on the Thickness map.

stmaccarelli commented 2 years ago

ok, let's wrap it up. My English is not so good, so I'll most probably have some difficulties explaining my concepts, but let's try and forgive me.

about the comment by @emackey KHR_materials_transmission itself, without volume declarations, is enough to define clear glass-like surfaces with virtually zero thickness, like your examples show. But, in real life, nothing is zero thickness. A car glass is about 3 to 5 mm, and refracts / distorts light, other that letting it pass through. Adding KHR_materials_volume addresses this, and makes everything more realistic.

Look at this model: https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/IridescentDishWithOlives Thick glass objects? glass statues? refractive realistic glass windows? Ice sculptures? Eye bulbs? Diamonds? With the actual Khronos Blender glTF2.0 exporter, this is simply impossible, and you have to use additional tools, like the one made by @donmccurdy , to add materials extensions to exported models.

And about the "manifold" in the documentation, I think it's not mandatory for calculating refraction or simple transmission: Babylon, Three, Blender's Eevee and Cycles, can render transmission and volume data on non-manifold meshes, although js renderers cannot combine multiple layers of transmissive objects, but that's not our business)

Actually declaring that mesh X, made even by a single quad, has a volume thickness of 0.5, tells the renderer: when lights passes through this mesh, distort it like it was a glass mass of 0.5meters. And they do the job quite well: https://threejs.org/examples/?q=trans#webgl_loader_gltf_transmission the different thicknesses you see along the glass cup, are addressed with a thickness texture, not by actually ray-tracing (that would be computationally overkill), so I don't understand why we would need a manifold mesh.

stmaccarelli commented 2 years ago

@donmccurdy

Since this plugin is enabled in Blender by default, I don't think we can/should add new UI panels unfortunately.

I agree.

Using a "Thickness" socket on a custom "glTF Settings" node has been our workaround for that, and since it's already required for Occlusion maps I think it would make sense for a Thickness map.

Maybe, yes. Does the glTF addon add a glTF Settings node? I didn't see it.

Support for subsurface in glTF is on the roadmap, so we probably don't want to misappropriate that slot. :)

@emackey did a great job here https://github.com/KhronosGroup/glTF-Blender-IO/issues/1454#issuecomment-928319444

As he states attenuationDistance and attenuationColor can correspond to properties of Volume Scatter node, and it's way better than taking them from subsurface data. In blender they serve the same purpose and I can even see the result in eevee.

stmaccarelli commented 2 years ago

@emackey I misunderstood some of your comments, pardon moi. To wrap it up, I'll update my plugin attenuation data according to your suggestion. And, it actually has the checkboxes in the export panel, and I could add checkboxes for every property and glTF extension he would add.

julienduroure commented 2 years ago

Since this plugin is enabled in Blender by default, I don't think we can/should add new UI panels unfortunately.

If necessary, we can add some addon preferences and restrict UI panel / operator to create glTF Settings node to be displayed only when option is activated in addon preferences (off by default)

stmaccarelli commented 2 years ago

Ok, I've changed a bit the logic of my addon.

Here it is: https://gist.github.com/stmaccarelli/acc97d9f9b00cd1f7169455d5404f388.js

I think this is a tool to simplify the export of KHR_materials_volume and KHR_materials_ior straight from Blender, but it's far from perfect. The main feature missing is exporting thicknessTexture, but as I can understand we are far from "standardising" this idea from blender.

For this reason, maybe is better to keep the export of volume extension into an external addon like this. Don't you think so?

donmccurdy commented 2 years ago

Awesome, thanks @stmaccarelli! For some reason the link above didn't work with the suffix, here's a fixed version:

https://gist.github.com/stmaccarelli/acc97d9f9b00cd1f7169455d5404f388

Blender is probably never going to have built-in sockets for baking outputs, like occlusion and thickness textures. Blender computes these on the fly, but runtime loaders often can't, so it's a difference in Blender's goals there. We do want to bring this support into the official addon. My opinion on handling thicknessTexture would be:

1) Look for a "Thickness" socket on "glTF Settings" node (as we do for Occlusion) 2) If neither refraction depth nor "Thickness" is present, export KHR_materials_ior but not KHR_materials_volume 3) Perhaps someday we can automatically bake thickness on export, but not yet

vrsebas commented 2 years ago

Since this plugin is enabled in Blender by default, I don't think we can/should add new UI panels unfortunately.

If necessary, we can add some addon preferences and restrict UI panel / operator to create glTF Settings node to be displayed only when option is activated in addon preferences (off by default)

Hi, I've been trying this for a work project and it was pretty useful, do you think this could be merged and added to the addon itself? may be it could be hold as an experimental feature.

image

julienduroure commented 2 years ago

Hello, Based on this comment : https://github.com/KhronosGroup/glTF-Blender-IO/issues/1454#issuecomment-928319444 I started to implement it here : #1646

julienduroure commented 2 years ago

Closing this ticket, as #1646 is now merged