/* The ground uses indexed drawing to draw the ground in an efficient way. 2 buffers are created, one for the vertices and one for the indices which point to a specific vertex. */ Ground::Ground() { hmScale = glm::vec3(1000.f, 200.f, 1000.f); std::cout << loadGroundTexture("Models/sandGrass.jpg"); loadHeightMap("Models/test1.bmp"); std::cout << "height at 5, 5: " << getHeight(5.f, 5.f); }
/* ================ Terrain::init ================ */ bool Terrain::init( ID3D10Device* device, char* heightmapFilename, WCHAR* textureFilename ) { bool result; result = loadHeightMap(heightmapFilename); if (!result) { return false; } normalizeHeightMap(); result = calculateNormals(); if (!result) { return true; } calculateTextureCoordinates(); result = loadTexture(device, textureFilename); if (!result) { return false; } result = initBuffers(device); if (!result) { return false; } return true; }
// init data bool Terrain::init (const char *filename) { // try to load map printf ("\nLOADING TERRAIN...\n", filename); printf ("\tMap file: %s\n", filename); if (!loadHeightMap (filename)) return false; int v_index = 0; // index for vertex array int n_index = 0; // index for normal array float x, z; // temp coord SDL_LockSurface(map_h); size = map_h -> w; num_vert = (long) (map_h -> w * map_h -> h * 4 / (res * res)); vertex = new Vector[num_vert]; // allocate vertex memory texcoord = new TexCoord[num_vert]; // allocate texture memory num_normal = (long) (map_h -> w * map_h -> h / (res * res)); normal = new Vector[num_normal]; // allocate normal memory printf ("\tVertex num: %d\n", num_vert); // loop for init vertex for (int i = 0; i < map_h -> w; i += (int) res) { // width for (int j = 0; j < map_h -> h; j += (int) res) { // height for (int n_tri = 0; n_tri < 4; n_tri++) { // polygon // x, y x = (float) i + ( ( n_tri == 1 || n_tri == 2) ? res : 0.0f ); z = (float) j + ( ( n_tri == 2 || n_tri == 3) ? res : 0.0f ); // set vertex vertex[v_index].x = (x - ( map_h -> w / 2 )); vertex[v_index].z = (z - ( map_h -> h / 2 )); vertex[v_index].y = getHeightFromMap (x, z); // set texture coord texcoord[v_index].u = x / map_h -> w; texcoord[v_index].v = z / map_h -> h; v_index++; // go to next vertex } // calculate normal coord Vector ab, bc; vectorSubtract (vertex[v_index-3], vertex[v_index-2], ab); vectorSubtract (vertex[v_index-2], vertex[v_index-1], bc); crossProduct (ab, bc, normal[n_index]); normalize (normal[n_index]); n_index++; } } SDL_UnlockSurface(map_h); return true; }
HRESULT Heightmap::init(ID3D11Device* device,ID3D11DeviceContext* deviceContext,Shader* shader,char* heightMapPath, DWORD m, DWORD n, float dx) { HRESULT hr = S_OK; mDevice = device; mDeviceContext = deviceContext; mShader = shader; hr = D3DX11CreateShaderResourceViewFromFile(device,"../Textures/ggrass.dds",0,0,&mAlbedoMap,0); mNumRows = m; mNumCols = n; mCellSpacing = dx; mNumVertices = mNumRows*mNumCols; mNumFaces = (mNumRows-1)*(mNumCols-1)*2; mHeightOffset = -1.5; mHeightScale = 0.25; loadHeightMap(heightMapPath); smooth(); Vertex* vertexArray = new Vertex[mNumVertices]; float halfWidth = (mNumCols-1)*mCellSpacing*0.5f; float halfDepth = (mNumRows-1)*mCellSpacing*0.5f; float du = 1.0f / (mNumCols-1); float dv = 1.0f / (mNumRows-1); for(DWORD i = 0; i < mNumRows; ++i) { float z = halfDepth - i*dx; for(DWORD j = 0; j < mNumCols; ++j) { int vIndex = i*mNumCols+j; vertexArray[vIndex].pos = D3DXVECTOR3(-halfWidth + j*dx, mHeightmap[i*mNumCols+j]-5, z); vertexArray[vIndex].texC = D3DXVECTOR2(j*du, i*dv); vertexArray[vIndex].normal = D3DXVECTOR3(); } } CalculateNormals(vertexArray); InitBuffers(vertexArray); delete vertexArray; return hr; }
/* Main Loop * Open window with initial window size, title bar, * RGBA display mode, and handle input events. */ int main(int argc, char** argv) { srand(time(NULL)); glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize (1024, 768); glutCreateWindow (argv[0]); init(); loadHeightMap(argc,argv); calcSurfaceNormals(); calcVertexNormals(); calcVertexColour(0); glutReshapeFunc(reshape); glutDisplayFunc(display); glutKeyboardFunc (keyboard); glutMouseFunc (mouse); glutMotionFunc(up); glutMainLoop(); return 0; }
void Terrain::init() { // material material = new Material(v4(0.2), v4(0.7), v4(0.0), 0.5); // load & create shaders int shaderID = shaderManager->loadShader("Terrain", TERRAIN_VS_FILENAME, TERRAIN_FS_FILENAME); shader = shaderManager->getShader(shaderID); border_values_location = shader->getLocation("border_values"); border_widths_location = shader->getLocation("border_widths"); heightInterval_location = shader->getLocation("visibleHeightInterval"); // load heightmap int resolution_x = TERRAIN_RESOLUTION_X; int resolution_y = TERRAIN_RESOLUTION_Y; float size_x = TERRAIN_SIZE_X; float size_y = TERRAIN_SIZE_Y; float step_x =size_x/float(resolution_x); float step_y =size_y/float(resolution_y); red_x = 1.f/step_x; red_y = 1.f/step_y; loadHeightMap(HEIGHTMAP_SOURCE, resolution_x, resolution_y); // load textures loadTextures(TERRAIN_TEX_NAME, TERRAIN_TEX_COUNT); // shadow map shader->linkTexture(textureManager->getTexture(textureManager->shadowMapID)); LCmatrixLoc = shader->getLocation("LightMVPCameraVInverseMatrix"); shadowMappingEnabledLoc = shader->getLocation("shadowMappingEnabled"); fastModeLoc = shader->getLocation("fastMode"); LMV_CVImatrixLoc = shader->getLocation("LightMViewCameraViewInverseMatrix"); LPmatrixLoc = shader->getLocation("LightProjectionMatrix"); dim_x = resolution_x; dim_y = resolution_y; drawingMethod = GL_TRIANGLE_STRIP; // create grid of triangles glGenBuffers(1, &eboId); glGenBuffers(1, &vboId); int ch = 3; vertices = new GLfloat[dim_x*dim_y*ch]; normals = new GLfloat[dim_x*dim_y*ch]; texCoords = new GLfloat[dim_x*dim_y*2]; elements = new GLuint[(dim_x-1)*2*dim_y]; channels [INDEX] = 1; channels [VERTEX] = 3; channels [NORMAL] = 3; channels [TEXCOORD0] = 2; typeSizes [INDEX] = sizeof(GLuint); typeSizes [VERTEX] = sizeof(GLfloat); typeSizes [NORMAL] = sizeof(GLfloat); typeSizes [TEXCOORD0] = sizeof(GLfloat); glTypes [INDEX] = GL_UNSIGNED_INT; glTypes [VERTEX] = GL_FLOAT; glTypes [NORMAL] = GL_FLOAT; glTypes [TEXCOORD0] = GL_FLOAT; for (int k = 0; k < VBO_ATR_COUNT; k++){ sizes[k]=0; } sizes [INDEX] = (dim_x-1)*2*dim_y * channels[INDEX] * typeSizes[INDEX]; sizes [VERTEX] = dim_x * dim_y * channels[VERTEX] * typeSizes[VERTEX]; sizes [NORMAL] = dim_x * dim_y * channels[NORMAL] * typeSizes[NORMAL]; sizes [TEXCOORD0] = dim_x * dim_y * channels[TEXCOORD0]* typeSizes[TEXCOORD0]; offsets [INDEX] = 0; offsets [VERTEX] = 0; offsets [NORMAL] = offsets [VERTEX] + sizes [VERTEX]; offsets [TEXCOORD0] = offsets [NORMAL] + sizes [NORMAL]; int x,y,n; vboCount = 0; float tex_cnt_x = 100.f; float tex_cnt_y = 100.f; sz_x = size_x; sz_y = size_y; float sx2 = sz_x/2.f; float sy2 = sz_y/2.f; int hx, hy; for (x=0; x<dim_x; x++){ for (y=0; y<dim_y; y++){ vertices[(x*dim_y + y)*ch + 0] = x*step_x - sx2;//x vertices[(x*dim_y + y)*ch + 1] = getHeightAt(x,y);//height vertices[(x*dim_y + y)*ch + 2] = y*step_y - sy2;//y // normals v3 normal; normal.x = getHeightAt(x-1,y) - getHeightAt(x+1,y); normal.y = step_x; normal.z = getHeightAt(x,y-1) - getHeightAt(x,y+1); normal.normalize(); if (normal.y<0){ normal = -normal; } normals[(x*dim_y + y)*ch + 0] = normal.x; normals[(x*dim_y + y)*ch + 1] = normal.y; normals[(x*dim_y + y)*ch + 2] = normal.z; // texCoords texCoords[(x*dim_y + y)*2 + 0] = x * tex_cnt_x / dim_x; texCoords[(x*dim_y + y)*2 + 1] = y * tex_cnt_y / dim_y; vboCount += 3; } } int eli = 0; bool reverse = false; for (x=0; x<dim_x-1; x++){ if (!reverse){ for (y=0; y<dim_y; y++){ elements[eli] = (x+1)*dim_y + y; eli++; elements[eli] = (x)*dim_y + y; eli++; } } else { for (y=dim_y-1; y>=0; y--){ elements[eli] = (x)*dim_y + y; eli++; elements[eli] = (x+1)*dim_y + y; eli++; } } reverse = !reverse; } eboCount = eli; // total vbo buffer size int vboSize=0; for (int b = 0; b < VBO_ATR_COUNT; b++){ if (b!=INDEX){ vboSize+=sizes[b]; } } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizes[INDEX], elements, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, vboId); // alloc space glBufferData(GL_ARRAY_BUFFER, vboSize, 0, GL_STATIC_DRAW); // fill vertices glBufferSubData(GL_ARRAY_BUFFER, offsets[VERTEX], sizes[VERTEX], vertices); // fill normals glBufferSubData(GL_ARRAY_BUFFER, offsets[NORMAL], sizes[NORMAL], normals); // fill texcoords glBufferSubData(GL_ARRAY_BUFFER, offsets[TEXCOORD0], sizes[TEXCOORD0], texCoords); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); }
/// <summary> /// Crea la malla de un terreno en base a un Heightmap /// </summary> /// <param name="heightmapPath">Imagen de Heightmap</param> /// <param name="scaleXZ">Escala para los ejes X y Z</param> /// <param name="scaleY">Escala para el eje Y</param> /// <param name="center">Centro de la malla del terreno</param> void TgcSimpleTerrain::loadHeightmap(string heightmapPath, float scaleXZ, float scaleY, Vector3 center) { Device d3dDevice = GuiController::Instance.D3dDevice; this->center = center; //Dispose de VertexBuffer anterior, si habia if (!vbTerrain.Disposed()) { vbTerrain.Dispose(); } //cargar heightmap heightmapData = loadHeightMap(d3dDevice, heightmapPath); float width = (float)heightmapData.GetLength(0); float length = (float)heightmapData.GetLength(1); //Crear vertexBuffer int vertexSize = CustomVertex::PositionTextured::Size(); totalVertices = 2 * 3 * (heightmapData.GetLength(0) - 1) * (heightmapData.GetLength(1) - 1); vbTerrain.Create(d3dDevice, CustomVertex::PositionTextured::Size()*totalVertices, Usage_Dynamic | Usage_WriteOnly, CustomVertex::PositionTextured::Format(), Pool_Default); //Cargar vertices int dataIdx = 0; vector<CustomVertex::PositionTextured> data(totalVertices); center.X = center.X * scaleXZ - (width / 2) * scaleXZ; center.Y = center.Y * scaleY; center.Z = center.Z * scaleXZ - (length / 2) * scaleXZ; for (int i = 0; i < width - 1; i++) { for (int j = 0; j < length - 1; j++) { //Vertices Vector3 v1 = Vector3(center.X + i * scaleXZ, center.Y + heightmapData.GetItem(i, j) * scaleY, center.Z + j * scaleXZ); Vector3 v2 = Vector3(center.X + i * scaleXZ, center.Y + heightmapData.GetItem(i, j + 1) * scaleY, center.Z + (j + 1) * scaleXZ); Vector3 v3 = Vector3(center.X + (i + 1) * scaleXZ, center.Y + heightmapData.GetItem(i + 1, j) * scaleY, center.Z + j * scaleXZ); Vector3 v4 = Vector3(center.X + (i + 1) * scaleXZ, center.Y + heightmapData.GetItem(i + 1, j + 1) * scaleY, center.Z + (j + 1) * scaleXZ); //Coordendas de textura Vector2 t1 = Vector2(i / width, j / length); Vector2 t2 = Vector2(i / width, (j + 1) / length); Vector2 t3 = Vector2((i + 1) / width, j / length); Vector2 t4 = Vector2((i + 1) / width, (j + 1) / length); //Cargar triangulo 1 data[dataIdx] = CustomVertex::PositionTextured(v1, t1.X, t1.Y); data[dataIdx + 1] = CustomVertex::PositionTextured(v2, t2.X, t2.Y); data[dataIdx + 2] = CustomVertex::PositionTextured(v4, t4.X, t4.Y); //Cargar triangulo 2 data[dataIdx + 3] = CustomVertex::PositionTextured(v1, t1.X, t1.Y); data[dataIdx + 4] = CustomVertex::PositionTextured(v4, t4.X, t4.Y); data[dataIdx + 5] = CustomVertex::PositionTextured(v3, t3.X, t3.Y); dataIdx += 6; } } vbTerrain.SetData(&(data[0]), totalVertices*vertexSize, LockFlags_None); }
int main(int argc, char* argv[]) { //----------------------------------------------------------------------- // INITIALIZATION //----------------------------------------------------------------------- printf ("\n"); printf ("-----------------------------------\n"); printf ("CHAI 3D\n"); printf ("Demo: 20-map\n"); printf ("Copyright 2003-2010\n"); printf ("-----------------------------------\n"); printf ("\n\n"); printf ("Instructions:\n\n"); printf ("- Use left mouse button to rotate camera view. \n"); printf ("- Use right mouse button to control camera zoom. \n"); printf ("- Use haptic device and user switch to rotate \n"); printf (" camera or deform terrain. \n"); printf ("\n\n"); printf ("Keyboard Options:\n\n"); printf ("[1] - Texture (ON/OFF)\n"); printf ("[2] - Wireframe (ON/OFF)\n"); printf ("[x] - Exit application\n"); printf ("\n\n"); // parse first arg to try and locate resources resourceRoot = string(argv[0]).substr(0,string(argv[0]).find_last_of("/\\")+1); //----------------------------------------------------------------------- // 3D - SCENEGRAPH //----------------------------------------------------------------------- // create a new world. world = new cWorld(); // set the background color of the environment // the color is defined by its (R,G,B) components. world->setBackgroundColor(0.1, 0.1, 0.1); // create a camera and insert it into the virtual world camera = new cCamera(world); world->addChild(camera); // define a default position of the camera (described in spherical coordinates) cameraAngleH = 0; cameraAngleV = 45; cameraDistance = 1.8 * MESH_SCALE_SIZE; updateCameraPosition(); // set the near and far clipping planes of the camera // anything in front/behind these clipping planes will not be rendered camera->setClippingPlanes(0.01, 10.0); // create a light source and attach it to the camera light = new cLight(world); camera->addChild(light); // attach light to camera light->setEnabled(true); // enable light source light->setPos(cVector3d( 0.0, 0.3, 0.3)); // position the light source light->setDir(cVector3d(-1.0,-0.1, -0.1)); // define the direction of the light beam light->m_ambient.set(0.5, 0.5, 0.5); light->m_diffuse.set(0.8, 0.8, 0.8); light->m_specular.set(1.0, 1.0, 1.0); //----------------------------------------------------------------------- // 2D - WIDGETS //----------------------------------------------------------------------- // create a 2D bitmap logo logo = new cBitmap(); // add logo to the front plane camera->m_front_2Dscene.addChild(logo); // load a "chai3d" bitmap image file bool fileload; fileload = logo->m_image.loadFromFile(RESOURCE_PATH("resources/images/chai3d.bmp")); if (!fileload) { #if defined(_MSVC) fileload = logo->m_image.loadFromFile("../../../bin/resources/images/chai3d.bmp"); #endif } // position the logo at the bottom left of the screen (pixel coordinates) logo->setPos(10, 10, 0); // scale the logo along its horizontal and vertical axis logo->setZoomHV(0.4, 0.4); // here we replace all black pixels (0,0,0) of the logo bitmap // with transparent black pixels (0, 0, 0, 0). This allows us to make // the background of the logo look transparent. logo->m_image.replace( cColorb(0, 0, 0), // original RGB color cColorb(0, 0, 0, 0) // new RGBA color ); // enable transparency logo->enableTransparency(true); //----------------------------------------------------------------------- // HAPTIC DEVICES / TOOLS //----------------------------------------------------------------------- // create a haptic device handler handler = new cHapticDeviceHandler(); // get access to the first available haptic device cGenericHapticDevice* hapticDevice; handler->getDevice(hapticDevice, 0); // retrieve information about the current haptic device cHapticDeviceInfo info; if (hapticDevice) { info = hapticDevice->getSpecifications(); } // create a 3D tool and add it to the world tool = new cGeneric3dofPointer(world); // attach tool to camera camera->addChild(tool); // position tool workspace in front of camera (x-axis of camera reference pointing towards the viewer) tool->setPos(-cameraDistance, 0.0, 0.0); // connect the haptic device to the tool tool->setHapticDevice(hapticDevice); // initialize tool by connecting to haptic device tool->start(); // map the physical workspace of the haptic device to a larger virtual workspace. tool->setWorkspaceRadius(1.0); // define a radius for the tool (graphical display) tool->setRadius(0.03); // hide the device sphere. only show proxy. tool->m_deviceSphere->setShowEnabled(false); // set the physical readius of the proxy. proxyRadius = 0.0; tool->m_proxyPointForceModel->setProxyRadius(proxyRadius); tool->m_proxyPointForceModel->m_collisionSettings.m_checkBothSidesOfTriangles = false; //----------------------------------------------------------------------- // COMPOSE THE VIRTUAL SCENE //----------------------------------------------------------------------- // create a new mesh to display a height map object = new cMesh(world); world->addChild(object); // load default map loadHeightMap(); // read the scale factor between the physical workspace of the haptic // device and the virtual workspace defined for the tool double workspaceScaleFactor = tool->getWorkspaceScaleFactor(); // define a maximum stiffness that can be handled by the current // haptic device. The value is scaled to take into account the // workspace scale factor double stiffnessMax = info.m_maxForceStiffness / workspaceScaleFactor; object->setStiffness(0.5 * stiffnessMax, true); // create a small vertical white magnetic line that will be activated when the // user deforms the mesh. magneticLine = new cShapeLine(cVector3d(0,0,0), cVector3d(0,0,0)); world->addChild(magneticLine); magneticLine->m_ColorPointA.set(0.6, 0.6, 0.6); magneticLine->m_ColorPointB.set(0.6, 0.6, 0.6); magneticLine->setShowEnabled(false); // set haptic properties magneticLine->m_material.setStiffness(0.05 * stiffnessMax); magneticLine->m_material.setMagnetMaxForce(0.2 * info.m_maxForce); magneticLine->m_material.setMagnetMaxDistance(0.25); magneticLine->m_material.setViscosity(0.05 * info.m_maxLinearDamping); // create a haptic magnetic effect cEffectMagnet* newEffect = new cEffectMagnet(magneticLine); magneticLine->addEffect(newEffect); // disable haptic feedback for now magneticLine->setHapticEnabled(false); // create two sphere that will be added at both ends of the line sphereA = new cShapeSphere(0.02); sphereB = new cShapeSphere(0.02); world->addChild(sphereA); world->addChild(sphereB); sphereA->setShowEnabled(false); sphereB->setShowEnabled(false); // define some material properties for spheres cMaterial matSphere; matSphere.m_ambient.set(0.5, 0.2, 0.2); matSphere.m_diffuse.set(0.8, 0.4, 0.4); matSphere.m_specular.set(1.0, 1.0, 1.0); sphereA->setMaterial(matSphere); sphereB->setMaterial(matSphere); //----------------------------------------------------------------------- // OPEN GL - WINDOW DISPLAY //----------------------------------------------------------------------- // initialize GLUT glutInit(&argc, argv); // retrieve the resolution of the computer display and estimate the position // of the GLUT window so that it is located at the center of the screen int screenW = glutGet(GLUT_SCREEN_WIDTH); int screenH = glutGet(GLUT_SCREEN_HEIGHT); int windowPosX = (screenW - WINDOW_SIZE_W) / 2; int windowPosY = (screenH - WINDOW_SIZE_H) / 2; // initialize the OpenGL GLUT window glutInitWindowPosition(windowPosX, windowPosY); glutInitWindowSize(WINDOW_SIZE_W, WINDOW_SIZE_H); glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); glutCreateWindow(argv[0]); glutDisplayFunc(updateGraphics); glutMouseFunc(mouseClick); glutMotionFunc(mouseMove); glutKeyboardFunc(keySelect); glutReshapeFunc(resizeWindow); glutSetWindowTitle("CHAI 3D"); //----------------------------------------------------------------------- // START SIMULATION //----------------------------------------------------------------------- // simulation in now running simulationRunning = true; // create a thread which starts the main haptics rendering loop cThread* hapticsThread = new cThread(); hapticsThread->set(updateHaptics, CHAI_THREAD_PRIORITY_HAPTICS); // start the main graphics rendering loop glutMainLoop(); // close everything close(); // exit return (0); }