Pass nil texture to metal fragment shader

Hello everyone, I am studying apply metal to scenekit.

I want to pass nil texture to fragment shader. But I don't know how...

This code is for pass texture named volume to fragment shader using scntechnique.

swift code

if let path = Bundle.main.path(
      forResource: "volumerendering-metal",
      ofType: "plist")
    {
      if let dico1 = NSDictionary(contentsOfFile: path) {
        let dico = dico1 as! [String: AnyObject]
        let technique = SCNTechnique(dictionary: dico)
         
        let screenSize = NSValue(
          cgSize: view.frame.size.applying(CGAffineTransform(scaleX: 2.0, y: 2.0)))
        technique?.setValue(screenSize,
                  forKeyPath: "screen_size")
         
        technique?.setValue(nil, forKey: "volume")
       // or? 
       // technique?.setObject(nil, forKeyedSubscript: "volume" as NSCopying)
         
        scnView.technique = technique
      }
    }

property list file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>passes</key>
	<dict>
		<key>pass_backface</key>
		<dict>
			<key>metalVertexShader</key>
			<string>backface_vertex</string>
			<key>metalFragmentShader</key>
			<string>backface_fragment</string>
			<key>program</key>
			<string>doesntexist</string>
			<key>depthStates</key>
			<dict>
				<key>clear</key>
				<true/>
			</dict>
			<key>colorStates</key>
			<dict>
				<key>clear</key>
				<true/>
				<key>clearColor</key>
				<string>sceneBackground</string>
			</dict>
			<key>cullMode</key>
			<string>front</string>
			<key>includeCategoryMask</key>
			<string>2</string>
			<key>draw</key>
			<string>DRAW_NODE</string>
			<key>inputs</key>
			<dict>
				<key>aPos</key>
				<string>vertex-symbol</string>
			</dict>
			<key>outputs</key>
			<dict>
				<key>color</key>
				<string>backface</string>
			</dict>
		</dict>
		<key>pass_mip</key>
		<dict>
			<key>colorStates</key>
			<dict>
				<key>clear</key>
				<true/>
				<key>clearColor</key>
				<string>sceneBackground</string>
			</dict>
			<key>depthStates</key>
			<dict>
				<key>clear</key>
				<true/>
			</dict>
			<key>metalVertexShader</key>
			<string>mip_vertex</string>
			<key>metalFragmentShader</key>
			<string>mip_fragment</string>
			<key>program</key>
			<string>doesntexist</string>
			<key>cullMode</key>
			<string>back</string>
			<key>includeCategoryMask</key>
			<string>2</string>
			<key>draw</key>
			<string>DRAW_NODE</string>
			<key>inputs</key>
			<dict>
				<key>aPos</key>
				<string>vertex-symbol</string>
				<key>viewport</key>
				<string>screen_size</string>
				<key>backface</key>
				<string>backface</string>
				<key>volume</key>
				<string>volume</string>
			</dict>
			<key>outputs</key>
			<dict>
				<key>color</key>
				<string>COLOR</string>
				<key>depth</key>
				<string>DEPTH</string>
			</dict>
		</dict>
	</dict>
	<key>sequence</key>
	<array>
		<string>pass_backface</string>
		<string>pass_mip</string>
	</array>
	<key>targets</key>
	<dict>
		<key>backface</key>
		<dict>
			<key>type</key>
			<string>color</string>
		</dict>
	</dict>
	<key>symbols</key>
	<dict>
		<key>vertex-symbol</key>
		<dict>
			<key>semantic</key>
			<string>vertex</string>
		</dict>
		<key>screen_size</key>
		<dict>
			<key>type</key>
			<string>vec2</string>
		</dict>
		<key>volume</key>
		<dict>
			<key>type</key>
			<string>sampler3D</string>
		</dict>
	</dict>
</dict>
</plist>

shader code

fragment float4 mip_fragment
(
  VertexOutput in [[stage_in]]
  , texture2d<float, access::sample> backface [[texture(0)]]
  , texture2d<float, access::sample> volume [[texture(1)]]
)
{
  ...  
  if (is_null_texture(volume)) return float4(1, 0, 0, 0);
  else return float4(0, 1, 0, 0);
}

I want to get red object but green object.... Because I want to set 3d texture at runtime. So before set it want to be nil, because error occurred. (https://developer.apple.com/forums/thread/688841)

Replies

I’m not an expert on SceneKit, but why do you have volume as type sampler3D in your plist, and volume as a texture2D in your shader? If you want it to be a texture3D, it should probably be set to that in your shader and plist.

  • sorry for my mistake texture3d in shader is right. I am checking when use 2d texture, whether error occurred or not. when use 3d texture, error occurred, but 2d texture doesn't. So I want to pass nil when using 3d texture for first and set texture at runtime.

    error : Fragment Function(mip_fragment): incorrect type of texture (MTLTextureType2D) bound at texture binding at index 1 (expect MTLTextureType3D) for volume[0].

  • No problem, are you able to post your entire project on GitHub or another site? It would be nice to see the full source code to better solve the problem.

  • Yeah, I working on my corporation git repository now. So I gonna set my own public repository for this work and upload link at follow comment.

Yes,

this shader code is right.

fragment float4 mip_fragment
(
  VertexOutput in [[stage_in]]
  , texture2d<float, access::sample> backface [[texture(0)]]
  , texture3d<float, access::sample> volume [[texture(1)]]
)
{
  ...  
  if (is_null_texture(volume)) return float4(1, 0, 0, 0);
  else return float4(0, 1, 0, 0);
}

And I check now, is_null_texture makes same error like volume.sample function.

https://bitbucket.org/skia_wonki/metal-volume-rendering/src/master/

This is full source of question.