Scenekit着色器 - 关闭平滑着色和任何常规插值

时间:2017-03-09 07:10:22

标签: scenekit

我有一个从Blender导出的动画模型(collada)。根据我的理解,着色器尝试在动画期间插入法线,我想防止这种情况发生。我的模型非常块,但Scenekit使其像Apple产品一样流畅。我希望它看起来像我的世界。

2 个答案:

答案 0 :(得分:5)

我假设你正在寻找一个类似于左下方所示的平面阴影低聚外观。

Flat and smooth shaded

此示例使用SCNSphere作为几何源,但它也应该对从dae文件加载的几何图形起作用。

您加载的模型和默认的SCNSphere由多个面组成。在平滑模型的情况下,顶点通常在面上共享,每个顶点只能有一个法线。我们需要做的是确保每个面不与相邻面共享顶点,并且每个顶点上使用的法线仅基于面的法线方向计算。

SceneKit本身没有任何本机功能,但Apple的另一个框架确实... ModelIO。

您需要导入ModelIO。

import ModelIO
import SceneKit.ModelIO

我用来生成上面两个球体的代码如下所示。

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)

当然我可能建议您在Blender中修改模型以便以这种方式导出(唯一顶点,非平滑法线)。这样可以使您的应用程序不必进行比加载资产时所需的更多处理。不幸的是,我的Blender知识缺乏一些。

答案 1 :(得分:-1)

平均顶点与所有相邻面的法线时会发生平滑阴影。在这种情况下,通过插入相邻面的颜色来渲染引擎渲染边缘,看起来像面部会变得更加平滑'。

您可以删除顶点的法线信息以防止这种情况。

如果您愿意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;
}

或ModelI / 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;
}