paysages3d/src/render/preview/AtmosphereColorPreviewRenderer.cpp

193 lines
3.9 KiB
C++

#include "AtmosphereColorPreviewRenderer.h"
#include "SoftwareRenderer.h"
#include "AtmosphereRenderer.h"
#include "AtmosphereResult.h"
#include "CameraDefinition.h"
#include "SurfaceMaterial.h"
#include "Scenery.h"
#include "BasePreview.h"
/*
* Atmosphere previews.
*/
typedef struct
{
Vector3 location;
double size;
} Mount;
#define MOUNTS_COUNT 11
static Mount MOUNTS[MOUNTS_COUNT] = {
{
{2.0, 0.0, -6.0}, 4.0
},
{
{-1.5, 0.0, -8.0}, 4.0
},
{
{3.0, 0.0, -10.0}, 6.0
},
{
{-8.0, 0.0, -15.0}, 6.0
},
{
{10.0, 0.0, -20.0}, 6.0
},
{
{-6.0, 0.0, -30.0}, 8.0
},
{
{15.0, 0.0, -40.0}, 8.0
},
{
{-20.0, 0.0, -50.0}, 8.0
},
{
{10.0, 0.0, -60.0}, 10.0
},
{
{-5.0, 0.0, -80.0}, 10.0
},
{
{30.0, 0.0, -100.0}, 10.0
},
};
static SurfaceMaterial MOUNT_MATERIAL(Color(0.4, 0.4, 0.4, 1.0));
static inline int _rayIntersectsTriangle(Vector3 p, Vector3 d, Vector3 v0, Vector3 v1, Vector3 v2, Vector3* hit)
{
Vector3 e1, e2, h, s, q;
double a, f, u, v, t;
e1 = v1.sub(v0);
e2 = v2.sub(v0);
h = d.crossProduct(e2);
a = e1.dotProduct(h);
if (a > -0.00001 && a < 0.00001)
{
return 0;
}
f = 1.0 / a;
s = p.sub(v0);
u = f * s.dotProduct(h);
if (u < 0.0 || u > 1.0)
{
return 0;
}
q = s.crossProduct(e1);
v = f * d.dotProduct(q);
if (v < 0.0 || u + v > 1.0)
{
return 0;
}
t = f * e2.dotProduct(q);
if (t > 0.00001)
{
*hit = p.add(d.scale(t));
return 1;
}
else
{
return 0;
}
}
static inline int _checkHitMountain(Vector3 eye, Vector3 direction, Mount mount, Vector3* hit)
{
Vector3 v0 = mount.location;
Vector3 v1 = mount.location;
Vector3 v2 = mount.location;
v0.x -= mount.size;
v1.x += mount.size;
v2.y += mount.size;
return _rayIntersectsTriangle(eye, direction, v0, v1, v2, hit);
}
static inline int _checkHitGround(Vector3 eye, Vector3 direction, Vector3* hit)
{
if (direction.y > -0.0001)
{
return 0;
}
else
{
hit->x = eye.x - direction.x * eye.y / direction.y;
hit->y = 0.0;
hit->z = eye.z - direction.z * eye.y / direction.y;
return 1;
}
}
static inline int _checkHit(Vector3 eye, Vector3 direction, Vector3* hit, Vector3* normal)
{
int i;
for (i = 0; i < MOUNTS_COUNT; i++)
{
if (_checkHitMountain(eye, direction, MOUNTS[i], hit))
{
*normal = VECTOR_SOUTH;
return 1;
}
}
*normal = VECTOR_UP;
return _checkHitGround(eye, direction, hit);
}
AtmosphereColorPreviewRenderer::AtmosphereColorPreviewRenderer(AtmosphereDefinition* definition, double heading):
definition(definition), heading(heading)
{
getScenery()->getCamera()->setLocation(Vector3(0.0, 7.0, 0.0));
render_camera->setLocation(Vector3(0.0, 7.0, 0.0));
disableClouds();
}
void AtmosphereColorPreviewRenderer::bindEvent(BasePreview* preview)
{
preview->configHdrToneMapping(true);
preview->configScaling(0.5, 5.0, 0.5, 2.5);
}
void AtmosphereColorPreviewRenderer::updateEvent()
{
getScenery()->setAtmosphere(definition);
prepare();
}
Color AtmosphereColorPreviewRenderer::getColor2D(double x, double y, double)
{
Vector3 eye(0.0, 7.0, 0.0);
Vector3 direction = Vector3(x, -y, -1.0).normalize();
Vector3 hit, normal;
Matrix4 rotation;
rotation = Matrix4::newRotateY(heading);
if (_checkHit(eye, direction, &hit, &normal))
{
Color color;
normal = rotation.transform(normal);
hit = rotation.transform(hit);
color = applyLightingToSurface(hit, normal, MOUNT_MATERIAL);
return applyMediumTraversal(hit, color);
}
else
{
direction = rotation.transform(direction);
return getAtmosphereRenderer()->getSkyColor(direction).final;
}
}