3d纹理在现实世界中并不存在,也不能用图片工具查看。可以理解为一个实心的立文体数据块,可以通过,x,y,z坐标获取对应点的纹素(像素)。
这里我学习了一个梯子的3d纹理,在实现3d纹理的同时,在其中加入了光照,效果如下
其渲染器实现如下
#ifndef TEXTURE3DRENDER_H
#define TEXTURE3DRENDER_H
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QOpenGLBuffer>
#include <QOpenGLExtraFunctions>
class Texture3DRender
{
public:
Texture3DRender() = default;
void initsize();
void render(QOpenGLExtraFunctions *f,QMatrix4x4 &pMatrix,QMatrix4x4 &vMatrix,QMatrix4x4 &mMatrix,QVector3D &cameraLocation,QVector3D &lightLocation);
private:
QOpenGLShaderProgram program_;
QOpenGLTexture *texture_{nullptr};
QOpenGLBuffer vbo_;
};
#endif // TEXTURE3DRENDER_H
#include "texture3drender.h"
void Texture3DRender::initsize()
{
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,"vsrc.vert");
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,"fsrc.frag");
GLfloat texData[]{
255,0,0,255,255,255,255,255,
255,255,255,255,255,0,0,255,
255,255,255,255,255,0,0,255,
255,255,255,255,255,0,0,255,
255,0,0,255,255,255,255,255
};
texture_ = new QOpenGLTexture(QOpenGLTexture::Target3D);
texture_->create();
texture_->setSize(2,2,2);
texture_->setFormat(QOpenGLTexture::RGBA8_UNorm);
texture_->allocateStorage();
texture_->setData(QOpenGLTexture::RGBA,QOpenGLTexture::Float32,texData);
texture_->setMinMagFilters(QOpenGLTexture::Nearest,QOpenGLTexture::Nearest);
texture_->setWrapMode(QOpenGLTexture::DirectionS,QOpenGLTexture::ClampToEdge);
texture_->setWrapMode(QOpenGLTexture::DirectionT,QOpenGLTexture::ClampToEdge);
texture_->setWrapMode(QOpenGLTexture::DirectionR,QOpenGLTexture::ClampToEdge);
GLfloat xSize=0.2f;
GLfloat y1Size=0.1f;
GLfloat y2Size=0.2f;
GLfloat y3Size=0.3f;
GLfloat y4Size=0.4f;
GLfloat z1Size=0.4f;
GLfloat z2Size=0.3f;
GLfloat z3Size=0.2f;
GLfloat z4Size=0.1f;
GLfloat vertices[]{
//第四个(最下面)立方体的下面
xSize,0,0,
xSize,0,z1Size,
-xSize,0,z1Size,
-xSize,0,z1Size,
-xSize,0,0,
xSize,0,0,
//第四个(最下面)立方体的上面
xSize,y1Size,0,
-xSize,y1Size,0,
-xSize,y1Size,z1Size,
-xSize,y1Size,z1Size,
xSize,y1Size,z1Size,
xSize,y1Size,0,
//第四个(最下面)立方体的前面
xSize,y1Size,z1Size,
-xSize,y1Size,z1Size,
-xSize,0,z1Size,
-xSize,0,z1Size,
xSize,0,z1Size,
xSize,y1Size,z1Size,
//第四个(最下面)立方体的后面
xSize,y1Size,0,
xSize,0,0,
-xSize,0,0,
-xSize,0,0,
-xSize,y1Size,0,
xSize,y1Size,0,
//第四个(最下面)立方体的左面
-xSize,y1Size,z1Size,
-xSize,y1Size,0,
-xSize,0,0,
-xSize,0,0,
-xSize,0,z1Size,
-xSize,y1Size,z1Size,
//第四个(最下面)立方体的右面
xSize,y1Size,z1Size,
xSize,0,z1Size,
xSize,0,0,
xSize,0,0,
xSize,y1Size,0,
xSize,y1Size,z1Size,
//第三个立方体的上面
xSize,y2Size,0,
-xSize,y2Size,0,
-xSize,y2Size,z2Size,
-xSize,y2Size,z2Size,
xSize,y2Size,z2Size,
xSize,y2Size,0,
//第三个立方体的前面
xSize,y2Size,z2Size,
-xSize,y2Size,z2Size,
-xSize,y1Size,z2Size,
-xSize,y1Size,z2Size,
xSize,y1Size,z2Size,
xSize,y2Size,z2Size,
//第三个立方体的后面
xSize,y2Size,0,
xSize,y1Size,0,
-xSize,y1Size,0,
-xSize,y1Size,0,
-xSize,y2Size,0,
xSize,y2Size,0,
//第三个立方体的左面
-xSize,y2Size,z2Size,
-xSize,y2Size,0,
-xSize,y1Size,0,
-xSize,y1Size,0,
-xSize,y1Size,z2Size,
-xSize,y2Size,z2Size,
//第三个立方体的右面
xSize,y2Size,z2Size,
xSize,y1Size,z2Size,
xSize,y1Size,0,
xSize,y1Size,0,
xSize,y2Size,0,
xSize,y2Size,z2Size,
//第二个立方体的上面
xSize,y3Size,0,
-xSize,y3Size,0,
-xSize,y3Size,z3Size,
-xSize,y3Size,z3Size,
xSize,y3Size,z3Size,
xSize,y3Size,0,
//第二个立方体的前面
xSize,y3Size,z3Size,
-xSize,y3Size,z3Size,
-xSize,y2Size,z3Size,
-xSize,y2Size,z3Size,
xSize,y2Size,z3Size,
xSize,y3Size,z3Size,
//第二个立方体的后面
xSize,y3Size,0,
xSize,y2Size,0,
-xSize,y2Size,0,
-xSize,y2Size,0,
-xSize,y3Size,0,
xSize,y3Size,0,
//第二个立方体的左面
-xSize,y3Size,z3Size,
-xSize,y3Size,0,
-xSize,y2Size,0,
-xSize,y2Size,0,
-xSize,y2Size,z3Size,
-xSize,y3Size,z3Size,
//第二个立方体的右面
xSize,y3Size,z3Size,
xSize,y2Size,z3Size,
xSize,y2Size,0,
xSize,y2Size,0,
xSize,y3Size,0,
xSize,y3Size,z3Size,
//第一个立方体的上面
xSize,y4Size,0,
-xSize,y4Size,0,
-xSize,y4Size,z4Size,
-xSize,y4Size,z4Size,
xSize,y4Size,z4Size,
xSize,y4Size,0,
//第一个立方体的前面
xSize,y4Size,z4Size,
-xSize,y4Size,z4Size,
-xSize,y3Size,z4Size,
-xSize,y3Size,z4Size,
xSize,y3Size,z4Size,
xSize,y4Size,z4Size,
//第一个立方体的后面
xSize,y4Size,0,
xSize,y3Size,0,
-xSize,y3Size,0,
-xSize,y3Size,0,
-xSize,y4Size,0,
xSize,y4Size,0,
//第一个立方体的左面
-xSize,y4Size,z4Size,
-xSize,y4Size,0,
-xSize,y3Size,0,
-xSize,y3Size,0,
-xSize,y3Size,z4Size,
-xSize,y4Size,z4Size,
//第一个立方体的右面
xSize,y4Size,z4Size,
xSize,y3Size,z4Size,
xSize,y3Size,0,
xSize,y3Size,0,
xSize,y4Size,0,
xSize,y4Size,z4Size,
//第四个(最下面)立方体的下面
0,-1,0, 0,-1,0, 0,-1,0,
0,-1,0, 0,-1,0, 0,-1,0,
//第四个(最下面)立方体的上面
0,1,0, 0,1,0, 0,1,0,
0,1,0, 0,1,0, 0,1,0,
//第四个(最下面)立方体的前面
0,0,1, 0,0,1, 0,0,1,
0,0,1, 0,0,1, 0,0,1,
//第四个(最下面)立方体的后面
0,0,-1, 0,0,-1, 0,0,-1,
0,0,-1, 0,0,-1, 0,0,-1,
//第四个(最下面)立方体的左面
-1,0,0, -1,0,0, -1,0,0,
-1,0,0, -1,0,0, -1,0,0,
//第四个(最下面)立方体的右面
1,0,0, 1,0,0, 1,0,0,
1,0,0, 1,0,0, 1,0,0,
//第三个立方体的上面
0,1,0, 0,1,0, 0,1,0,
0,1,0, 0,1,0, 0,1,0,
//第三个立方体的前面
0,0,1, 0,0,1, 0,0,1,
0,0,1, 0,0,1, 0,0,1,
//第三个立方体的后面
0,0,-1, 0,0,-1, 0,0,-1,
0,0,-1, 0,0,-1, 0,0,-1,
//第三个立方体的左面
-1,0,0, -1,0,0, -1,0,0,
-1,0,0, -1,0,0, -1,0,0,
//第三个立方体的右面
1,0,0, 1,0,0, 1,0,0,
1,0,0, 1,0,0, 1,0,0,
//第二个立方体的上面
0,1,0, 0,1,0, 0,1,0,
0,1,0, 0,1,0, 0,1,0,
//第二个立方体的前面
0,0,1, 0,0,1, 0,0,1,
0,0,1, 0,0,1, 0,0,1,
//第二个立方体的后面
0,0,-1, 0,0,-1, 0,0,-1,
0,0,-1, 0,0,-1, 0,0,-1,
//第二个立方体的左面
-1,0,0, -1,0,0, -1,0,0,
-1,0,0, -1,0,0, -1,0,0,
//第二个立方体的右面
1,0,0, 1,0,0, 1,0,0,
1,0,0, 1,0,0, 1,0,0,
//第一个立方体的上面
0,1,0, 0,1,0, 0,1,0,
0,1,0, 0,1,0, 0,1,0,
//第一个立方体的前面
0,0,1, 0,0,1, 0,0,1,
0,0,1, 0,0,1, 0,0,1,
//第一个立方体的后面
0,0,-1, 0,0,-1, 0,0,-1,
0,0,-1, 0,0,-1, 0,0,-1,
//第一个立方体的左面
-1,0,0, -1,0,0, -1,0,0,
-1,0,0, -1,0,0, -1,0,0,
//第一个立方体的右面
1,0,0, 1,0,0, 1,0,0,
1,0,0, 1,0,0, 1,0,0,
};
vbo_.create();
vbo_.bind();
vbo_.allocate(vertices,sizeof vertices);
}
void Texture3DRender::render(QOpenGLExtraFunctions *f, QMatrix4x4 &pMatrix, QMatrix4x4 &vMatrix, QMatrix4x4 &mMatrix, QVector3D &cameraLocation, QVector3D &lightLocation)
{
f->glEnable(GL_CULL_FACE);
f->glEnable(GL_DEPTH_TEST);
program_.bind();
vbo_.bind();
f->glActiveTexture(GL_TEXTURE0 + 0);
program_.setUniformValue("uPMatrix",pMatrix);
program_.setUniformValue("uVMatrix",vMatrix);
program_.setUniformValue("uMMatrix",mMatrix);
program_.setUniformValue("uCamera",cameraLocation);
program_.setUniformValue("uLightLocation",lightLocation);
program_.setUniformValue("sTexture",0);
program_.enableAttributeArray(0);
program_.enableAttributeArray(1);
program_.setAttributeBuffer(0,GL_FLOAT,0,3,3*sizeof(GLfloat));
program_.setAttributeBuffer(1,GL_FLOAT,21*6*3*sizeof(GLfloat),3,3*sizeof(GLfloat));
texture_->bind(0);
f->glDrawArrays(GL_TRIANGLES,0,21 * 6);
program_.disableAttributeArray(0);
program_.disableAttributeArray(1);
texture_->release();
vbo_.release();
program_.release();
f->glDisable(GL_CULL_FACE);
f->glDisable(GL_DEPTH_TEST);
}
其shader实现如下
#version 330
uniform mat4 uPMatrix,uVMatrix,uMMatrix;
uniform vec3 uCamera,uLightLocation;
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec3 aNormal;
smooth out vec3 vPosition;
smooth out vec4 vAmbient,vDiffuse,vSpecular;
void pointLight(in vec3 normal,inout vec4 ambient,inout vec4 diffuse,inout vec4 specular,in vec4 lightAmbient,in vec4 lightDiffuse,in vec4 lightSpecular,in float shininess){
ambient = lightAmbient;
vec3 normalTarget = aPosition + normal;
vec3 newNormal = normalize((uMMatrix * vec4(normalTarget,1)).xyz - (uMMatrix * vec4(aPosition,1)).xyz);
vec3 eye = normalize(uCamera - (uMMatrix * vec4(aPosition,1)).xyz);
vec3 vp = normalize(uLightLocation - (uMMatrix * vec4(aPosition,1)).xyz);
vec3 halfVector = normalize(eye + vp);
float nDotViewPotision = max(0.0,dot(newNormal,vp));
diffuse = lightDiffuse * nDotViewPotision;
float nDotViewHalfVector = dot(newNormal,halfVector);
float powerFactor = max(0.0,pow(nDotViewHalfVector,shininess));
specular = lightSpecular * powerFactor;
}
void main(void)
{
gl_Position = uPMatrix * uVMatrix * uMMatrix * vec4(aPosition,1);
vec4 ambient = vec4(0.0,0.0,0.0,0.0),diffuse = vec4(0.0,0.0,0.0,0.0),specular = vec4(0.0,0.0,0.0,0.0);
pointLight(aNormal,ambient,diffuse,specular,vec4(0.15,0.15,0.15,1),vec4(0.8,0.8,0.8,1),vec4(0.7,0.7,0.7,1),50.0);
vAmbient = ambient;
vDiffuse = diffuse;
vSpecular = specular;
vPosition = aPosition;
}
#version 330
uniform sampler3D sTexture;
in vec3 vPosition;
in vec4 vAmbient,vDiffuse,vSpecular;
out vec4 fragColor;
void main(void)
{
//根据片元的位置折算出3D纹理坐标
vec3 texCoor=vec3(((vPosition.x/0.2)+1.0)/2.0,vPosition.y/0.4,vPosition.z/0.4);
vec4 noiseVec=texture(sTexture,texCoor);
//vec4 noiseVec = vec4(0.1,0.5,0.0,1.0); 用于测试顶点是否正确
fragColor = noiseVec*vAmbient+noiseVec*vSpecular+noiseVec*vDiffuse;
}
在widget中的使用如下
#ifndef WIDGET_H
#define WIDGET_H
#include <QOpenGLWidget>
#include "texture3drender.h"
class Widget : public QOpenGLWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
protected:
void initializeGL() override;
void resizeGL(int w,int h) override;
void paintGL() override;
private:
Texture3DRender render_;
QMatrix4x4 pMatrix_;
QVector3D cameraLocation_,lightLocation_;
};
#endif // WIDGET_H
#include "widget.h"
Widget::Widget(QWidget *parent)
: QOpenGLWidget(parent)
{
}
Widget::~Widget()
{
}
void Widget::initializeGL()
{
render_.initsize();
lightLocation_.setX(0.0);
lightLocation_.setY(0.0);
lightLocation_.setZ(5);
cameraLocation_.setX(0.0);
cameraLocation_.setY(1.0);
cameraLocation_.setZ(1.5);
}
void Widget::resizeGL(int w, int h)
{
pMatrix_.setToIdentity();
pMatrix_.perspective(30,float(w)/h,0.01f,100.0f);
}
void Widget::paintGL()
{
QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
f->glClearColor(0.0f,0.0f,0.0f,1.0f);
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 vMatrix;
vMatrix.lookAt(cameraLocation_,QVector3D(0.0,0.0,0.0),QVector3D(0.0,1.0,0.0));
QMatrix4x4 mMatrix;
mMatrix.rotate(-30,0,1,0);
render_.render(f,pMatrix_,vMatrix,mMatrix,cameraLocation_,lightLocation_);
}
到此结束