4 votes

Scenekit Shader - Désactivez l'ombrage lisse et toute interpolation normale.

J'ai un modèle animé (collada) exporté depuis Blender. D'après ce que j'ai compris, le shader tente d'interpoler la normale pendant l'animation et je veux empêcher que cela ne se produise. Mon modèle est très bloc mais Scenekit le rend lisse comme un produit Apple. Je veux qu'il ressemble à Minecraft.

5voto

lock Points 1796

Je suppose que vous recherchez un look low poly avec des ombres plates, similaire à celui illustré à gauche ci-dessous.

Flat and smooth shaded

Cet exemple utilise un SCNSphere comme source de géométrie, mais il devrait également fonctionner sur la géométrie que vous avez chargée à partir du fichier dae.

Le modèle que vous avez chargé et la SCNSphere par défaut sont constitués de plusieurs faces. Dans le cas des modèles lisses, les sommets sont souvent partagés entre les faces, chaque sommet ne pouvant avoir qu'une seule normale. Nous devons nous assurer que chaque face ne partage pas de sommets avec les faces voisines et que la normale utilisée pour chaque sommet est calculée en fonction de la direction de la normale de la face uniquement.

SceneKit n'a pas de fonctionnalité native pour faire cela lui-même, mais un autre des frameworks d'Apple le fait... ModelIO.

Vous devez importer ModelIO.

import ModelIO
import SceneKit.ModelIO

Le code que j'ai utilisé pour générer les deux sphères ci-dessus est présenté ci-dessous.

let geom = SCNSphere(radius: 0.5)

// convert SceneKit geometry to ModelIO mesh object
let modelMesh = MDLMesh(scnGeometry: geom)
// ensure vertices are not shared with neighbouring faces
modelMesh.makeVerticesUnique()
// replace existing 'smooth' normal definition with an 'non-smoothed' normal
modelMesh.addNormals(withAttributeNamed: "normal", creaseThreshold: 1.0)

// create SceneKit geometry from ModelIO mesh object
let flattenedGeom = SCNGeometry(mdlMesh: modelMesh)
let flattenedNode = SCNNode(geometry: flattenedGeom)
scene.rootNode.addChildNode(flattenedNode)

// smooth sphere for comparison only
let sphereNodeSmooth = SCNNode(geometry: SCNSphere(radius: 0.5))
sphereNodeSmooth.position = SCNVector3Make(0, 1.2, 0)
scene.rootNode.addChildNode(sphereNodeSmooth)

Bien sûr, je vous recommanderais probablement de modifier votre modèle dans Blender pour qu'il puisse être exporté de cette manière (sommets uniques, normales non lissées). Cela éviterait à votre application d'avoir à faire plus de traitement que nécessaire lors du chargement des actifs. Malheureusement, mes connaissances sur Blender sont quelque peu insuffisantes.

-1voto

ooOlly Points 916

L'ombrage lisse est obtenu en calculant la moyenne de la normale d'un sommet avec toutes les faces adjacentes. Dans ce cas, le moteur de rendu rend le bord en interpolant la couleur des faces adjacentes, ce qui donne l'impression que la rencontre des faces devient plus "lisse".

Vous pouvez supprimer les informations sur les normales des sommets pour éviter cela.

Si vous préférez SCNGeometry

SCNGeometry* flatGeoUsingScnKit(SCNGeometry *geo){
    NSArray<SCNGeometrySource*> *SourceArr = geo.geometrySources;
    NSMutableArray<SCNGeometrySource*> *newSourceArr = [NSMutableArray new];
    for (SCNGeometrySource *source in SourceArr) {
        if (source.semantic != SCNGeometrySourceSemanticNormal) {
            [newSourceArr addObject:source];
        }
    }
    SCNGeometry *flatGeo = [SCNGeometry geometryWithSources:newSourceArr elements:geo.geometryElements];
    return flatGeo;
}

Ou ModèleI/O

SCNGeometry* flatGeoUsingModelIO(SCNGeometry *geo){
    MDLMesh *mesh = [MDLMesh meshWithSCNGeometry:geo];
    MDLMesh *newMesh = [MDLMesh newSubdividedMesh:mesh submeshIndex:0 subdivisionLevels:0];
    [newMesh removeAttributeNamed:@"normals"];
    //Replace current vertex normals with a non-smooth one. Same result with above line
    //creaseThreshold is the cos value of MAX crease angle you can tolerate
    //[newMesh addNormalsWithAttributeNamed:@"normals" creaseThreshold:1];
    SCNGeometry *flatGeo = [SCNGeometry geometryWithMDLMesh:newMesh];
    return flatGeo;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X