public static void SetupPaintColorMask(this SCNGeometry geometry, string name) { // if we've already set it up, don't do it again if (geometry.ValueForKey(new NSString(PaintMaskColorKey)) == null) { if (PaintColorMaskTextures.TryGetValue(name, out string paintMask)) { // all textures are absolute paths from the app folder var texturePath = $"art.scnassets/textures/{paintMask}.ktx"; if (name.Contains("catapult")) { //os_log(.debug, "visited %s for texture", name) } var surfaceScript = @" #pragma arguments texture2d<float> paintMaskTexture; //sampler paintMaskSampler; float4 paintMaskColor; #pragma body // 0 is use diffuse texture.rgb, 1 is use paintMaskColor.rgb float paintMaskSelector = paintMaskTexture.sample( sampler(filter::linear), // paintMaskSampler, _surface.diffuseTexcoord.xy).r; _surface.diffuse.rgb = mix(_surface.diffuse.rgb, paintMaskColor.rgb, paintMaskSelector); "; geometry.ShaderModifiers = new SCNShaderModifiers() { EntryPointSurface = surfaceScript }; // mask pro var prop = SCNMaterialProperty.Create(new NSString(texturePath)); prop.MinificationFilter = SCNFilterMode.Linear; prop.MagnificationFilter = SCNFilterMode.Nearest; prop.MipFilter = SCNFilterMode.Nearest; prop.MaxAnisotropy = 1; // set the uniforms, these will be overridden in the runtime geometry.SetTexture("paintMaskTexture", prop); geometry.SetFloat4(PaintMaskColorKey, SCNVector4.One); } } }
// Updates the secondary image of the floor if needed private void UpdateFloorImage(NSImage image, Slide slide) { // We don't want to animate if we replace the secondary image by a new one // Otherwise we want to translate the secondary image to the new location var disableAction = false; if (FloorImage != image) { FloorImage = image; disableAction = true; if (image != null) { // Set a new material property with this image to the "floorMap" custom property of the floor var property = SCNMaterialProperty.Create(image); property.WrapS = SCNWrapMode.Repeat; property.WrapT = SCNWrapMode.Repeat; property.MipFilter = SCNFilterMode.Linear; Floor.FirstMaterial.SetValueForKey(property, new NSString("floorMap")); } } if (image != null) { var slidePosition = slide.GroundNode.ConvertPositionToNode(new SCNVector3(0, 0, 10), null); if (disableAction) { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0; Floor.FirstMaterial.SetValueForKey(NSValue.FromVector(slidePosition), new NSString("floorImageNamePosition")); SCNTransaction.Commit(); } else { Floor.FirstMaterial.SetValueForKey(NSValue.FromVector(slidePosition), new NSString("floorImageNamePosition")); } } }
// https://developer.apple.com/documentation/scenekit/scnshadable#1654834 // Some of these can be animated inside of an SCNTransaction. // Sets shader modifier data onto a material or all materials in a geometry. public static void SetTexture(this SCNGeometry geometry, string uniform, SCNMaterialProperty texture) { // this must be the texture name, and not the sampler name geometry.SetValueForKey(texture, new NSString(uniform)); }