3

我想使用片段着色器渲染到屏幕外的纹理。完成此操作后,我想将其结果用作另一个片段着色器的输入。

我创建了一个纹理并用红色清除它(知道它已设置)。我使用连接到目标纹理的渲染通道并进行绘制。然后我使用 blit 命令编码器将该目标纹理的内容传输到缓冲区。缓冲区包含红色,所以我知道它正在正确读取纹理,但绘图应该使纹理变为绿色,所以出了点问题。

let textureDescriptor = MTLTextureDescriptor()
textureDescriptor.textureType = MTLTextureType.type2D
textureDescriptor.width = 2048
textureDescriptor.height = 1024
textureDescriptor.pixelFormat = .rgba8Unorm
textureDescriptor.storageMode = .shared
textureDescriptor.usage = [.renderTarget, .shaderRead, .shaderWrite]

bakeTexture = device.makeTexture(descriptor: textureDescriptor)

bakeRenderPass = MTLRenderPassDescriptor()
bakeRenderPass.colorAttachments[0].texture = bakeTexture
bakeRenderPass.colorAttachments[0].loadAction = .clear
bakeRenderPass.colorAttachments[0].clearColor = MTLClearColor(red:1.0,green:0.0,blue:0.0,alpha:1.0)
bakeRenderPass.colorAttachments[0].storeAction = .store

对于绘图,我这样做:

let bakeCommandEncoder = commandBuffer.makeRenderCommandEncode(descriptor: bakeRenderPass)
let vp = MTLViewport(originX:0, originY:0, width:2048, height:1024,znear:0.0,zfar:1.0)
bakeCommandEncoder.setViewport(vp)
bakeCommandEncoder.setCullMode(.none) // disable culling
// draw here.  Fragment shader sets final color to float4(0.0,1.0,0.0,1.0);
bakeCommandEncoder.endEncoding()

let blitEncoder = commandBuffer.makeBlitCommandEncoder()
blitEncoder!.copy(...) // this works as my buffer is all red
blitEncoder.endEncoding()

这是顶点着色器 - 它基于 OpenGL 顶点着色器来转储纹理的 uv 布局:

struct VertexOutBake {
    float4 position [[position]];
    float3 normal;
    float3 tangent;
    float3 binormal;
    float3 worldPosition;
    float2 texCoords;
};

vertex VertexOutBake vertex_main_bake(VertexInBake vertexIn [[stage_in]],
                        constant VertexUniforms &uniforms [[buffer(1)]])
{
    VertexOutBake vertexOut;
    float4 worldPosition = uniforms.modelMatrix * float4(vertexIn.position, 1);
    vertexOut.worldPosition = worldPosition.xyz;
    vertexOut.normal = normalize(vertexIn.normal);
    vertexOut.tangent = normalize(vertexIn.tangent);
    vertexOut.binormal = normalize(vertexIn.binormal);
    vertexOut.texCoords = vertexIn.texCoords;
    vertexOut.texCoords.y = 1.0 - vertexOut.texCoords.y; // flip image

    // now use uv coordinates instead of 3D positions
    vertexOut.position.x = vertexOut.texCoords.x * 2.0 - 1.0;
    vertexOut.position.y = 1.0 - vertexOut.texCoords.y * 2.0;
    vertexOut.position.z = 1.0;
    vertexOut.position.w = 1.0;

    return vertexOut;
}

由于 blit 复制而填充的缓冲区应该是绿色的,但它是红色的。这似乎意味着 bakeTexture 没有被写入片段着色器中,或者它被写入,但是在我进行复制时缺少一些同步以使内容可用。

4

0 回答 0