2015-11-25 22:15:58 +00:00
|
|
|
#include "OpenGLVegetationImpostor.h"
|
|
|
|
|
2015-11-29 18:18:36 +00:00
|
|
|
#include <cassert>
|
2015-11-25 22:15:58 +00:00
|
|
|
#include "OpenGLShaderProgram.h"
|
|
|
|
#include "OpenGLSharedState.h"
|
|
|
|
#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) {
|
|
|
|
return Matrix4::newRotateZ(M_PI_2);
|
|
|
|
} else if (index < 6) {
|
|
|
|
return Matrix4::newRotateY(M_2PI * (double)(index - 1) * 0.2).mult(Matrix4::newRotateZ(M_PI_4));
|
|
|
|
} else {
|
|
|
|
return Matrix4::newRotateY(M_2PI * (double)(index - 6) * 0.1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-25 22:15:58 +00:00
|
|
|
OpenGLVegetationImpostor::OpenGLVegetationImpostor(int partsize) {
|
2015-11-29 18:18:36 +00:00
|
|
|
int parts = 4;
|
|
|
|
|
|
|
|
vertices = new float[4 * parts * parts * 3];
|
|
|
|
uv = new float[4 * 2];
|
|
|
|
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-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() {
|
|
|
|
delete[] vertices;
|
|
|
|
delete texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLVegetationImpostor::render(OpenGLShaderProgram *program, const OpenGLVegetationInstance *instance,
|
2015-11-29 18:18:36 +00:00
|
|
|
int instance_index, const Vector3 &camera_location) {
|
|
|
|
if (instance_index == 0 or texture_changed) {
|
2015-11-25 22:15:58 +00:00
|
|
|
texture_changed = false;
|
|
|
|
program->getState()->set("impostorTexture", texture);
|
|
|
|
}
|
2015-11-29 18:18:36 +00:00
|
|
|
|
|
|
|
int index = getIndex(camera_location, instance->getBase());
|
|
|
|
program->getState()->setInt("index", index);
|
2015-11-25 22:15:58 +00:00
|
|
|
program->getState()->set("offset", instance->getBase());
|
2015-11-29 18:18:36 +00:00
|
|
|
program->getState()->set("size", 2.0 * instance->getSize());
|
|
|
|
program->drawTriangleStripUV(vertices + index * 4 * 3, uv, 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++) {
|
|
|
|
double dx = (double)x / (double)partsize;
|
|
|
|
for (int y = 0; y < partsize; y++) {
|
|
|
|
double dy = (double)y / (double)partsize;
|
|
|
|
|
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 {
|
|
|
|
double angle = diff.phi / M_2PI;
|
|
|
|
if (diff.theta > 0.4) {
|
|
|
|
angle = (angle >= 0.9) ? 0.0 : (angle + 0.1);
|
|
|
|
return 1 + (int)(5.0 * angle);
|
|
|
|
} else {
|
|
|
|
angle = (angle >= 0.95) ? 0.0 : (angle + 0.05);
|
|
|
|
return 6 + (int)(10.0 * angle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)));
|
|
|
|
vertices[index * 4 * 3 + i * 3] = vertex.x;
|
|
|
|
vertices[index * 4 * 3 + i * 3 + 1] = vertex.y;
|
|
|
|
vertices[index * 4 * 3 + i * 3 + 2] = vertex.z;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
uv[i * 2] = u;
|
|
|
|
uv[i * 2 + 1] = v;
|
2015-11-25 22:15:58 +00:00
|
|
|
}
|