#scenekit #metal
#scenekit #Металлические
Вопрос:
У меня есть текстурированный квадрат, который нужно нарисовать в screenspace, размер / выравнивание по экранному экрану, в SceneKit
сцене на дальней плоскости — думайте об этом как о текстурированном квадрате для заливки фона.
Я вручную создал четырехугольник с 4 вершинами в пространстве клипов и написал шейдер вершин / фрагментов для его рисования. Вершины установлены на z = 1, что должно поместить их в дальнюю плоскость.
Однако, хотя квадрат правильно отображается, как и ожидалось, в пространстве экрана (например, он правильно выровнен), он рисуется поверх всего содержимого сцены — при z = 1 для вершин пространства клипов он должен быть позади всего.
Я смог обойти это, установив низкое renderingOrder
значение и отключив запись глубины, но это не исправление, это хак.
// build the plane vertices in clip space
let vertices: [SCNVector3] = [
SCNVector3(-1, -1, 1),
SCNVector3( 1, -1, 1),
SCNVector3( 1, 1, 1),
SCNVector3(-1, 1, 1),
]
let texCoords: [CGPoint] = [
CGPoint(x: 0, y: 1),
CGPoint(x: 1, y: 1),
CGPoint(x: 1, y: 0),
CGPoint(x: 0, y: 0),
]
let indices: [UInt16] = [
0,1,2,
0,2,3,
]
let vertexSource = SCNGeometrySource(vertices: vertices)
let texCoordSource = SCNGeometrySource(textureCoordinates: texCoords)
let elementSource = SCNGeometryElement(indices: indices, primitiveType: .triangles)
let planeGeometry = SCNGeometry(sources: [vertexSource, texCoordSource], elements: [elementSource])
let program = SCNProgram()
program.library = ShaderUtilities.metalLibrary
program.vertexFunctionName = "plane_vertex"
program.fragmentFunctionName = "plane_fragment"
if let material = planeGeometry.firstMaterial {
material.program = program
material.setValue(SCNMaterialProperty(contents: backdropImage as Any), forKey: "backgroundTexture")
}
let planeNode = SCNNode(geometry: planeGeometry)
meshCameraNode.addChildNode(planeNode)
Соответствующие металлические шейдеры:
struct PlaneVertexIn {
float3 position [[attribute(SCNVertexSemanticPosition)]];
float2 uv [[attribute(SCNVertexSemanticTexcoord0)]];
};
struct PlaneVertexOut {
float4 position [[position]];
float2 uv;
};
vertex PlaneVertexOut plane_vertex(PlaneVertexIn in [[ stage_in ]],
constant SCNSceneBufferamp; scn_frame [[buffer(0)]],
constant NodeBufferamp; scn_node [[buffer(1)]]) {
PlaneVertexOut out;
// the vertices are already in clip space to form a screen-aligned quad, so no need to apply a transform.
out.position = float4(in.position.x, in.position.y, in.position.z, 1.0);
out.uv = in.uv;
return out;
}
fragment float4 plane_fragment(PlaneVertexOut out [[ stage_in ]],
constant SCNSceneBufferamp; scn_frame [[buffer(0)]],
texture2d<float, access::sample> backgroundTexture [[texture(0)]]) {
constexpr sampler textureSampler(coord::normalized, filter::linear, address::repeat);
return backgroundTexture.sample(textureSampler, out.uv);
}