4

I would like to use a fragment shader to render to a texture offscreen. Once this is done I want to use the result of that as the input for another fragment shader.

I create a texture and clear it with red (to know it is set). I use the render pass that is connected to my target texture and draw. I then use a blit command encoder to transfer the contents of that target texture to a buffer. The buffer contains red so I know it is reading the texture correctly but the drawing should make the texture green so something is wrong.

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

for drawing I do this:

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()

Here is the vertex shader - it is based on an OpenGL vertex shader to dump out the uv-layout of the texture:

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;
}

The buffer that gets filled as a result of the blit copy should be green but it is red. This seems to mean that either the bakeTexture is not being written to in the fragment shader or that it is, but there is some synchronization missing to make the content available at the time I am doing the copy.

  • 1
    You've left out the most important part, the drawing commands and the shaders. Also, `znear` and `zfar` must be between 0.0 and 1.0. See the docs for `setViewport()`. – Ken Thomases Apr 17 '19 at 16:28
  • Thanks Ken. I adjusted the znear and zfar as you suggested. As for the shader ,the fragment is just the output color as mentioned above. The vertex shader is a bit more complicated since I want to dump out the uv layout of the texture so I have shown what I am using based on my OpenGL vertex shader used in Android. – user1675629 Apr 17 '19 at 18:54
  • 1
    What do you actually draw? A triangle list, a triangle strip? What's the vertex data? Etc. I suspect you're failing to draw anything. Perhaps it's outside of the frustum and clipped away. That vertex shader is way more complicated than needed to fill a texture with green. Lots of things could go wrong and probably are. Start with a much simpler pass-through vertex shader and vertexes at (-1, -1), (-1, 1), (1, 1), and (1, -1). – Ken Thomases Apr 17 '19 at 20:20
  • I am drawing a triangle list. I did indeed have an issue and was not drawing anything (nil texture detected so draw was skipped). Once I resolved that it worked but my texture was upside down until I made the coordinate change to 1.0 - y * 2.0. Now that it is rendering I enabled the actual fragment shader which is more complicated than just green but I needed to eliminate possible sources of error so that is why I went with the simple green output. – user1675629 Apr 17 '19 at 20:46

0 Answers0