HLSL シェーダ間でデータを渡したり、既存のカラー値を読み取るにはどうすればよいですか?
-
25-09-2019 - |
質問
HLSL ps2.0 シェーダーが 2 つあります。簡略化すると次のとおりです。
シェーダー1
- テクスチャを読み取ります
- このテクスチャに基づいてカラー値を出力します
シェーダー2
- 問題:シェーダー 1 からカラーを読み取る必要があります
- 入力色の関数である最終色を出力します。
(1 つのシェーダーの最大頂点シェーダー出力に達したため、それらは異なるシェーダーである必要があります)
私の問題は、Shader 2 が既存のフラグメント/ピクセルの色にどのようにアクセスできるかを理解できないことです。
HLSL を使用してこれらのことを実行する方法を知っていれば、私の問題は解決します。
- 既存のピクセルの色を読み取ります (これは不可能だと思います)
- Shader 1 の結果を float4 として Shader 2 に渡す
- シェーダー 1 の結果をメモリ内のテクスチャとしてレンダリングし、シェーダー 2 にそれを読み込ませます。
解決 3
Compositorのスクリプトのみをフルスクリーン(またはより正確に、完全なビューポート)効果のためにあるように見える。
レンダリング・ツー・質感が移動するための方法です。それは、必ずしもコンポジスクリプトを成し遂げていない。
上の私のこのスレッドする鬼のフォーラムは、より多くの詳細に立ち入り;
Ogre::Root r(...);
Ogre::RenderWindow* window = r.createRenderWindow(...);
//...
Ogre::SceneManager* sm = r.createSceneManager(Ogre::ST_GENERIC, "sm");
//...
//Main scene camera
Ogre::Camera* c = sm->createCamera("camera");
{
c->setNearClipDistance(5);
Ogre::Viewport* v = window->addViewport(c);
v->setBackgroundColour (Ogre::ColourValue(0, 0, 0));
c->setAspectRatio (static_cast<double> (v->getActualWidth ()) / v->getActualHeight ());
}
//RTT
Ogre::TexturePtr ptrTexture = Ogre::TextureManager::getSingleton().createManual(
"RttTex",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::TEX_TYPE_2D,
512,//window->getWidth(),
512,//window->getHeight(),
0, //MIP_DEFAULT?
Ogre::PF_R8G8B8,
Ogre::TU_RENDERTARGET,
0
);
Ogre::RenderTexture* renderTexture = ptrTexture->getBuffer()->getRenderTarget();
renderTexture->setAutoUpdated(true);
//Create material to use with rect
{
//You should replace this with the material you wish to render to texture
//It can be defined in c++ (as this is) or in a material script
Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create("material", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
Ogre::Technique* tech = material->createTechnique();
tech->createPass();
material->getTechnique(0)->getPass(0)->setLightingEnabled(false);
material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false);
material->getTechnique(0)->getPass(0)->createTextureUnitState("my_square_texture.dds");
}
//Create rect2D in yz plane to which we will draw our textures
//Most likely you'll wish to reposition the node so it's offscreen
const static float r_dimension = 1000.0;
Ogre::SceneNode* rect_node = sm->getRootSceneNode()->createChildSceneNode("rect_node");
{
Ogre::ManualObject *rect = sm->createManualObject("rect");
rect->begin("material", Ogre::RenderOperation::OT_TRIANGLE_FAN);
rect->position(0, r_dimension, r_dimension);
rect->textureCoord(0,0);
rect->normal(0, 1, 0);
rect->position(0, -r_dimension, r_dimension);
rect->textureCoord(0,1);
rect->normal(0, 1, 0);
rect->position(0, -r_dimension, -r_dimension);
rect->textureCoord(1,1);
rect->normal(0, 1, 0);
rect->position(0, r_dimension, -r_dimension);
rect->textureCoord(1,0);
rect->normal(0, 1, 0);
rect->end();
rect_node->attachObject(rect);
}
//Create camera, make it look at this rect2D
Ogre::Camera* rtt_cam = sm->createCamera("rtt_cam");
//Use same FOV as main camera
Ogre::Radian fov_y = c->getFOVy();
rtt_cam->setFOVy(fov_y);
//Position the camera such that the texture fills the viewpoint
{
//Angle from normal (ie, "vector origin->camera") to to top of tecture is FOV/2
//Distance origin to top of texture is r_dimension
double cam_to_rect_distance = r_dimension/tan((fov_y.valueRadians())/2);
rtt_cam->setPosition(cam_to_rect_distance, 0, 0);
rtt_cam->lookAt(rect_node->getPosition());
}
//Debug using main window
//window->addViewport(rtt_cam);
//Write to RTT
Ogre::Viewport* v = renderTexture->addViewport(rtt_cam);
v->setClearEveryFrame(true); //You may wish to set this to false and render only when your material updates/changes
v->setBackgroundColour(Ogre::ColourValue::Blue); //Debug colour. If we see blue border in RTT our cam position is wrong.
v->setOverlaysEnabled(false); //We don't want overlays to show up on the RTT
//TEMP Create debug screen (lifted from Ogre Tutorial 7)
//Draws the result of RTT onscreen picture-in-picture
{
Ogre::Rectangle2D *miniScreen = new Ogre::Rectangle2D(true);
miniScreen->setCorners(0.5f, -0.5f, 1.0f, -1.0f);
//miniScreen->setBoundingBox(Ogre::AxisAlignedBox(-100000.0f * Ogre::Vector3::UNIT_SCALE, 100000.0f * Ogre::Vector3::UNIT_SCALE));
Ogre::SceneNode* miniScreenNode = sm->getRootSceneNode()->createChildSceneNode("MiniScreenNode");
miniScreenNode->attachObject(miniScreen);
//Create material to read result of Rtt, purely for debug purposes
Ogre::MaterialPtr screenMaterial = Ogre::MaterialManager::getSingleton().create("ScreenMatt", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
Ogre::Technique* screenTechnique = screenMaterial->createTechnique();
screenTechnique->createPass();
screenMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false);
screenMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex");
miniScreen->setMaterial("ScreenMatt");
//TODO ideally we'd have render target listeners call setVisible(false) on pre update and setVisible(true) post update,
//so we don't get the infinite line picture-in-picture-in-picture in the preview window.
}
//Now you can bind your shader's material script to the rtt
{
Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName("your_material_name");
Ogre::Technique *technique = material->getTechnique(0);
Ogre::Pass *pass = technique->getPass(0);
Ogre::TextureUnitState *tunit = pass->getTextureUnitState("your_materials_tunit_name");
tunit->setTextureName("Rtt");
}
//...
while (! window->isClosed ()) {
//...
r.renderOneFrame();
}
他のヒント
オプション3:
あなたのHLSLコードがシンプルになり、第二のシェーダだけにTexture2Dからのサンプルとウントそれの計算のためのものでしょう。
それは、他にTexture2Dであるかのようにあなたはのあなたの最初のシェーダでのレンダーターゲットに描画する必要があるでしょう、そしてあなたは、テクスチャ、および第二のシェーダからのアクセスにそれをするあなたのレンダーターゲットをバインドすることができます。あなたが現在設定されているレンダリングターゲットから読み取ることができないことに注意してください、あなたの第二のパスの前にフレームバッファにとてもセットバックます。
また、あなたが頂点シェーダ出力の上限に達することができた方法を説明する気?私は好奇心旺盛だ:P
あなたはshader1とshader2の実行の間にレンダーターゲットを切り替えることができ、あなたがやりたいです。 あなた出力テクスチャにあなたの最初のシェーダと、あなたはあなたの第二のシェーダにこのテクスチャを渡します。
これは Compositorのスクリプトとターゲットます。
と鬼に行われています