これが尋ねられた場所をいくつか見つけましたが、まだ良い答えを見つけていません。
問題: テクスチャにレンダリングしたいのですが、そのレンダリングされたテクスチャを、テクスチャへのレンダリングのステップをスキップして画面に直接レンダリングした場合と同じように画面に描画したいと考えています。現在、ブレンド モード glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) を使用しています。私もglBlendFuncSeparateを使って遊んでいます。
部分的に透明な重なり合うアイテムをこのテクスチャにレンダリングできるようにしたいと考えています。ブレンド関数が現在、アルファに基づいて RGB 値を台無しにしていることを知っています。「事前に乗算されたアルファ」を使用するという漠然とした提案を見たことがありますが、それが何を意味するかについての説明は貧弱です。私は Photoshop で png ファイルを作成します。それらには半透明ビットがあり、TGA のようにアルファ チャネルを個別に簡単に編集することはできません。PNG の方が便利ですが、必要に応じて TGA に切り替えることもできます。
今のところ、この質問のために、画像を使用していないと仮定します。代わりに、アルファ付きのフルカラー クワッドを使用しています。
シーンをテクスチャにレンダリングしたら、そのテクスチャを別のシーンにレンダリングする必要があります。また、部分的な透明度を想定してテクスチャをブレンドする必要があります。ここで物事がバラバラになります。前のブレンディング手順では、アルファに基づいて RGB 値を明確に変更しました。アルファが 0 または 1 の場合は再度変更しても問題ありませんが、その間にある場合は、部分的に半透明のピクセルがさらに暗くなります。
ブレンドモードで遊んでいて、運がほとんどありませんでした。私ができる最善の方法は、次の方法でテクスチャにレンダリングすることです。
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) を使用して複数回レンダリングすると、適切な色に近づくことがわかりました (重複しない限り)。しかし、それは完全ではありません (次の画像でわかるように、緑/赤/青のボックスが重なっている部分が暗くなるか、アルファが蓄積されます。(編集: 画面部分へのレンダリングで複数の描画を行うと、テクスチャに 1 回レンダリングすると、アルファ蓄積の問題がなくなり、機能しますが、なぜ?! 同じテクスチャを画面に何百回もレンダリングして適切に蓄積する必要はありません)
問題の詳細を示すいくつかの画像を次に示します (複数のレンダー パスは基本的なブレンディング (GL_SRC_ALPHA、GL_ONE_MINUS_SRC_ALPHA) を使用しており、テクスチャ レンダリング ステップで複数回レンダリングされます。右側の 3 つのボックスは、100% の赤、緑、または青でレンダリングされます。 (0-255) ただし、青の 50%、赤の 25%、緑の 75% のアルファ値:
だから、私が知りたいことの内訳:
- ブレンド モードをX ?に設定しました。
- シーンをテクスチャにレンダリングします。(おそらく、いくつかのブレンド モードで、または複数回レンダリングする必要がありますか?)
- ブレンド モードをYに設定しました。
- 既存のシーンの上にテクスチャを画面にレンダリングします。(多分、別のシェーダーが必要ですか? テクスチャを数回レンダリングする必要があるのでしょうか?)
望ましい動作は、そのステップの最後に、最終的なピクセル結果が、これを実行した場合と同じになることです。
- ブレンドモードを次のように設定しました: (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
- シーンを画面にレンダリングします。
そして、完全を期すために、ここに私の最初の素朴な試み(通常のブレンディングのみ)を含むコードの一部を示します。
//RENDER TO TEXTURE.
void Clipped::refreshTexture(bool a_forceRefresh) {
if(a_forceRefresh || dirtyTexture){
auto pointAABB = basicAABB();
auto textureSize = castSize<int>(pointAABB.size());
clippedTexture = DynamicTextureDefinition::make("", textureSize, {0.0f, 0.0f, 0.0f, 0.0f});
dirtyTexture = false;
texture(clippedTexture->makeHandle(Point<int>(), textureSize));
framebuffer = renderer->makeFramebuffer(castPoint<int>(pointAABB.minPoint), textureSize, clippedTexture->textureId());
{
renderer->setBlendFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
SCOPE_EXIT{renderer->defaultBlendFunction(); };
renderer->modelviewMatrix().push();
SCOPE_EXIT{renderer->modelviewMatrix().pop(); };
renderer->modelviewMatrix().top().makeIdentity();
framebuffer->start();
SCOPE_EXIT{framebuffer->stop(); };
const size_t renderPasses = 1; //Not sure?
if(drawSorted){
for(size_t i = 0; i < renderPasses; ++i){
sortedRender();
}
} else{
for(size_t i = 0; i < renderPasses; ++i){
unsortedRender();
}
}
}
alertParent(VisualChange::make(shared_from_this()));
}
}
シーンをセットアップするために使用しているコードは次のとおりです。
bool Clipped::preDraw() {
refreshTexture();
pushMatrix();
SCOPE_EXIT{popMatrix(); };
renderer->setBlendFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
SCOPE_EXIT{renderer->defaultBlendFunction();};
defaultDraw(GL_TRIANGLE_FAN);
return false; //returning false blocks the default rendering steps for this node.
}
シーンをレンダリングするコード:
test = MV::Scene::Rectangle::make(&renderer, MV::BoxAABB({0.0f, 0.0f}, {100.0f, 110.0f}), false);
test->texture(MV::FileTextureDefinition::make("Assets/Images/dogfox.png")->makeHandle());
box = std::shared_ptr<MV::TextBox>(new MV::TextBox(&textLibrary, MV::size(110.0f, 106.0f)));
box->setText(UTF_CHAR_STR("ABCDE FGHIJKLM NOPQRS TUVWXYZ"));
box->scene()->make<MV::Scene::Rectangle>(MV::size(65.0f, 36.0f))->color({0, 0, 1, .5})->position({80.0f, 10.0f})->setSortDepth(100);
box->scene()->make<MV::Scene::Rectangle>(MV::size(65.0f, 36.0f))->color({1, 0, 0, .25})->position({80.0f, 40.0f})->setSortDepth(101);
box->scene()->make<MV::Scene::Rectangle>(MV::size(65.0f, 36.0f))->color({0, 1, 0, .75})->position({80.0f, 70.0f})->setSortDepth(102);
test->make<MV::Scene::Rectangle>(MV::size(65.0f, 36.0f))->color({.0, 0, 1, .5})->position({110.0f, 10.0f})->setSortDepth(100);
test->make<MV::Scene::Rectangle>(MV::size(65.0f, 36.0f))->color({1, 0, 0, .25})->position({110.0f, 40.0f})->setSortDepth(101);
test->make<MV::Scene::Rectangle>(MV::size(65.0f, 36.0f))->color({.0, 1, 0, .75})->position({110.0f, 70.0f})->setSortDepth(102);
そして、ここに私のスクリーンドローがあります:
renderer.clearScreen();
test->draw(); //this is drawn directly to the screen.
box->scene()->draw(); //everything in here is in a clipped node with a render texture.
renderer.updateScreen();
*編集: フレームバッファのセットアップ/ティアダウン コード:
void glExtensionFramebufferObject::startUsingFramebuffer(std::shared_ptr<Framebuffer> a_framebuffer, bool a_push){
savedClearColor = renderer->backgroundColor();
renderer->backgroundColor({0.0, 0.0, 0.0, 0.0});
require(initialized, ResourceException("StartUsingFramebuffer failed because the extension could not be loaded"));
if(a_push){
activeFramebuffers.push_back(a_framebuffer);
}
glBindFramebuffer(GL_FRAMEBUFFER, a_framebuffer->framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, a_framebuffer->texture, 0);
glBindRenderbuffer(GL_RENDERBUFFER, a_framebuffer->renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, roundUpPowerOfTwo(a_framebuffer->frameSize.width), roundUpPowerOfTwo(a_framebuffer->frameSize.height));
glViewport(a_framebuffer->framePosition.x, a_framebuffer->framePosition.y, a_framebuffer->frameSize.width, a_framebuffer->frameSize.height);
renderer->projectionMatrix().push().makeOrtho(0, static_cast<MatrixValue>(a_framebuffer->frameSize.width), 0, static_cast<MatrixValue>(a_framebuffer->frameSize.height), -128.0f, 128.0f);
GLenum buffers[] = {GL_COLOR_ATTACHMENT0};
//pglDrawBuffersEXT(1, buffers);
renderer->clearScreen();
}
void glExtensionFramebufferObject::stopUsingFramebuffer(){
require(initialized, ResourceException("StopUsingFramebuffer failed because the extension could not be loaded"));
activeFramebuffers.pop_back();
if(!activeFramebuffers.empty()){
startUsingFramebuffer(activeFramebuffers.back(), false);
} else {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glViewport(0, 0, renderer->window().width(), renderer->window().height());
renderer->projectionMatrix().pop();
renderer->backgroundColor(savedClearColor);
}
}
そして私のクリアスクリーンコード:
void Draw2D::clearScreen(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}