HLSL How can I pass data between shaders / read an existing color value?

I have 2 HLSL ps2.0 shaders. Simplified:

Shader 1

  • Reads a texture
  • Outputs a color value based on this texture

Shader 2

  • Problem: Need to read color from Shader 1
  • Outputs the final color, which is a function of the input color

(They must be different shaders as I have reached the max vertex shader outputs for 1 shader)


My problem: I can't figure out how Shader 2 can access the existing fragment / pixel color.

Knowing how to do any of these things with HLSL will solve my problem;

  • Read the existing pixel color (I don't think this is possible)
  • Pass Shader 1 result to Shader 2 as float4
  • Render the result of Shader 1 as a texture in memory and ask Shader 2 to read what's in
+2


a source to share


3 answers


Compositor scripts only appear for full screen (or more accurately full view) effects.

Render-to-texture - path. This is not necessarily done through linker scripting.



This thread on the Ogre forums is covered in more detail;

   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 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 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();
   }

      

+1


a source


Option 3:

Your HLSL code will be simple, the second shader will just pick from texture2D and calculate for that.



You will need to draw the render target with your first shader, then you can bind your render target to the texture and access it from the second shader as if it were any other 2D texture. Note that you cannot read from the render target that is currently set, so go back to the framebuffer before your second pass.

Also, you should explain how you managed to reach the limit on vertex shader pins? I'm curious: P.

+2


a source


To do what you want, you can switch render objects between executing shader1 and shader2. You output your first shader to a texture and then pass that texture to the second shader.

This is done in Ogre with the Compositor and target scripts .

+1


a source







All Articles