HLSL Como pode passar dados entre shaders / ler o valor de cor existente?
-
25-09-2019 - |
Pergunta
Eu tenho 2 shaders HLSL PS2.0. Simplificado, eles são:
Shader 1
- Lê textura
- Produz valor de cor com base nesta textura
Shader 2
- Problema: precisa ler na cor do shader 1
- Produz a cor final que é uma função da cor de entrada
(Eles precisam ser shaders diferentes quando eu atingi as saídas máximas de vértice-shader para 1 shader)
Meu problema é que não posso descobrir como o Shader 2 pode acessar a cor do fragmento/pixel existente.
Saber fazer alguma dessas coisas com o HLSL resolveria meu problema;
- Leia a cor do pixel existente (não acho que isso seja possível)
- Passe o resultado do shader 1 para o shader 2 como um float4
- Renderizar o resultado do shader 1 como uma textura na memória e fazer com que o Shader 2 leia isso em
Solução 3
Os scripts do compositor parecem ser apenas para efeitos de tela cheia (ou mais precisamente, viewport completa).
Render-to-texture é o caminho a percorrer. Não é necessariamente realizado com scripts do Compositor.
Este tópico Do meu nos fóruns OGRE entra em mais detalhes;
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();
}
Outras dicas
Opção 3:
Seu código HLSL será simples, o segundo shader apenas amostrará de uma textura2D e unde que, para seus cálculos.
Você precisará desenhar para um renderizar alvo Com o seu primeiro shader, você pode vincular seu alvo de renderização a uma textura e acessá -lo do segundo shader como se fosse alguma outra textura2D. Observe que você não pode ler em um alvo de renderização que está atualmente definido, portanto, volte para o Framebuffer antes do seu segundo passe.
Além disso, cuide de explicar como você conseguiu atingir o limite nas saídas do shadex do vértice? Estou curioso: p.
Para fazer o que quiser, você pode alternar os alvos de renderização entre a execução do Shader1 e o Shader2. Você produz seu primeiro shader para uma textura e depois passa esta textura para o seu segundo shader.
Isso é feito em ogre com Scripts compositores e alvo.