Normal mapping for generated planets (full shader mode only). Normal/baked shadow intensity is now consistent when changing planet texture size. Switched to 1024x1024 except for reduced detail mode. NB: texture debug dump requires new methods which aren't implemented for SDL, but is switched off.

git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@2881 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
Jens Ayton 2009-12-13 12:35:42 +00:00
parent cb41cf425d
commit 1c0251db3a
13 changed files with 504 additions and 109 deletions

View File

@ -1704,7 +1704,7 @@
1AD88FAF103F29D300AA36F4 /* oolite-options.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = "oolite-options.xcconfig"; path = "src/Cocoa/oolite-options.xcconfig"; sourceTree = "<group>"; };
1ADA564710CD68D800E891B8 /* OOStellarBody.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOStellarBody.h; sourceTree = "<group>"; };
1ADA576710CDB1C300E891B8 /* oolite-default-planet.vertex */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "oolite-default-planet.vertex"; sourceTree = "<group>"; };
1ADA576910CDB1C600E891B8 /* oolite-default-planet.fragment */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "oolite-default-planet.fragment"; sourceTree = "<group>"; };
1ADA576910CDB1C600E891B8 /* oolite-default-planet.fragment */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "oolite-default-planet.fragment"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.glsl; };
1ADA8AB10F42DBA80001BEC9 /* OODeepCopy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OODeepCopy.h; sourceTree = "<group>"; };
1ADA8AB20F42DBA80001BEC9 /* OODeepCopy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OODeepCopy.m; sourceTree = "<group>"; };
1ADBA54E0BD0F173008FC99C /* OOBasicMaterial.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOBasicMaterial.h; sourceTree = "<group>"; };

View File

@ -39,13 +39,29 @@
"planet-synthetic-macros" =
{
IS_OOLITE = 1;
OOSTD_DIFFUSE_AND_SPECULAR_MAP = 1;
OOSTD_DIFFUSE_MAP = 1;
OOSTD_NORMAL_AND_SPECULAR_MAP = 1;
OOSTD_CUBE_MAP = 0;
};
"moon-synthetic-macros" =
{
IS_OOLITE = 1;
OOSTD_DIFFUSE_MAP = 1;
OOSTD_NORMAL_AND_SPECULAR_MAP = 1;
OOSTD_CUBE_MAP = 0;
OOSTD_HARSH_MISTRESS = 1;
};
"planet-customized-macros" =
{
IS_OOLITE = 1;
OOSTD_DIFFUSE_MAP = 1;
OOSTD_CUBE_MAP = 0;
};
"moon-customized-macros" =
{
IS_OOLITE = 1;
OOSTD_DIFFUSE_MAP = 1;
OOSTD_CUBE_MAP = 0;
OOSTD_HARSH_MISTRESS = 1;
};
}

View File

@ -35,8 +35,8 @@
#ifndef OOSTD_NORMAL_AND_SPECULAR_MAP
#define OOSTD_NORMAL_AND_SPECULAR_MAP 0
#endif
#ifndef OOSTD_DIFFUSE_AND_SPECULAR_MAP
#define OOSTD_DIFFUSE_AND_SPECULAR_MAP 0
#ifndef OOSTD_HARSH_MISTRESS
#define OOSTD_HARSH_MISTRESS 0
#endif
@ -51,16 +51,37 @@ uniform sampler2D uIlluminationMap;
// Specular map parameters.
// NOTE: OOSTD_DIFFUSE_AND_SPECULAR_MAP is a temporary arrangement for dynamic planets.
// Separate OOSTD_SPECULAR_MAP is for testing in OpenGL Shader Builder, which doesnt deal with alpha channels sensibly.
#define USE_SPECULAR OOSTD_SPECULAR_MAP || OOSTD_NORMAL_AND_SPECULAR_MAP || OOSTD_DIFFUSE_AND_SPECULAR_MAP
#define USE_SPECULAR OOSTD_SPECULAR_MAP || OOSTD_NORMAL_AND_SPECULAR_MAP
#if (OOSTD_SPECULAR_MAP)
uniform sampler2D uSpecularMap;
#define SPECULAR_FACTOR (texture2D(uSpecularMap, texCoords).r)
#elif OOSTD_NORMAL_AND_SPECULAR_MAP
#define SPECULAR_FACTOR (normalMapSample.a)
#elif OOSTD_DIFFUSE_AND_SPECULAR_MAP
#define SPECULAR_FACTOR (diffuseMapSample.a)
#endif
// Normal map parameters.
#define USE_NORMAL_MAP OOSTD_NORMAL_MAP || OOSTD_NORMAL_AND_SPECULAR_MAP
#if USE_NORMAL_MAP
uniform sampler2D uNormalMap;
#endif
/* "Harsh shadow factor": degree to which normal map affects global diffuse light
with terminator and full shadow, as opposed to "local light" which is a normal
Lambertian light.
Terminator threshold: defines the width and colour of the terminator. The
numbers are cosines of the angle where it transitions to full light.
Both of these factors are ignored in simple shader mode.
*/
#if OOSTD_HARSH_MISTRESS
const float kHarshShadowFactor = 0.3;
const vec3 kTerminatorThreshold = vec3(0.08);
#else
const float kHarshShadowFactor = 0.05;
const vec3 kTerminatorThreshold = vec3(0.1, 0.105, 0.12);
#endif
@ -85,21 +106,38 @@ varying vec3 vCoords;
vec3 CalcDiffuseIntensity(in vec3 lightVector, in vec3 normal)
{
float LdotN = lightVector.z;
#if USE_NORMAL_MAP
float globalTerm = dot(normalize(mix(vec3(0.0, 0.0, 1.0), normal, kHarshShadowFactor)), lightVector);
#else
float globalTerm = LdotN;
#endif
#if OO_REDUCED_COMPLEXITY
// Hardish terminator.
float rev = min(1.0 - LdotN, 1.0);
float rev = min(1.0 - globalTerm, 1.0);
rev *= rev;
return vec3(1.0 - (rev * rev));
vec3 baseLight = vec3(1.0 - (rev * rev));
#else
// Hard terminator with slight redish-orange tinge. Note: threshold values are cosines.
return smoothstep(vec3(0.0), vec3(0.1, 0.105, 0.12), vec3(LdotN));
vec3 baseLight = smoothstep(vec3(0.0), kTerminatorThreshold, vec3(globalTerm));
#endif
#if USE_NORMAL_MAP
// Modulate with normal-mapped "local" illumination.
float local = dot(lightVector, normal);
local -= LdotN;
baseLight *= local + 1.0;
#endif
return baseLight;
}
vec3 CalcSpecularLight(in vec3 lightVector, in vec3 eyeVector, in float exponent, in vec3 normal, in vec3 lightColor)
{
#if OOSTD_NORMAL_MAP
#if USE_NORMAL_MAP
vec3 reflection = -reflect(lightVector, normal);
float NdotE = dot(normal, eyeVector);
#else
@ -110,6 +148,7 @@ vec3 CalcSpecularLight(in vec3 lightVector, in vec3 eyeVector, in float exponent
vec3 reflection = vec3(-lightVector.x, -lightVector.y, lightVector.z);
float NdotE = eyeVector.z;
#endif
float RdotE = max(dot(reflection, eyeVector), 0.0);
float intensity = pow(max(RdotE, 0.0), exponent);
@ -149,6 +188,10 @@ float TexLongitude(float z, float y)
void main()
{
vec3 totalColor = vec3(0);
vec3 coords = normalize(vCoords);
vec2 texCoords = TEXTURE_COORDS;
/* Fun sphere facts: the normalized coordinates of a point on a sphere at the origin
is equal to the object-space normal of the surface at that point.
Furthermore, we can construct the binormal (a vector pointing westward along the
@ -157,14 +200,12 @@ void main()
Hairy Ball Theorem.) The tangent (a vector north along the surface) is then the
inverse of the cross product of the normal and binormal.
*/
vec3 coords = normalize(vCoords);
#if USE_NORMAL_MAP
vec4 normalMapSample = texture2D(uNormalMap, texCoords);
vec3 normal = normalize(normalMapSample.xyz - vec3(0.5));
#else
vec3 normal = vec3(0, 0, 1);
vec3 binormal = cross(normal, vec3(0, 1, 0));
vec3 tangent = -cross(normal, binormal);
vec3 totalColor = vec3(0);
vec2 texCoords = TEXTURE_COORDS;
#endif
// Diffuse light
vec3 light1Vector = normalize(vLight1Vector);
@ -176,7 +217,7 @@ void main()
// Ambient light, biased towards blue.
vec3 ambientColor = diffuseColor;
#if !OO_REDUCED_COMPLEXITY
#if !OO_REDUCED_COMPLEXITY && !OOSTD_HARSH_MISTRESS
ambientColor *= vec3(0.8, 0.8, 1.0);
#endif
totalColor += AMBIENT_LIGHT * ambientColor;

View File

@ -162,12 +162,32 @@ extern int debug;
- (BOOL)pollShiftKey;
#ifndef NDEBUG
// General image-dumping method.
// General image-dumping methods.
- (void) dumpRGBAToFileNamed:(NSString *)name
bytes:(uint8_t *)bytes
width:(OOUInteger)width
height:(OOUInteger)height
rowBytes:(OOUInteger)rowBytes;
- (void) dumpRGBToFileNamed:(NSString *)name
bytes:(uint8_t *)bytes
width:(OOUInteger)width
height:(OOUInteger)height
rowBytes:(OOUInteger)rowBytes;
- (void) dumpGrayToFileNamed:(NSString *)name
bytes:(uint8_t *)bytes
width:(OOUInteger)width
height:(OOUInteger)height
rowBytes:(OOUInteger)rowBytes;
// Split alpha into separate file.
- (void) dumpRGBAToRGBFileNamed:(NSString *)rgbName
andGrayFileNamed:(NSString *)grayName
bytes:(uint8_t *)bytes
width:(OOUInteger)width
height:(OOUInteger)height
rowBytes:(OOUInteger)rowBytes;
#endif
@end

View File

@ -802,6 +802,116 @@ static NSString * kOOLogKeyDown = @"input.keyMapping.keyPress.keyDown";
[[bitmap representationUsingType:NSPNGFileType properties:nil] writeToFile:filepath atomically:YES];
}
}
- (void) dumpRGBToFileNamed:(NSString *)name
bytes:(uint8_t *)bytes
width:(OOUInteger)width
height:(OOUInteger)height
rowBytes:(OOUInteger)rowBytes
{
if (name == nil || bytes == NULL || width == 0 || height == 0 || rowBytes < width * 3) return;
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&bytes
pixelsWide:width
pixelsHigh:height
bitsPerSample:8
samplesPerPixel:3
hasAlpha:NO
isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bytesPerRow:rowBytes
bitsPerPixel:24];
if (bitmap != nil)
{
[bitmap autorelease];
NSString *filepath = [[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:name] stringByAppendingPathExtension:@"png"];
[[bitmap representationUsingType:NSPNGFileType properties:nil] writeToFile:filepath atomically:YES];
}
}
- (void) dumpGrayToFileNamed:(NSString *)name
bytes:(uint8_t *)bytes
width:(OOUInteger)width
height:(OOUInteger)height
rowBytes:(OOUInteger)rowBytes
{
if (name == nil || bytes == NULL || width == 0 || height == 0 || rowBytes < width) return;
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&bytes
pixelsWide:width
pixelsHigh:height
bitsPerSample:8
samplesPerPixel:1
hasAlpha:NO
isPlanar:NO
colorSpaceName:NSCalibratedWhiteColorSpace
bytesPerRow:rowBytes
bitsPerPixel:8];
if (bitmap != nil)
{
[bitmap autorelease];
NSString *filepath = [[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:name] stringByAppendingPathExtension:@"png"];
[[bitmap representationUsingType:NSPNGFileType properties:nil] writeToFile:filepath atomically:YES];
}
}
- (void) dumpRGBAToRGBFileNamed:(NSString *)rgbName
andGrayFileNamed:(NSString *)grayName
bytes:(uint8_t *)bytes
width:(OOUInteger)width
height:(OOUInteger)height
rowBytes:(OOUInteger)rowBytes
{
if ((rgbName == nil && grayName == nil) || bytes == NULL || width == 0 || height == 0 || rowBytes < width * 4) return;
uint8_t *rgbBytes, *rgbPx, *grayBytes, *grayPx, *srcPx;
OOUInteger x, y;
rgbPx = rgbBytes = malloc(width * height * 3);
if (rgbBytes == NULL) return;
grayPx = grayBytes = malloc(width * height);
if (grayBytes == NULL)
{
free(rgbBytes);
return;
}
for (y = 0; y < height; y++)
{
srcPx = bytes + rowBytes * y;
for (x = 0; x < width; x++)
{
*rgbPx++ = *srcPx++;
*rgbPx++ = *srcPx++;
*rgbPx++ = *srcPx++;
*grayPx++ = *srcPx++;
}
}
[self dumpRGBToFileNamed:rgbName
bytes:rgbBytes
width:width
height:height
rowBytes:width * 3];
[self dumpGrayToFileNamed:grayName
bytes:grayBytes
width:width
height:height
rowBytes:width];
free(rgbBytes);
free(grayBytes);
}
#endif

View File

@ -26,7 +26,7 @@ MA 02110-1301, USA.
#if NEW_PLANETS
#define SHADY_PLANETS 1
#define SHADY_PLANETS !NO_SHADERS
#import "OOPlanetDrawable.h"
@ -407,14 +407,9 @@ static OOColor *ColorWithHSBColorAndAlpha(Vector c, float a)
}
[_planetDrawable renderOpaqueParts];
if (_atmosphereDrawable != nil)
if (0)//(_atmosphereDrawable != nil)
{
// Disable Z testing and writing to avoid Z-fighting
OOGL(glDisable(GL_DEPTH_TEST));
OOGL(glDepthMask(GL_FALSE));
[_atmosphereDrawable renderOpaqueParts];
OOGL(glEnable(GL_DEPTH_TEST));
OOGL(glDepthMask(GL_TRUE));
}
if ([UNIVERSE wireframeGraphics]) GLDebugWireframeModeOff();
@ -498,6 +493,7 @@ static OOColor *ColorWithHSBColorAndAlpha(Vector c, float a)
}
#else
OOTexture *diffuseMap = nil;
OOTexture *normalMap = nil;
NSDictionary *macros = nil;
NSDictionary *materialDefaults = [ResourceManager materialDefaults];
#if !NO_SHADERS
@ -515,7 +511,9 @@ static OOColor *ColorWithHSBColorAndAlpha(Vector c, float a)
}
else
{
diffuseMap = [OOPlanetTextureGenerator planetTextureWithInfo:_materialParameters];
[OOPlanetTextureGenerator generatePlanetTexture:&diffuseMap
secondaryTexture:(shaderLevel == SHADERS_FULL) ? &normalMap : NULL
withInfo:_materialParameters];
if (shadersOn) macros = [materialDefaults oo_dictionaryForKey:@"planet-synthetic-macros"];
textureName = @"dynamic";
}
@ -525,7 +523,7 @@ static OOColor *ColorWithHSBColorAndAlpha(Vector c, float a)
if (shadersOn)
{
NSMutableDictionary *config = [[[materialDefaults oo_dictionaryForKey:@"planet-material"] mutableCopy] autorelease];
[config setObject:[NSArray arrayWithObjects:diffuseMap, nil] forKey:@"_oo_texture_objects"];
[config setObject:[NSArray arrayWithObjects:diffuseMap, normalMap, nil] forKey:@"_oo_texture_objects"];
material = [OOShaderMaterial shaderMaterialWithName:textureName
configuration:config
macros:macros

View File

@ -223,7 +223,6 @@ END:
if (success)
{
NSString *name = [NSString stringWithFormat:@"atmosphere-%u-%u-new", _seed.high, _seed.low];
OOLog(@"planetTex.temp", [NSString stringWithFormat:@"Saving generated texture to file %@.", name]);
[[UNIVERSE gameView] dumpRGBAToFileNamed:name
bytes:buffer

View File

@ -28,22 +28,25 @@ MA 02110-1301, USA.
#import "OOTextureGenerator.h"
#import "OOMaths.h"
@class OOPlanetNormalMapGenerator;
@interface OOPlanetTextureGenerator: OOTextureGenerator
{
@private
float _landFraction;
FloatRGB _landColor;
FloatRGB _seaColor;
FloatRGB _polarLandColor;
FloatRGB _polarSeaColor;
unsigned _width, _height;
RANROTSeed _seed;
float _landFraction;
FloatRGB _landColor;
FloatRGB _seaColor;
FloatRGB _polarLandColor;
FloatRGB _polarSeaColor;
RANROTSeed _seed;
OOPlanetNormalMapGenerator *_nMapGenerator;
OOUInteger _planetScale;
}
- (id) initWithPlanetInfo:(NSDictionary *)planetInfo;
+ (OOTexture *) planetTextureWithInfo:(NSDictionary *)planetInfo;
//+ (void) generatePlanetTexture:(OOTexture **)texture secondaryTexture:(OOTexture **)secondaryTexture forShaderLevel:(OOShaderSetting)shaderLevel;
+ (BOOL) generatePlanetTexture:(OOTexture **)texture secondaryTexture:(OOTexture **)secondaryTexture withInfo:(NSDictionary *)planetInfo;
@end

View File

@ -27,26 +27,56 @@ MA 02110-1301, USA.
#define DEBUG_DUMP ( 0 && !defined(NDEBUG))
#define DISABLE_SPECULAR ( 0 && DEBUG_DUMP) // No transparency in debug dump to make life easier.
#import "OOPlanetTextureGenerator.h"
#import "OOCollectionExtractors.h"
#import "OOColor.h"
#import "OOTexture.h"
#import "Universe.h"
#if DEBUG_DUMP
#import "Universe.h"
#import "MyOpenGLView.h"
#endif
#define PLANET_TEXTURE_OPTIONS (kOOTextureMinFilterLinear | kOOTextureMagFilterLinear | kOOTextureRepeatS | kOOTextureNoShrink)
enum
{
kNoiseBufferSize = 128
};
@interface OOPlanetTextureGenerator (Private)
- (NSString *) cacheKeyForType:(NSString *)type;
- (OOTextureGenerator *) normalMapGenerator; // Must be called before generator is enqueued for rendering.
@end
/* The planet generator actually generates two textures when shaders are
active, but the texture loader interface assumes we only load/generate
one texture per loader. Rather than complicate that, we use a mock
generator for the normal/light map.
*/
@interface OOPlanetNormalMapGenerator: OOTextureGenerator
{
@private
NSString *_cacheKey;
RANROTSeed _seed;
}
- (id) initWithCacheKey:(NSString *)cacheKey seed:(RANROTSeed)seed;
- (void) completeWithData:(void *)data width:(unsigned)width height:(unsigned)height;
@end
static FloatRGB FloatRGBFromDictColor(NSDictionary *dictionary, NSString *key);
static void FillNoiseBuffer(float *noiseBuffer, RANROTSeed seed);
@ -58,9 +88,14 @@ static FloatRGB Blend(float fraction, FloatRGB a, FloatRGB b);
//static FloatRGBA PolarMix(float q, float maxQ, FloatRGB cloudColor, float alpha);
static FloatRGBA PlanetMix(float q, float maxQ, FloatRGB landColor, FloatRGB seaColor, FloatRGB paleLandColor, FloatRGB paleSeaColor);
#define PLANET_ASPECT_RATIO 1 // Ideally, aspect ratio would be 2:1 - keeping it as 1:1 for now - Kaks 20091211
#define PLANET_HEIGHT 512
#define PLANET_WIDTH (PLANET_HEIGHT * PLANET_ASPECT_RATIO)
enum
{
kPlanetScale = 3,
kPlanetAspectRatio = 1, // Ideally, aspect ratio would be 2:1 - keeping it as 1:1 for now - Kaks 20091211
kPlanetScaleOffset = 8 - kPlanetAspectRatio
};
@implementation OOPlanetTextureGenerator
@ -75,8 +110,15 @@ static FloatRGBA PlanetMix(float q, float maxQ, FloatRGB landColor, FloatRGB sea
_polarSeaColor = FloatRGBFromDictColor(planetInfo, @"polar_sea_color");
[[planetInfo objectForKey:@"noise_map_seed"] getValue:&_seed];
_width = PLANET_WIDTH;
_height = PLANET_HEIGHT;
if ([UNIVERSE reducedDetail])
{
_planetScale = 2; // 512x512
}
else
{
_planetScale = 3; // 1024x1024
}
}
return self;
@ -97,6 +139,36 @@ static FloatRGBA PlanetMix(float q, float maxQ, FloatRGB landColor, FloatRGB sea
}
+ (BOOL) generatePlanetTexture:(OOTexture **)texture secondaryTexture:(OOTexture **)secondaryTexture withInfo:(NSDictionary *)planetInfo
{
NSParameterAssert(texture != NULL);
OOPlanetTextureGenerator *diffuseGen = [[[self alloc] initWithPlanetInfo:planetInfo] autorelease];
if (diffuseGen == nil) return NO;
if (secondaryTexture != NULL)
{
OOTextureGenerator *normalGen = [diffuseGen normalMapGenerator];
if (normalGen == nil) return NO;
*secondaryTexture = [OOTexture textureWithGenerator:normalGen];
if (*secondaryTexture == nil) return NO;
}
*texture = [OOTexture textureWithGenerator:diffuseGen];
return *texture != nil;
}
- (void) dealloc
{
DESTROY(_nMapGenerator);
[super dealloc];
}
- (NSString *) descriptionComponents
{
return [NSString stringWithFormat:@"seed: %u,%u", _seed.high, _seed.low];
@ -105,14 +177,21 @@ static FloatRGBA PlanetMix(float q, float maxQ, FloatRGB landColor, FloatRGB sea
- (uint32_t) textureOptions
{
return kOOTextureMinFilterLinear | kOOTextureMagFilterLinear | kOOTextureRepeatS | kOOTextureNoShrink;
return PLANET_TEXTURE_OPTIONS;
}
- (NSString *) cacheKey
{
return [NSString stringWithFormat:@"OOPlanetTextureGenerator-base\n\n%u,%u/%g/%u,%u/%f,%f,%f/%f,%f,%f/%f,%f,%f/%f,%f,%f",
_width, _height, _landFraction, _seed.high, _seed.low,
return [self cacheKeyForType:(_nMapGenerator == nil) ? @"diffuse-baked" : @"diffuse-raw"];
}
- (NSString *) cacheKeyForType:(NSString *)type
{
return [NSString stringWithFormat:@"OOPlanetTextureGenerator-%@@%u\n\n%u,%u/%g/%u,%u/%f,%f,%f/%f,%f,%f/%f,%f,%f/%f,%f,%f",
type, _planetScale,
width, height, _landFraction, _seed.high, _seed.low,
_landColor.r, _landColor.g, _landColor.b,
_seaColor.r, _seaColor.g, _seaColor.b,
_polarLandColor.r, _polarLandColor.g, _polarLandColor.b,
@ -120,6 +199,16 @@ static FloatRGBA PlanetMix(float q, float maxQ, FloatRGB landColor, FloatRGB sea
}
- (OOTextureGenerator *) normalMapGenerator
{
if (_nMapGenerator == nil)
{
_nMapGenerator = [[OOPlanetNormalMapGenerator alloc] initWithCacheKey:[self cacheKeyForType:@"normal"] seed:_seed];
}
return _nMapGenerator;
}
- (BOOL)getResult:(void **)outData
format:(OOTextureDataFormat *)outFormat
width:(uint32_t *)outWidth
@ -152,18 +241,27 @@ static FloatRGBA PlanetMix(float q, float maxQ, FloatRGB landColor, FloatRGB sea
OOLog(@"planetTex.temp", @"Started generator %@", self);
BOOL success = NO;
BOOL generateNormalMap = (_nMapGenerator != nil);
uint8_t *buffer = NULL, *px = NULL;
uint8_t *nBuffer = NULL, *npx = NULL;
float *accBuffer = NULL;
float *randomBuffer = NULL;
width = _width;
height = _height;
height = 1 << (_planetScale + kPlanetScaleOffset);
width = height * kPlanetAspectRatio;
buffer = malloc(4 * width * height);
if (buffer == NULL) goto END;
px = buffer;
if (generateNormalMap)
{
nBuffer = malloc(4 * width * height);
if (nBuffer == NULL) goto END;
npx = nBuffer;
}
accBuffer = calloc(sizeof (float), width * height);
if (accBuffer == NULL) goto END;
@ -172,7 +270,7 @@ static FloatRGBA PlanetMix(float q, float maxQ, FloatRGB landColor, FloatRGB sea
FillNoiseBuffer(randomBuffer, _seed);
// Generate basic Perlin noise.
unsigned octave = 8 * PLANET_ASPECT_RATIO;
unsigned octave = 8 * kPlanetAspectRatio;
float scale = 0.5f;
while (octave < height)
{
@ -194,6 +292,8 @@ static FloatRGBA PlanetMix(float q, float maxQ, FloatRGB landColor, FloatRGB sea
*/
FloatRGB paleSeaColor = Blend(0.45, _polarSeaColor, Blend(0.7, _seaColor, _landColor));
float normalScale = 1 << _planetScale;
if (!generateNormalMap) normalScale *= 3.0f;
unsigned x, y;
FloatRGBA color;
@ -213,34 +313,47 @@ static FloatRGBA PlanetMix(float q, float maxQ, FloatRGB landColor, FloatRGB sea
yW = QFactor(accBuffer, x - 1, y, width, height, poleValue, seaBias);
yE = QFactor(accBuffer, x + 1, y, width, height, poleValue, seaBias);
norm = vector_normal(make_vector(24.0f * (yW - yE), 24.0f * (yS - yN), 2.0f));
color = PlanetMix(q, _landFraction, _landColor, _seaColor, _polarLandColor, paleSeaColor);
/* Terrain shading
was: _powf(norm.z, 3.2). Changing exponent to 3 makes very
little difference, other than being faster.
norm = vector_normal(make_vector(normalScale * (yW - yE), normalScale * (yS - yN), 1.0f));
if (generateNormalMap)
{
shade = 1.0f;
FIXME: need to work out a decent way to scale this with texture
size, so overall darkness is constant. As an experiment, I used
a size of 128 << k and shade = pow(norm.z, k + 1); this was
better, but still darker at smaller resolutions.
*/
shade = norm.z * norm.z * norm.z;
// Flatten in the sea.
norm = OOVectorInterpolate(norm, kBasisZVector, color.a);
// Put norm in normal map, scaled from [-1..1] to [0..255].
*npx++ = 127.5f * (-norm.y + 1.0f);
*npx++ = 127.5f * (norm.x + 1.0f);
*npx++ = 127.5f * (norm.z + 1.0f);
*npx++ = 255.0f * color.a; // Specular channel.
}
else
{
/* Terrain shading
was: _powf(norm.z, 3.2). Changing exponent to 3 makes very
little difference, other than being faster.
FIXME: need to work out a decent way to scale this with texture
size, so overall darkness is constant. Should probably be based
on normalScale.
*/
shade = norm.z * norm.z * norm.z;
/* We don't want terrain shading in the sea. The alpha channel
of color is a measure of "seaishness" for the specular map,
so we can recycle that to avoid branching.
*/
shade = color.a + (1.0f - color.a) * shade;
}
/* We don't want terrain shading in the sea. The alpha channel
of color is a measure of "seaishness" for the specular map,
so we can recycle that to avoid branching.
*/
shade = color.a + (1.0f - color.a) * shade;
*px++ = 255.0f * color.r * shade;
*px++ = 255.0f * color.g * shade;
*px++ = 255.0f * color.b * shade;
*px++ = 255 * color.r * shade;
*px++ = 255 * color.g * shade;
*px++ = 255 * color.b * shade;
#if DISABLE_SPECULAR
*px++ = 255;
#else
*px++ = 255 * color.a;
#endif
*px++ = 0; // FIXME: light map goes here.
}
}
@ -250,22 +363,32 @@ static FloatRGBA PlanetMix(float q, float maxQ, FloatRGB landColor, FloatRGB sea
END:
free(accBuffer);
free(randomBuffer);
if (success) data = buffer;
else free(buffer);
if (success)
{
data = buffer;
[_nMapGenerator completeWithData:nBuffer width:width height:height];
}
else
{
free(buffer);
free(nBuffer);
}
DESTROY(_nMapGenerator);
OOLog(@"planetTex.temp", @"Completed generator %@ %@successfully", self, success ? @"" : @"un");
#if DEBUG_DUMP
if (success)
{
NSString *name = [NSString stringWithFormat:@"planet-%u-%u-new", _seed.high, _seed.low];
OOLog(@"planetTex.temp", [NSString stringWithFormat:@"Saving generated texture to file %@.", name]);
[[UNIVERSE gameView] dumpRGBAToFileNamed:name
bytes:buffer
width:width
height:height
rowBytes:width * 4];
NSString *diffuseName = [NSString stringWithFormat:@"planet-%u-%u-diffuse-new", _seed.high, _seed.low];
NSString *lightsName = [NSString stringWithFormat:@"planet-%u-%u-lights-new", _seed.high, _seed.low];
[[UNIVERSE gameView] dumpRGBAToRGBFileNamed:diffuseName
andGrayFileNamed:lightsName
bytes:buffer
width:width
height:height
rowBytes:width * 4];
}
#endif
}
@ -281,7 +404,7 @@ static FloatRGB Blend(float fraction, FloatRGB a, FloatRGB b)
{
fraction * a.r + prime * b.r,
fraction * a.g + prime * b.g,
fraction * a.b + prime * b.b,
fraction * a.b + prime * b.b
};
}
@ -296,11 +419,9 @@ static FloatRGBA PlanetMix(float q, float maxQ, FloatRGB landColor, FloatRGB sea
#define COASTLINE_PORTION (1.0f / RECIP_COASTLINE_PORTION)
#define SHALLOWS (2.0f * COASTLINE_PORTION) // increased shallows area.
#define RECIP_SHALLOWS (1.0f / SHALLOWS)
#define BEACH_SPECULAR_FACTOR (0.9f) // Portion of specular transition that occurs in paleSeaColor/landColor transition (rest is in paleSeaColor/seaColor transition)
#define SHALLOWS_SPECULAR_FACTOR (1.0f - BEACH_SPECULAR_FACTOR)
const FloatRGB white = { 1.0f, 1.0f, 1.0f };
FloatRGB result;
FloatRGB diffuse;
float specular = 0.0f;
// Offset to reduce coastline-lowering effect of r2823 coastline smoothing improvement.
@ -308,42 +429,42 @@ static FloatRGBA PlanetMix(float q, float maxQ, FloatRGB landColor, FloatRGB sea
if (q <= 0.0f)
{
// Below datum - sea.
if (q > -SHALLOWS)
{
// Coastal waters
result = Blend(-q * RECIP_SHALLOWS, seaColor, paleSeaColor);
/* specular = -(q * RECIP_SHALLOWS) * SHALLOWS_SPECULAR_FACTOR + BEACH_SPECULAR_FACTOR;
specular = specular * specular * specular;*/
specular = 1.0f;
// Coastal waters.
diffuse = Blend(-q * RECIP_SHALLOWS, seaColor, paleSeaColor);
}
else
{
// Open sea
result = seaColor;
specular = 1.0f;
// Open sea.
diffuse = seaColor;
}
}
else if (q > 1.0f)
{
result = white;
specular = 1.0f;
}
else if (q < COASTLINE_PORTION)
{
// Coastline
result = Blend(q * RECIP_COASTLINE_PORTION, landColor, paleSeaColor);
// Coastline.
diffuse = Blend(q * RECIP_COASTLINE_PORTION, landColor, paleSeaColor);
specular = (1.0f - (q * RECIP_COASTLINE_PORTION));
specular = specular * specular * specular;
}
else if (q > 1.0f)
{
// High up - snow-capped peaks.
diffuse = white;
}
else if (q > hi)
{
result = Blend((q - hi) * ih, white, paleLandColor); // Snow-capped peaks
diffuse = Blend((q - hi) * ih, white, paleLandColor); // Snowline.
}
else
{
result = Blend((hi - q) * oh, landColor, paleLandColor);
// Normal land.
diffuse = Blend((hi - q) * oh, landColor, paleLandColor);
}
return (FloatRGBA){ result.r, result.g, result.b, specular };
return (FloatRGBA){ diffuse.r, diffuse.g, diffuse.b, specular };
}
@ -420,3 +541,79 @@ static float QFactor(float *accbuffer, int x, int y, unsigned width, unsigned he
return q;
}
@implementation OOPlanetNormalMapGenerator
- (id) initWithCacheKey:(NSString *)cacheKey seed:(RANROTSeed)seed
{
if ((self = [super init]))
{
_cacheKey = [cacheKey copy];
_seed = seed;
}
return self;
}
- (void) dealloc
{
DESTROY(_cacheKey);
[super dealloc];
}
- (NSString *) cacheKey
{
return _cacheKey;
}
- (uint32_t) textureOptions
{
return PLANET_TEXTURE_OPTIONS;
}
- (BOOL) enqueue
{
/* This generator doesn't do any work, so it doesn't need to be queued
at the normal time.
(The alternative would be for it to block a work thread waiting for
the real generator to complete, which seemed silly.)
*/
return YES;
}
- (void) loadTexture
{
// Do nothing.
}
- (void) completeWithData:(void *)data_ width:(unsigned)width_ height:(unsigned)height_
{
data = data_;
width = width_;
height = height_;
format = kOOTextureDataRGBA;
// Enqueue so superclass can apply texture options and so forth.
[super enqueue];
#if DEBUG_DUMP
NSString *normalName = [NSString stringWithFormat:@"planet-%u-%u-normal-new", _seed.high, _seed.low];
NSString *specularName = [NSString stringWithFormat:@"planet-%u-%u-specular-new", _seed.high, _seed.low];
[[UNIVERSE gameView] dumpRGBAToRGBFileNamed:normalName
andGrayFileNamed:specularName
bytes:data
width:width
height:height
rowBytes:width * 4];
#endif
}
@end

View File

@ -56,7 +56,6 @@
#import "OOMacroOpenGL.h"
#import "OOCPUInfo.h"
#import "OOCache.h"
#import "OOAsyncWorkManager.h"
/* Texture caching:
@ -344,7 +343,7 @@ static BOOL sRectangleTextureAvailable;
+ (id) textureWithGenerator:(OOTextureGenerator *)generator
{
if (generator == nil) return nil;
if (![[OOAsyncWorkManager sharedAsyncWorkManager] addTask:generator priority:kOOAsyncPriorityMedium])
if (![generator enqueue])
{
OOLog(@"planetTex.temp", @"Failed to queue generator %@!", generator);
return nil;

View File

@ -73,4 +73,7 @@ typedef struct
// Key for in-memory cache; nil for no cache.
- (NSString *) cacheKey;
// For use by OOTexture.
- (BOOL) enqueue;
@end

View File

@ -47,6 +47,7 @@ SOFTWARE.
*/
#import "OOTextureGenerator.h"
#import "OOAsyncWorkManager.h"
@implementation OOTextureGenerator
@ -74,4 +75,10 @@ SOFTWARE.
return nil;
}
- (BOOL) enqueue
{
return [[OOAsyncWorkManager sharedAsyncWorkManager] addTask:self priority:kOOAsyncPriorityMedium];
}
@end

View File

@ -194,12 +194,14 @@
const OOPlanetDataLevel *data = &kPlanetData[_lod];
OO_ENTER_OPENGL();
OOGL(glPushAttrib(GL_ENABLE_BIT));
OOGL(glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT));
OOGL(glShadeModel(GL_SMOOTH));
if (_isAtmosphere)
{
OOGL(glEnable(GL_BLEND));
OOGL(glDisable(GL_DEPTH_TEST));
OOGL(glDepthMask(GL_FALSE));
}
else
{