void Blendmap::Generate (Heightmap *rootHm, int lodLevel, float hmScale, float hmOffset) { Heightmap *heightmap = rootHm->GetLevel(-lodLevel); // Allocate the blendmap image AlphaImage *bm = new AlphaImage; bm->Alloc (heightmap->w-1, heightmap->h-1); // texture dimensions have to be power-of-two Blendmap::GeneratorInfo *gi = generatorInfo; // Calculate blend factors using the function parameters and heightmap input: for (int y=0;y<bm->h;y++) { for (int x=0;x<bm->w;x++) { float h = (heightmap->at (x,y) - hmOffset) / hmScale; float factor=1.0f; if(h < gi->minHeight - gi->minHeightFuzzy) { bm->at (x,y) = 0.0f; continue; } else if (gi->minHeightFuzzy > 0.0f && h < gi->minHeight + gi->minHeightFuzzy) factor = (h - (gi->minHeight - gi->minHeightFuzzy)) / (2.0f * gi->minHeightFuzzy); if(h > gi->maxHeight + gi->maxHeightFuzzy) { bm->at (x,y) = 0.0f; continue; } else if (gi->maxHeightFuzzy > 0.0f && h > gi->maxHeight - gi->maxHeightFuzzy) factor *= ((gi->maxHeight + gi->maxHeightFuzzy) - h) / (2.0f * gi->maxHeightFuzzy); float norm_y = 0.0f; if (heightmap->normalData) { uchar *cnorm = heightmap->GetNormal (x,y); norm_y = cnorm[1] / 255.0f * 2.0f - 1.0f; if (norm_y > 1.0f) norm_y = 1.0f; } else { Vector3 tangent, binormal; CalculateTangents(heightmap, x,y,tangent,binormal); Vector3 normal = tangent.cross(binormal); normal.ANormalize(); norm_y = normal.y; } // flatness=dotproduct of surface normal with up vector float slope = 1.0f - fabs(norm_y); if (slope < gi->minSlope - gi->minSlopeFuzzy) { bm->at (x,y) = 0.0f; continue; } else if (gi->minSlopeFuzzy > 0.0f && slope < gi->minSlope + gi->minSlopeFuzzy) factor *= (h - (gi->minSlope - gi->minSlopeFuzzy)) / ( 2.0f * gi->minSlopeFuzzy); if (slope > gi->maxSlope + gi->maxSlopeFuzzy) { bm->at (x,y) = 0.0f; continue; } else if (gi->maxSlopeFuzzy > 0.0f && slope > gi->maxSlope - gi->maxSlopeFuzzy) factor *= ((gi->maxSlope + gi->maxSlopeFuzzy) - h) / (2.0f * gi->maxSlopeFuzzy); factor *= gi->coverage; factor *= (rand () < gi->noise * RAND_MAX) ? 0.0f : 1.0f; bm->at (x,y) = factor; } } BlendmapFilter(bm); image = bm; }
Lightmap::Lightmap(Heightmap *orghm, int level, LightingInfo *li) { int startTicks = SDL_GetTicks(); tilesize.x = orghm->w-1; tilesize.y = orghm->h-1; name = "lightmap"; Heightmap *hm = orghm->GetLevel(-level); int w=hm->w-1; float org2c = w/float(orghm->w-1); float c2org = (float)(orghm->w-1)/w; float *centerhm = new float[w*w]; Vector3 *shading = new Vector3[w*w]; for (int y=0;y<w;y++) for (int x=0;x<w;x++) { centerhm[y*w+x] = hm->scale * 0.25f * ( (int)hm->at(x,y)+ (int)hm->at(x+1,y)+ (int)hm->at(x,y+1) + (int)hm->at(x+1,y+1) ) + hm->offset; shading[y*w+x] = li->ambient; } uchar *lightMap = new uchar[w*w]; int lightIndex = 0; for (std::vector<StaticLight>::const_iterator l=li->staticLights.begin();l!=li->staticLights.end();++l) { memset(lightMap, 255, w*w); // 255 is lit, 0 is unlit int lightx = (int)(l->position.x / hm->squareSize); int lighty = (int)(l->position.z / hm->squareSize); for (int y=0;y<w;y++) { for (int x=0;x<w;x++) { if (!lightMap[y*w+x]) // shadowed pixels can't shadow other pixels continue; if (x==lightx && y==lighty) continue; float dx = lightx-x; float dy = lighty-y; float h = centerhm[y*w+x]; float dh = l->position.y-h; float len = sqrtf(dx*dx+dy*dy); const float step = 5.0f; float invLength2d = step/len; dx *= invLength2d; dy *= invLength2d; dh *= invLength2d; float px = x + dx, py = y + dy; h += dh; while (px >= 0.0f && px < w && py >= 0.0f && py < w && len >= 0.0f) { int index = (int)py * w + (int)px; if (centerhm[index] > h + 2.0f) { lightMap[y*w+x]=0; break; } px += dx; py += dy; h += dh; len -= step; } } } BlurGrayscaleImage(w,w,lightMap); char sm_fn[64]; SNPRINTF(sm_fn, sizeof(sm_fn), "shadowmap%d.bmp", lightIndex++); SaveImage(sm_fn, 1, IL_UNSIGNED_BYTE, w,w, lightMap); for (int y=0;y<w;y++) { for (int x=0;x<w;x++) { if (!lightMap[y*w+x]) continue; Vector3 wp((x+0.5f)*hm->squareSize,centerhm[y*w+x],(y+0.5f)*hm->squareSize); wp = l->position - wp; uchar* normal = hm->GetNormal (x,y); Vector3 normv((2 * (int)normal[0] - 256)/255.0f, (2 * (int)normal[1] - 256)/255.0f, (2 * (int)normal[2] - 256)/255.0f); wp.Normalize(); float dot = wp.dot(normv); if(dot < 0.0f) dot = 0.0f; if(dot > 1.0f) dot = 1.0f; dot *= lightMap[y*w+x]*(1.0f/255.0f); shading[y*w+x] += l->color * dot; } } } delete[] lightMap; shadingTex.Bind(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); uchar *shadingTexData=new uchar[w*w*3], *td = shadingTexData; for(int y=0;y<w;y++) { for (int x=0;x<w;x++) { shadingTexData[(y*w+x)*3+0] = (uchar)(min(1.0f, shading[y*w+x].x) * 255); shadingTexData[(y*w+x)*3+1] = (uchar)(min(1.0f, shading[y*w+x].y) * 255); shadingTexData[(y*w+x)*3+2] = (uchar)(min(1.0f, shading[y*w+x].z) * 255); } } SaveImage ("lightmap.png", 3, IL_UNSIGNED_BYTE, w,w, shadingTexData); gluBuild2DMipmaps(GL_TEXTURE_2D, 3, w,w, GL_RGB, GL_UNSIGNED_BYTE, shadingTexData); delete[] shadingTexData; id = shadingTex; delete[] shading; delete[] centerhm; int numTicks = SDL_GetTicks() - startTicks; d_trace ("Lightmap generation: %2.3f seconds\n", numTicks * 0.001f); }
Lightmap::Lightmap(Heightmap *orghm, int level, int shadowLevelDif, LightingInfo *li) { const spring_time startTicks = spring_gettime(); tilesize.x = orghm->w-1; tilesize.y = orghm->h-1; name = "lightmap"; Heightmap *hm; int w; for(;;) { hm = orghm->GetLevel(-level); w=hm->w-1; GLint maxw; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxw); if (w > maxw) level ++; else break; } shadowLevelDif=0; Heightmap *shadowhm = orghm->GetLevel(-(level+shadowLevelDif)); int shadowScale=1<<shadowLevelDif; int shadowW=shadowhm->w-1; assert (w/shadowW == shadowScale); //float org2c = w/float(orghm->w-1); //float c2org = (float)(orghm->w-1)/w; float *centerhm = new float[w*w]; Vector3 *shading = new Vector3[w*w]; for (int y=0;y<w;y++) for (int x=0;x<w;x++) { centerhm[y*w+x] =/* hm->scale * */ 0.25f * ( (int)hm->at(x,y)+ (int)hm->at(x+1,y)+ (int)hm->at(x,y+1) + (int)hm->at(x+1,y+1) ); //+ hm->offset; shading[y*w+x] = li->ambient; } uchar *lightMap = new uchar[shadowW*shadowW]; for (std::vector<StaticLight>::const_iterator l=li->staticLights.begin();l!=li->staticLights.end();++l) { float lightx; float lighty; if (l->directional) { lightx = l->position.x; lighty = l->position.y; } else { lightx = (int)(l->position.x / shadowhm->squareSize); lighty = (int)(l->position.z / shadowhm->squareSize); } CalculateShadows(lightMap, shadowW, lightx, lighty, l->position.y, centerhm, w, shadowScale, l->directional); for (int y=0;y<w;y++) { for (int x=0;x<w;x++) { if (!lightMap[(y*shadowW+x)/shadowScale]) continue; Vector3 wp; if (l->directional) wp = l->position; else wp = l->position - Vector3((x+0.5f)*hm->squareSize,centerhm[y*w+x],(y+0.5f)*hm->squareSize); uchar* normal = hm->GetNormal (x,y); Vector3 normv((2 * (int)normal[0] - 256)/255.0f, (2 * (int)normal[1] - 256)/255.0f, (2 * (int)normal[2] - 256)/255.0f); wp.ANormalize(); float dot = wp.dot(normv); if(dot < 0.0f) dot = 0.0f; if(dot > 1.0f) dot = 1.0f; dot *= lightMap[(y*shadowW+x)/shadowScale]*(1.0f/255.0f); shading[y*w+x] += l->color * dot; } } } delete[] lightMap; glGenTextures(1,&shadingTex); glBindTexture (GL_TEXTURE_2D, shadingTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); uchar *shadingTexData=new uchar[w*w*4]; for(int y=0;y<w;y++) { for (int x=0;x<w;x++) { shadingTexData[(y*w+x)*4+0] = (uchar)(min(1.0f, shading[y*w+x].x) * 255); shadingTexData[(y*w+x)*4+1] = (uchar)(min(1.0f, shading[y*w+x].y) * 255); shadingTexData[(y*w+x)*4+2] = (uchar)(min(1.0f, shading[y*w+x].z) * 255); shadingTexData[(y*w+x)*4+3] = CReadMap::EncodeHeight(centerhm[w*y+x]); } } SaveImage ("lightmap.png", 4, IL_UNSIGNED_BYTE, w,w, shadingTexData); glBuildMipmaps(GL_TEXTURE_2D, 4, w,w, GL_RGBA, GL_UNSIGNED_BYTE, shadingTexData); delete[] shadingTexData; id = shadingTex; delete[] shading; delete[] centerhm; const spring_duration numTicks = spring_gettime() - startTicks; d_trace ("Lightmap generation: %2.3f seconds\n", spring_tomsecs(numTicks) * 0.001f); }
void RenderDataManager::InitializeNodeNormalMap(TQuad* q, int cfgNormalMapLevel) { QuadRenderData* rd = q->renderData; if (q->isLeaf()) { if (rd->normalMap) { glDeleteTextures(1, &rd->normalMap); rd->normalMap = 0; rd->normalMapW = 0; } return; } // find the right level heightmap to generate the normal map from Heightmap* hm = roothm; int level = 0; for (; hm->highDetail; hm = hm->highDetail, level++) if (level == q->depth + cfgNormalMapLevel) break; // calculate dimensions const int scale = 1 << (level - q->depth); size_t w = QUAD_W * scale + 1; const size_t h = w; const int startx = q->hmPos.x * scale; // use power-of-two texture sizes if required size_t texw = 1; //if (GLEW_ARB_texture_non_power_of_two) texw = w; //else while (texw < w) texw *= 2; // if not yet created, create a texture for it GLuint texture; if (rd->normalMap && (rd->normalMapW == w) && (rd->normalMapTexWidth == texw)) { texture = rd->normalMap; glBindTexture(GL_TEXTURE_2D, texture); } else { if (rd->normalMap) glDeleteTextures(1,&rd->normalMap); glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); rd->normalMap = texture; rd->normalMapW = w; rd->normalMapTexWidth = texw; } // allocate temporary storage for normals uchar* normals = new uchar[texw*texw*3]; // calculate normals for (size_t y=0; y<h; y++) { const uchar* src = hm->GetNormal(startx, y + q->hmPos.y * scale); memcpy(&normals [3 * y * texw], src, 3 * w); } // fill texture glTexImage2D(GL_TEXTURE_2D, 0, 3, texw,texw,0, GL_RGB, GL_UNSIGNED_BYTE, normals); delete[] normals; }