2015-11-25 22:15:58 +00:00
|
|
|
#include "OpenGLVegetationImpostor.h"
|
|
|
|
|
2015-11-29 18:18:36 +00:00
|
|
|
#include <cassert>
|
2015-12-30 23:36:22 +00:00
|
|
|
#include "Maths.h"
|
2015-11-25 22:15:58 +00:00
|
|
|
#include "OpenGLShaderProgram.h"
|
|
|
|
#include "OpenGLSharedState.h"
|
2015-12-08 00:28:15 +00:00
|
|
|
#include "OpenGLVertexArray.h"
|
2015-11-25 22:15:58 +00:00
|
|
|
#include "OpenGLVegetationInstance.h"
|
|
|
|
#include "Texture2D.h"
|
|
|
|
#include "SoftwareRenderer.h"
|
|
|
|
#include "Scenery.h"
|
|
|
|
#include "AtmosphereDefinition.h"
|
|
|
|
#include "GodRaysSampler.h"
|
|
|
|
#include "VegetationRenderer.h"
|
|
|
|
#include "VegetationInstance.h"
|
|
|
|
#include "RayCastingResult.h"
|
|
|
|
#include "SpaceSegment.h"
|
|
|
|
#include "Matrix4.h"
|
|
|
|
#include "LightingManager.h"
|
|
|
|
#include "CameraDefinition.h"
|
|
|
|
|
2015-11-29 18:18:36 +00:00
|
|
|
// Get the rotation matrix for an impostor grid index
|
|
|
|
static inline Matrix4 matrixForIndex(int index) {
|
|
|
|
if (index == 0) {
|
2015-12-30 23:36:22 +00:00
|
|
|
return Matrix4::newRotateZ(Maths::PI_2);
|
2015-11-29 18:18:36 +00:00
|
|
|
} else if (index < 6) {
|
2015-12-30 23:36:22 +00:00
|
|
|
return Matrix4::newRotateY(Maths::TWOPI * to_double(index - 1) * 0.2).mult(Matrix4::newRotateZ(Maths::PI_4));
|
2015-11-29 18:18:36 +00:00
|
|
|
} else {
|
2015-12-30 23:36:22 +00:00
|
|
|
return Matrix4::newRotateY(Maths::TWOPI * to_double(index - 6) * 0.1);
|
2015-11-29 18:18:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-25 22:15:58 +00:00
|
|
|
OpenGLVegetationImpostor::OpenGLVegetationImpostor(int partsize) {
|
2015-11-29 18:18:36 +00:00
|
|
|
int parts = 4;
|
|
|
|
|
2015-12-08 00:28:15 +00:00
|
|
|
vertices = new OpenGLVertexArray(true, true);
|
|
|
|
vertices->setVertexCount(4 * parts * parts);
|
2015-11-29 18:18:36 +00:00
|
|
|
texture_size = partsize * parts;
|
2015-11-25 22:15:58 +00:00
|
|
|
texture = new Texture2D(texture_size, texture_size);
|
2015-11-29 18:18:36 +00:00
|
|
|
texture_changed = false;
|
2015-11-25 22:15:58 +00:00
|
|
|
|
2015-12-08 00:28:15 +00:00
|
|
|
state = new OpenGLSharedState();
|
|
|
|
|
2015-11-29 18:18:36 +00:00
|
|
|
setVertex(0, 0.0f, 0.0f);
|
|
|
|
setVertex(1, 0.0f, 1.0f);
|
|
|
|
setVertex(2, 1.0f, 0.0f);
|
|
|
|
setVertex(3, 1.0f, 1.0f);
|
2015-11-25 22:15:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
OpenGLVegetationImpostor::~OpenGLVegetationImpostor() {
|
2015-12-08 00:28:15 +00:00
|
|
|
delete vertices;
|
|
|
|
delete state;
|
2015-11-25 22:15:58 +00:00
|
|
|
delete texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLVegetationImpostor::render(OpenGLShaderProgram *program, const OpenGLVegetationInstance *instance,
|
2015-12-14 23:14:06 +00:00
|
|
|
const Vector3 &camera_location) {
|
|
|
|
if (texture_changed) {
|
2015-11-25 22:15:58 +00:00
|
|
|
texture_changed = false;
|
2015-12-08 00:28:15 +00:00
|
|
|
state->set("impostorTexture", texture);
|
2015-11-25 22:15:58 +00:00
|
|
|
}
|
2015-11-29 18:18:36 +00:00
|
|
|
|
|
|
|
int index = getIndex(camera_location, instance->getBase());
|
2015-12-08 00:28:15 +00:00
|
|
|
state->set("offset", instance->getBase());
|
|
|
|
state->set("size", 2.0 * instance->getSize());
|
|
|
|
program->draw(vertices, state, index * 4, 4);
|
2015-11-25 22:15:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLVegetationImpostor::prepareTexture(const VegetationModelDefinition &model, const Scenery &environment,
|
|
|
|
bool *interrupt) {
|
|
|
|
Scenery scenery;
|
|
|
|
environment.getAtmosphere()->copy(scenery.getAtmosphere());
|
|
|
|
SoftwareRenderer renderer(&scenery);
|
|
|
|
// FIXME Self light filtering
|
|
|
|
renderer.getLightingManager()->clearFilters();
|
|
|
|
renderer.getGodRaysSampler()->setEnabled(false);
|
|
|
|
VegetationRenderer *vegetation = renderer.getVegetationRenderer();
|
|
|
|
VegetationInstance instance(model, VECTOR_ZERO);
|
|
|
|
|
|
|
|
int parts = 4;
|
|
|
|
int partsize = texture_size / parts;
|
|
|
|
for (int py = 0; py < parts; py++) {
|
|
|
|
for (int px = 0; px < parts; px++) {
|
|
|
|
int index = py * parts + px;
|
2015-11-29 18:18:36 +00:00
|
|
|
Matrix4 rotation = matrixForIndex(index);
|
2015-11-25 22:15:58 +00:00
|
|
|
|
2015-11-29 18:18:36 +00:00
|
|
|
Vector3 cam(5.0, 0.0, 0.0);
|
2015-11-25 22:15:58 +00:00
|
|
|
scenery.getCamera()->setLocation(rotation.multPoint(cam));
|
|
|
|
scenery.getCamera()->setTarget(VECTOR_ZERO);
|
|
|
|
renderer.prepare();
|
|
|
|
|
|
|
|
int startx = px * partsize;
|
|
|
|
int starty = py * partsize;
|
|
|
|
|
|
|
|
for (int x = 0; x < partsize; x++) {
|
2015-12-17 00:13:20 +00:00
|
|
|
double dx = to_double(x) / to_double(partsize);
|
2015-11-25 22:15:58 +00:00
|
|
|
for (int y = 0; y < partsize; y++) {
|
2015-12-17 00:13:20 +00:00
|
|
|
double dy = to_double(y) / to_double(partsize);
|
2015-11-25 22:15:58 +00:00
|
|
|
|
2015-11-29 18:18:36 +00:00
|
|
|
Vector3 near(5.0, dy - 0.5, -(dx - 0.5));
|
|
|
|
Vector3 far(-5.0, dy - 0.5, -(dx - 0.5));
|
|
|
|
SpaceSegment segment(rotation.multPoint(near.scale(2.0)).add(VECTOR_UP.scale(0.5)),
|
|
|
|
rotation.multPoint(far.scale(2.0)).add(VECTOR_UP.scale(0.5)));
|
2015-11-25 22:15:58 +00:00
|
|
|
|
|
|
|
RayCastingResult result = vegetation->renderInstance(segment, instance, false, true);
|
|
|
|
texture->setPixel(startx + x, starty + y,
|
|
|
|
result.hit ? result.hit_color.normalized() : COLOR_TRANSPARENT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
texture_changed = true;
|
|
|
|
}
|
|
|
|
|
2015-11-29 18:18:36 +00:00
|
|
|
int OpenGLVegetationImpostor::getIndex(const Vector3 &camera, const Vector3 &instance) const {
|
|
|
|
int result;
|
|
|
|
|
|
|
|
VectorSpherical diff = camera.sub(instance).toSpherical();
|
|
|
|
if (diff.theta > 1.0) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
2015-12-30 23:36:22 +00:00
|
|
|
double angle = diff.phi / Maths::TWOPI;
|
2015-11-29 18:18:36 +00:00
|
|
|
if (diff.theta > 0.4) {
|
|
|
|
angle = (angle >= 0.9) ? 0.0 : (angle + 0.1);
|
2015-12-17 00:13:20 +00:00
|
|
|
return 1 + trunc_to_int(5.0 * angle);
|
2015-11-29 18:18:36 +00:00
|
|
|
} else {
|
|
|
|
angle = (angle >= 0.95) ? 0.0 : (angle + 0.05);
|
2015-12-17 00:13:20 +00:00
|
|
|
return 6 + trunc_to_int(10.0 * angle);
|
2015-11-29 18:18:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(result >= 0 and result <= 16);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLVegetationImpostor::setVertex(int i, float u, float v) {
|
|
|
|
int parts = 4;
|
|
|
|
for (int py = 0; py < parts; py++) {
|
|
|
|
for (int px = 0; px < parts; px++) {
|
|
|
|
int index = py * parts + px;
|
|
|
|
Matrix4 rotation = matrixForIndex(index);
|
|
|
|
|
|
|
|
Vector3 vertex = rotation.multPoint(Vector3(1.0, u, -(v - 0.5)));
|
2015-12-23 23:16:50 +00:00
|
|
|
vertices->set(index * 4 + i, vertex, (u + to_double(px)) / to_double(parts),
|
|
|
|
(v + to_double(py)) / to_double(parts));
|
2015-11-29 18:18:36 +00:00
|
|
|
}
|
|
|
|
}
|
2015-11-25 22:15:58 +00:00
|
|
|
}
|