add nonlinearImager

This commit is contained in:
David Rose 2001-12-13 23:43:24 +00:00
parent 4a0b5d3d7e
commit f030c6333f
6 changed files with 523 additions and 1 deletions

View File

@ -10,6 +10,7 @@
config_distort.cxx config_distort.h \
cylindricalLens.cxx cylindricalLens.h cylindricalLens.I \
fisheyeLens.cxx fisheyeLens.h fisheyeLens.I \
nonlinearImager.cxx nonlinearImager.h nonlinearImager.I \
pSphereLens.cxx pSphereLens.h pSphereLens.I \
projectionScreen.cxx projectionScreen.h projectionScreen.I

View File

@ -0,0 +1,43 @@
// Filename: nonlinearImager.I
// Created by: drose (12Dec01)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::set_camera
// Access: Published
// Description: Specifies the virtual camera that will be used to
// view the various ProjectionScreens. It should be in
// the same scene graph with the ProjectionScreens, to
// establish a relative coordinate system with them.
////////////////////////////////////////////////////////////////////
INLINE void NonlinearImager::
set_camera(LensNode *camera) {
_camera = camera;
_stale = true;
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::get_camera
// Access: Published
// Description: Returns the virtual camera that will be used to
// view the various ProjectionScreens.
////////////////////////////////////////////////////////////////////
INLINE LensNode *NonlinearImager::
get_camera() const {
return _camera;
}

View File

@ -0,0 +1,365 @@
// Filename: nonlinearImager.cxx
// Created by: drose (12Dec01)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "nonlinearImager.h"
#include "config_distort.h"
#include "graphicsStateGuardian.h"
#include "textureTransition.h"
#include "matrixLens.h"
#include "renderRelation.h"
#include "graphicsWindow.h"
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::Constructor
// Access: Published
// Description: The NonlinearImager is associated with a particular
// DisplayRegion when it is created. It will throw away
// whatever camera is currently associated with the
// DisplayRegion, and create a speciality camera for
// itself.
////////////////////////////////////////////////////////////////////
NonlinearImager::
NonlinearImager(DisplayRegion *dr) {
_dr = dr;
_internal_camera = new Camera("NonlinearImager");
_internal_camera->set_lens(new MatrixLens);
_internal_scene = new NamedNode("NonlinearImager");
_internal_camera->set_scene(_internal_scene);
_dr->set_camera(_internal_camera);
_stale = true;
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::Destructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
NonlinearImager::
~NonlinearImager() {
_internal_camera->set_scene((Node *)NULL);
_dr->set_camera((Camera *)NULL);
remove_all_screens();
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::add_screen
// Access: Published
// Description: Adds a new ProjectionScreen to the list of screens
// that will be processed by the NonlinearImager. Each
// ProjectionScreen represents a view into the world.
// It must be based on a linear camera (or whatever kind
// of camera is respected by the graphics engine).
//
// width and height indicate the size of the texture
// that will be created to render the scene for the
// screen. See set_size().
//
// Each ProjectionScreen object should already have some
// screen geometry created.
//
// When render() is called, the graphics state guardian
// will be used to render a scene for each
// ProjectionScreen object, and then each resulting
// image will be applied to a mesh to be rendered to the
// screen.
//
// The return value is the index number of the new
// screen.
////////////////////////////////////////////////////////////////////
int NonlinearImager::
add_screen(ProjectionScreen *screen) {
_screens.push_back(Screen());
Screen &new_screen = _screens.back();
new_screen._screen = screen;
new_screen._mesh_arc = (NodeRelation *)NULL;
new_screen._texture = (Texture *)NULL;
new_screen._tex_width = 256;
new_screen._tex_height = 256;
// If the LensNode associated with the ProjectionScreen is an actual
// Camera, then it has a scene associated. Otherwise, the user will
// have to specify the scene later.
LensNode *projector = screen->get_projector();
if (projector->is_of_type(Camera::get_class_type())) {
Camera *camera = DCAST(Camera, projector);
new_screen._scene = camera->get_scene();
}
_stale = true;
return _screens.size() - 1;
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::find_screen
// Access: Published
// Description: Returns the index number of the first appearance of
// the indicated screen within the imager's list, or -1
// if it does not appear.
////////////////////////////////////////////////////////////////////
int NonlinearImager::
find_screen(ProjectionScreen *screen) const {
for (size_t i = 0; i < _screens.size(); i++) {
if (_screens[i]._screen == screen) {
return i;
}
}
return -1;
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::remove_screen
// Access: Published
// Description: Removes the screen with the indicated index number
// from the imager.
////////////////////////////////////////////////////////////////////
void NonlinearImager::
remove_screen(int index) {
nassertv_always(index >= 0 && index < (int)_screens.size());
Screen &screen = _screens[index];
if (screen._mesh_arc != (NodeRelation *)NULL) {
remove_arc(screen._mesh_arc);
}
_screens.erase(_screens.begin() + index);
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::remove_all_screens
// Access: Published
// Description: Removes all screens from the imager.
////////////////////////////////////////////////////////////////////
void NonlinearImager::
remove_all_screens() {
Screens::iterator si;
for (si = _screens.begin(); si != _screens.end(); ++si) {
Screen &screen = (*si);
if (screen._mesh_arc != (NodeRelation *)NULL) {
remove_arc(screen._mesh_arc);
}
}
_screens.clear();
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::get_num_screens
// Access: Published
// Description: Returns the number of screens that have been added to
// the imager.
////////////////////////////////////////////////////////////////////
int NonlinearImager::
get_num_screens() const {
return _screens.size();
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::get_screen
// Access: Published
// Description: Returns the nth screen that has been added to the
// imager.
////////////////////////////////////////////////////////////////////
ProjectionScreen *NonlinearImager::
get_screen(int index) const {
nassertr(index >= 0 && index < (int)_screens.size(), (ProjectionScreen *)NULL);
return _screens[index]._screen;
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::set_size
// Access: Published
// Description: Sets the width and height of the texture used to
// render the scene for the indicated screen. This must
// be less than or equal to the window size, and it
// should be a power of two.
//
// In general, the larger the texture, the greater the
// detail of the rendered scene.
////////////////////////////////////////////////////////////////////
void NonlinearImager::
set_size(int index, int width, int height) {
nassertv(index >= 0 && index < (int)_screens.size());
_screens[index]._tex_width = width;
_screens[index]._tex_height = height;
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::set_source
// Access: Published
// Description: Specifies the camera and root of the scene that will
// be used to render the image for this particular
// screen.
////////////////////////////////////////////////////////////////////
void NonlinearImager::
set_source(int index, LensNode *source, Node *scene) {
nassertv(index >= 0 && index < (int)_screens.size());
_screens[index]._source = source;
_screens[index]._scene = scene;
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::set_source
// Access: Published
// Description: Specifies the camera and root of the scene that will
// be used to render the image for this particular
// screen.
//
// Since this flavor accepts a Camera node, instead of
// just a LensNode, the scene is specified within the
// Camera itself.
////////////////////////////////////////////////////////////////////
void NonlinearImager::
set_source(int index, Camera *source) {
nassertv(index >= 0 && index < (int)_screens.size());
_screens[index]._source = source;
_screens[index]._scene = source->get_scene();
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::recompute
// Access: Published
// Description: Forces a regeneration of all the mesh objects, etc.
////////////////////////////////////////////////////////////////////
void NonlinearImager::
recompute() {
Screens::iterator si;
for (si = _screens.begin(); si != _screens.end(); ++si) {
recompute_screen(*si);
}
if (_camera != (LensNode *)NULL && _camera->get_lens() != (Lens *)NULL) {
_camera_lens_change = _camera->get_lens()->get_last_change();
}
_stale = false;
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::render
// Access: Published
// Description: Uses the DisplayRegion's GSG to render a scene for
// each ProjectionScreen, and makes our DisplayRegion
// ready to render the combined results. This will
// destroy the contents of the frame buffer; it should
// be done before any of the actual frame has started
// rendering.
////////////////////////////////////////////////////////////////////
void NonlinearImager::
render() {
recompute_if_stale();
Screens::iterator si;
for (si = _screens.begin(); si != _screens.end(); ++si) {
render_screen(*si);
}
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::recompute_if_stale
// Access: Private
// Description: Calls recompute() if it needs to be called.
////////////////////////////////////////////////////////////////////
void NonlinearImager::
recompute_if_stale() {
if (_camera != (LensNode *)NULL &&
_camera->get_lens() != (Lens *)NULL) {
UpdateSeq lens_change = _camera->get_lens()->get_last_change();
if (_stale || lens_change != _camera_lens_change) {
recompute();
}
}
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::recompute_screen
// Access: Private
// Description: Regenerates the mesh objects just for the indicated
// screen.
////////////////////////////////////////////////////////////////////
void NonlinearImager::
recompute_screen(NonlinearImager::Screen &screen) {
if (screen._mesh_arc != (NodeRelation *)NULL) {
remove_arc(screen._mesh_arc);
screen._mesh_arc = (NodeRelation *)NULL;
}
screen._texture.clear();
if (_camera == (LensNode *)NULL) {
// Not much we can do without a camera.
return;
}
PT_Node mesh = screen._screen->make_flat_mesh(_camera);
screen._mesh_arc = new RenderRelation(_internal_scene, mesh);
PT(Texture) texture = new Texture;
texture->set_minfilter(Texture::FT_linear);
texture->set_magfilter(Texture::FT_linear);
texture->set_wrapu(Texture::WM_clamp);
texture->set_wrapv(Texture::WM_clamp);
texture->_pbuffer->set_xsize(screen._tex_width);
texture->_pbuffer->set_ysize(screen._tex_height);
screen._texture = texture;
screen._mesh_arc->set_transition(new TextureTransition(texture));
}
////////////////////////////////////////////////////////////////////
// Function: NonlinearImager::render_screen
// Access: Private
// Description: Renders the scene just for the indicated screen, into
// the screen's own texture.
////////////////////////////////////////////////////////////////////
void NonlinearImager::
render_screen(NonlinearImager::Screen &screen) {
if (screen._source == (LensNode *)NULL) {
distort_cat.error()
<< "No source lens specified for screen " << screen._screen->get_name()
<< "\n";
return;
}
if (screen._scene == (Node *)NULL) {
distort_cat.error()
<< "No scene specified for screen " << screen._screen->get_name()
<< "\n";
return;
}
GraphicsStateGuardian *gsg = _dr->get_window()->get_gsg();
// Make a display region of the proper size and clear it to prepare for
// rendering the scene.
PT(DisplayRegion) scratch_region =
gsg->get_window()->make_scratch_display_region(screen._tex_width, screen._tex_height);
gsg->clear(gsg->get_render_buffer(RenderBuffer::T_back |
RenderBuffer::T_depth),
scratch_region);
DisplayRegionStack old_dr = gsg->push_display_region(scratch_region);
gsg->prepare_display_region();
gsg->render_scene(screen._scene, screen._source);
// Copy the results of the render from the frame buffer into the
// screen's texture.
screen._texture->copy(gsg, scratch_region,
gsg->get_render_buffer(RenderBuffer::T_back));
// Restore the original display region.
gsg->pop_display_region(old_dr);
}

View File

@ -0,0 +1,101 @@
// Filename: nonlinearImager.h
// Created by: drose (12Dec01)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef NONLINEARIMAGER_H
#define NONLINEARIMAGER_H
#include "pandabase.h"
#include "projectionScreen.h"
#include "displayRegion.h"
#include "camera.h"
#include "texture.h"
#include "pvector.h"
////////////////////////////////////////////////////////////////////
// Class : NonlinearImager
// Description : This class object combines the rendered output of a
// 3-d from one or more linear cameras, as seen through
// a single, possibly non-linear camera.
//
// This can be used to generate real-time imagery of a
// 3-d scene using a nonlinear camera, for instance a
// fisheye camera, even though the 3-d graphics engine
// only supports linear cameras.
//
// The NonlinearImager collects together a number of
// ProjectionScreens, each of which has a standard,
// linear Camera. Each frame, the Imager renders each
// scene into a texture and then maps that texture onto
// a mesh which is presented to the graphics engine for
// rendering the final, non-linear output.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAFX NonlinearImager {
PUBLISHED:
NonlinearImager(DisplayRegion *dr);
~NonlinearImager();
int add_screen(ProjectionScreen *screen);
int find_screen(ProjectionScreen *screen) const;
void remove_screen(int index);
void remove_all_screens();
int get_num_screens() const;
ProjectionScreen *get_screen(int index) const;
void set_size(int index, int width, int height);
void set_source(int index, LensNode *source, Node *scene);
void set_source(int index, Camera *source);
INLINE void set_camera(LensNode *camera);
INLINE LensNode *get_camera() const;
void recompute();
void render();
private:
class Screen {
public:
PT(ProjectionScreen) _screen;
NodeRelation *_mesh_arc;
PT(Texture) _texture;
PT(LensNode) _source;
PT_Node _scene;
int _tex_width, _tex_height;
};
void recompute_if_stale();
void recompute_screen(Screen &screen);
void render_screen(Screen &screen);
PT(DisplayRegion) _dr;
typedef pvector<Screen> Screens;
Screens _screens;
PT(LensNode) _camera;
PT(Camera) _internal_camera;
PT_Node _internal_scene;
bool _stale;
UpdateSeq _camera_lens_change;
};
#include "nonlinearImager.I"
#endif

View File

@ -610,11 +610,17 @@ render_subgraph(RenderTraverser *traverser,
// activate();
Lens *lens = projnode->get_lens();
if (!lens->is_linear()) {
glgsg_cat.error()
<< "Cannot render with a nonlinear lens!\n";
return;
}
LensNode *old_camera = _current_camera;
_current_camera = projnode;
LMatrix4f old_projection_mat = _current_projection_mat;
Lens *lens = projnode->get_lens();
const LMatrix4f &projection_mat = lens->get_projection_mat();
// The projection matrix must always be right-handed Y-up, even if
@ -1998,6 +2004,7 @@ copy_texture(TextureContext *tc, const DisplayRegion *dr) {
get_internal_image_format(pb->get_format()),
pb->get_xorg(), pb->get_yorg(),
pb->get_xsize(), pb->get_ysize(), pb->get_border());
clear_attribute(TextureTransition::get_class_type());
}
////////////////////////////////////////////////////////////////////

View File

@ -78,6 +78,11 @@ sub_render(NodeRelation *arc, const AllTransitionsWrapper &,
// DisplayRegion instead of the GSG.
const DisplayRegion *dr = gsg->get_current_display_region();
LensNode *camera = dr->get_cull_frustum();
if (camera == (LensNode *)NULL) {
// Never mind; ask the gsg.
camera = gsg->get_current_camera();
}
nassertr(camera != (LensNode *)NULL, true);
// And the relative coordinate space.