Repository for OpenCV's extra modules
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

896 lines
27 KiB

// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "precomp.hpp"
#include <OgreApplicationContext.h>
#include <OgreCameraMan.h>
#include <OgreRectangle2D.h>
#include <OgreCompositorManager.h>
#include <opencv2/calib3d.hpp>
namespace cv
{
namespace ovis
{
using namespace Ogre;
const char* RESOURCEGROUP_NAME = "OVIS";
Ptr<Application> _app;
static const char* RENDERSYSTEM_NAME = "OpenGL 3+ Rendering Subsystem";
static std::vector<String> _extraResourceLocations;
// convert from OpenCV to Ogre coordinates:
static Quaternion toOGRE(Degree(180), Vector3::UNIT_X);
static Vector2 toOGRE_SS = Vector2(1, -1);
WindowScene::~WindowScene() {}
void _createTexture(const String& name, Mat image)
{
PixelFormat format;
switch(image.type())
{
case CV_8UC4:
format = PF_BYTE_BGRA;
break;
case CV_8UC3:
format = PF_BYTE_BGR;
break;
case CV_8UC1:
format = PF_BYTE_L;
break;
case CV_16UC1:
format = PF_L16;
break;
case CV_32FC1:
format = PF_FLOAT32_R;
break;
default:
CV_Error(Error::StsBadArg, "currently supported formats are only CV_8UC1, CV_8UC3, CV_8UC4, CV_16UC1, CV_32FC1");
break;
}
TextureManager& texMgr = TextureManager::getSingleton();
TexturePtr tex = texMgr.getByName(name, RESOURCEGROUP_NAME);
Image im;
im.loadDynamicImage(image.ptr(), image.cols, image.rows, 1, format);
if (tex)
{
// update
PixelBox box = im.getPixelBox();
tex->getBuffer()->blitFromMemory(box, box);
return;
}
texMgr.loadImage(name, RESOURCEGROUP_NAME, im);
}
static void _convertRT(InputArray rot, InputArray tvec, Quaternion& q, Vector3& t, bool invert = false)
{
CV_Assert_N(rot.empty() || rot.rows() == 3 || rot.size() == Size(3, 3),
tvec.empty() || tvec.rows() == 3);
q = Quaternion::IDENTITY;
t = Vector3::ZERO;
if (!rot.empty())
{
Mat _R;
if (rot.size() == Size(3, 3))
{
_R = rot.getMat();
}
else
{
Rodrigues(rot, _R);
}
Matrix3 R;
_R.copyTo(Mat_<Real>(3, 3, R[0]));
q = Quaternion(R);
if (invert)
{
q = q.Inverse();
}
}
if (!tvec.empty())
{
tvec.copyTo(Mat_<Real>(3, 1, t.ptr()));
if(invert)
{
t = q * -t;
}
}
}
static void _setCameraIntrinsics(Camera* cam, InputArray _K, const Size& imsize)
{
CV_Assert(_K.size() == Size(3, 3));
cam->setAspectRatio(float(imsize.width) / imsize.height);
Matx33f K = _K.getMat();
float near = cam->getNearClipDistance();
float top = near * K(1, 2) / K(1, 1);
float left = -near * K(0, 2) / K(0, 0);
float right = near * (imsize.width - K(0, 2)) / K(0, 0);
float bottom = -near * (imsize.height - K(1, 2)) / K(1, 1);
// use frustum extents instead of setFrustumOffset as the latter
// assumes centered FOV, which is not the case
cam->setFrustumExtents(left, right, top, bottom);
// top and bottom parts of the FOV
float fovy = atan2(K(1, 2), K(1, 1)) + atan2(imsize.height - K(1, 2), K(1, 1));
cam->setFOVy(Radian(fovy));
}
static SceneNode& _getSceneNode(SceneManager* sceneMgr, const String& name)
{
MovableObject* mo = NULL;
try
{
mo = sceneMgr->getMovableObject(name, "Camera");
// with cameras we have an extra CS flip node
if(mo)
return *mo->getParentSceneNode()->getParentSceneNode();
}
catch (ItemIdentityException&)
{
// ignore
}
try
{
if (!mo)
mo = sceneMgr->getMovableObject(name, "Light");
}
catch (ItemIdentityException&)
{
// ignore
}
if (!mo)
mo = sceneMgr->getMovableObject(name, "Entity"); // throws if not found
return *mo->getParentSceneNode();
}
struct Application : public OgreBites::ApplicationContext, public OgreBites::InputListener
{
Ptr<LogManager> logMgr;
Ogre::SceneManager* sceneMgr;
Ogre::String title;
uint32_t w;
uint32_t h;
int key_pressed;
int flags;
Application(const Ogre::String& _title, const Size& sz, int _flags)
: OgreBites::ApplicationContext("ovis", false), sceneMgr(NULL), title(_title), w(sz.width),
h(sz.height), key_pressed(-1), flags(_flags)
{
logMgr.reset(new LogManager());
logMgr->createLog("ovis.log", true, true, true);
logMgr->setLogDetail(LL_LOW);
}
void setupInput(bool /*grab*/)
{
// empty impl to show cursor
}
bool keyPressed(const OgreBites::KeyboardEvent& evt) CV_OVERRIDE
{
key_pressed = evt.keysym.sym;
return true;
}
bool oneTimeConfig() CV_OVERRIDE
{
Ogre::RenderSystem* rs = getRoot()->getRenderSystemByName(RENDERSYSTEM_NAME);
CV_Assert(rs);
getRoot()->setRenderSystem(rs);
return true;
}
OgreBites::NativeWindowPair createWindow(const Ogre::String& name, uint32_t _w, uint32_t _h,
NameValuePairList miscParams = NameValuePairList()) CV_OVERRIDE
{
Ogre::String _name = name;
if (!sceneMgr)
{
_w = w;
_h = h;
_name = title;
}
if (flags & SCENE_AA)
miscParams["FSAA"] = "4";
miscParams["vsync"] = "true";
OgreBites::NativeWindowPair ret =
OgreBites::ApplicationContext::createWindow(_name, _w, _h, miscParams);
addInputListener(ret.native, this); // handle input for all windows
return ret;
}
void locateResources() CV_OVERRIDE
{
OgreBites::ApplicationContext::locateResources();
ResourceGroupManager& rgm = ResourceGroupManager::getSingleton();
rgm.createResourceGroup(RESOURCEGROUP_NAME);
for (size_t i = 0; i < _extraResourceLocations.size(); i++)
{
String loc = _extraResourceLocations[i];
String type = StringUtil::endsWith(loc, ".zip") ? "Zip" : "FileSystem";
if (!FileSystemLayer::fileExists(loc))
{
loc = FileSystemLayer::resolveBundlePath(getDefaultMediaDir() + "/" + loc);
}
rgm.addResourceLocation(loc, type, RESOURCEGROUP_NAME);
}
}
void setup() CV_OVERRIDE
{
OgreBites::ApplicationContext::setup();
MaterialManager& matMgr = MaterialManager::getSingleton();
matMgr.setDefaultTextureFiltering(TFO_ANISOTROPIC);
matMgr.setDefaultAnisotropy(16);
}
};
class WindowSceneImpl : public WindowScene
{
String title;
Root* root;
SceneManager* sceneMgr;
SceneNode* camNode;
RenderWindow* rWin;
Ptr<OgreBites::CameraMan> camman;
Ptr<Rectangle2D> bgplane;
Ogre::RenderTarget* depthRTT;
public:
WindowSceneImpl(Ptr<Application> app, const String& _title, const Size& sz, int flags)
: title(_title), root(app->getRoot()), depthRTT(NULL)
{
if (!app->sceneMgr)
{
flags |= SCENE_SEPERATE;
}
if (flags & SCENE_SEPERATE)
{
sceneMgr = root->createSceneManager("DefaultSceneManager", title);
RTShader::ShaderGenerator& shadergen = RTShader::ShaderGenerator::getSingleton();
shadergen.addSceneManager(sceneMgr); // must be done before we do anything with the scene
sceneMgr->setAmbientLight(ColourValue(.1, .1, .1));
_createBackground();
}
else
{
sceneMgr = app->sceneMgr;
}
if(flags & SCENE_SHOW_CS_CROSS)
{
sceneMgr->setDisplaySceneNodes(true);
}
Camera* cam = sceneMgr->createCamera(title);
cam->setNearClipDistance(0.5);
cam->setAutoAspectRatio(true);
camNode = sceneMgr->getRootSceneNode()->createChildSceneNode();
camNode->setOrientation(toOGRE);
camNode->attachObject(cam);
if (flags & SCENE_INTERACTIVE)
{
camman.reset(new OgreBites::CameraMan(camNode));
camman->setStyle(OgreBites::CS_ORBIT);
camNode->setFixedYawAxis(true, Vector3::NEGATIVE_UNIT_Y);
}
if (!app->sceneMgr)
{
app->sceneMgr = sceneMgr;
rWin = app->getRenderWindow();
if (camman)
app->addInputListener(camman.get());
}
else
{
OgreBites::NativeWindowPair nwin = app->createWindow(title, sz.width, sz.height);
rWin = nwin.render;
if (camman)
app->addInputListener(nwin.native, camman.get());
}
rWin->addViewport(cam);
}
void setBackground(InputArray image) CV_OVERRIDE
{
CV_Assert(bgplane);
String name = sceneMgr->getName() + "_Background";
_createTexture(name, image.getMat());
// correct for pixel centers
Vector2 pc(0.5 / image.cols(), 0.5 / image.rows());
bgplane->setUVs(pc, Vector2(pc[0], 1 - pc[1]), Vector2(1 - pc[0], pc[1]), Vector2(1, 1) - pc);
Pass* rpass = bgplane->getMaterial()->getBestTechnique()->getPasses()[0];
rpass->getTextureUnitStates()[0]->setTextureName(name);
// ensure bgplane is visible
bgplane->setVisible(true);
}
void setCompositors(const std::vector<String>& names) CV_OVERRIDE
{
CompositorManager& cm = CompositorManager::getSingleton();
// this should be applied to all owned render targets
Ogre::RenderTarget* targets[] = {rWin, depthRTT};
for(int j = 0; j < 2; j++)
{
Ogre::RenderTarget* tgt = targets[j];
if(!tgt) continue;
Viewport* vp = tgt->getViewport(0);
cm.removeCompositorChain(vp); // remove previous configuration
for(size_t i = 0; i < names.size(); i++)
{
if (!cm.addCompositor(vp, names[i])) {
LogManager::getSingleton().logError("Failed to add compositor: " + names[i]);
continue;
}
cm.setCompositorEnabled(vp, names[i], true);
}
}
}
void getCompositorTexture(const String& compname, const String& texname, OutputArray out,
int mrtIndex) CV_OVERRIDE
{
CompositorManager& cm = CompositorManager::getSingleton();
CompositorChain* chain = cm.getCompositorChain(rWin->getViewport(0));
CV_Assert(chain && "no active compositors");
CompositorInstance* inst = chain->getCompositor(compname);
if(!inst)
CV_Error_(Error::StsBadArg, ("no active compositor named: %s", compname.c_str()));
TexturePtr tex = inst->getTextureInstance(texname, mrtIndex);
if(!tex)
CV_Error_(Error::StsBadArg, ("no texture named: %s", texname.c_str()));
PixelFormat src_type = tex->getFormat();
int dst_type;
switch(src_type)
{
case PF_R8:
case PF_L8:
dst_type = CV_8U;
break;
case PF_BYTE_RGB:
dst_type = CV_8UC3;
break;
case PF_BYTE_RGBA:
dst_type = CV_8UC4;
break;
case PF_FLOAT32_R:
dst_type = CV_32F;
break;
case PF_FLOAT32_RGB:
dst_type = CV_32FC3;
break;
case PF_FLOAT32_RGBA:
dst_type = CV_32FC4;
break;
case PF_L16:
case PF_DEPTH16:
dst_type = CV_16U;
break;
default:
CV_Error(Error::StsNotImplemented, "unsupported texture format");
}
out.create(tex->getHeight(), tex->getWidth(), dst_type);
Mat mat = out.getMat();
PixelBox pb(tex->getWidth(), tex->getHeight(), 1, src_type, mat.ptr());
tex->getBuffer()->blitToMemory(pb, pb);
if(CV_MAT_CN(dst_type) < 3)
return;
// convert to OpenCV channel order
cvtColor(mat, mat, CV_MAT_CN(dst_type) == 3 ? COLOR_RGB2BGR : COLOR_RGBA2BGRA);
}
void setBackground(const Scalar& color) CV_OVERRIDE
{
// hide background plane
bgplane->setVisible(false);
// BGRA as uchar
ColourValue _color = ColourValue(color[2], color[1], color[0], color[3]) / 255;
rWin->getViewport(0)->setBackgroundColour(_color);
}
void createEntity(const String& name, const String& meshname, InputArray tvec, InputArray rot) CV_OVERRIDE
{
Entity* ent = sceneMgr->createEntity(name, meshname, RESOURCEGROUP_NAME);
Quaternion q;
Vector3 t;
_convertRT(rot, tvec, q, t);
SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(t, q);
node->attachObject(ent);
}
void removeEntity(const String& name) CV_OVERRIDE {
SceneNode& node = _getSceneNode(sceneMgr, name);
node.getAttachedObject(name)->detachFromParent();
// only one of the following will do something
sceneMgr->destroyLight(name);
sceneMgr->destroyEntity(name);
sceneMgr->destroyCamera(name);
sceneMgr->destroySceneNode(&node);
}
Rect2d createCameraEntity(const String& name, InputArray K, const Size& imsize, float zFar,
InputArray tvec, InputArray rot) CV_OVERRIDE
{
MaterialPtr mat = MaterialManager::getSingleton().create(name, RESOURCEGROUP_NAME);
Pass* rpass = mat->getTechniques()[0]->getPasses()[0];
rpass->setEmissive(ColourValue::White);
Camera* cam = sceneMgr->createCamera(name);
cam->setMaterial(mat);
cam->setVisible(true);
cam->setDebugDisplayEnabled(true);
cam->setNearClipDistance(1e-9);
cam->setFarClipDistance(zFar);
_setCameraIntrinsics(cam, K, imsize);
Quaternion q;
Vector3 t;
_convertRT(rot, tvec, q, t);
SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(t, q);
node = node->createChildSceneNode();
node->setOrientation(toOGRE); // camera mesh is oriented by OGRE conventions by default
node->attachObject(cam);
RealRect ext = cam->getFrustumExtents();
float scale = zFar / cam->getNearClipDistance(); // convert to ext at zFar
return Rect2d(toOGRE_SS[0] * (ext.right - ext.width() / 2) * scale,
toOGRE_SS[1] * (ext.bottom - ext.height() / 2) * scale, ext.width() * scale,
ext.height() * scale);
}
void createLightEntity(const String& name, InputArray tvec, InputArray rot, const Scalar& diffuseColour,
const Scalar& specularColour) CV_OVERRIDE
{
Light* light = sceneMgr->createLight(name);
light->setDirection(Vector3::NEGATIVE_UNIT_Z);
// convert to BGR
light->setDiffuseColour(ColourValue(diffuseColour[2], diffuseColour[1], diffuseColour[0]));
light->setSpecularColour(ColourValue(specularColour[2], specularColour[1], specularColour[0]));
Quaternion q;
Vector3 t;
_convertRT(rot, tvec, q, t);
SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(t, q);
node->attachObject(light);
}
void updateEntityPose(const String& name, InputArray tvec, InputArray rot) CV_OVERRIDE
{
SceneNode& node = _getSceneNode(sceneMgr, name);
Quaternion q;
Vector3 t;
_convertRT(rot, tvec, q, t);
node.rotate(q, Ogre::Node::TS_LOCAL);
node.translate(t, Ogre::Node::TS_LOCAL);
}
void setEntityPose(const String& name, InputArray tvec, InputArray rot, bool invert) CV_OVERRIDE
{
SceneNode& node = _getSceneNode(sceneMgr, name);
Quaternion q;
Vector3 t;
_convertRT(rot, tvec, q, t, invert);
node.setOrientation(q);
node.setPosition(t);
}
void setEntityProperty(const String& name, int prop, const String& value) CV_OVERRIDE
{
CV_Assert(prop == ENTITY_MATERIAL);
SceneNode& node = _getSceneNode(sceneMgr, name);
MaterialPtr mat = MaterialManager::getSingleton().getByName(value, RESOURCEGROUP_NAME);
CV_Assert(mat && "material not found");
Camera* cam = dynamic_cast<Camera*>(node.getAttachedObject(name));
if(cam)
{
cam->setMaterial(mat);
return;
}
Entity* ent = dynamic_cast<Entity*>(node.getAttachedObject(name));
CV_Assert(ent && "invalid entity");
ent->setMaterial(mat);
}
void setEntityProperty(const String& name, int prop, const Scalar& value) CV_OVERRIDE
{
CV_Assert(prop == ENTITY_SCALE);
SceneNode& node = _getSceneNode(sceneMgr, name);
node.setScale(value[0], value[1], value[2]);
}
void getEntityProperty(const String& name, int prop, OutputArray value)
{
SceneNode& node = _getSceneNode(sceneMgr, name);
switch(prop)
{
case ENTITY_SCALE:
{
Vector3 s = node.getScale();
Mat_<Real>(1, 3, s.ptr()).copyTo(value);
return;
}
case ENTITY_AABB_WORLD:
{
Entity* ent = dynamic_cast<Entity*>(node.getAttachedObject(name));
CV_Assert(ent && "invalid entity");
AxisAlignedBox aabb = ent->getWorldBoundingBox(true);
Vector3 mn = aabb.getMinimum();
Vector3 mx = aabb.getMaximum();
Mat_<Real> ret(2, 3);
Mat_<Real>(1, 3, mn.ptr()).copyTo(ret.row(0));
Mat_<Real>(1, 3, mx.ptr()).copyTo(ret.row(1));
ret.copyTo(value);
return;
}
default:
CV_Error(Error::StsBadArg, "unsupported property");
}
}
void _createBackground()
{
String name = "_" + sceneMgr->getName() + "_DefaultBackground";
Mat_<Vec3b> img = (Mat_<Vec3b>(2, 1) << Vec3b(2, 1, 1), Vec3b(240, 120, 120));
_createTexture(name, img);
MaterialPtr mat = MaterialManager::getSingleton().create(name, RESOURCEGROUP_NAME);
Pass* rpass = mat->getTechniques()[0]->getPasses()[0];
rpass->setLightingEnabled(false);
rpass->setDepthCheckEnabled(false);
rpass->setDepthWriteEnabled(false);
rpass->createTextureUnitState(name);
bgplane.reset(new Rectangle2D(true));
bgplane->setCorners(-1.0, 1.0, 1.0, -1.0);
// correct for pixel centers
Vector2 pc(0.5 / img.cols, 0.5 / img.rows);
bgplane->setUVs(pc, Vector2(pc[0], 1 - pc[1]), Vector2(1 - pc[0], pc[1]), Vector2(1, 1) - pc);
bgplane->setMaterial(mat);
bgplane->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND);
bgplane->setBoundingBox(AxisAlignedBox(AxisAlignedBox::BOX_INFINITE));
sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(bgplane.get());
}
void getScreenshot(OutputArray frame) CV_OVERRIDE
{
frame.create(rWin->getHeight(), rWin->getWidth(), CV_8UC3);
Mat out = frame.getMat();
PixelBox pb(rWin->getWidth(), rWin->getHeight(), 1, PF_BYTE_RGB, out.ptr());
rWin->copyContentsToMemory(pb, pb);
// convert to OpenCV channel order
cvtColor(out, out, COLOR_RGB2BGR);
}
void getDepth(OutputArray depth) CV_OVERRIDE
{
Camera* cam = sceneMgr->getCamera(title);
if (!depthRTT)
{
// render into an offscreen texture
// currently this draws everything twice as OGRE lacks depth texture attachments
TexturePtr tex = TextureManager::getSingleton().createManual(
title + "_Depth", RESOURCEGROUP_NAME, TEX_TYPE_2D, rWin->getWidth(),
rWin->getHeight(), 0, PF_DEPTH, TU_RENDERTARGET);
depthRTT = tex->getBuffer()->getRenderTarget();
depthRTT->addViewport(cam);
depthRTT->setAutoUpdated(false); // only update when requested
}
Mat tmp(depthRTT->getHeight(), depthRTT->getWidth(), CV_16U);
PixelBox pb(depthRTT->getWidth(), depthRTT->getHeight(), 1, PF_DEPTH, tmp.ptr());
depthRTT->update(false);
depthRTT->copyContentsToMemory(pb, pb);
// convert to NDC
double alpha = 2.0/std::numeric_limits<uint16>::max();
tmp.convertTo(depth, CV_64F, alpha, -1);
// convert to linear
float n = cam->getNearClipDistance();
float f = cam->getFarClipDistance();
Mat ndc = depth.getMat();
ndc = -ndc * (f - n) + (f + n);
ndc = (2 * f * n) / ndc;
}
void fixCameraYawAxis(bool useFixed, InputArray _up) CV_OVERRIDE
{
Vector3 up = Vector3::NEGATIVE_UNIT_Y;
if (!_up.empty())
{
_up.copyTo(Mat_<Real>(3, 1, up.ptr()));
}
camNode->setFixedYawAxis(useFixed, up);
}
void setCameraPose(InputArray tvec, InputArray rot, bool invert) CV_OVERRIDE
{
Quaternion q;
Vector3 t;
_convertRT(rot, tvec, q, t, invert);
if (!rot.empty())
camNode->setOrientation(q*toOGRE);
if (!tvec.empty())
camNode->setPosition(t);
}
void getCameraPose(OutputArray R, OutputArray tvec, bool invert) CV_OVERRIDE
{
Matrix3 _R;
// toOGRE.Inverse() == toOGRE
(camNode->getOrientation()*toOGRE).ToRotationMatrix(_R);
if (invert)
{
_R = _R.Transpose();
}
if (tvec.needed())
{
Vector3 _tvec = camNode->getPosition();
if (invert)
{
_tvec = _R * -_tvec;
}
Mat_<Real>(3, 1, _tvec.ptr()).copyTo(tvec);
}
if (R.needed())
{
Mat_<Real>(3, 3, _R[0]).copyTo(R);
}
}
void setCameraIntrinsics(InputArray K, const Size& imsize, float zNear, float zFar) CV_OVERRIDE
{
Camera* cam = sceneMgr->getCamera(title);
if(zNear >= 0) cam->setNearClipDistance(zNear);
if(zFar >= 0) cam->setFarClipDistance(zFar);
if(!K.empty()) _setCameraIntrinsics(cam, K, imsize);
}
void setCameraLookAt(const String& target, InputArray offset) CV_OVERRIDE
{
SceneNode* tgt = sceneMgr->getEntity(target)->getParentSceneNode();
Vector3 _offset = Vector3::ZERO;
if (!offset.empty())
{
offset.copyTo(Mat_<Real>(3, 1, _offset.ptr()));
}
camNode->lookAt(tgt->_getDerivedPosition() + _offset, Ogre::Node::TS_WORLD);
}
};
CV_EXPORTS_W void addResourceLocation(const String& path) { _extraResourceLocations.push_back(path); }
Ptr<WindowScene> createWindow(const String& title, const Size& size, int flags)
{
if (!_app)
{
_app = makePtr<Application>(title.c_str(), size, flags);
_app->initApp();
}
return makePtr<WindowSceneImpl>(_app, title, size, flags);
}
CV_EXPORTS_W int waitKey(int delay)
{
CV_Assert(_app);
_app->key_pressed = -1;
_app->getRoot()->renderOneFrame();
// wait for keypress, using vsync instead of sleep
while(!delay && _app->key_pressed == -1)
_app->getRoot()->renderOneFrame();
return (_app->key_pressed != -1) ? (_app->key_pressed & 0xff) : -1;
}
void setMaterialProperty(const String& name, int prop, const Scalar& val)
{
CV_Assert(_app);
MaterialPtr mat = MaterialManager::getSingleton().getByName(name, RESOURCEGROUP_NAME);
CV_Assert(mat);
Pass* rpass = mat->getTechniques()[0]->getPasses()[0];
ColourValue col;
switch (prop)
{
case MATERIAL_POINT_SIZE:
rpass->setPointSize(val[0]);
break;
case MATERIAL_OPACITY:
col = rpass->getDiffuse();
col.a = val[0];
rpass->setDiffuse(col);
rpass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
rpass->setDepthWriteEnabled(false);
break;
case MATERIAL_EMISSIVE:
col = ColourValue(val[2], val[1], val[0]) / 255; // BGR as uchar
col.saturate();
rpass->setEmissive(col);
break;
case MATERIAL_LINE_WIDTH:
#if OGRE_VERSION >= ((1 << 16) | (11 << 8) | 2)
rpass->setLineWidth(val[0]);
#else
CV_Error(Error::StsError, "needs OGRE 1.11.2+ for this");
#endif
break;
default:
CV_Error(Error::StsBadArg, "invalid or non Scalar property");
break;
}
}
void setMaterialProperty(const String& name, int prop, const String& value)
{
CV_Assert_N(prop >= MATERIAL_TEXTURE0, prop <= MATERIAL_TEXTURE3, _app);
MaterialPtr mat = MaterialManager::getSingleton().getByName(name, RESOURCEGROUP_NAME);
CV_Assert(mat);
Pass* rpass = mat->getTechniques()[0]->getPasses()[0];
size_t texUnit = prop - MATERIAL_TEXTURE0;
CV_Assert(texUnit <= rpass->getTextureUnitStates().size());
if (rpass->getTextureUnitStates().size() <= texUnit)
{
rpass->createTextureUnitState(value);
return;
}
rpass->getTextureUnitStates()[texUnit]->setTextureName(value);
}
static bool setShaderProperty(const GpuProgramParametersSharedPtr& params, const String& prop,
const Scalar& value)
{
const GpuConstantDefinition* def = params->_findNamedConstantDefinition(prop, false);
if(!def)
return false;
Vec4f valf = value;
switch(def->constType)
{
case GCT_FLOAT1:
params->setNamedConstant(prop, valf[0]);
return true;
case GCT_FLOAT2:
params->setNamedConstant(prop, Vector2(valf.val));
return true;
case GCT_FLOAT3:
params->setNamedConstant(prop, Vector3(valf.val));
return true;
case GCT_FLOAT4:
params->setNamedConstant(prop, Vector4(valf.val));
return true;
default:
CV_Error(Error::StsBadArg, "currently only float[1-4] uniforms are supported");
return false;
}
}
void setMaterialProperty(const String& name, const String& prop, const Scalar& value)
{
CV_Assert(_app);
MaterialPtr mat = MaterialManager::getSingleton().getByName(name, RESOURCEGROUP_NAME);
CV_Assert(mat);
Pass* rpass = mat->getTechniques()[0]->getPasses()[0];
bool set = false;
if(rpass->hasGpuProgram(GPT_VERTEX_PROGRAM))
{
GpuProgramParametersSharedPtr params = rpass->getVertexProgramParameters();
set = setShaderProperty(params, prop, value);
}
if(rpass->hasGpuProgram(GPT_FRAGMENT_PROGRAM))
{
GpuProgramParametersSharedPtr params = rpass->getFragmentProgramParameters();
set = set || setShaderProperty(params, prop, value);
}
if(!set)
CV_Error_(Error::StsBadArg, ("shader parameter named '%s' not found", prop.c_str()));
}
void updateTexture(const String& name, InputArray image)
{
CV_Assert(_app);
TexturePtr tex = TextureManager::getSingleton().getByName(name, RESOURCEGROUP_NAME);
CV_Assert(tex);
_createTexture(name, image.getMat());
}
}
}