OpenGL 纹理[转]
目录
uv坐标
- 图片左下角(0,0),图片右上角(1,1)
- 把图像缩放到一单位大小,需要乘以图片长宽然后找到真正对应的像素坐标位置
- 图像除以自己的宽高,进行映射
- 参考:https://blog.csdn.net/wang15061955806/article/details/51000450
- 要使用纹理映射,我们必须做以下三件事情:在OpenGL中装入纹理,为顶点提供纹理坐标(为了把纹理映射到顶点),用纹理坐标在纹理上执行一个采样操作,得到一个像素颜色。
- 点信息
struct Vertex { int2 p0; float2 uv0; Rgba c0; int2 p1; float2 uv1; Rgba c1; int2 p2; float2 uv2; Rgba c2; };
- 边信息(由两个点决定)
class Ege { public: int _x1; int _y1; float2 _uv1; Rgba _color1; int _x2; int _y2; float2 _uv2; Rgba _color2; Ege(int x1,int y1,Rgba color1,float2 uv1,int x2,int y2,Rgba color2,float2 uv2) { if (y1 < y2) { _x1 = x1; _y1 = y1; _uv1 = uv1; _color1 = color1; _x2 = x2; _y2 = y2; _uv2 = uv2; _color2 = color2; } else { _x1 = x2; _y1 = y2; _uv1 = uv2; _color1 = color2; _x2 = x1; _y2 = y1; _uv2 = uv1; _color2 = color1; } } };
- 水平边信息(由两条边上的两个点决定)
class Span { public: int _xStart; int _xEnd; Rgba _colorStart; Rgba _colorEnd; float2 _uvStart; float2 _uvEnd; int _y; public: Span(int xStart,int xEnd,int y,Rgba colorStart,Rgba colorEnd,float2 uvStart,float2 uvEnd) { if (xStart < xEnd) { _xStart = xStart; _xEnd = xEnd; _colorStart = colorStart; _colorEnd = colorEnd; _uvStart = uvStart; _uvEnd = uvEnd; _y = y; } else { _xStart = xEnd; _xEnd = xStart; _colorStart = colorEnd; _colorEnd = colorStart; _uvStart = uvEnd; _uvEnd = uvStart; _y = y; } } };
- 颜色插值,UV插值
inline Rgba4Byte colorLerp(const Rgba4Byte& c1, const Rgba4Byte& c2, float s) { Rgba4Byte color; color._r = (unsigned char)(c1._r + s * (c2._r - c1._r)); color._g = (unsigned char)(c1._g + s * (c2._g - c1._g)); color._b = (unsigned char)(c1._b + s * (c2._b - c1._b)); color._a = (unsigned char)(c1._a + s * (c2._a - c1._a)); return color; } inline tvec2<float> uvLerp(const tvec2<float>& c1, const tvec2<float>& c2, float s) { tvec2<float> color; color.x = (c1.x + s * (c2.x - c1.x)); color.y = (c1.y + s * (c2.y - c1.y)); return color; }
- 设置和获取某像素点颜色
inline void setPixelEx(unsigned x, unsigned y, Rgba color) { _buffer[y * _width + x] = color._color; } inline Rgba getPixel(unsigned x, unsigned y) { return Rgba(_buffer[y * _width + x]); } inline void setPixel(unsigned x, unsigned y, Rgba color) { if (x >= _width || y >= _height) { return; } _buffer[y * _width + x] = color._color; }
- 根据UV获取对应图像像素点的颜色信息
Rgba pixelUV(float u, float v) { float x = u * _width; float y = v * _height; return pixelAt(x, y); }
- 绘制水平图像数据(获取UV,UV就代表着图像上某个像素点的颜色信息)
void drawSpan(const Span& span, Image* image) { float length = span._xEnd - span._xStart; float scale = 0; float step = 1.0f / length; for (int x = span._xStart; x < span._xEnd; ++x) { //Rgba color = colorLerp(span._colorStart,span._colorEnd,scale); float2 uv = uvLerp(span._uvStart, span._uvEnd, scale); Rgba color = image->pixelUV(uv.x, uv.y); scale += step; setPixel(x, span._y, color); } }
- 通过两条边绘制平面图像
void drawEge(const Ege& e1, const Ege& e2, Image* image) { float yOffset1 = e1._y2 - e1._y1; if (yOffset1 == 0) { return; } float yOffset = e2._y2 - e2._y1; if (yOffset == 0) { return; } float xOffset = e2._x2 - e2._x1; float scale = 0; float step = 1.0f / yOffset; float xOffset1 = e1._x2 - e1._x1; float scale1 = (float)(e2._y1 - e1._y1) / yOffset1; float step1 = 1.0f / yOffset1; for (int y = e2._y1; y < e2._y2; ++y) { int x1 = e1._x1 + (int)(scale1 * xOffset1); int x2 = e2._x1 + (int)(scale * xOffset); Rgba color2 = colorLerp(e2._color1, e2._color2, scale); Rgba color1 = colorLerp(e1._color1, e1._color2, scale1); float2 uvStart = uvLerp(e1._uv1, e1._uv2, scale1); float2 uvEnd = uvLerp(e2._uv1, e2._uv2, scale); Span span(x1, x2, y, color1, color2, uvStart, uvEnd); drawSpan(span, image); scale += step; scale1 += step1; } }
- 根据定点绘制三角形
void drawTriangle(const Vertex& vertex, Image* image) { Ege eges[3] = { Ege(vertex.p0.x,vertex.p0.y,vertex.c0, vertex.uv0, vertex.p1.x,vertex.p1.y,vertex.c1, vertex.uv1), Ege(vertex.p1.x,vertex.p1.y,vertex.c1, vertex.uv1, vertex.p2.x,vertex.p2.y,vertex.c2, vertex.uv2), Ege(vertex.p2.x,vertex.p2.y,vertex.c2, vertex.uv2, vertex.p0.x,vertex.p0.y,vertex.c0, vertex.uv0), }; int iMax = 0; int length = eges[0]._y2 - eges[0]._y1; for (int i = 1; i < 3; ++i) { int len = eges[i]._y2 - eges[i]._y1; if (len > length) { length = len; iMax = i; } } int iShort1 = (iMax + 1) % 3; int iShort2 = (iMax + 2) % 3; drawEge(eges[iMax], eges[iShort1], image); drawEge(eges[iMax], eges[iShort2], image); }
- 调用:
CELL::Raster::Vertex vertex = { CELL::int2(10,10), CELL::float2(0.0f,0.0f), CELL::Rgba(), CELL::int2(10,110), CELL::float2(0.0f,1.0f), CELL::Rgba(), CELL::int2(110,110), CELL::float2(1.0f,1.0f), CELL::Rgba(), }; CELL::Raster::Vertex vertex1 = { CELL::int2(10,10), CELL::float2(0.0f,0.0f), CELL::Rgba(), CELL::int2(110,110), CELL::float2(1.0f,1.0f), CELL::Rgba(), CELL::int2(110,10), CELL::float2(1.0f,0.0f), CELL::Rgba(), }; raster.drawTriangle(vertex,image1); raster.drawTriangle(vertex1,image1);
friend Rgba4Byte operator + (const Rgba4Byte& left,const Rgba4Byte& right) { return Rgba4Byte(left._r * right._r ,left._g * right._g ,left._b * right._b ,left._a * right._a); }
- uv与颜色混合
void drawSpan(const Span& span,Image* image) { float length = span._xEnd - span._xStart; float scale = 0; float step = 1.0f/length; for (int x = span._xStart ; x < span._xEnd; ++ x) { Rgba color = colorLerp(span._colorStart,span._colorEnd,scale); float2 uv = uvLerp(span._uvStart,span._uvEnd,scale); Rgba pixel = image->pixelUV(uv.x,uv.y); Rgba dst = color + pixel; scale += step; setPixel(x,span._y,dst); } }
状态机
- 应用:
- 顶点信息:
struct Vertex { float x,y; float u,v; CELL::Rgba color; };
Vertex vertexs[] = { {10, 10, 0.0f, 0.0f, CELL::Rgba(255,255,255,255)}, {210, 210, 1.0f, 1.0f, CELL::Rgba(255,255,255,255)}, {210, 10, 1.0f, 0.0f, CELL::Rgba(255,255,255,255)}, {10, 10, 0.0f, 0.0f, CELL::Rgba(255,255,255,255)}, {210, 210, 1.0f, 1.0f, CELL::Rgba(255,255,255,255)}, {10, 210, 0.0f, 1.0f, CELL::Rgba(255,255,255,255)}, }; //注意:偏移量 比如取当前顶点坐标xy,然后取下一个顶点坐标xy需要跨越多长数据大小 raster.vertexPointer(2,CELL::DT_FLOAT, sizeof(Vertex),&vertexs[0].x); raster.textureCoordPointer(2,CELL::DT_FLOAT,sizeof(Vertex),&vertexs[0].u); raster.colorPointer(4,CELL::DT_BYTE, sizeof(Vertex),&vertexs[0].color); raster.drawArrays(CELL::DM_TRIANGES,0,6); //注意是6个点
- 数据类型定义
enum DRAWMODE { DM_POINTS = 0, DM_LINES = 1, DM_LINE_LOOP = 2, DM_LINE_STRIP = 3, DM_TRIANGES = 4, }; enum DATETYPE { DT_BYTE, DT_FLOAT, DT_DOUBLE, }; struct DateElementDes { int _size; DATETYPE _type; int _stride; const void* _data; };
- 变量声明:
class Raster { public: uint* _buffer; int _width; int _height; Rgba _color; Image* _texture; //纹理 DateElementDes _poitionPointer; //记录当前状态信息 DateElementDes _colorPointer; DateElementDes _uvPointer; DateElementDes _defaultColorPointer; //默认值,防止空指针解引用 DateElementDes _defaultUVPointer; Rgba _defaultColorArray[3]; //示例画三角形,,给三个 float2 _detaultUVArray[3]; //.... }
- 变量初始化:
Raster::Raster( int w,int h,void* buffer ) { _texture = 0; _width = w; _height = h; _buffer = (uint*)buffer; memset(&_poitionPointer,0, sizeof(_poitionPointer)); memset(&_colorPointer, 0, sizeof(_colorPointer)); memset(&_uvPointer, 0, sizeof(_uvPointer)); _defaultColorPointer._size = 4; _defaultColorPointer._type = DT_BYTE; _defaultColorPointer._stride= sizeof(Rgba); _defaultColorPointer._data = _defaultColorArray; _defaultUVPointer._size = 2; _defaultUVPointer._type = DT_FLOAT; _defaultUVPointer._stride = sizeof(float2); _defaultUVPointer._data = _detaultUVArray; }
- 初始化或者更改状态:
void vertexPointer(int size, DATETYPE type, int stride, const void* data) { _poitionPointer._size = size; _poitionPointer._type = type; _poitionPointer._stride = stride; _poitionPointer._data = data; } void colorPointer(int size, DATETYPE type, int stride, const void* data) { _colorPointer._size = size; _colorPointer._type = type; _colorPointer._stride = stride; _colorPointer._data = data; } void textureCoordPointer(int size, DATETYPE type, int stride, const void* data) { _uvPointer._size = size; _uvPointer._type = type; _uvPointer._stride = stride; _uvPointer._data = data; }
- 绑定纹理
void bindTexture(Image* image) { _texture = image; }
- 注意,使用模运算,可使纹理重复
Rgba pixelUV(float u,float v) { float x = u * _width; float y = v * _height; return pixelAt((unsigned)(x)%_width,(unsigned)(y)%_height); }
- 绘制三角形:
void drawTrianle(Ege eges[3]) { int iMax = 0; int length = eges[0]._y2 - eges[0]._y1; for (int i = 1; i < 3; ++i) { int len = eges[i]._y2 - eges[i]._y1; if (len > length) { length = len; iMax = i; } } int iShort1 = (iMax + 1) % 3; int iShort2 = (iMax + 2) % 3; drawEge(eges[iMax], eges[iShort1], _texture); drawEge(eges[iMax], eges[iShort2], _texture); }
- 绘制顶点图形:
void drawArrays(DRAWMODE pri, int start, int count) { if (_poitionPointer._data == 0) { return; } //用户没给值 _colorPointer 保持原状态,后面使用临时变量 DateElementDes colorPointerdesc = _colorPointer; DateElementDes uvPointerdesc = _uvPointer; if (colorPointerdesc._data == 0) //如果没有传值,就给默认值 { colorPointerdesc = _defaultColorPointer; } if (uvPointerdesc._data == 0) //如果没有传值,就给默认值 { uvPointerdesc = _defaultUVPointer; } char* posData = (char*)_poitionPointer._data; char* cData = (char*)colorPointerdesc._data; char* uvData = (char*)uvPointerdesc._data; for (int i = start; i < start + count; i += 3) //每次画三个点 { float* fData = (float*)posData; int2 p0(fData[0], fData[1]); posData += _poitionPointer._stride; fData = (float*)(posData); int2 p1(fData[0], fData[1]); posData += _poitionPointer._stride; fData = (float*)(posData); int2 p2(fData[0], fData[1]); posData += _poitionPointer._stride; Rgba* pColor = (Rgba*)cData; Rgba c0(*pColor); cData += _colorPointer._stride; Rgba c1(*pColor); cData += _colorPointer._stride; Rgba c2(*pColor); cData += _colorPointer._stride; float* pUV = (float*)uvData; float2 uv0(pUV[0], pUV[1]); uvData += _uvPointer._stride; pUV = (float*)uvData; float2 uv1(pUV[0], pUV[1]); uvData += _uvPointer._stride; pUV = (float*)uvData; float2 uv2(pUV[0], pUV[1]); uvData += _uvPointer._stride; Ege eges[3] = { Ege(p0.x,p0.y,c0, uv0, p1.x,p1.y,c1, uv1), Ege(p1.x,p1.y,c1, uv1, p2.x,p2.y,c2, uv2), Ege(p2.x,p2.y,c2, uv2, p0.x,p0.y,c0, uv0), }; drawTrianle(eges); if (_colorPointer._data == 0) //恢复,防止绘制多个三角形越界 { cData = (char*)colorPointerdesc._data; } if (_uvPointer._data == 0) { uvData = (char*)uvPointerdesc._data; } } }
- 纹理滚动显示
static float step = 0; // Vertex vertexs[] ={.......} for (int i = 0 ;i < 6 ; ++ i ) { vertexs[i].v += step; }
- 设置纹理贴图UV值大于1,边重复
Rgba pixelUV(float u,float v) { float x = u * _width; float y = v * _height; if (_wrapType == 0) { return pixelAt((unsigned)(x)%_width,(unsigned)(y)%_height); } else { if (x >= _width) { x = _width - 1; } if (y >= _height) { y = _height - 1; } return pixelAt(x,y); } }
- 矩阵:
template <typename T> struct tmat3x3 { typedef T value_type; typedef std::size_t size_type; typedef tvec3<T> col_type; typedef tvec3<T> row_type; typedef tmat3x3<T> type; typedef tmat3x3<T> transpose_type; private: // Data col_type value[3]; public: size_type length() const { return 3; } size_type col_size() { return 3; } size_type row_size() { return 3; } tmat3x3() { value_type const Zero(0); value_type const One(1); this->value[0] = col_type(One, Zero, Zero); this->value[1] = col_type(Zero, One, Zero); this->value[2] = col_type(Zero, Zero, One); } tmat3x3 ( tmat3x3<T> const & m ) { this->value[0] = m.value[0]; this->value[1] = m.value[1]; this->value[2] = m.value[2]; } tmat3x3(value_type const & s) { value_type const Zero(0); this->value[0] = col_type(s, Zero, Zero); this->value[1] = col_type(Zero, s, Zero); this->value[2] = col_type(Zero, Zero, s); } tmat3x3 ( value_type const & x0, value_type const & y0, value_type const & z0, value_type const & x1, value_type const & y1, value_type const & z1, value_type const & x2, value_type const & y2, value_type const & z2 ) { this->value[0] = col_type(x0, y0, z0); this->value[1] = col_type(x1, y1, z1); this->value[2] = col_type(x2, y2, z2); } tmat3x3 ( col_type const & v0, col_type const & v1, col_type const & v2 ) { this->value[0] = v0; this->value[1] = v1; this->value[2] = v2; } template <typename U> tmat3x3(U const & s) { value_type const Zero(0); this->value[0] = tvec3<T>(value_type(s), Zero, Zero); this->value[1] = tvec3<T>(Zero, value_type(s), Zero); this->value[2] = tvec3<T>(Zero, Zero, value_type(s)); } template < typename X1, typename Y1, typename Z1, typename X2, typename Y2, typename Z2, typename X3, typename Y3, typename Z3> tmat3x3 ( X1 const & x1, Y1 const & y1, Z1 const & z1, X2 const & x2, Y2 const & y2, Z2 const & z2, X3 const & x3, Y3 const & y3, Z3 const & z3 ) { this->value[0] = col_type(value_type(x1), value_type(y1), value_type(z1)); this->value[1] = col_type(value_type(x2), value_type(y2), value_type(z2)); this->value[2] = col_type(value_type(x3), value_type(y3), value_type(z3)); } template <typename V1, typename V2, typename V3> tmat3x3 ( tvec3<V1> const & v1, tvec3<V2> const & v2, tvec3<V3> const & v3 ) { this->value[0] = col_type(v1); this->value[1] = col_type(v2); this->value[2] = col_type(v3); } template <typename U> tmat3x3(tmat3x3<U> const & m) { this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); } tmat3x3<T> _inverse() const { T S00 = value[0][0]; T S01 = value[0][1]; T S02 = value[0][2]; T S10 = value[1][0]; T S11 = value[1][1]; T S12 = value[1][2]; T S20 = value[2][0]; T S21 = value[2][1]; T S22 = value[2][2]; tmat3x3<T> Inverse( S11 * S22 - S21 * S12, S12 * S20 - S22 * S10, S10 * S21 - S20 * S11, S02 * S21 - S01 * S22, S00 * S22 - S02 * S20, S01 * S20 - S00 * S21, S12 * S01 - S11 * S02, S10 * S02 - S12 * S00, S11 * S00 - S10 * S01); T Determinant = S00 * (S11 * S22 - S21 * S12) - S10 * (S01 * S22 - S21 * S02) + S20 * (S01 * S12 - S11 * S02); Inverse /= Determinant; return Inverse; } col_type & operator[](size_type i) { assert(i < this->length()); return this->value[i]; } col_type const & operator[](size_type i) const { assert(i < this->length()); return this->value[i]; } tmat3x3<T> & operator=(tmat3x3<T> const & m) { this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; return *this; } template <typename U> tmat3x3<T> & operator=(tmat3x3<U> const & m) { this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; return *this; } template <typename U> tmat3x3<T> & operator+= (U const & s) { this->value[0] += s; this->value[1] += s; this->value[2] += s; return *this; } template <typename U> tmat3x3<T> & operator+=(tmat3x3<U> const & m) { this->value[0] += m[0]; this->value[1] += m[1]; this->value[2] += m[2]; return *this; } template <typename U> tmat3x3<T> & operator-= (U const & s) { this->value[0] -= s; this->value[1] -= s; this->value[2] -= s; return *this; } template <typename U> tmat3x3<T> & operator-= (tmat3x3<U> const & m) { this->value[0] -= m[0]; this->value[1] -= m[1]; this->value[2] -= m[2]; return *this; } template <typename U> tmat3x3<T> & operator*= (U const & s) { this->value[0] *= s; this->value[1] *= s; this->value[2] *= s; return *this; } template <typename U> tmat3x3<T> & operator*= (tmat3x3<U> const & m) { return (*this = *this * m); } template <typename U> tmat3x3<T> & operator/= (U const & s) { this->value[0] /= s; this->value[1] /= s; this->value[2] /= s; return *this; } template <typename U> tmat3x3<T> & operator/= (tmat3x3<U> const & m) { return (*this = *this / m); } tmat3x3<T> & operator++ () { ++this->value[0]; ++this->value[1]; ++this->value[2]; return *this; } tmat3x3<T> & operator-- () { --this->value[0]; --this->value[1]; --this->value[2]; return *this; } tvec3<T> operator*(const tvec3<T> &v) const { return tvec3<T>( value[0][0] * v[0] + value[1][0] * v[1] + value[2][0] * v[2] ,value[0][1] * v[0] + value[1][1] * v[1] + value[2][1] * v[2] ,value[0][2] * v[0] + value[1][2] * v[1] + value[2][2] * v[2] ); } tvec2<T> operator*(const tvec2<T> &v) const { return tvec2<T>( value[0][0] * v[0] + value[1][0] * v[1] + value[2][0] ,value[0][1] * v[0] + value[1][1] * v[1] + value[2][1] ); } void scale(T x,T y) { this->value[0] = col_type(value_type(x), value_type(0), value_type(0)); this->value[1] = col_type(value_type(0), value_type(y), value_type(0)); this->value[2] = col_type(value_type(0), value_type(0), value_type(1)); } void rotate(T angle) { T rad = DEG2RAD(angle); T c = cos(rad); T s = sin(rad); this->value[0] = col_type(value_type(c), value_type(-s), value_type(0)); this->value[1] = col_type(value_type(s), value_type(c), value_type(0)); this->value[2] = col_type(value_type(0), value_type(0), value_type(1)); } void translate(T x,T y) { this->value[0] = col_type(value_type(1), value_type(0), value_type(0)); this->value[1] = col_type(value_type(0), value_type(1), value_type(0)); this->value[2] = col_type(value_type(x), value_type(y), value_type(1)); } };