paysages : Progress on bruneton atmospheric model (WIP).

git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@481 b1fd45b6-86a6-48da-8261-f70d1f35bdcc
This commit is contained in:
Michaël Lemaire 2012-12-15 10:14:57 +00:00 committed by ThunderK
parent 9da260a5e8
commit 70b42a33c0
5 changed files with 252 additions and 65 deletions

View file

@ -25,24 +25,28 @@ static const double Rt = 6420.0;
static const double RL = 6421.0;
static const double exposure = 0.4;
static const double ISun = 100.0;
static const double AVERAGE_GROUND_REFLECTANCE = 0.1;
#define RES_MU 128
#define RES_MU_S 32
#define RES_R 32
#define RES_NU 8
#define TRANSMITTANCE_INTEGRAL_SAMPLES 500
#define SKY_W 64
#define SKY_H 16
#define TRANSMITTANCE_W 256
#define TRANSMITTANCE_H 64
#define TRANSMITTANCE_INTEGRAL_SAMPLES 500
#define INSCATTER_INTEGRAL_SAMPLES 50
#define IRRADIANCE_INTEGRAL_SAMPLES 32
#define INSCATTER_SPHERICAL_INTEGRAL_SAMPLES 16
Texture2D* _transmittanceTexture = NULL;
Texture2D* _irrDeltaETexture = NULL;
Texture2D* _deltaETexture = NULL;
Texture2D* _irradianceTexture = NULL;
Texture3D* _inscatterTexture = NULL;
Texture3D* _deltaSMTexture = NULL;
Texture3D* _deltaSRTexture = NULL;
Texture3D* _deltaJTexture = NULL;
// Rayleigh
static const double HR = 8.0;
@ -369,29 +373,27 @@ static Color _hdr(Color c1, Color c2, Color c3)
static void _getMuMuSNu(double x, double y, double r, Color dhdH, double* mu, double* muS, double* nu)
{
x -= 0.5;
y -= 0.5;
#ifdef INSCATTER_NON_LINEAR
double d;
if (y < (double)(RES_MU) / 2.0)
{
d = 1.0 - y / ((double)(RES_MU) / 2.0 - 1.0);
d = 1.0 - y / ((double)(RES_MU) / 2.0);
d = min(max(dhdH.b, d * dhdH.a), dhdH.a * 0.999);
*mu = (Rg * Rg - r * r - d * d) / (2.0 * r * d);
*mu = min(*mu, -sqrt(1.0 - (Rg / r) * (Rg / r)) - 0.001);
}
else
{
double d = (y - (double)(RES_MU) / 2.0) / ((double)(RES_MU) / 2.0 - 1.0);
double d = (y - (double)(RES_MU) / 2.0) / ((double)(RES_MU) / 2.0);
d = min(max(dhdH.r, d * dhdH.g), dhdH.g * 0.999);
*mu = (Rt * Rt - r * r - d * d) / (2.0 * r * d);
}
*muS = fmod(x, (double)(RES_MU_S)) / ((double)(RES_MU_S) - 1.0);
*muS = fmod(x, (double)(RES_MU_S)) / ((double)(RES_MU_S));
/* paper formula :
* muS = -(0.6 + log(1.0 - muS * (1.0 - exp(-3.6)))) / 3.0; */
/* better formula */
*muS = tan((2.0 * (*muS) - 1.0 + 0.26) * 1.1) / tan(1.26 * 1.1);
*nu = -1.0 + floor(x / (double)(RES_MU_S)) / ((double)(RES_NU) - 1.0) * 2.0;
*nu = -1.0 + floor(x / (double)(RES_MU_S)) / ((double)(RES_NU)) * 2.0;
#else
mu = -1.0 + 2.0 * y / (float(RES_MU) - 1.0);
muS = mod(x, float(RES_MU_S)) / (float(RES_MU_S) - 1.0);
@ -400,6 +402,19 @@ static void _getMuMuSNu(double x, double y, double r, Color dhdH, double* mu, do
#endif
}
static void _getIrradianceUV(double r, double muS, double* uMuS, double* uR)
{
*uR = (r - Rg) / (Rt - Rg);
*uMuS = (muS + 0.2) / (1.0 + 0.2);
}
static Color _irradiance(Texture2D* sampler, double r, double muS)
{
double u, v;
_getIrradianceUV(r, muS, &u, &v);
return texture2DGetLinear(sampler, u, v);
}
/*********************** Texture precomputing ***********************/
static void _precomputeTransmittanceTexture()
@ -439,14 +454,13 @@ static void _precomputeIrrDeltaETexture()
trans = _transmittance(r, muS);
_getTransmittanceUV(r, muS, &u, &v);
//printf("%d %d -> %f %f -> %f %f %f\n", x, y, u, v, trans.r, trans.g, trans.b);
irr.r = trans.r * max(muS, 0.0);
irr.g = trans.g * max(muS, 0.0);
irr.b = trans.b * max(muS, 0.0);
irr.a = 1.0;
texture2DSetPixel(_irrDeltaETexture, x, y, irr);
texture2DSetPixel(_deltaETexture, x, y, irr);
}
}
}
@ -544,7 +558,7 @@ static void _inscatter1Prog(Texture3D* tex_rayleigh, Texture3D* tex_mie)
Color ray = COLOR_BLACK;
Color mie = COLOR_BLACK;
double mu, muS, nu;
_getMuMuSNu((double)x + 0.5, (double)y + 0.5, _r, _dhdH, &mu, &muS, &nu);
_getMuMuSNu((double)x, (double)y, _r, _dhdH, &mu, &muS, &nu);
_inscatter1(_r, mu, muS, nu, &ray, &mie);
/* store separately Rayleigh and Mie contributions, WITHOUT the phase function factor
* (cf "Angular precision") */
@ -552,7 +566,177 @@ static void _inscatter1Prog(Texture3D* tex_rayleigh, Texture3D* tex_mie)
texture3DSetPixel(tex_mie, x, y, _layer, mie);
}
}
/* TODO Iterate texture */
}
/*********************** inscatterS.glsl ***********************/
static Color _inscatterS(double r, double mu, double muS, double nu, int first)
{
Color raymie = COLOR_BLACK;
double dphi = M_PI / (double)(INSCATTER_SPHERICAL_INTEGRAL_SAMPLES);
double dtheta = M_PI / (double)(INSCATTER_SPHERICAL_INTEGRAL_SAMPLES);
r = clamp(r, Rg, Rt);
mu = clamp(mu, -1.0, 1.0);
muS = clamp(muS, -1.0, 1.0);
double var = sqrt(1.0 - mu * mu) * sqrt(1.0 - muS * muS);
nu = clamp(nu, muS * mu - var, muS * mu + var);
double cthetamin = -sqrt(1.0 - (Rg / r) * (Rg / r));
Vector3 v = vec3(sqrt(1.0 - mu * mu), 0.0, mu);
double sx = v.x == 0.0 ? 0.0 : (nu - muS * mu) / v.x;
Vector3 s = vec3(sx, sqrt(max(0.0, 1.0 - sx * sx - muS * muS)), muS);
/* integral over 4.PI around x with two nested loops over w directions (theta,phi) -- Eq (7) */
int itheta;
for (itheta = 0; itheta < INSCATTER_SPHERICAL_INTEGRAL_SAMPLES; ++itheta)
{
double theta = ((double)(itheta) + 0.5) * dtheta;
double ctheta = cos(theta);
double greflectance = 0.0;
double dground = 0.0;
Color gtransp = {0.0, 0.0, 0.0, 0.0};
if (ctheta < cthetamin)
{
/* if ground visible in direction w
* compute transparency gtransp between x and ground */
greflectance = AVERAGE_GROUND_REFLECTANCE / M_PI;
dground = -r * ctheta - sqrt(r * r * (ctheta * ctheta - 1.0) + Rg * Rg);
gtransp = _transmittance3(Rg, -(r * ctheta + dground) / Rg, dground);
}
int iphi;
for (iphi = 0; iphi < 2 * INSCATTER_SPHERICAL_INTEGRAL_SAMPLES; ++iphi)
{
double phi = ((double)(iphi) + 0.5) * dphi;
double dw = dtheta * dphi * sin(theta);
Vector3 w = vec3(cos(phi) * sin(theta), sin(phi) * sin(theta), ctheta);
double nu1 = v3Dot(s, w);
double nu2 = v3Dot(v, w);
double pr2 = _phaseFunctionR(nu2);
double pm2 = _phaseFunctionM(nu2);
/* compute irradiance received at ground in direction w (if ground visible) =deltaE */
Vector3 gnormal;
gnormal.x = dground * w.x / Rg;
gnormal.y = dground * w.y / Rg;
gnormal.z = r + dground * w.z / Rg;
Color girradiance = _irradiance(_deltaETexture, Rg, v3Dot(gnormal, s));
Color raymie1; /* light arriving at x from direction w */
/* first term = light reflected from the ground and attenuated before reaching x, =T.alpha/PI.deltaE */
raymie1.r = greflectance * girradiance.r * gtransp.r;
raymie1.g = greflectance * girradiance.g * gtransp.g;
raymie1.b = greflectance * girradiance.b * gtransp.b;
/* second term = inscattered light, =deltaS */
if (first)
{
/* first iteration is special because Rayleigh and Mie were stored separately,
* without the phase functions factors; they must be reintroduced here */
double pr1 = _phaseFunctionR(nu1);
double pm1 = _phaseFunctionM(nu1);
Color ray1 = _texture4D(_deltaSRTexture, r, w.z, muS, nu1);
Color mie1 = _texture4D(_deltaSMTexture, r, w.z, muS, nu1);
raymie.r += ray1.r * pr1 + mie1.r + pm1;
raymie.g += ray1.g * pr1 + mie1.g + pm1;
raymie.b += ray1.b * pr1 + mie1.b + pm1;
}
else
{
Color col = _texture4D(_deltaSRTexture, r, w.z, muS, nu1);
raymie1.r += col.r;
raymie1.g += col.g;
raymie1.b += col.b;
}
/* light coming from direction w and scattered in direction v
= light arriving at x from direction w (raymie1) * SUM(scattering coefficient * phaseFunction)
see Eq (7) */
raymie.r += raymie1.r * (betaR.r * exp(-(r - Rg) / HR) * pr2 + betaMSca.x * exp(-(r - Rg) / HM) * pm2) * dw;
raymie.g += raymie1.g * (betaR.g * exp(-(r - Rg) / HR) * pr2 + betaMSca.y * exp(-(r - Rg) / HM) * pm2) * dw;
raymie.b += raymie1.b * (betaR.b * exp(-(r - Rg) / HR) * pr2 + betaMSca.z * exp(-(r - Rg) / HM) * pm2) * dw;
}
}
/* output raymie = J[T.alpha/PI.deltaE + deltaS] (line 7 in algorithm 4.1) */
return raymie;
}
static void _jProg(Texture3D* result, int first)
{
int x, y;
for (x = 0; x < RES_MU_S * RES_NU; x++)
{
for (y = 0; y < RES_MU; y++)
{
Color raymie;
double mu, muS, nu;
_getMuMuSNu((double)x, (double)y, _r, _dhdH, &mu, &muS, &nu);
raymie = _inscatterS(_r, mu, muS, nu, first);
texture3DSetPixel(result, x, y, _layer, raymie);
}
}
}
/*********************** irradianceN.glsl ***********************/
void _irradianceNProg(Texture2D* tex, int first)
{
int x, y;
double dphi = M_PI / (double)(IRRADIANCE_INTEGRAL_SAMPLES);
double dtheta = M_PI / (double)(IRRADIANCE_INTEGRAL_SAMPLES);
for (x = 0; x < SKY_W; x++)
{
for (y = 0; y < SKY_H; y++)
{
double r, muS;
int iphi;
_getIrradianceRMuS((double)x / SKY_W, (double)y / SKY_H, &r, &muS);
Vector3 s = vec3(max(sqrt(1.0 - muS * muS), 0.0), 0.0, muS);
Color result = COLOR_BLACK;
/* integral over 2.PI around x with two nested loops over w directions (theta,phi) -- Eq (15) */
for (iphi = 0; iphi < 2 * IRRADIANCE_INTEGRAL_SAMPLES; ++iphi)
{
double phi = ((double)(iphi) + 0.5) * dphi;
int itheta;
for (itheta = 0; itheta < IRRADIANCE_INTEGRAL_SAMPLES / 2; ++itheta)
{
double theta = ((double)(itheta) + 0.5) * dtheta;
double dw = dtheta * dphi * sin(theta);
Vector3 w = vec3(cos(phi) * sin(theta), sin(phi) * sin(theta), cos(theta));
double nu = v3Dot(s, w);
if (first)
{
/* first iteration is special because Rayleigh and Mie were stored separately,
without the phase functions factors; they must be reintroduced here */
double pr1 = _phaseFunctionR(nu);
double pm1 = _phaseFunctionM(nu);
Color ray1 = _texture4D(_deltaSRTexture, r, w.z, muS, nu);
Color mie1 = _texture4D(_deltaSMTexture, r, w.z, muS, nu);
result.r += (ray1.r * pr1 + mie1.r * pm1) * w.z * dw;
result.g += (ray1.g * pr1 + mie1.g * pm1) * w.z * dw;
result.b += (ray1.b * pr1 + mie1.b * pm1) * w.z * dw;
}
else
{
Color col = _texture4D(_deltaSRTexture, r, w.z, muS, nu);
result.r += col.r * w.z * dw;
result.g += col.g * w.z * dw;
result.b += col.b * w.z * dw;
}
}
}
texture2DSetPixel(tex, x, y, result);
}
}
}
/*********************** Final getters ***********************/
@ -717,25 +901,25 @@ static Color _sunColor(Vector3 x, double t, Vector3 v, Vector3 s, double r, doub
}
else
{
Color transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : COLOR_WHITE; // T(x,xo)
double isun = step(cos(M_PI / 180.0), v3Dot(v, s)) * ISun; // Lsun
Color transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : COLOR_WHITE; /* T(x,xo) */
double isun = step(cos(M_PI / 180.0), v3Dot(v, s)) * ISun; /* Lsun */
transmittance.r *= isun;
transmittance.g *= isun;
transmittance.b *= isun;
transmittance.a *= isun;
return transmittance; // Eq (9)
return transmittance; /* Eq (9) */
}
}
/*********************** Cache methods ***********************/
static int _tryLoadCache2D(Texture2D* tex, const char* tag)
static int _tryLoadCache2D(Texture2D* tex, const char* tag, int order)
{
CacheFile* cache;
int xsize, ysize;
texture2DGetSize(tex, &xsize, &ysize);
cache = cacheFileCreateAccessor("atmo-br", "png", tag, xsize, ysize, 0);
cache = cacheFileCreateAccessor("atmo-br", "png", tag, xsize, ysize, 0, order);
if (cacheFileIsReadable(cache))
{
texture2DLoadFromFile(tex, cacheFileGetPath(cache));
@ -749,13 +933,13 @@ static int _tryLoadCache2D(Texture2D* tex, const char* tag)
}
}
static void _saveCache2D(Texture2D* tex, const char* tag)
static void _saveCache2D(Texture2D* tex, const char* tag, int order)
{
CacheFile* cache;
int xsize, ysize;
texture2DGetSize(tex, &xsize, &ysize);
cache = cacheFileCreateAccessor("atmo-br", "png", tag, xsize, ysize, 0);
cache = cacheFileCreateAccessor("atmo-br", "png", tag, xsize, ysize, 0, order);
if (cacheFileIsWritable(cache))
{
texture2DSaveToFile(tex, cacheFileGetPath(cache));
@ -763,13 +947,13 @@ static void _saveCache2D(Texture2D* tex, const char* tag)
cacheFileDeleteAccessor(cache);
}
static int _tryLoadCache3D(Texture3D* tex, const char* tag)
static int _tryLoadCache3D(Texture3D* tex, const char* tag, int order)
{
CacheFile* cache;
int xsize, ysize, zsize;
texture3DGetSize(tex, &xsize, &ysize, &zsize);
cache = cacheFileCreateAccessor("atmo-br", "png", tag, xsize, ysize, zsize);
cache = cacheFileCreateAccessor("atmo-br", "png", tag, xsize, ysize, zsize, order);
if (cacheFileIsReadable(cache))
{
texture3DLoadFromFile(tex, cacheFileGetPath(cache));
@ -783,13 +967,13 @@ static int _tryLoadCache3D(Texture3D* tex, const char* tag)
}
}
static void _saveCache3D(Texture3D* tex, const char* tag)
static void _saveCache3D(Texture3D* tex, const char* tag, int order)
{
CacheFile* cache;
int xsize, ysize, zsize;
texture3DGetSize(tex, &xsize, &ysize, &zsize);
cache = cacheFileCreateAccessor("atmo-br", "png", tag, xsize, ysize, zsize);
cache = cacheFileCreateAccessor("atmo-br", "png", tag, xsize, ysize, zsize, order);
if (cacheFileIsWritable(cache))
{
texture3DSaveToFile(tex, cacheFileGetPath(cache));
@ -809,34 +993,34 @@ void brunetonInit()
/* computes transmittance texture T (line 1 in algorithm 4.1) */
_transmittanceTexture = texture2DCreate(TRANSMITTANCE_W, TRANSMITTANCE_H);
if (!_tryLoadCache2D(_transmittanceTexture, "transmittance"))
if (!_tryLoadCache2D(_transmittanceTexture, "transmittance", 0))
{
_precomputeTransmittanceTexture();
_saveCache2D(_transmittanceTexture, "transmittance");
_saveCache2D(_transmittanceTexture, "transmittance", 0);
}
/* computes irradiance texture deltaE (line 2 in algorithm 4.1) */
_irrDeltaETexture = texture2DCreate(SKY_W, SKY_H);
if (!_tryLoadCache2D(_irrDeltaETexture, "irradianceDeltaE"))
_deltaETexture = texture2DCreate(SKY_W, SKY_H);
if (!_tryLoadCache2D(_deltaETexture, "irradianceDeltaE", 0))
{
_precomputeIrrDeltaETexture();
_saveCache2D(_irrDeltaETexture, "irradianceDeltaE");
_saveCache2D(_deltaETexture, "irradianceDeltaE", 0);
}
/* computes single scattering texture deltaS (line 3 in algorithm 4.1)
* Rayleigh and Mie separated in deltaSR + deltaSM */
_deltaSRTexture = texture3DCreate(RES_MU_S * RES_NU, RES_MU, RES_R);
_deltaSMTexture = texture3DCreate(RES_MU_S * RES_NU, RES_MU, RES_R);
if (!_tryLoadCache3D(_deltaSRTexture, "deltaSR") || !_tryLoadCache3D(_deltaSMTexture, "deltaSM"))
if (!_tryLoadCache3D(_deltaSRTexture, "deltaSR", 0) || !_tryLoadCache3D(_deltaSMTexture, "deltaSM", 0))
{
for (layer = 0; layer < RES_R; ++layer)
{
printf("%d\n", layer);
printf("deltaS %d\n", layer);
_setLayer(layer);
_inscatter1Prog(_deltaSRTexture, _deltaSMTexture);
}
_saveCache3D(_deltaSRTexture, "deltaSR");
_saveCache3D(_deltaSMTexture, "deltaSM");
_saveCache3D(_deltaSRTexture, "deltaSR", 0);
_saveCache3D(_deltaSMTexture, "deltaSM", 0);
}
/* copies deltaE into irradiance texture E (line 4 in algorithm 4.1) */
@ -846,7 +1030,7 @@ void brunetonInit()
/* copies deltaS into inscatter texture S (line 5 in algorithm 4.1) */
_inscatterTexture = texture3DCreate(RES_MU_S * RES_NU, RES_MU, RES_R);
if (!_tryLoadCache3D(_inscatterTexture, "inscatter"))
if (!_tryLoadCache3D(_inscatterTexture, "inscatter", 0))
{
for (x = 0; x < RES_MU_S * RES_NU; x++)
{
@ -861,35 +1045,31 @@ void brunetonInit()
}
}
}
_saveCache3D(_inscatterTexture, "inscatter");
_saveCache3D(_inscatterTexture, "inscatter", 0);
}
/* loop for each scattering order (line 6 in algorithm 4.1) */
for (order = 2; order <= 4; ++order) {
for (order = 2; order <= 4; ++order)
{
/* computes deltaJ (line 7 in algorithm 4.1) */
/*glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, deltaJTexture, 0);
glViewport(0, 0, RES_MU_S * RES_NU, RES_MU);
glUseProgram(jProg);
glUniform1f(glGetUniformLocation(jProg, "first"), order == 2 ? 1.0 : 0.0);
glUniform1i(glGetUniformLocation(jProg, "transmittanceSampler"), transmittanceUnit);
glUniform1i(glGetUniformLocation(jProg, "deltaESampler"), deltaEUnit);
glUniform1i(glGetUniformLocation(jProg, "deltaSRSampler"), deltaSRUnit);
glUniform1i(glGetUniformLocation(jProg, "deltaSMSampler"), deltaSMUnit);
for (int layer = 0; layer < RES_R; ++layer) {
setLayer(jProg, layer);
drawQuad();
}*/
_deltaJTexture = texture3DCreate(RES_MU_S * RES_NU, RES_MU, RES_R);
if (!_tryLoadCache3D(_deltaJTexture, "deltaJ", order))
{
for (layer = 0; layer < RES_R; ++layer)
{
_setLayer(layer);
_jProg(_deltaJTexture, order == 2);
}
_saveCache3D(_deltaJTexture, "deltaJ", order);
}
/* computes deltaE (line 8 in algorithm 4.1) */
/*glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, deltaETexture, 0);
glViewport(0, 0, SKY_W, SKY_H);
glUseProgram(irradianceNProg);
glUniform1f(glGetUniformLocation(irradianceNProg, "first"), order == 2 ? 1.0 : 0.0);
glUniform1i(glGetUniformLocation(irradianceNProg, "transmittanceSampler"), transmittanceUnit);
glUniform1i(glGetUniformLocation(irradianceNProg, "deltaSRSampler"), deltaSRUnit);
glUniform1i(glGetUniformLocation(irradianceNProg, "deltaSMSampler"), deltaSMUnit);
drawQuad();*/
_deltaETexture = texture2DCreate(SKY_W, SKY_H);
if (!_tryLoadCache2D(_deltaETexture, "deltaE", order))
{
_irradianceNProg(_deltaETexture, order == 2);
_saveCache2D(_deltaETexture, "deltaE", order);
}
/* computes deltaS (line 9 in algorithm 4.1) */
/*glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, deltaSRTexture, 0);
@ -925,11 +1105,11 @@ void brunetonInit()
drawQuad();
}
glDisable(GL_BLEND);*/
/* DEBUG */
break;
}
}
/* DEBUG */
exit(1);
}
Color brunetonGetSkyColor(AtmosphereDefinition* definition, Vector3 eye, Vector3 direction, Vector3 sun_position)

View file

@ -18,6 +18,8 @@ typedef struct
LightDefinition lights[MAX_SKYDOME_LIGHTS];
} AtmosphereRendererCache;
static int _inited = 0;
/******************** Definition ********************/
static void _validateDefinition(AtmosphereDefinition* definition)
{
@ -28,7 +30,12 @@ static AtmosphereDefinition* _createDefinition()
{
AtmosphereDefinition* result;
//brunetonInit(); /* DEBUG */
/* TODO Find a better place for this */
if (!_inited)
{
_inited = 1;
brunetonInit();
}
result = malloc(sizeof(AtmosphereDefinition));
result->model = ATMOSPHERE_MODEL_PREETHAM;

View file

@ -11,14 +11,14 @@ struct CacheFile
char* filepath;
};
CacheFile* cacheFileCreateAccessor(const char* module, const char* ext, const char* tag1, int tag2, int tag3, int tag4)
CacheFile* cacheFileCreateAccessor(const char* module, const char* ext, const char* tag1, int tag2, int tag3, int tag4, int tag5)
{
CacheFile* result;
result = (CacheFile*)malloc(sizeof(CacheFile));
result->filepath = malloc(sizeof(char) * 501);
snprintf(result->filepath, 500, "./cache/%s-%s-%d-%d-%d.%s", module, tag1, tag2, tag3, tag4, ext);
snprintf(result->filepath, 500, "./cache/%s-%s-%d-%d-%d-%d.%s", module, tag1, tag2, tag3, tag4, tag5, ext);
return result;
}

View file

@ -11,7 +11,7 @@ extern "C" {
typedef struct CacheFile CacheFile;
CacheFile* cacheFileCreateAccessor(const char* module, const char* ext, const char* tag1, int tag2, int tag3, int tag4);
CacheFile* cacheFileCreateAccessor(const char* module, const char* ext, const char* tag1, int tag2, int tag3, int tag4, int tag5);
void cacheFileDeleteAccessor(CacheFile* cache);
int cacheFileIsReadable(CacheFile* cache);
int cacheFileIsWritable(CacheFile* cache);

View file

@ -89,7 +89,7 @@ Color texture2DGetLinear(Texture2D* tex, double dx, double dy)
Color texture2DGetCubic(Texture2D* tex, double dx, double dy)
{
/* TODO */
return texture2DGetNearest(tex, dx, dy);
return texture2DGetLinear(tex, dx, dy);
}
void texture2DSaveToFile(Texture2D* tex, const char* filepath)
@ -188,7 +188,7 @@ Color texture3DGetLinear(Texture3D* tex, double dx, double dy, double dz)
Color texture3DGetCubic(Texture3D* tex, double dx, double dy, double dz)
{
/* TODO */
return texture3DGetNearest(tex, dx, dy, dz);
return texture3DGetLinear(tex, dx, dy, dz);
}
static Color _callbackTex3dSave(Texture3D* tex, int x, int y)