Simple background image that change every fram

Hi,
I want to display image on the background of the scene (no skycube or skydome; just 800x600 image on the background, always facing camera).
I want to change this image every frame (with data form a webcam but also data from fractal generated in the memory. (so OpenCVexture wan’t go)
What is the most efficient and eassyest :wink: way to do that?
Currently I’m putting image in the background like this:

((DisplayRegion*) window->get_camera(0)->    get_display_region(0))->set_sort(20);
window->get_display_region_3d()-> set_clear_color_active(false);
window->get_display_region_2d()-> set_clear_color_active(true);

    CardMaker cm("bcg");
    PointerTo<PandaNode> pn = cm.generate();
    NodePath n = window->get_render_2d().attach_new_node(pn);
    Texture *t = TexturePool::load_texture("bcg.png");
    n.set_texture(t);
    n.set_bin("background", 0);
    n.set_billboard_axis();

But don’t know how to change texture data. I was considering texture->set_void_ptr or set_raw_data
but it ins’t obvious how to convert my row data RGBRGBRGB… to fit classes.

I was looking for solution like

texture->set_new_pixel_buffer_ptr(void* mem, newWidth, newHeight, newBpp)

and then

texture->reread_data_from_that_new_buffer()

But any other solution wold be ok. :wink:

You can call modify_ram_image, which returns a PTA(uchar) (Panda’s reference-counted equivalent of uchar*) that you can modify.

Here’s an example:

#include "pandaFramework.h"
#include "cardMaker.h"
#include "texture.h"
#include "asyncTaskManager.h"
#include "asyncTask.h"
#include "perlinNoise3.h"
#include "math.h"

static const int tsize = 64;
static const double scale = 16.0;
static const double period = 20.0;
static const double speed = 1.0;

PandaFramework framework;

class FlowTask : public AsyncTask {
public:
  FlowTask(Texture *tex);
  ALLOC_DELETED_CHAIN(FlowTask);
  virtual DoneStatus do_task();
  inline unsigned char pixel(double n) {
    return (unsigned char)(n * 127.0 + 128.0);
  }

  PerlinNoise3 _red, _grn, _blu;
  PT(Texture) _tex;
};

FlowTask::FlowTask(Texture *tex) : 
  _red(tsize, tsize, period),
  _grn(tsize, tsize, period),
  _blu(tsize, tsize, period),
  _tex(tex)
{
  _red.set_scale(scale, scale, speed);
  _grn.set_scale(scale, scale, speed);
  _blu.set_scale(scale, scale, speed);
}

FlowTask::DoneStatus FlowTask::
do_task() {
  PTA_uchar image = _tex->modify_ram_image();
  double t = get_elapsed_time() / period;
  t = (t - floor(t)) * period;

  for (int yi = 0; yi < tsize; ++yi) {
    for (int xi = 0; xi < tsize; ++xi) {
      int i = (yi * tsize + xi) * 3;
      image[i] = pixel(_blu(xi, yi, t));
      image[i + 1] = pixel(_grn(xi, yi, t));
      image[i + 2] = pixel(_red(xi, yi, t));
    }
  }

  return DS_cont;
}

int
main(int argc, char *argv[]) {
  framework.open_framework(argc, argv);

  WindowFramework *window = framework.open_window();

  CardMaker cm("cm");
  cm.set_frame(-0.9, 0.9, -0.9, 0.9);
  NodePath card = window->get_render_2d().attach_new_node(cm.generate());
  PT(Texture) tex = new Texture("tex");
  tex->setup_2d_texture(tsize, tsize, Texture::T_unsigned_byte, Texture::F_rgb);
  AsyncTaskManager *task_mgr = AsyncTaskManager::get_global_ptr();
  task_mgr->add(new FlowTask(tex));
  card.set_texture(tex);

  framework.main_loop();

  framework.close_framework();
  return (0);
}

Thanks, that works.

Actually, after reading rdb replay, i come back to put my code as example, but I see that example is already here!

So, I only add that I had problems before i realized that result of modify_ram_image can’t be cashed as char* pointer :wink:

Hi,
I tried the code (using Panda 1.6.2) described above and managed to get input from the webcam and render it into a card through a texture.

However I haven’t been able to send the card to the background using the get_render_2d method. Any help would be appreciated! Thanks!

(
I’m actually sending to background to the card reparenting it to the camera and setting the bin and depth attributes …

    webcamcard = NodePath(cm.generate()); 
  
    webcamcard.reparent_to (window->get_camera_group()); 
    webcamcard.set_pos (window->get_render(),0.0,4.0,0.0);
    
    webcamcard.set_texture(tex); 

    webcamcard.set_bin("background", 0); 
    webcamcard.set_depth_write (false); 
    

but I rather parent the card to the render2d
)

By default, render2d renders after render, so that gui items are drawn on top of the 3-D scene. You can change this so that render2d is drawn first, but then all of render2d will be behind the 3-D scene. If that’s OK to you, you can do it with this:

window->get_display_region_2d()->set_sort(-10);

Note that render and render2d each have their own DisplayRegion, and that the DisplayRegions are drawn in order according to their sort values. So setting render2d’s sort value to a negative number makes it draw before render (whose sort value is 0).

If you want to use a render2d-like scene graph for your background card, and still have gui elements on top, then you will need to create a third DisplayRegion for this purpose. This is easy to do; examine the code in windowFramework.cxx for examples, or look in this forum, or look in the manual.

David

Thanks.
Well it seems in Panda 1.6 there is no get_display_region* in class WindowFramework, nor a get_graphics_output so I can create a new display region …

Use get_graphics_window(). You can also get to the DisplayRegion from the Camera node.

David