Tôi có hình ảnh mà tôi tạo theo chương trình và tôi muốn gửi hình ảnh này dưới dạng kết cấu cho trình đổ bóng tính toán. Cách tôi tạo ra hình ảnh này là tôi tính từng thành phần RGBA là các giá trị UInt8
và kết hợp chúng thành một UInt32
và lưu nó vào bộ đệm của hình ảnh. Tôi làm điều này với đoạn mã sau:Chuyển họa tiết với kiểu thành phần UInt8 tới bóng đổ Tính toán kim loại
guard let cgContext = CGContext(data: nil,
width: width,
height: height,
bitsPerComponent: 8,
bytesPerRow: 0,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: RGBA32.bitmapInfo) else {
print("Unable to create CGContext")
return
}
guard let buffer = cgContext.data else {
print("Unable to create textures")
return
}
let pixelBuffer = buffer.bindMemory(to: RGBA32.self, capacity: width * height)
let heightFloat = Float(height)
let widthFloat = Float(width)
for i in 0 ..< height {
let latitude = Float(i + 1)/heightFloat
for j in 0 ..< width {
let longitude = Float(j + 1)/widthFloat
let x = UInt8(((sin(longitude * Float.pi * 2) * cos(latitude * Float.pi) + 1)/2) * 255)
let y = UInt8(((sin(longitude * Float.pi * 2) * sin(latitude * Float.pi) + 1)/2) * 255)
let z = UInt8(((cos(latitude * Float.pi) + 1)/2) * 255)
let offset = width * i + j
pixelBuffer[offset] = RGBA32(red: x, green: y, blue: z, alpha: 255)
}
}
let coordinateConversionImage = cgContext.makeImage()
nơi RGBA32
là một cấu trúc nhỏ mà không được chuyển dịch và tạo ra giá trị UInt32
. Hình ảnh này trở nên ổn khi tôi có thể chuyển đổi nó thành UIImage
và lưu nó vào thư viện ảnh của tôi.
Sự cố xảy ra khi tôi cố gắng gửi hình ảnh này dưới dạng kết cấu cho trình đổ bóng tính toán. Dưới đây là mã shader của tôi:
kernel void updateEnvironmentMap(texture2d<uint, access::read> currentFrameTexture [[texture(0)]],
texture2d<uint, access::read> coordinateConversionTexture [[texture(1)]],
texture2d<uint, access::write> environmentMap [[texture(2)]]
uint2 gid [[thread_position_in_grid]])
{
const uint4 pixel = {255, 127, 63, 255};
environmentMap.write(pixel, gid);
}
Vấn đề với mã này là các loại kết cấu của tôi là uint
, đó là 32-bit, và tôi muốn tạo ra 32-bit pixel giống như cách tôi làm trên CPU, bằng cách thêm 4 giá trị 8 bit. Tuy nhiên, tôi không thể làm điều đó trên Kim loại vì không có loại byte
mà tôi có thể nối thêm với nhau và tạo thành uint32
. Vì vậy, câu hỏi của tôi là, cách chính xác để xử lý các họa tiết 2D và thiết lập các pixel 32-bit trên một bóng đổ tính toán bằng kim loại là gì?
Câu hỏi tiền thưởng: Ngoài ra, tôi đã thấy mã shader mẫu với texture2d<float, access::read>
làm loại kết cấu đầu vào. Tôi giả định nó đại diện cho một giá trị giữa 0,0 và 1,0 nhưng những gì lợi thế mà không có trên một int unsigned với các giá trị giữa 0 và 255?
Chỉnh sửa: Để làm rõ, kết cấu đầu ra của bóng đổ, environmentMap
, có cùng các thuộc tính giống nhau (chiều rộng, chiều cao, pixelFormat, v.v ...) làm kết cấu đầu vào. Tại sao tôi nghĩ rằng điều này phản trực giác là chúng tôi đang đặt một uint4
làm pixel, có nghĩa là nó bao gồm 4 giá trị 32 bit, trong khi mỗi pixel phải là 32 bit. Với mã hiện tại, {255, 127, 63, 255}
có kết quả chính xác giống như {2550, 127, 63, 255}
, có nghĩa là các giá trị bằng cách nào đó được kẹp giữa 0-255 trước khi được ghi vào kết cấu đầu ra. Nhưng điều này cực kỳ phản trực giác.
Cảm ơn Warren, điều này đã làm sáng tỏ rất nhiều điều. Ngoài ra, nếu có ai muốn biết thêm thông tin về vấn đề này, Chương 7.7 của Quy định về Ngôn ngữ của Metal Shading 7.7 Địa chỉ Texture và Quy tắc Chuyển đổi là nơi để xem xét. – halileohalilei