光线追踪
#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; }