#include <osgViewer/Viewer>
#include <osgDB/WriteFile>
const int GRID_WIDTH = 1024;
const int GRID_HEIGHT = 800;
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgDBd.lib")
class CRay
{
public:
CRay(osg::Vec3 orgin, osg::Vec3 direction)
:_orgin(orgin)
,_direction(direction)
{
}
osg::Vec3 GetOrgin()
{
return _orgin;
}
void SetOrgin(osg::Vec3 orgin)
{
_orgin = orgin;
}
osg::Vec3 GetDirection()
{
return _direction;
}
void SetDirection(osg::Vec3 dir)
{
_direction = dir;
}
osg::Vec3 GetPoint(float t)
{
return _orgin + _direction * t;
}
private:
osg::Vec3 _orgin;
osg::Vec3 _direction;
float _t;
};
class CIntersectResult
{
public:
CIntersectResult()
:_isHit(false)
{
}
static CIntersectResult NoHit()
{
return CIntersectResult();
}
public:
bool _isHit;
float _distance;
osg::Vec3 _position;
osg::Vec3 _normal;
};
class CGeometry
{
public:
CGeometry()
{
}
virtual CIntersectResult IsIntersect(CRay ray) = 0;
};
class CSphere : public CGeometry
{
public:
CSphere()
:CGeometry()
{
}
CSphere(osg::Vec3 center, double radius)
:CGeometry()
,_center(center)
,_radius(radius)
{
}
CSphere(CSphere & s)
{
_center = s.GetCenter();
_radius = s.GetRadius();
}
void SetCenter(osg::Vec3 & center)
{
_center = center;
}
void SetRadius(float radius)
{
_radius = radius;
}
osg::Vec3 GetCenter()
{
return _center;
}
float GetRadius()
{
return _radius;
}
osg::Vec3 GetNormal(osg::Vec3 p)
{
return p - _center;
}
virtual CIntersectResult IsIntersect(CRay ray)
{
CIntersectResult result = CIntersectResult::NoHit();
osg::Vec3 v = ray.GetOrgin() - _center;
float a0 = v * v - _radius * _radius;
float dir_dot_v = ray.GetDirection() * v;
if (dir_dot_v < 0)
{
float discr = dir_dot_v * dir_dot_v - a0;
if (discr >= 0)
{
result._isHit = true;
result._distance = -dir_dot_v - std::sqrt(discr);
result._position = ray.GetPoint(result._distance);
result._normal = result._position - _center;
result._normal.normalize();
}
}
return result;
}
private:
osg::Vec3 _center;
float _radius;
};
class CPerspectiveCamera
{
public:
CPerspectiveCamera()
{
}
~CPerspectiveCamera()
{
}
CPerspectiveCamera(const osg::Vec3 & eye, const osg::Vec3 & front, const osg::Vec3 & refUp, float fov)
{
_eye = eye;
_front = front;
_refUp = refUp;
_fov = fov;
_right = _front ^ _refUp;
_up = _right ^ _front;
_fovScale = std::tan(fov * osg::PI * 0.5 / 180.0) * 2.0;
}
CRay GenerateRay(float x, float y)
{
osg::Vec3 r = _right * ((x - 0.5f) * _fovScale);
osg::Vec3 u = _up * ((y - 0.5f) * _fovScale);
osg::Vec3 temp = _front + r + u;
temp.normalize();
return CRay(_eye, temp);
}
private:
osg::Vec3 _eye;
osg::Vec3 _front;
osg::Vec3 _refUp;
float _fov;
osg::Vec3 _right;
osg::Vec3 _up;
float _fovScale;
};
osg::ref_ptr<osg::Image> CreateImage()
{
osg::ref_ptr<osg::Image> image = new osg::Image;
image->allocateImage(1024, 800, 1, GL_RGBA, GL_UNSIGNED_BYTE);
unsigned char * data = image->data();
CPerspectiveCamera camera(osg::Vec3(0.0, 10.0, 10), osg::Vec3(0.0, 0.0, -1.0), osg::Vec3(0.0, 1.0, 0.0), 90);
float depth = 7.0;
float maxDepth = 18.0;
CSphere sphere(osg::Vec3(0.0, 10, -10.0), 10.0);
float dx = 1.0f/GRID_WIDTH;
float dy = 1.0f/GRID_HEIGHT;
float dDepth = 255.0f/maxDepth;
int i = 0;
for (int y = 0; y < GRID_HEIGHT; ++y)
{
float sy = 1 - dy * y;
for (int x = 0; x < GRID_WIDTH; ++x)
{
float sx = dx * x;
CRay ray(camera.GenerateRay(sx, sy));
CIntersectResult result = sphere.IsIntersect(ray);
if (result._isHit)
{
float t = std::min(result._distance * dDepth, 255.0f);
int depth = (int)(255 - t);
data[i] = depth;
data[i+1] = depth;
data[i+2] = depth;
data[i+3] = 255;
}
i += 4;
}
}
return image.get();
}
int main()
{
osg::ref_ptr<osg::Image> image = CreateImage();
osgDB::writeImageFile(*image.get(), "H:/1.png");
return 0;
}