More work on spannerizing heightfields.

This commit is contained in:
Andrzej Kapolka 2014-11-11 14:40:05 -08:00
parent 93a61dd0c2
commit caef237376
6 changed files with 189 additions and 36 deletions

View file

@ -15,10 +15,10 @@
uniform sampler2D heightMap;
// the distance between height points in texture space
uniform float heightScale;
uniform vec3 heightScale;
// the scale between height and color textures
uniform float colorScale;
uniform vec2 colorScale;
// the interpolated normal
varying vec4 normal;
@ -26,14 +26,14 @@ varying vec4 normal;
void main(void) {
// transform and store the normal for interpolation
vec2 heightCoord = gl_MultiTexCoord0.st;
vec4 neighborHeights = vec4(texture2D(heightMap, heightCoord - vec2(heightScale, 0.0)).r,
texture2D(heightMap, heightCoord + vec2(heightScale, 0.0)).r,
texture2D(heightMap, heightCoord - vec2(0.0, heightScale)).r,
texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r);
vec4 neighborsZero = step(1.0 / 255.0, neighborHeights);
vec4 neighborHeights = vec4(texture2D(heightMap, heightCoord - vec2(heightScale.s, 0.0)).r,
texture2D(heightMap, heightCoord + vec2(heightScale.s, 0.0)).r,
texture2D(heightMap, heightCoord - vec2(0.0, heightScale.t)).r,
texture2D(heightMap, heightCoord + vec2(0.0, heightScale.t)).r);
vec4 neighborsZero = step(1.0 / 65535.0, neighborHeights);
normal = normalize(gl_ModelViewMatrix * vec4(
(neighborHeights.x - neighborHeights.y) * neighborsZero.x * neighborsZero.y, heightScale,
(neighborHeights.z - neighborHeights.w) * neighborsZero.z * neighborsZero.w, 0.0));
heightScale.s * (neighborHeights.x - neighborHeights.y) * neighborsZero.x * neighborsZero.y, heightScale.p,
heightScale.t * (neighborHeights.z - neighborHeights.w) * neighborsZero.z * neighborsZero.w, 0.0));
// add the height to the position
float height = texture2D(heightMap, heightCoord).r;
@ -43,5 +43,5 @@ void main(void) {
gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0));
// pass along the scaled/offset texture coordinates
gl_TexCoord[0] = (gl_MultiTexCoord0 - vec4(heightScale, heightScale, 0.0, 0.0)) * colorScale;
gl_TexCoord[0] = vec4((heightCoord - heightScale.st) * colorScale, 0.0, 1.0);
}

View file

@ -3016,7 +3016,134 @@ void HeightfieldRenderer::init(Spanner* spanner) {
}
void HeightfieldRenderer::render(const glm::vec4& color, Mode mode) {
// create the buffer objects lazily
Heightfield* heightfield = static_cast<Heightfield*>(_spanner);
if (!heightfield->getHeight() || !Menu::getInstance()->isOptionChecked(MenuOption::RenderHeightfields)) {
return;
}
int width = heightfield->getHeight()->getWidth();
int height = heightfield->getHeight()->getContents().size() / width;
int innerWidth = width - 2 * HeightfieldBuffer::HEIGHT_BORDER;
int innerHeight = height - 2 * HeightfieldBuffer::HEIGHT_BORDER;
int vertexCount = width * height;
int rows = height - 1;
int columns = width - 1;
int indexCount = rows * columns * 3 * 2;
BufferPair& bufferPair = _bufferPairs[IntPair(width, height)];
if (!bufferPair.first.isCreated()) {
QVector<HeightfieldPoint> vertices(vertexCount);
HeightfieldPoint* point = vertices.data();
float xStep = 1.0f / (innerWidth - 1);
float zStep = 1.0f / (innerHeight - 1);
float z = -zStep;
float sStep = 1.0f / innerWidth;
float tStep = 1.0f / innerHeight;
float t = -tStep / 2.0f;
for (int i = 0; i < height; i++, z += zStep, t += tStep) {
float x = -xStep;
float s = -sStep / 2.0f;
const float SKIRT_LENGTH = 0.25f;
float baseY = (i == 0 || i == height - 1) ? -SKIRT_LENGTH : 0.0f;
for (int j = 0; j < width; j++, point++, x += xStep, s += sStep) {
point->vertex = glm::vec3(x, (j == 0 || j == width - 1) ? -SKIRT_LENGTH : baseY, z);
point->textureCoord = glm::vec2(s, t);
}
}
bufferPair.first.setUsagePattern(QOpenGLBuffer::StaticDraw);
bufferPair.first.create();
bufferPair.first.bind();
bufferPair.first.allocate(vertices.constData(), vertexCount * sizeof(HeightfieldPoint));
QVector<int> indices(indexCount);
int* index = indices.data();
for (int i = 0; i < rows; i++) {
int lineIndex = i * width;
int nextLineIndex = (i + 1) * width;
for (int j = 0; j < columns; j++) {
*index++ = lineIndex + j;
*index++ = nextLineIndex + j;
*index++ = nextLineIndex + j + 1;
*index++ = nextLineIndex + j + 1;
*index++ = lineIndex + j + 1;
*index++ = lineIndex + j;
}
}
bufferPair.second = QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
bufferPair.second.create();
bufferPair.second.bind();
bufferPair.second.allocate(indices.constData(), indexCount * sizeof(int));
} else {
bufferPair.first.bind();
bufferPair.second.bind();
}
glPushMatrix();
glTranslatef(heightfield->getTranslation().x, heightfield->getTranslation().y, heightfield->getTranslation().z);
glm::vec3 axis = glm::axis(heightfield->getRotation());
glRotatef(glm::degrees(glm::angle(heightfield->getRotation())), axis.x, axis.y, axis.z);
glScalef(heightfield->getScale(), heightfield->getScale() * heightfield->getAspectY(),
heightfield->getScale() * heightfield->getAspectZ());
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
HeightfieldPoint* point = 0;
glVertexPointer(3, GL_FLOAT, sizeof(HeightfieldPoint), &point->vertex);
glTexCoordPointer(2, GL_FLOAT, sizeof(HeightfieldPoint), &point->textureCoord);
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_EQUAL, 0.0f);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().bind();
DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().setUniformValue(
DefaultMetavoxelRendererImplementation::getBaseHeightScaleLocation(), 1.0f / innerWidth, 1.0f / innerHeight,
2.0f / (innerWidth * innerHeight));
if (heightfield->getColor()) {
int colorWidth = heightfield->getColor()->getWidth();
int colorHeight = heightfield->getColor()->getContents().size() / (colorWidth * DataBlock::COLOR_BYTES);
DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().setUniformValue(
DefaultMetavoxelRendererImplementation::getBaseColorScaleLocation(), (float)innerWidth / colorWidth,
(float)innerHeight / colorHeight);
}
glBindTexture(GL_TEXTURE_2D, _heightTextureID);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _colorTextureID);
glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().release();
glDisable(GL_ALPHA_TEST);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true);
glPopMatrix();
bufferPair.first.release();
bufferPair.second.release();
}
void HeightfieldRenderer::applyHeight(const HeightfieldHeightPointer& height) {
@ -3075,3 +3202,6 @@ void HeightfieldRenderer::applyMaterial(const HeightfieldMaterialPointer& materi
}
glBindTexture(GL_TEXTURE_2D, 0);
}
QHash<HeightfieldRenderer::IntPair, HeightfieldRenderer::BufferPair> HeightfieldRenderer::_bufferPairs;

View file

@ -475,8 +475,9 @@ private:
GLuint _materialTextureID;
QVector<NetworkTexturePointer> _networkTextures;
typedef QPair<int, int> IntPair;
typedef QPair<QOpenGLBuffer, QOpenGLBuffer> BufferPair;
static QHash<int, BufferPair> _bufferPairs;
static QHash<IntPair, BufferPair> _bufferPairs;
};
#endif // hifi_MetavoxelSystem_h

View file

@ -135,6 +135,8 @@ MetavoxelEditor::MetavoxelEditor() :
connect(Application::getInstance(), SIGNAL(simulating(float)), SLOT(simulate(float)));
connect(Application::getInstance(), SIGNAL(renderingInWorldInterface()), SLOT(render()));
connect(Application::getInstance()->getMetavoxels(), &MetavoxelSystem::rendering,
this, &MetavoxelEditor::renderPreview);
Application::getInstance()->getGLWidget()->installEventFilter(this);
@ -369,6 +371,13 @@ void MetavoxelEditor::render() {
glDepthMask(GL_TRUE);
}
void MetavoxelEditor::renderPreview() {
MetavoxelTool* tool = getActiveTool();
if (tool) {
tool->renderPreview();
}
}
void MetavoxelEditor::addTool(MetavoxelTool* tool) {
_tools.append(tool);
layout()->addWidget(tool);
@ -406,6 +415,10 @@ void MetavoxelTool::render() {
// nothing by default
}
void MetavoxelTool::renderPreview() {
// nothing by default
}
BoxTool::BoxTool(MetavoxelEditor* editor, const QString& name, bool usesValue, bool userFacing) :
MetavoxelTool(editor, name, usesValue, userFacing) {
@ -586,6 +599,15 @@ void GlobalSetTool::apply() {
PlaceSpannerTool::PlaceSpannerTool(MetavoxelEditor* editor, const QString& name, const QString& placeText, bool usesValue) :
MetavoxelTool(editor, name, usesValue) {
QWidget* widget = new QWidget(this);
layout()->addWidget(widget);
QHBoxLayout* box = new QHBoxLayout();
widget->setLayout(box);
box->setContentsMargins(QMargins());
box->addStretch(1);
box->addWidget(_followMouse = new QCheckBox("Follow Mouse"));
box->addStretch(1);
if (!placeText.isEmpty()) {
QPushButton* button = new QPushButton(placeText);
layout()->addWidget(button);
@ -594,12 +616,12 @@ PlaceSpannerTool::PlaceSpannerTool(MetavoxelEditor* editor, const QString& name,
}
void PlaceSpannerTool::simulate(float deltaTime) {
if (Application::getInstance()->isMouseHidden()) {
if (!Application::getInstance()->getGLWidget()->hasFocus() || Application::getInstance()->isMouseHidden()) {
return;
}
Spanner* spanner = static_cast<Spanner*>(getSpanner(true).data());
Transformable* transformable = qobject_cast<Transformable*>(spanner);
if (transformable) {
if (transformable && _followMouse->isChecked()) {
// find the intersection of the mouse ray with the grid and place the transformable there
glm::quat rotation = _editor->getGridRotation();
glm::quat inverseRotation = glm::inverse(rotation);
@ -613,14 +635,10 @@ void PlaceSpannerTool::simulate(float deltaTime) {
spanner->getRenderer()->simulate(deltaTime);
}
void PlaceSpannerTool::render() {
if (Application::getInstance()->isMouseHidden()) {
return;
}
void PlaceSpannerTool::renderPreview() {
Spanner* spanner = static_cast<Spanner*>(getSpanner().data());
const float SPANNER_ALPHA = 0.25f;
QColor color = getColor();
spanner->getRenderer()->render(glm::vec4(color.redF(), color.greenF(), color.blueF(), SPANNER_ALPHA),
spanner->getRenderer()->render(glm::vec4(color.redF(), color.greenF(), color.blueF(), 1.0f),
SpannerRenderer::DEFAULT_MODE);
}
@ -782,9 +800,10 @@ ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) :
_form->addRow("Color:", _color = new QPushButton());
connect(_color, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectColorFile);
connect(Application::getInstance()->getMetavoxels(), &MetavoxelSystem::rendering,
this, &ImportHeightfieldTool::renderPreview);
}
void ImportHeightfieldTool::renderPreview() {
_preview.render(_translation->getValue(), _translation->getSingleStep());
}
void ImportHeightfieldTool::apply() {
@ -961,12 +980,6 @@ void ImportHeightfieldTool::updatePreview() {
_preview.setBuffers(buffers);
}
void ImportHeightfieldTool::renderPreview() {
if (isVisible()) {
_preview.render(_translation->getValue(), _translation->getSingleStep());
}
}
EraseHeightfieldTool::EraseHeightfieldTool(MetavoxelEditor* editor) :
HeightfieldTool(editor, "Erase Heightfield") {

View file

@ -62,6 +62,7 @@ private slots:
void simulate(float deltaTime);
void render();
void renderPreview();
private:
@ -104,6 +105,9 @@ public:
/// Renders the tool's interface, if any.
virtual void render();
/// Renders the tool's metavoxel preview, if any.
virtual void renderPreview();
protected:
MetavoxelEditor* _editor;
@ -184,7 +188,7 @@ public:
virtual void simulate(float deltaTime);
virtual void render();
virtual void renderPreview();
virtual bool appliesTo(const AttributePointer& attribute) const;
@ -199,6 +203,10 @@ protected:
protected slots:
void place();
private:
QCheckBox* _followMouse;
};
/// Allows inserting a spanner into the scene.
@ -273,6 +281,8 @@ public:
ImportHeightfieldTool(MetavoxelEditor* editor);
virtual void renderPreview();
protected:
virtual void apply();
@ -283,7 +293,6 @@ private slots:
void selectColorFile();
void updateHeightImage();
void updatePreview();
void renderPreview();
private:

View file

@ -687,11 +687,6 @@ void HeightfieldHeightEditor::select() {
return;
}
settings.setValue("heightDir", QFileInfo(result).path());
QImage image;
if (!image.load(result)) {
QMessageBox::warning(this, "Invalid Image", "The selected image could not be read.");
return;
}
const quint16 CONVERSION_OFFSET = 1;
if (result.toLower().endsWith(".raw")) {
QFile input(result);
@ -723,6 +718,11 @@ void HeightfieldHeightEditor::select() {
_clear->setEnabled(true);
return;
}
QImage image;
if (!image.load(result)) {
QMessageBox::warning(this, "Invalid Image", "The selected image could not be read.");
return;
}
image = image.convertToFormat(QImage::Format_RGB888);
int width = getHeightfieldSize(image.width()) + 2 * HeightfieldHeight::HEIGHT_BORDER;
int height = getHeightfieldSize(image.height()) + 2 * HeightfieldHeight::HEIGHT_BORDER;
@ -949,5 +949,5 @@ QByteArray Heightfield::getRendererClassName() const {
void Heightfield::updateBounds() {
glm::vec3 extent(getScale(), getScale() * _aspectY, getScale() * _aspectZ);
glm::mat4 rotationMatrix = glm::mat4_cast(getRotation());
setBounds(glm::translate(getTranslation()) * rotationMatrix * Box(-extent, extent));
setBounds(glm::translate(getTranslation()) * rotationMatrix * Box(glm::vec3(), extent));
}