#include #include "OpenGLWidget.h" #include using namespace PolyVox; using namespace std; OpenGLWidget::OpenGLWidget(QWidget *parent) :QGLWidget(parent) ,m_xRotation(0) ,m_yRotation(0) ,radius(0) { for (int i=0;i<8;i++) { subdivisionMesh[i]=new SurfaceMesh (); subdivisionFlag[i]=true;//false flags present that need to update. m_uEndIndex[i]=0; //Build an OpenGL index buffer } //rayCallback = new RaycastIntersectionFinder(); //volData=NULL; //createSphereInVolume(30); volData=NULL; surfaceExtractor= NULL; //mesh=new SurfaceMesh();//set to NULL may return false error! /*subdivisionReg[0]=Region(Vector3DInt32(-32,-32,-32), Vector3DInt32(0,0,0)); subdivisionReg[1]=Region(Vector3DInt32(0,-32,-32), Vector3DInt32(32, 0, 0)); subdivisionReg[2]=Region(Vector3DInt32(-32,-32,0), Vector3DInt32(0, 0, 32)); subdivisionReg[3]=Region(Vector3DInt32(0,-32,0), Vector3DInt32(32, 0, 32)); subdivisionReg[4]=Region(Vector3DInt32(-32,0,-32), Vector3DInt32(0, 32, 0)); subdivisionReg[5]=Region(Vector3DInt32(0,0,-32), Vector3DInt32(32, 32, 0)); subdivisionReg[6]=Region(Vector3DInt32(-32,0,0), Vector3DInt32(0, 32, 32)); subdivisionReg[7]=Region(Vector3DInt32(0,0,0), Vector3DInt32(32, 32, 32));*/ subdivisionReg[0]=Region(Vector3DInt32(0,0,0), Vector3DInt32(32, 16, 32)); subdivisionReg[1]=Region(Vector3DInt32(32,0,0), Vector3DInt32(64, 16, 32)); subdivisionReg[2]=Region(Vector3DInt32(0,0,32), Vector3DInt32(32, 16, 64)); subdivisionReg[3]=Region(Vector3DInt32(32,0,32), Vector3DInt32(64, 16, 64)); subdivisionReg[4]=Region(Vector3DInt32(0,16,0), Vector3DInt32(32, 32, 32)); subdivisionReg[5]=Region(Vector3DInt32(32,16,0), Vector3DInt32(64, 32, 32)); subdivisionReg[6]=Region(Vector3DInt32(0,16,32), Vector3DInt32(32, 32, 64)); subdivisionReg[7]=Region(Vector3DInt32(32,16,32), Vector3DInt32(64, 32, 64)); /*subdivisionReg[8] = { Region(Vector3DInt32(0,0,0), Vector3DInt32(32, 16, 32)), Region(Vector3DInt32(32,0,0), Vector3DInt32(64, 16, 32)), Region(Vector3DInt32(0,0,32), Vector3DInt32(32, 16, 64)), Region(Vector3DInt32(32,0,32), Vector3DInt32(64, 16, 64)), Region(Vector3DInt32(0,16,0), Vector3DInt32(32, 32, 32)), Region(Vector3DInt32(32,16,0), Vector3DInt32(64, 32, 32)), Region(Vector3DInt32(0,16,32), Vector3DInt32(32, 32, 64)), Region(Vector3DInt32(32,16,32), Vector3DInt32(64, 32, 64)) };*/ //////////////////////////Fmod Initalize result = FMOD::System_Create(&fmodSys); // Create the main system object. ERRCHECK(result); result = fmodSys->init(100, FMOD_INIT_NORMAL, 0); // Initialize FMOD. ERRCHECK(result); //////创建声音 result = fmodSys->createSound("./soundFX/BG.mp3", FMOD_HARDWARE|FMOD_LOOP_NORMAL, 0, &soundBG); ERRCHECK(result); result = fmodSys->createSound("./soundFX/carve.mp3", FMOD_HARDWARE, 0, &soundCarve); ERRCHECK(result); /////////////播放背景音 result = fmodSys->playSound(FMOD_CHANNEL_FREE, soundBG, false, &channel); ERRCHECK(result); } QSize OpenGLWidget::minimumSizeHint() const { return QSize(50, 50); } QSize OpenGLWidget::sizeHint() const { return QSize(400, 400); } void OpenGLWidget::setRadius(int angle) { radius = angle; emit radiusChanged(angle); //updateGL(); update(); } SimpleVolume* OpenGLWidget::updateVolData(float fRadius, Vector3DInt32 intersectVoxel) { for (int i=0;i<8;i++) { std::cout<getVoxelAt(x,y,z)!=0) { //Store our current position as a vector... //Vector3DFloat v3dCurrentPos(x,y,z); Vector3DInt32 v3dCurrentPos(x,y,z); //And compute how far the current position is from the center of the volume float fDistToCenter = (v3dCurrentPos - intersectVoxel).length(); //If the current voxel is more than 'radius' units from the center //then we make it solid, otherwise we make it empty space. if(fDistToCenter >= fRadius) { volData->setVoxelAt(x, y, z, 255); } else { volData->setVoxelAt(x, y, z, 0); } } } } } } } //get the center of your knife!! //smoothRegion(*volData, PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(31, 31, 31))); //smoothRegion(*volData, PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(31, 31, 31))); //smoothRegion(*volData, PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(31, 31, 31))); return volData; } /* SimpleVolume* OpenGLWidget::updateVolDataKnife(Vector3DInt32 intersectVoxel) { for (int i=0;i<8;i++) { std::cout<getVoxelAt(x,y,z).getDensity()!=MaterialDensityPair44::getMinDensity()) { //Store our current position as a vector... //Vector3DFloat v3dCurrentPos(x,y,z); //Vector3DInt32 v3dCurrentPos(x,y,z); //And compute how far the current position is from the center of the volume //float fDistToCenter = (v3dCurrentPos - intersectVoxel).length(); //If the current voxel is more than 'radius' units from the center //then we make it solid, otherwise we make it empty space. //if(fDistToCenter >= fRadius) if((x>=intersectVoxel.getX()&&x<=intersectVoxel.getX()+2)&&(y>=intersectVoxel.getY()-1&&y<=intersectVoxel.getY()+1)&&(z>=intersectVoxel.getZ()-1&&x<=intersectVoxel.getZ()+1)) { uint8_t uDensity = MaterialDensityPair44::getMinDensity(); //Get the old voxel MaterialDensityPair44 voxel = volData->getVoxelAt(x,y,z); //Modify the density voxel.setDensity(uDensity); //Wrte the voxel value into the volume volData->setVoxelAt(x, y, z, voxel); } else { //volData->setVoxelAt(x,y,z, MaterialDensityPair44(uValue,MaterialDensityPair44::getMaxDensity())); //volData->setVoxelAt(x,y,z, MaterialDensityPair44(uValue, uValue > 0 ? MaterialDensityPair44::getMaxDensity() : MaterialDensityPair44::getMinDensity())); //volData->setVoxelAt(x,y,z, MaterialDensityPair44(uValue, MaterialDensityPair44::getMaxDensity())); //Our new density value uint8_t uDensity = MaterialDensityPair44::getMaxDensity(); //Get the old voxel MaterialDensityPair44 voxel = volData->getVoxelAt(x,y,z); //Modify the density voxel.setDensity(uDensity); //Wrte the voxel value into the volume volData->setVoxelAt(x, y, z, voxel); } } } } } } } //get the center of your knife!! //smoothRegion(*volData, PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(31, 31, 31))); //smoothRegion(*volData, PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(31, 31, 31))); //smoothRegion(*volData, PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(31, 31, 31))); return volData; } */ void OpenGLWidget::setSurfaceMeshToRender(SurfaceMesh* surfaceMesh,int i) { //Convenient access to the vertices and indices const vector& vecIndices = surfaceMesh->getIndices(); const vector& vecVertices = surfaceMesh->getVertices(); //Build an OpenGL index buffer //glGenBuffers(1, &indexBuffer[i]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer[i]);//GL_ELEMENT_ARRAY_BUFFER表示为索引数组 const GLvoid* pIndices = static_cast(&(vecIndices[0])); glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), pIndices, GL_STATIC_DRAW); //glBufferData函数从客户机内存复制到缓冲区对象 //Build an OpenGL vertex buffer //glGenBuffers(1, &vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[i]); const GLvoid* pVertices = static_cast(&(vecVertices[0])); glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(PositionMaterialNormal), pVertices, GL_STATIC_DRAW); m_uBeginIndex = 0; m_uEndIndex[i] = vecIndices.size(); } void OpenGLWidget::initializeGL() { //We need GLEW to access recent OpenGL functionality std::cout << "Initialising GLEW..."; //glewExperimental=GL_TRUE; GLenum result = glewInit(); if (result == GLEW_OK) { std::cout << "success" << std::endl; } else { /* Problem: glewInit failed, something is seriously wrong. */ std::cout << "failed" << std::endl; std::cout << "Initialising GLEW failed with the following error: " << glewGetErrorString(result) << std::endl; exit(EXIT_FAILURE); } //Print out some information about the OpenGL implementation. std::cout << "OpenGL Implementation Details:" << std::endl; if(glGetString(GL_VENDOR)) std::cout << "\tGL_VENDOR: " << glGetString(GL_VENDOR) << std::endl; if(glGetString(GL_RENDERER)) std::cout << "\tGL_RENDERER: " << glGetString(GL_RENDERER) << std::endl; if(glGetString(GL_VERSION)) std::cout << "\tGL_VERSION: " << glGetString(GL_VERSION) << std::endl; if(glGetString(GL_SHADING_LANGUAGE_VERSION)) std::cout << "\tGL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; //Check our version of OpenGL is recent enough. //We need at least 1.5 for vertex buffer objects, if (!GLEW_VERSION_1_5) { std::cout << "Error: You need OpenGL version 1.5 to run this example." << std::endl; exit(EXIT_FAILURE); } //Set up the clear colour glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearDepth(1.0f); //Enable the depth buffer glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); //glPolygonMode(GL_FRONT_AND_BACK ,GL_LINE );/////线框渲染模式 //Anable smooth lighting glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glShadeModel(GL_SMOOTH); //We'll be rendering with index/vertex arrays glEnableClientState(GL_VERTEX_ARRAY);//激活顶点数组 glEnableClientState(GL_NORMAL_ARRAY);//激活法线数组 glGenBuffers(8, indexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer[8]);//GL_ELEMENT_ARRAY_BUFFER表示为索引数组 glGenBuffers(8, vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[8]); volData = new SimpleVolume(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(63, 63, 63))); createCubeInVolume(volData, Vector3DInt32(1, 1, 1), Vector3DInt32(62, 30, 62)); generateMeshBasedOnflags(); } void OpenGLWidget::resizeGL(int w, int h) { //Setup the viewport glViewport(0, 0, w, h); //Set up the projection matrix glMatrixMode(GL_PROJECTION); glLoadIdentity(); float frustumSize = 32.0f; //Half the volume size float aspect = static_cast(width()) / static_cast(height()); glOrtho(frustumSize*aspect, -frustumSize*aspect, frustumSize, -frustumSize, 1.0, 1000); } void OpenGLWidget::paintGL() { //Clear the screen glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Set up the viewing transformation glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(-31.0f,-15.0f,-130.0f); //Centre volume and move back glRotatef(-m_xRotation, 0.0f, 1.0f, 0.0f); glRotatef(-m_yRotation, 1.0f, 0.0f, 0.0f); //glTranslatef(-31.0f,-15.0f,-31.0f); //Centre volume and move back //glScalef(0.5,0.5,0.5); for(int i=0;i<8;i++) { glMatrixMode(GL_MODELVIEW); //glLoadIdentity(); //glTranslatef(0.0f,0.0f,-100.0f); glPushMatrix(); Vector3DInt32 center=(subdivisionReg[i].getLowerCorner()+subdivisionReg[i].getUpperCorner())/2; glTranslatef(center.getX()-16,center.getY()-8,center.getZ()-16); //minus offset. //glRotatef(-m_xRotation, 0.0f, 1.0f, 0.0f); //glRotatef(-m_yRotation, 1.0f, 0.0f, 0.0f); /* glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glPushMatrix(); glTranslatef(-50.0f,-25.0f,-100.0f); //Centre volume and move back glRotatef(-m_xRotation, 0.0f, 1.0f, 0.0f); glRotatef(-m_yRotation, 1.0f, 0.0f, 0.0f); //Vector3DInt32 center=(subdivisionReg[i].getLowerCorner()+subdivisionReg[i].getUpperCorner())/2; //glTranslatef(center.getX(),center.getY(),center.getZ()); //glPopMatrix(); */ //Bind the index buffer glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer[i]); //再次调用glBindBuffer,表示这个缓冲区成为活动的缓冲区对象 //Bind the vertex buffer glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[i]); //if(subdivisionFlag[i]==true) { glVertexPointer(3, GL_FLOAT, sizeof(PositionMaterialNormal), 0); glNormalPointer(GL_FLOAT, sizeof(PositionMaterialNormal), (GLvoid*)12); } //gl*Pointer用于指定顶点数组数据,数据还在客户端 //glDrawElements(GL_TRIANGLES,m_uEndIndex - m_uBeginIndex,GL_UNSIGNED_INT,0); glDrawRangeElements(GL_TRIANGLES, m_uBeginIndex, m_uEndIndex[i]-1, m_uEndIndex[i] - m_uBeginIndex, GL_UNSIGNED_INT, 0); //数组中的数据被提取,发送到服务器,在pipeline中进行渲染 glPopMatrix(); GLenum errCode = glGetError(); if(errCode != GL_NO_ERROR) { //What has replaced getErrorString() in the latest OpenGL? std::cout << "OpenGL Error: " << errCode <pos(); m_LastFrameMousePos = m_CurrentMousePos; ///////////// GLfloat winX, winY, winZ; GLdouble posX, posY, posZ; GLint viewport[4]; GLdouble modelview[16]; GLdouble projection[16]; winX = GLfloat(event->x()); winY = height()- GLfloat(event->y()); glGetIntegerv(GL_VIEWPORT, viewport); // 得到的是最后一个设置视口的参数 glGetDoublev(GL_MODELVIEW_MATRIX, modelview); glGetDoublev(GL_PROJECTION_MATRIX, projection); //获取像素对应的前裁剪面的点坐标 bool bResult = gluUnProject(winX, winY, 0.0, modelview, projection, viewport, &posX, &posY, &posZ); Vector3DFloat nearPoint(posX,posY,posZ); //获取像素对应的后裁剪面的点坐标 bResult = gluUnProject(winX, winY, 1.0, modelview, projection, viewport, &posX, &posY, &posZ); Vector3DFloat farPoint(posX,posY,posZ); //cal the vector of ray Vector3DFloat direction(farPoint.getX()-nearPoint.getX(),farPoint.getY()-nearPoint.getY(),farPoint.getZ()-nearPoint.getZ()); //PolyVox::Vector3DFloat start(pos.x,pos.z,pos.z); //PolyVox::Vector3DFloat direction(dir.x, dir.y, dir.z); std::cout << nearPoint << std::endl; std::cout << direction << std::endl; direction.normalise(); direction *= 10000.0f; //Casts ray of length 1000 /*PolyVox::RaycastResult raycastResult; PolyVox::Raycast raycast(volData, nearPoint, direction, raycastResult); raycast.execute(); */ PolyVox::RaycastResult raycastResult=raycastWithDirection( &volData, nearPoint, direction, rayCallback); if(rayCallback.bFoundIntersection) { result = fmodSys->playSound(FMOD_CHANNEL_FREE, soundCarve, false, &channel); ERRCHECK(result); //std::cout << raycastResult.intersectionVoxel << std::endl; //int subVolID; for (int i=0;i<8;i++) { subdivisionFlag[i]=false; } whichAreaToRender(rayCallback.v3dLastPosition); cout<<"flag_set_finish"<> (volData, subdivisionReg[i], subdivisionMesh[i]); //MarchingCubesSurfaceExtractor< SimpleVolume > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); //CubicSurfaceExtractorWithNormals surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); //extractSurfaceForRegion() //surfaceExtractor->->extractSurfaceFor surfaceExtractor->execute(); /* mesh decimator on smooth surface is too slow std::cout << "before decimate"<< std::endl; SurfaceMesh decimatedMesh; MeshDecimator decimator(subdivisionMesh[i], &decimatedMesh,1.0f); decimator.execute(); std::cout << "decimation finished"<< std::endl; */ setSurfaceMeshToRender(subdivisionMesh[i],i); //paintGL(); //SurfaceMesh decimatedMesh; //MeshDecimator decimator(&mesh, &decimatedMesh); } //surfaceExtractor = new SurfaceExtractor (volData, volData->getEnclosingRegion(), subdivisionMesh[7]); //surfaceExtractor->execute(); //setSurfaceMeshToRender(subdivisionMesh[7],7); } } void OpenGLWidget::whichAreaToRender(Vector3DInt32 intersectionVoxel) { if (intersectionVoxel.getX()<=32&&intersectionVoxel.getX()>=0) { if (intersectionVoxel.getY()<=16&&intersectionVoxel.getY()>=0) { if (intersectionVoxel.getZ()<=32&&intersectionVoxel.getZ()>=0) { subdivisionFlag[0]=true;//need to update } else { subdivisionFlag[2]=true;//need to update } } else { if (intersectionVoxel.getZ()>32) { subdivisionFlag[6]=true;//need to update } else { subdivisionFlag[4]=true;//need to update } } } else { if (intersectionVoxel.getY()<16) { if (intersectionVoxel.getZ()<32) { subdivisionFlag[1]=true;//need to update } else { subdivisionFlag[3]=true;//need to update } } else { if (intersectionVoxel.getZ()>32) { subdivisionFlag[7]=true;//need to update } else { subdivisionFlag[5]=true;//need to update } } } } void OpenGLWidget::createSphereInVolume(SimpleVolume* volData,float fRadius) { //This vector hold the position of the center of the volume Vector3DFloat v3dVolCenter(volData->getWidth() / 2, volData->getHeight() / 2, volData->getDepth() / 2); //This three-level for loop iterates over every voxel in the volume for (int z = 0; z < volData->getWidth(); z++) { for (int y = 0; y < volData->getHeight(); y++) { for (int x = 0; x < volData->getDepth(); x++) { //Store our current position as a vector... Vector3DFloat v3dCurrentPos(x,y,z); //And compute how far the current position is from the center of the volume float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length(); uint8_t uVoxelValue = 0; //If the current voxel is less than 'radius' units from the center then we make it solid. if(fDistToCenter <= fRadius) { uVoxelValue = 255; } volData->setVoxelAt(x, y, z, uVoxelValue); } } } } void OpenGLWidget::createCubeInVolume(SimpleVolume* volData, Vector3DInt32 lowerCorner, Vector3DInt32 upperCorner) { //This three-level for loop iterates over every voxel between the specified corners for (int z = lowerCorner.getZ(); z <= upperCorner.getZ(); z++) { for (int y = lowerCorner.getY(); y <= upperCorner.getY(); y++) { for (int x = lowerCorner.getX() ; x <= upperCorner.getX(); x++) { volData->setVoxelAt(x, y, z, 255); } } } } void OpenGLWidget::mouseMoveEvent(QMouseEvent* event) { m_CurrentMousePos = event->pos(); QPoint diff = m_CurrentMousePos - m_LastFrameMousePos; m_xRotation += diff.x(); m_yRotation += diff.y(); m_LastFrameMousePos = m_CurrentMousePos; update(); } void OpenGLWidget::ERRCHECK(FMOD_RESULT result) { if (result != FMOD_OK) { WCHAR str[80]; //wsprintf(str, TEXT("hello %s", L"world"); wchar_t *wc=(wchar_t *)malloc( sizeof( wchar_t )); //char *c=(char*)FMOD_ErrorString(result); mbstowcs( wc, FMOD_ErrorString(result), MB_CUR_MAX ); //wcstombs( (char*)FMOD_ErrorString(result), wc, MB_CUR_MAX ); wsprintf(str,TEXT("FMOD error! (%d) %s\n"), result, wc); MessageBox(NULL, (str), TEXT(""), MB_OK); /* CString string; string.format("FMOD error! (%d)%s\n",result, FMOD_ErrorString(result)); //将变量组装到字符串中 MessageBox(string,"ERROR",MB_OKCANCEL); printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));*/ exit(-1); } }