mirror of
https://github.com/lubosz/overte.git
synced 2025-04-13 21:06:32 +02:00
More work on spannerizing heightfields.
This commit is contained in:
parent
93a61dd0c2
commit
caef237376
6 changed files with 189 additions and 36 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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") {
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue