ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

写一个软光栅器绘制正方体

2021-12-13 01:00:28  阅读:211  来源: 互联网

标签:正方体 std int 光栅 back Vec3 push 绘制 osg


    这个程序对正方体的绘制时通过软光栅器的方法绘制的,相当于GPU是硬件加速的光栅化,所谓光栅化其实是一种绘画方法,就是在

物体前面放块带栅格的透明玻璃,然后画家在玻璃后面不要动,由于光沿着直线传播,所以从物体上的一小块面片的光射到画家眼睛里面以后

在物体和画家眼睛之间 的栅格玻璃就会投影出一小块面片的相,这块相会占据玻璃上的一些栅格。然后数学上研究,确定物体,栅格,画家眼睛

位置,等一些参数,可以通过几何学精确的计算栅格上哪些格子被占据了,而且哪些格子的颜色,所以都是可以计算的,即计算投影,计算空间变换

计算光照,达到预见真实世界的目的。到电子计算机出现,计算过程被加速了,但是用到的几何学还是几百年前的,现在图片代替了栅格玻璃,像素

即为玻璃上的格子,物体需要先三角化为三角形,这样硬件只需要对一种简单面片实现加速,更多的加速时通过单指令多数据方式实现多个三角面片

同时绘制。

        顶点处理阶段,每个点上要预先计算点的法向量,将确定点在光照下的颜色,越和眼睛观察的方向接近的颜色强度越大。

        当三角形被确定为图片上的像素后,同时重心插值就开始计算,确定了三角形内某个像素在三角形中的重心坐标,这个归一化的坐标将确定

这个像素的最终颜色,当然还有很多其它用处。

       接着这个重心坐标也能确定它离眼睛的距离,经由Z缓冲进入深度剔除阶段,这是实现物体不可见部分上的像素被丢掉的方法。

       终于,这个像素可见,颜色已计算出,可以写入图片它应有的格子位置了。

 

这个程序是用熟悉的Qt的图片读写及显示功能写的,程序主要是备份到博客,实际VC打开全局优化下,动画还很流畅,模仿的nehe的box的例子

3d math是用的osg的vec类,这个osg不用编译,因为vec类很简单,头文件粘贴来都能用,当然更多的OpenGL特性并没有实现,毕竟是研究分享的目的

,软光栅软CPU一般是硬件仿真模拟目的。

 

tracepix.h    trace pixel意思就是描像素,感觉光栅化这个术语很神秘,不知道是不是直译的。整个程序就是一堆计算,最后实际动作就是在QImge上setPixel

#ifndef TRACEPIX_H
#define TRACEPIX_H

#include <QPainter>
#include <osg/Vec2i>
#include <osg/Vec3>
#include <osg/Vec4>

class TracePix
{
public:
    enum ElementType
    {
        ET_POINTS = 1,
        ET_LINES,
        ET_TRIANGLES
    };

    struct Transform
    {
        Transform()
        {
            center.set(0, 0, 0);
            xaxis.set(1.f, 0, 0);
            yaxis.set(0, 1.f, 0);
            yaxis.set(0, 0, 1.f);
        }
        osg::Vec3 center;
        osg::Vec3 xaxis;
        osg::Vec3 yaxis;
        osg::Vec3 zaxis;
    };

private:
    std::vector<osg::Vec3> vboPoints;
    std::vector<osg::Vec3> vboNormals;
    std::vector<osg::Vec4> vboColors;

    std::vector<osg::Vec3> vboPointsReg;
    std::vector<osg::Vec3> vboNormalsReg;
    std::vector<osg::Vec4> vboColorsReg;

    std::vector<unsigned int> indices;
    ElementType elementType;

    QImage* cbuf;
    int viewwidth;
    int viewheight;
    std::vector<float> zbuf;
    Transform trans;

public:
    void init(QImage* img)
    {
        cbuf = img;
        viewwidth = cbuf->width();
        viewheight = cbuf->height();
        zbuf.resize(viewwidth*viewheight,1e4);
        
    }

    const std::vector<osg::Vec3>& getPoints()
    {
        return vboPoints;
    }

    void  setPoints(std::vector<osg::Vec3>& data)
    {
        vboPoints = data;
        vboPointsReg.resize(vboPoints.size());
    }

    const std::vector<osg::Vec3>& getNormals()
    {
        return vboNormals;
    }

    void  setNormals(std::vector<osg::Vec3>& data)
    {
        vboNormals = data;
        vboNormalsReg.resize(vboNormals.size());
    }

    const std::vector<osg::Vec4>& getColors()
    {
        return vboColors;
    }

    void  setColors(std::vector<osg::Vec4>& data)
    {
        vboColors = data;
        vboColorsReg.resize(vboColors.size());
    }

    const std::vector<unsigned int>& getElementsIndices()
    {
        return indices;
    }

    ElementType getElementType()
    {
        return elementType;
    }

    void  setElementsIndices(ElementType type, std::vector<unsigned int>& data)
    {
        elementType = type;
        indices = data;
    }

    void setTransform(osg::Vec3 center,
        osg::Vec3 xaxis,
        osg::Vec3 yaxis, 
        osg::Vec3 zaxis)
    {
        trans.center = center;
        trans.xaxis = xaxis;
        trans.yaxis = yaxis;
        trans.zaxis = zaxis;
    }

    void setTransform(Transform& t)
    {
        trans.center = t.center;
        trans.xaxis = t.xaxis;
        trans.yaxis = t.yaxis;
        trans.zaxis = t.zaxis;
    }

    Transform getTransform()
    {
        return trans;
    }

    void drawElements()
    {
        if (elementType == ET_POINTS)
        {
            drawPoints();
        }
        else if (elementType == ET_LINES)
        {
            drawLines();
        }
        else if (elementType == ET_TRIANGLES)
        {
            drawTriangles();
        }
        else
        {
            return;
        }
    }

    void clear()
    {
        cbuf->fill(qRgb(51, 51, 102));
        zbuf.assign(viewwidth*viewheight, 1e4);
    }

    osg::Vec3 rotateVector(osg::Vec3 vec, osg::Vec3 rotateAxis, float rotateAngleDeg)
    {
        float x = rotateAxis.x();
        float y = rotateAxis.y();
        float z = rotateAxis.z();

        float length = sqrt(x * x + y * y + z * z);
        

        float inversenorm = 1.0 / length;
        float coshalfangle = cos(0.5 * rotateAngleDeg);
        float sinhalfangle = sin(0.5 * rotateAngleDeg);

        float _v[4];

        _v[0] = x * sinhalfangle * inversenorm;
        _v[1] = y * sinhalfangle * inversenorm;
        _v[2] = z * sinhalfangle * inversenorm;
        _v[3] = coshalfangle;

        osg::Vec3f uv, uuv;
        osg::Vec3f qvec(_v[0], _v[1], _v[2]);
        uv = qvec ^ vec;
        uuv = qvec ^ uv;
        uv *= (2.0f * _v[3]);
        uuv *= 2.0f;
        return vec + uv + uuv;
    }

private:

    osg::Vec3 transformPoint(osg::Vec3& pt)
    {
        return trans.center +
            trans.xaxis * pt.x() +
            trans.yaxis * pt.y() +
            trans.zaxis * pt.z();
    }

    osg::Vec3 transformVec(osg::Vec3& vec)
    {
        return trans.xaxis * vec.x() +
            trans.yaxis * vec.y() +
            trans.zaxis * vec.z();
    }

    void drawTriangles()
    {
        vertex_process();

        for (int ti = 0; ti < indices.size(); ti += 3)
        {
            int ti0 = indices[ti];
            int ti1 = indices[ti+1];
            int ti2 = indices[ti+2];


            draw_tri(vboPointsReg[ti0], vboPointsReg[ti1], vboPointsReg[ti2],
                     vboNormalsReg[ti0], vboNormalsReg[ti1], vboNormalsReg[ti2],
                     vboColorsReg[ti0], vboColorsReg[ti1], vboColorsReg[ti2]);
        }
    }

    void drawPoints()
    {

    }

    void drawLines()
    {

    }

    void vertex_process()
    {
        osg::Vec4 lightColor(1, 1, 0, 1);
        osg::Vec3 toEyeDir(0, 0, 1);

        for (int i = 0; i < vboPoints.size(); i++)
        {
            vboPointsReg[i] = transformPoint(vboPoints[i]);
            vboNormalsReg[i] = transformVec(vboNormals[i]);
            vboColorsReg[i] = vboColors[i];

            auto n = vboNormalsReg[i];

            float s = fabs(toEyeDir * n);
            if (s > 1.f)
            {
                s = 1.f;
            }
            auto& c = vboColorsReg[i];
            c = lightColor * s;
            c.w() = 1.0;
        }
    }

    void draw_tri(osg::Vec3& point_a, osg::Vec3& point_b, osg::Vec3& point_c,
                  osg::Vec3& normal_a, osg::Vec3& normal_b, osg::Vec3& normal_c,
                  osg::Vec4& color_a, osg::Vec4& color_b, osg::Vec4& color_c)
    {
        osg::Vec2i a(point_a._v[0], point_a._v[1]);
        osg::Vec2i b(point_b._v[0], point_b._v[1]);
        osg::Vec2i c(point_c._v[0], point_c._v[1]);

        float depth_a = fabs(point_a._v[2]);
        float depth_b = fabs(point_b._v[2]);
        float depth_c = fabs(point_c._v[2]);

        int af_b = (a.y() - b.y()) * (c.x() - b.x()) - (a.x() - b.x()) * (c.y() - b.y());
        if (af_b == 0)
        {
            return;
        }

        int bt_b = (b.y() - c.y()) * (a.x() - c.x()) - (b.x() - c.x()) * (a.y() - c.y());
        if (bt_b == 0)
        {
            return;
        }

        int xmin = 1e6;
        int xmax = -1e6;

        int ymin = 1e6;
        int ymax = -1e6;

        update_rect(a, xmin, xmax, ymin, ymax);
        update_rect(b, xmin, xmax, ymin, ymax);
        update_rect(c, xmin, xmax, ymin, ymax);

        if (xmax < 0 || xmin >= viewwidth||
            ymax < 0 || ymin >= viewheight)
        {
            return;
        }

        for (int j = ymin; j<=ymax; j++)
        {
            for (int i = xmin; i <= xmax; i++)
            {
                if (i < 0 || i >= viewwidth ||
                    j < 0 || j >= viewheight)
                {
                    continue;
                }

                osg::Vec2i p(i,j);
                osg::Vec2i ab = b - a;
                osg::Vec2i bc = c - b;
                osg::Vec2i ca = a - c;

                osg::Vec2i ap = p - a;
                osg::Vec2i bp = p - b;
                osg::Vec2i cp = p - c;

                bool iflag = vec2i_cross(ab, ap) >= 0 &&
                        vec2i_cross(bc, bp) >= 0 &&
                        vec2i_cross(ca, cp) >= 0;
                if (!iflag)
                {
                    iflag = vec2i_cross(ab, ap) <= 0 &&
                            vec2i_cross(bc, bp) <= 0 &&
                            vec2i_cross(ca, cp) <= 0;
                }

                if (!iflag)
                {
                    continue;
                }


                int af_t = (p.y() - b.y()) * (c.x() - b.x()) - (p.x() - b.x()) * (c.y() - b.y());
                int bt_t = (p.y() - c.y()) * (a.x() - c.x()) - (p.x() - c.x()) * (a.y() - c.y());

                float af = float(af_t) / float(af_b);
                float bt = float(bt_t) / float(bt_b);
                float ga = 1.f - af - bt;

                // pixel_process


                osg::Vec4 color_p = color_a * af + color_b * bt + color_c * ga;

                float depth_p = depth_a * af + depth_b * bt + depth_c * ga;

                float depth_dbuf = getDepth(i,j);
                if (depth_p > depth_dbuf)
                    continue;

                setDepth(i,j, depth_p);


                setPixelColor(i,j,color_p);

            }
        }
    }

    int vec2i_cross(osg::Vec2i& a, osg::Vec2i& b)
    {
        return a.x()* b.y() - b.x() * a.y();
    }

    void update_rect(osg::Vec2i& a, int& xmin, int& xmax, int& ymin, int& ymax)
    {
        if (a.x() < xmin)
        {
            xmin = a.x();
        }
        if (a.x() > xmax)
        {
            xmax = a.x();
        }

        if (a.y() < ymin)
        {
            ymin = a.y();
        }
        if (a.y() > ymax)
        {
            ymax = a.y();
        }
    }

    void setDepth(int i, int j, float d)
    {
        zbuf[viewwidth*j+i] = d;
    }

    float getDepth(int i, int j)
    {
        return zbuf[viewwidth*j+i];
    }

    void setPixelColor(int i, int j, osg::Vec4 c)
    {
        int ir = 255*c.x();
        int ig = 255*c.y();
        int ib = 255*c.z();
        cbuf->setPixel(i, viewheight - 1 - j, qRgb(ir, ig, ib));
    }





};


#endif // TRACEPIX_H

  

PixPanel.h

#pragma once

#include <QWidget>
#include <QTimer>
#include "ui_PixPanel.h"

class QImage;
class TracePix;
class PixPanel : public QWidget
{
	Q_OBJECT

public:
	PixPanel(QWidget *parent = Q_NULLPTR);
	~PixPanel();
	virtual void paintEvent(QPaintEvent* e);

private:
	Ui::PixPanel ui;
	QImage* mImage;
	TracePix* mTracePix;
	QTimer* mTimer;
	double mXRotAngle;
	double mYRotAngle;
};

  

PixPanel.cpp

#include "PixPanel.h"
#include <QPainter>
#include <QImage>
#include <iostream>
#include "tracepix.h"

osg::Vec3 _localToWorld(osg::Vec3& center, osg::Vec3& xaxis,
	osg::Vec3& yaxis, osg::Vec3& zaxis, osg::Vec3& localVec3)
{
	return center +
		xaxis * localVec3.x() +
		yaxis * localVec3.y() +
		zaxis * localVec3.z();
}

void createCubeMeshData(osg::Vec3 center, osg::Vec3 xaxis,
	osg::Vec3 yaxis, osg::Vec3 zaxis,
	double m, double n, double h,
	std::vector<osg::Vec3>& points,
	std::vector<osg::Vec3>& normals, 
	std::vector<unsigned int>& indices)
{
	// ^z top
	// |
	//     7------6
    //   / |     /|
    //  4------5  |
	//  |  3---|--2
	//  | /    | /   ---->x right
	//  0------1
	//    /
	//   /
	// |/-y front

	std::vector<osg::Vec3> vertices;
	double halfx = m * 0.5;
	double halfy = n * 0.5;
	double halfz = h * 0.5;
	vertices.push_back(osg::Vec3(-halfx, -halfy, -halfz));
	vertices.push_back(osg::Vec3(halfx, -halfy, -halfz));
	vertices.push_back(osg::Vec3(halfx, halfy, -halfz));
	vertices.push_back(osg::Vec3(-halfx, halfy, -halfz));
	vertices.push_back(osg::Vec3(-halfx, -halfy, halfz));
	vertices.push_back(osg::Vec3(halfx, -halfy, halfz));
	vertices.push_back(osg::Vec3(halfx, halfy, halfz));
	vertices.push_back(osg::Vec3(-halfx, halfy, halfz));
	for (int i = 0; i < 8; i++)
	{
		vertices[i] = _localToWorld(center, xaxis, yaxis, zaxis, vertices[i]);
	}


	std::vector<osg::Vec3> plnNormals;
	plnNormals.push_back(osg::Vec3(0, -1, 0)); //front
	plnNormals.push_back(osg::Vec3(0, 1, 0)); //back
	plnNormals.push_back(osg::Vec3(-1, 0, 0)); //left
	plnNormals.push_back(osg::Vec3(1, 0, 0)); //right
	plnNormals.push_back(osg::Vec3(0, 0, -1)); //bottom
	plnNormals.push_back(osg::Vec3(0, 0, 1)); //top
	osg::Vec3 worldCenter(0, 0, 0);
	for (int i = 0; i < 6; i++)
	{
		plnNormals[i] = _localToWorld(worldCenter, xaxis, yaxis, zaxis, plnNormals[i]);
	}

	points.reserve(24);
	normals.reserve(24);
	indices.reserve(36);
	// cube six facets
	int facets[24] = { 
		0,1,5,4,
		2,3,7,6,
		0,4,7,3,
		1,2,6,5,
		0,3,2,1,
		4,5,6,7
	};

	int normalIdx = 0;
	int offseti = 0;
	for (int j = 0; j < 6; j++)
	{
		for (int i = 0; i < 4; i++)
		{
			points.push_back(vertices[facets[i+offseti]]);
			normals.push_back(plnNormals[j]);
		}

		indices.push_back(0 + offseti);
		indices.push_back(1 + offseti);
		indices.push_back(2 + offseti);
		indices.push_back(0 + offseti);
		indices.push_back(2 + offseti);
		indices.push_back(3 + offseti);

		offseti += 4;
	}
}

void createTwoTriangles(TracePix* tracePix)
{
	// v4        v1
	//
	//
	// v2(v5)              v0(v3)

	std::vector<osg::Vec3> pts;
	pts.push_back(osg::Vec3(80, 20, -150));
	pts.push_back(osg::Vec3(60, 60, -200));
	pts.push_back(osg::Vec3(20, 20, -150));

	pts.push_back(osg::Vec3(80, 20, -150));
	pts.push_back(osg::Vec3(20, 56, -50));
	pts.push_back(osg::Vec3(20, 20, -150));

	osg::Vec3 facet0_n = (pts[1] - pts[0]) ^ (pts[2] - pts[0]);
	facet0_n.normalize();
	osg::Vec3 facet1_n = (pts[4] - pts[3]) ^ (pts[5] - pts[3]);
	facet1_n.normalize();

	std::vector<osg::Vec3> nms;
	//nms.push_back(osg::Vec3(0, 0, -1));
	//nms.push_back(osg::Vec3(0, 0, -1));
	//nms.push_back(osg::Vec3(0, 0, -1));
	//nms.push_back(osg::Vec3(0, 0, -1));
	nms.push_back(facet0_n);
	nms.push_back(facet0_n);
	nms.push_back(facet0_n);
	nms.push_back(facet1_n);
	nms.push_back(facet1_n);
	nms.push_back(facet1_n);

	std::vector<osg::Vec4> cos;
	cos.push_back(osg::Vec4(0, 0, 1, 1));
	cos.push_back(osg::Vec4(0, 1, 0, 1));
	cos.push_back(osg::Vec4(1, 0, 0, 1));
	cos.push_back(osg::Vec4(0, 0, 1, 1));
	cos.push_back(osg::Vec4(0, 1, 0, 1));
	cos.push_back(osg::Vec4(1, 0, 0, 1));

	std::vector<unsigned int> idx;
	idx.push_back(0);
	idx.push_back(1);
	idx.push_back(2);
	idx.push_back(3);
	idx.push_back(4);
	idx.push_back(5);

	tracePix->setPoints(pts);
	tracePix->setNormals(nms);
	tracePix->setColors(cos);
	tracePix->setElementsIndices(TracePix::ET_TRIANGLES, idx);
}

void createACube(TracePix* tracePix,
	osg::Vec3 origin,
	double xsize,
	double ysize,
	double zsize,
	float xRotAngle = 32.f, 
	float yRotAngle = 12.f)
{
	std::vector<osg::Vec3> pts;
	std::vector<osg::Vec3> nms;
	std::vector<osg::Vec4> cols;
	std::vector<unsigned int> idx;

	osg::Vec3 wc(0, 0, 0);
	osg::Vec3 c = origin;
	osg::Vec3 xa(1, 0, 0);
	osg::Vec3 ya(0, 1, 0);
	osg::Vec3 za(0, 0, 1);
	osg::Vec3 tya = tracePix->rotateVector(ya, xa, osg::DegreesToRadians(xRotAngle));
	osg::Vec3 tza = tracePix->rotateVector(za, xa, osg::DegreesToRadians(xRotAngle));
	osg::Vec3 txa = tracePix->rotateVector(xa, osg::Vec3(0,1,0), osg::DegreesToRadians(yRotAngle));
	tya = tracePix->rotateVector(tya, osg::Vec3(0, 1, 0), osg::DegreesToRadians(yRotAngle));
	tza = tracePix->rotateVector(tza, osg::Vec3(0, 1, 0), osg::DegreesToRadians(yRotAngle));
	tracePix->setTransform(c, txa, tya, tza);

	createCubeMeshData(wc, xa, ya, za, xsize, ysize, zsize, pts, nms, idx);
	cols.resize(pts.size(), osg::Vec4(0, 1, 0, 1));

	tracePix->setPoints(pts);
	tracePix->setNormals(nms);
	tracePix->setColors(cols);
	tracePix->setElementsIndices(TracePix::ET_TRIANGLES, idx);
}

PixPanel::PixPanel(QWidget *parent)
	: QWidget(parent)
{
	ui.setupUi(this);
	mImage = new QImage(640, 480, QImage::Format_ARGB32);
	mTracePix = new TracePix();
	mTracePix->init(mImage);

	// createTwoTriangles(mTracePix);

	mXRotAngle = 32.f;
	mYRotAngle = 12.f;
	createACube(mTracePix, 
		osg::Vec3(320,240,-300), 
		200,200,200,
		mXRotAngle, mYRotAngle);

	mTimer = new QTimer();
	mTimer->setInterval(60);
	connect(mTimer, SIGNAL(timeout()), this, SLOT(update()));
	mTimer->start();
}

PixPanel::~PixPanel()
{
	delete mImage;
	delete mTracePix;
}

void PixPanel::paintEvent(QPaintEvent* e)
{
	mXRotAngle += 2.0;
	if (mXRotAngle > 360.0)
	{
		mXRotAngle -= 360.0;
	}

	mYRotAngle += 3.0;
	if (mYRotAngle > 360.0)
	{
		mYRotAngle -= 360.0;
	}

	osg::Vec3 xa(1, 0, 0);
	osg::Vec3 ya(0, 1, 0);
	osg::Vec3 za(0, 0, 1);
	osg::Vec3 tya = mTracePix->rotateVector(ya, xa, osg::DegreesToRadians(mXRotAngle));
	osg::Vec3 tza = mTracePix->rotateVector(za, xa, osg::DegreesToRadians(mXRotAngle));
	osg::Vec3 txa = mTracePix->rotateVector(xa, osg::Vec3(0, 1, 0), osg::DegreesToRadians(mYRotAngle));
	tya = mTracePix->rotateVector(tya, osg::Vec3(0, 1, 0), osg::DegreesToRadians(mYRotAngle));
	tza = mTracePix->rotateVector(tza, osg::Vec3(0, 1, 0), osg::DegreesToRadians(mYRotAngle));

	TracePix::Transform trans = mTracePix->getTransform();
	trans.xaxis = txa;
	trans.yaxis = tya;
	trans.zaxis = tza;
	mTracePix->setTransform(trans);

	mTracePix->clear();
	mTracePix->drawElements();
	QPainter p(this);
	p.drawImage(20, 20, *mImage);
	p.end();

	//static int s_counter = 0;
	//std::cout << "update " << s_counter << std::endl;
	//s_counter++;
}

  

PixPanel.ui

<UI version="4.0" >
 <class>PixPanel</class>
 <widget class="QWidget" name="PixPanel" >
  <property name="objectName" >
   <string notr="true">PixPanel</string>
  </property>
  <property name="geometry" >
   <rect>
	<x>0</x>
	<y>0</y>
	<width>400</width>
	<height>300</height>
   </rect>
  </property>
  <property name="windowTitle" >
   <string>PixPanel</string>
  </property>
 </widget>
 <layoutDefault spacing="6" margin="11" />
 <pixmapfunction></pixmapfunction>
 <resources/>
 <connections/>
</UI>

  

截个图

 

标签:正方体,std,int,光栅,back,Vec3,push,绘制,osg
来源: https://www.cnblogs.com/abcstar/p/15681349.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有