在着色器修改器SceneKit

时间:2015-05-01 09:00:27

标签: ios glsl scenekit

寻找

我无法访问世界空间中渲染像素的z坐标。在SceneKit中,我正在寻找一个3d平面,其渲染颜色与渲染点的z坐标直接相关。

情况

我正在使用SpriteKit,我正在使用SK3DNode在我的SpriteKit场景中嵌入SceneKit场景。对于SceneKit场景,我使用从Blender导出的.dae Collada文件。它包含一个平面网格和一个光。 我正在应用着色器修改器来修改几何体和光照模型。

  self.waterGeometry.shaderModifiers = @{
    SCNShaderModifierEntryPointGeometry : self.geomModifier,
    SCNShaderModifierEntryPointSurface : self.cellShadingModifier
  };

几何修改器代码(self.geomModifier):

// Waves Modifier
float Amplitude = 0.02;
float Frequency = 15.0;
vec2 nrm = _geometry.position.xz;
float len = length(nrm)+0.0001; // for robustness
nrm /= len;
float a = len + Amplitude*sin(Frequency * _geometry.position.z + u_time * 1.6);
_geometry.position.xz = nrm * a;

几何修改器将正弦变换应用于_surface属性以模拟波浪。在下图中,勾画的精灵是SpriteKit精灵,它具有更高的zPosition并且不会干扰SK3DNode。注意几何修改器导致的细微波(z位移)。

The 3D plane, deformed using the geometry shader modifier

下一步,我想输出基于世界空间中点的z坐标计算的颜色。这可能是_surface.diffuse或_output.color,这对于(对于着色器修饰符而言意味着不同的插入点而言意味着什么并不重要)。

我试过

表面修饰符(self.cellShadingModifier)中的以下代码。

vec4 geometry = u_inverseViewTransform * vec4(_surface.position, 1.0);
if (geometry.y < 0.0) {
_surface.diffuse.rgb *= vec3(0.4);
}

_surface.position位于视图空间中,我希望使用u_inverseViewTransform将其转换为世界空间。 Apple docs说:

  

几何字段(例如位置和法线)在视图中表示   空间。你可以使用SceneKit的制服(比如   u_inverseViewTransform)在不同的坐标空间中操作,   [...]

The 3D plane with the geometry modifier and the surface modifier

正如你所看到的那样,它是闪烁的,似乎不是基于geometry.position我只是修改了。我已经在模拟器和设备(iPad Air)上对此进行了测试。我相信我犯了一个简单的错误,因为我可能会混淆_surface_geometry属性。

有谁能告诉我在哪里可以获得网格当前阴影点的z坐标(世界空间),所以我可以在渲染方法中使用它?

注意

我还尝试在“表面着色器”修改器中访问_geometry,但我收到错误Use of undeclared identifier '_geometry',这很奇怪,因为Apple documentation说:

  

您可以在以后使用先前入口点定义的结构   切入点。例如,与该片段相关联的片段   SCNShaderModifierEntryPointFragment入口点可以从中读取   _Surface结构由SCNShaderModifierEntryPointSurface入口点定义。

注2

我可以让LightingModel着色器计算生成的正弦波(并避免搜索z坐标),但将来我可能会添加额外的波,使用z坐标会更易于维护,而不是提到优雅。

1 个答案:

答案 0 :(得分:4)

我也一直在学习如何使用着色器修饰符。我有一个适合我的解决方案,使用逆模型变换和逆视图变换。

以下代码将使用红色调绘制场景中心的模型右侧。您应该能够检查其他位置元素(我认为),以获得您想要的结果。

vec4 orig = _surface.diffuse;
vec4 transformed_position = u_inverseModelTransform * u_inverseViewTransform * vec4(_surface.position, 1.0);
if (transformed_position.z < 0.0) {
    _surface.diffuse = mix(vec4(1.0,0.0,0.0,1.0), orig, 0.5);
}