HLSL 如何在着色器之间传递数据/读取现有颜色值?

发布于 2024-08-31 17:14:08 字数 465 浏览 9 评论 0原文

我有 2 个 HLSL ps2.0 着色器。简单来说,它们是:

Shader 1

  • 读取纹理,
  • 根据该纹理输出颜色值

Shader 2

  • 问题:需要从 Shader 1 读取颜色
  • 输出最终颜色,它是一个函数输入颜色的

(它们需要是不同的着色器,因为我已经达到 1 个着色器的最大顶点着色器输出)


我的问题是我无法弄清楚着色器 2 如何访问现有的片段/像素颜色。

知道如何使用 HLSL 执行这些操作可以解决我的问题;

  • 读取现有的像素颜色(我认为这是不可能的)
  • 将着色器 1 的结果作为 float4 传递给着色器 2
  • 将着色器 1 的渲染结果作为内存中的纹理,并让着色器 2 读取该结果

I have 2 HLSL ps2.0 shaders. Simplified, they are:

Shader 1

  • Reads texture
  • Outputs colour value based on this texture

Shader 2

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

(They need to be different shaders as I've reached the maximum vertex-shader outputs for 1 shader)


My problem is I cannot work out how Shader 2 can access the existing fragment/pixel colour.

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

  • Read existing pixel colour (I don't think this is possible)
  • Pass result of Shader 1 to Shader 2 as a float4
  • Render result of Shader 1 as a texture in memory, and have Shader 2 read that in

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

千年*琉璃梦 2024-09-07 17:14:08

选项 3:

您的 HLSL 代码将很简单,第二个着色器将仅从texture2D 中采样并进行计算。

您需要使用第一个着色器绘制渲染目标,然后您可以将渲染目标绑定到纹理,并从第二个着色器访问它,就像它是任何其他texture2D一样。请注意,您无法读取当前设置的渲染目标,因此请在第二遍之前设置回帧缓冲区。

另外,请解释一下您是如何设法达到顶点着色器输出的限制的?我很好奇:P。

Option 3:

Your HLSL code will be simple, the second shader will just sample from a texture2D and und that for it's calculations.

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

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

行至春深 2024-09-07 17:14:08

要执行您想要的操作,您可以在执行着色器 1 和着色器 2 之间切换渲染目标。
您将第一个着色器输出到纹理,然后将此纹理传递到第二个着色器。

这是在 Ogre 中使用 合成器脚本 和目标完成的。

To do what you want, you can switch render targets between execution of shader1 and shader2.
You output your first shader to a texture and then you pass this texture to your second shader.

This is done in Ogre with Compositor scripts and target.

鸢与 2024-09-07 17:14:08

合成器脚本似乎仅适用于全屏(或更准确地说,全视口)效果。

渲染到纹理是必经之路。它不一定是通过合成器脚本来完成的。

我的这个帖子 Ogre 论坛有更详细的内容;

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

Compositor scripts seem to be only for fullscreen (or more accurately, full viewport) effects.

Render-to-texture is the way to go. It's not necessarily accomplished with compositor scripts.

This thread of mine on the Ogre forums goes into 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'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();
   }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文