Code Monkey home page Code Monkey logo

Comments (4)

zeux avatar zeux commented on September 26, 2024

The way you would check the condition you're asking about is material->has_pbr_metallic_roughness && material->pbr_metallic_roughness.metallic_factor > 0 and material->has_pbr_metallic_roughness && material->pbr_metallic_roughness.roughness_factor > 0, respectively.

has_pbr_metallic_roughness specifically refers to the presence of pbrMetallicRoughness node in glTF material file; cgltf mirrors the structure of glTF files pretty much one to one, so since glTF files don't have metallic and roughness separated, other than through factors, that's how cgltf represents this as well.

from cgltf.

chaoticbob avatar chaoticbob commented on September 26, 2024

Hi Arseny, I apologize in advanced that I'm responding in the early hours of the morning. Hopefully my response is still comprehensible.

Here's some clarification to what I was trying to ask originally: What I'm trying to do is figure out from cgltf if I should use the values from metallicFactor/roughnessFactor or from the texture. Based on my understanding, I think there are some ambiguous cases using the checks that have been suggested.

I beg your patience, this is a long example. Below I have 4 materials. Each material name has a suffix for metallic or roughness that indicates what/where the value for each respective field should come from:
_F - means the value for metallic and/or roughness should come from the *Factor variable(s).
_T - means the value for metallic and/or roughness should come from the texture. *Factor variables are ignored.
_Z - means the value for metallic and/or roughness is zero but should also come from the *Factor variable(s).

I created a scene in Blender with the 4 materials and exported:

	"materials":[
		// We know there is a metallicRoughness texture.
		// cgltf will have 0 for metallicFactor and 1.0 for roughnessFactor.
		// The intent of this material is to have metallic be 0 and 
		//   use the roughness from the texture.
		// From the cgltf perspective, it's ambiguous if roughness
		//   should come from the the factor or the texture.
		// We know from looking at the GLTF file that there isn't roughnessFactor
		//   so this must mean that roughness must come from the texture. 
		{
			"doubleSided":true,
			"name":"metallic_Z_and_roughness_T",
			"pbrMetallicRoughness":{
				"baseColorFactor":[
					0.800000011920929,
					0.800000011920929,
					0.800000011920929,
					1
				],
				"metallicFactor":0,
				"metallicRoughnessTexture":{
					"index":0
				}
			}
		},
		// We know 100% that both metallic and roughness are factors.
		// cgltf will have 0.25 for metallicFactor and 0.5 for roughnessFactor.
		// The intent of this material is to use both metallic and roughness from the factors.
		// The absence of a metallicRoughness texture means that this
		//   material will not have texture reads.
		{
			"doubleSided":true,
			"name":"mettalic_F_and_roughness_F",
			"pbrMetallicRoughness":{
				"baseColorFactor":[
					0.800000011920929,
					0.800000011920929,
					0.800000011920929,
					1
				],
				"metallicFactor":0.25,
				"roughnessFactor":0.5
			}
		},
		// We know there is a metallicRoughness texture.
		// cgltf will have 1.0 for both metallicFactor and roughnessFactor.
		// The intent of this material is to use both metallic and roughness from the texture.
		// From the cgltf perspective, it's ambiguous if metallica nd roughness
		//   should come from the factor or the texture. 
		// We know by looking at the GLTF file that isn't metallicFactor 
		//   or roughnessFactor, so this must mean that both metallic and roughness
		//   must come from the texture.
		{
			"doubleSided":true,
			"name":"metallic_T_and_roughness_T",
			"pbrMetallicRoughness":{
				"baseColorFactor":[
					0.800000011920929,
					0.800000011920929,
					0.800000011920929,
					1
				],
				"metallicRoughnessTexture":{
					"index":1
				}
			}
		},
		// We know there is a metallicRoughness texture.
		// cgltf will have 1.0 for metallicFactor and 0 for roughness.
		// The intent of this material is to have metallic come from the texture
		//   and roughness be 0.
		// From the cgltf perspective, it's ambiguous if metallic
		//   should come from the the factor or the texture.
		// We know from looking at the GLTF file that there isn't metallicFactor
		//   so this must mean that metallic must come from the texture. 		{
			"doubleSided":true,
			"name":"metallic_T_and_roughness_Z",
			"pbrMetallicRoughness":{
				"baseColorFactor":[
					0.800000011920929,
					0.800000011920929,
					0.800000011920929,
					1
				],
				"metallicRoughnessTexture":{
					"index":2
				},
				"roughnessFactor":0
			}
		}
	],

From what I understand, a check like material->has_pbr_metallic_roughness && material->pbr_metallic_roughness.metallic_factor > 0 even with an additional check for material->pbr_metallic_roughness.metallic_roughness_texture.texture != NULL can't indicate with certainty whether the value for metallic should come from the factor or thet exture. Also want to note that both metallic_factor = 0 and 'roughness_factor = 0are both legit use cases for a material. By looking at the GLTF JSON we can know with certainty that ifmetallicFactorand/orroughnessFactoris not present then the values for metallic/roughness must from the texture - assuming the JSON is well formed andmetallicRoughnessTexture` exists.

Based on what I've said above (fully admit my understanding might be flawed), it seems like if there existed something like:

cgltf_bool has_metallic_factor; // starts out as false and becomes true IFF metallicFactor is in JSON
cgltf_bool has_roughness_factor; // starts out as false and becomes true IFF roughnessFactor is in JSON

then could be certainty on which source the values metallic/roughness could come from.

from cgltf.

zeux avatar zeux commented on September 26, 2024

Let's ignore cgltf for now, as I said it tries to give a 1-1 semantic mirror of the glTF file.

The way glTF metallic roughness node works is that for every pixel, the metalness value is computed as metallicFactor * textureSample(metallicRoughnessTexture, uv).b, and roughness value is computed as roughnessFactor * textureSample(metallicRoughnessTexture, uv).g. When texture is absent, the texture sample is assumed to return (1, 1, 1, 1). When either factor is absent, it is assumed to be 1. See https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#metallic-roughness-material.

A factor is not ignored when a texture is present. A factor that is absent is indistinguishable from a factor that is specified and equal to 1.

As such, you can determine the definite absence of metalness (if the goal is to skip some computations) by checking if metalnessFactor is exactly 0 - even if texture is present, that will nullify whatever values the texture has.

If the factor is not 0 or absent (which means it's 1), and the texture is present, you can't definitively say whether any pixels of the mesh must be rendered as a metallic material - this requires analyzing the blue channel of the texture and seeing if all pixels are 0, which glTF file doesn't provide anywhere.

Hopefully that clarifies this? Getting back to cgltf, since absence of metallicFactor is equivalent to metallicFactor being specified as 1, cgltf doesn't store the presence of the factor in source document anywhere because from the spec perspective it doesn't matter if it exists.

from cgltf.

chaoticbob avatar chaoticbob commented on September 26, 2024

That's a helpful explanation. Thanks!

I had forgotten that the factors acts as multiplier in the cases I stated above. In thinking about it, the ambiguous case(s) will need to be addressed with workflow requirements.

from cgltf.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.