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:
parent
cb41cf425d
commit
1c0251db3a
@ -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>"; };
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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 doesn’t 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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -73,4 +73,7 @@ typedef struct
|
||||
// Key for in-memory cache; nil for no cache.
|
||||
- (NSString *) cacheKey;
|
||||
|
||||
// For use by OOTexture.
|
||||
- (BOOL) enqueue;
|
||||
|
||||
@end
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user