조각 셰이더에 값 목록 전달
프래그먼트 셰이더에 값 목록을 보내고 싶습니다. 이것은 단 정밀도 부동의 큰 (수천 개의 항목 길이) 목록 일 수 있습니다. 조각 셰이더는이 목록에 대한 임의 액세스가 필요하며 각 프레임의 CPU에서 값을 새로 고치고 싶습니다.
이 작업을 수행하는 방법에 대한 옵션을 고려하고 있습니다.
배열 유형의 균일 변수 ( "uniform float x [10];"). 그러나 여기에는 한계가있는 것 같습니다. GPU에서 수백 개 이상의 값을 보내는 것은 매우 느리며 런타임에서 변경하고 싶을 때 셰이더에서 상한을 하드 코딩해야합니다.
내 목록의 높이 1과 너비를 가진 텍스처로 glCopyTexSubImage2D를 사용하여 데이터를 새로 고칩니다.
다른 방법? 최근에 GL 사양의 모든 변경 사항을 따라 가지 못했습니다.이 목적을 위해 특별히 설계된 다른 방법이 있습니까?
현재이를 수행하는 방법에는 표준 1D 텍스처, 버퍼 텍스처, 균일 버퍼 및 셰이더 저장소 버퍼의 4 가지 방법이 있습니다.
1D 텍스처
이 방법을 사용 glTex(Sub)Image1D하면 데이터로 1D 텍스처를 채울 수 있습니다. 데이터는 부동 소수점 배열 일 뿐이므로 이미지 형식 은 GL_R32F. 그런 다음 간단한 texelFetch호출로 셰이더에서 액세스합니다 . texelFetch텍셀 좌표 (따라서 이름)를 취하고 모든 필터링을 차단합니다. 따라서 정확히 하나의 텍셀을 얻습니다.
참고 : texelFetch3.0 이상입니다. 이전 GL 버전을 사용하려면 크기를 셰이더에 전달하고 텍스처 좌표를 수동으로 정규화해야합니다.
여기에서 주요 장점은 호환성과 소형화입니다. 이것은 GL 2.1 하드웨어에서 작동합니다 (표기법 사용). 그리고 당신은하지 않습니다 이 사용에 GL_R32F형식; GL_R16F하프 플로트를 사용할 수 있습니다 . 또는 GL_R8데이터가 정규화 된 바이트에 합당한 경우. 크기는 전반적인 성능에 많은 것을 의미 할 수 있습니다.
가장 큰 단점은 크기 제한입니다. 최대 텍스처 크기의 1D 텍스처로 제한됩니다. GL 3.x 클래스 하드웨어에서 이것은 약 8,192가 될 것이지만 4,096 이상이 보장됩니다.
균일 한 버퍼 객체
이것이 작동하는 방식은 셰이더에서 균일 한 블록을 선언하는 것입니다.
layout(std140) uniform MyBlock
{
float myDataArray[size];
};
그런 다음 배열처럼 셰이더에서 해당 데이터에 액세스합니다.
C / C ++ / etc 코드로 돌아가서 버퍼 객체를 만들고 부동 소수점 데이터로 채 웁니다. 그런 다음 해당 버퍼 개체를 MyBlock균일 블록 과 연결할 수 있습니다 . 자세한 내용은 여기에서 확인할 수 있습니다.
이 기술의 주요 장점은 속도와 의미입니다. 속도는 구현이 텍스처에 비해 균일 한 버퍼를 처리하는 방식 때문입니다. 텍스처 가져 오기는 전역 메모리 액세스입니다. 균일 한 버퍼 액세스는 일반적으로 그렇지 않습니다. 균일 한 버퍼 데이터는 일반적으로 셰이더가 렌더링에 사용될 때 초기화 될 때 셰이더에로드됩니다. 거기에서 훨씬 더 빠른 로컬 액세스입니다.
의미 적으로 이것은 단순한 평면 배열이 아니기 때문에 더 좋습니다. 특정 요구에 대해 필요한 것이 모두이면 float[]상관 없습니다. 그러나 데이터 구조가 더 복잡한 경우 의미 체계가 중요 할 수 있습니다. 예를 들어 조명 배열을 고려하십시오. 조명에는 위치와 색상이 있습니다. 텍스처를 사용하는 경우 특정 조명의 위치와 색상을 가져 오는 코드는 다음과 같습니다.
vec4 position = texelFetch(myDataArray, 2*index);
vec4 color = texelFetch(myDataArray, 2*index + 1);
균일 한 버퍼를 사용하면 다른 균일 한 액세스처럼 보입니다. position및 이라고 부를 수있는 멤버를 지정했습니다 color. 따라서 모든 의미 정보가 있습니다. 무슨 일이 일어나고 있는지 이해하는 것이 더 쉽습니다.
이것에도 크기 제한이 있습니다. OpenGL은 구현시 균일 한 블록의 최대 크기에 대해 최소 16,384 바이트를 제공해야합니다. 즉, float 배열의 경우 4,096 개의 요소 만 얻습니다. 이것은 구현에 필요한 최소값입니다 . 일부 하드웨어는 훨씬 더 큰 버퍼를 제공 할 수 있습니다. 예를 들어 AMD는 DX10 급 하드웨어에서 65,536을 제공합니다.
버퍼 텍스처
이것은 일종의 "슈퍼 1D 텍스처"입니다. 이를 통해 텍스처 단위에서 버퍼 객체에 효과적으로 액세스 할 수 있습니다 . 1 차원이지만 1D 텍스처는 아닙니다.
GL 3.0 이상에서만 사용할 수 있습니다. 그리고 texelFetch기능을 통해서만 액세스 할 수 있습니다 .
여기서 가장 큰 장점은 크기입니다. 버퍼 텍스처는 일반적으로 꽤 거대 할 수 있습니다. 사양은 일반적으로 보수적이며 버퍼 텍스처에 최소 65,536 바이트를 요구하지만 대부분의 GL 구현에서는 메가 바이트 크기의 범위를 허용합니다 . 사실, 일반적으로 최대 크기는 하드웨어 제한이 아니라 사용 가능한 GPU 메모리에 의해 제한됩니다.
또한 버퍼 텍스처는 1D 텍스처와 같이 불투명 한 텍스처 개체가 아닌 버퍼 개체에 저장됩니다. 즉, 일부 버퍼 개체 스트리밍 기술 을 사용 하여 업데이트 할 수 있습니다.
여기서 가장 큰 단점은 1D 텍스처와 마찬가지로 성능입니다. 버퍼 텍스처는 아마도 1D 텍스처보다 느리지 않을 것이지만 UBO만큼 빠르지는 않을 것입니다. 플로트 하나만 빼내고 있다면 걱정할 필요가 없습니다. 그러나 그들로부터 많은 데이터를 가져 오는 경우 대신 UBO를 사용하는 것이 좋습니다.
셰이더 저장소 버퍼 개체
OpenGL 4.3은이를 처리하는 또 다른 방법을 제공합니다 : 셰이더 스토리지 버퍼 . 그들은 균일 한 버퍼와 매우 유사합니다. 균일 블록의 구문과 거의 동일한 구문을 사용하여 지정합니다. 원칙적인 차이점은 그들에게 쓸 수 있다는 것입니다. 분명히 그것은 당신의 필요에 유용하지 않지만 다른 차이점이 있습니다.
셰이더 저장소 버퍼는 개념적으로 말하면 버퍼 텍스처의 대체 형태입니다. 따라서 셰이더 저장소 버퍼의 크기 제한 은 균일 한 버퍼보다 훨씬 큽니다. 최대 UBO 크기에 대한 OpenGL 최소값은 16KB입니다. 최대 SSBO 크기에 대한 OpenGL 최소값은 16MB 입니다. 따라서 하드웨어가 있다면 UBO에 대한 흥미로운 대안입니다.
readonly글을 쓰지 않기 때문에 로 선언해야 합니다.
여기서 잠재적 인 단점은 UBO에 비해 성능입니다. SSBO는 버퍼 텍스처를 통해 이미지로드 / 저장 작업처럼 작동 합니다. 기본적으로 imageBuffer이미지 유형 주변의 (매우 멋진) 구문 설탕 입니다. 따라서 이들로부터의 읽기는 readonly imageBuffer.
Whether reading via image load/store through buffer images is faster or slower than buffer textures is unclear at this point.
Another potential issue is that you must abide by the rules for non-synchronous memory access. These are complex and can very easily trip you up.
This sounds like a nice use case for texture buffer objects. These don't have much to do with regular textures and basically allow you to access a buffer object's memory in a shader as a simple linear array. They are similar to 1D textures, but are not filtered and only accessed by an integer index, which sounds like what you need to do when you call it a list of values. And they also support much larger sizes than 1D textures. For updating it you can then use the standard buffer object methods (glBufferData, glMapBuffer, ...).
But on the other hand they require GL3/DX10 hardware to use and have even been made core in OpenGL 3.1, I think. If your hardware/driver doesn't support it, then your 2nd solution would be the method of choice, but rather use a 1D texture than a width x 1 2D texture). In this case you can also use a non-flat 2D texture and some index magic to support lists larger than the maximum texture size.
But texture buffers are the perfect match for your problem, I think. For more exact insight you might also look into the corresponding extension specification.
EDIT: In response to Nicol's comment about uniform buffer objects, you can also look here for a little comparison of the two. I still tend to TBOs, but cannot really reason why, only because I see it a better fit conceptually. But maybe Nicol can provide an anwer with some more insight into the matter.
One way would be to use uniform arrays like you mention. Another way to do it, is to use a 1D "texture". Look for GL_TEXTURE_1D and glTexImage1D. I personally prefer this way as you don't need to hardcode the size of the array in the shader code as you said, and opengl already has built-in functions for uploading/accessing 1D data on the GPU.
I'd say probably not number 1.. you have a limited number of registers for shader uniforms, which varies by card. You can query GL_MAX_FRAGMENT_UNIFORM_COMPONENTS to find out your limit. On newer cards it runs into the thousands, e.g. a Quadro FX 5500 has 2048, apparently. (http://www.nvnews.net/vbulletin/showthread.php?t=85925). It depends what hardware you want it to run on, and what other uniforms you might want to send to the shader too.
Number 2 could be made to work depending on your requirements. Sorry for the vagueness here, hopefully someone else can give you a more precise answer, but you must be explicit in how many texture calls you make in older shader model cards. It also depends how many texture reads you want to do per fragment, you probably wouldn't want to be trying to read 1000's of elements per fragment, again, depending on your shader model and performance requirements. You could pack values into RGBAs of a texture, giving you 4 reads per texture call, but with random access as a requirement, this might not help you.
I'm not sure about number 3, but I'd suggest maybe looking at UAV (unordered access views) although i think that is DirectX only, with no decent openGL equivalent. I think there's an nVidia extension for openGL, but again you then restrict yourself to a pretty strict minimum spec.
It's unlikely that passing 1000's of items of data to your fragment shader is the best solution to your problem.. perhaps if you gave more details on what you're trying to achieve you may get alternative suggestions?
참고URL : https://stackoverflow.com/questions/7954927/passing-a-list-of-values-to-fragment-shader
'program story' 카테고리의 다른 글
| 마지막으로 가져온 이후 변경된 사항에 대한 git diff를 생성하려면 어떻게해야합니까? (0) | 2020.11.05 |
|---|---|
| GUID가 GUID인지 확인하는 방법 (0) | 2020.11.04 |
| TLD는 얼마나 오래 걸릴 수 있습니까? (0) | 2020.11.04 |
| Symfony 2에 JSON 객체 게시 (0) | 2020.11.04 |
| $ http는 요청에서 쿠키를 보내지 않습니다. (0) | 2020.11.04 |