Allow drawing cursor on dual contour surface, wired up material paint tool.

This commit is contained in:
Andrzej Kapolka 2014-10-10 17:18:52 -07:00
parent 1911cfd0be
commit 60da0f1567
8 changed files with 326 additions and 19 deletions

View file

@ -0,0 +1,32 @@
#version 120
//
// metavoxel_voxel_base.frag
// fragment shader
//
// Created by Andrzej Kapolka on 10/10/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// the inner radius of the outline, squared
const float SQUARED_OUTLINE_INNER_RADIUS = 0.81;
// the outer radius of the outline, squared
const float SQUARED_OUTLINE_OUTER_RADIUS = 1.0;
// the inner radius of the inset, squared
const float SQUARED_INSET_INNER_RADIUS = 0.855625;
// the outer radius of the inset, squared
const float SQUARED_INSET_OUTER_RADIUS = 0.950625;
void main(void) {
// use the distance to compute the ring color, then multiply it by the varying color
float squaredDistance = dot(gl_TexCoord[0].str, gl_TexCoord[0].str);
float alpha = step(SQUARED_OUTLINE_INNER_RADIUS, squaredDistance) * step(squaredDistance, SQUARED_OUTLINE_OUTER_RADIUS);
float white = step(SQUARED_INSET_INNER_RADIUS, squaredDistance) * step(squaredDistance, SQUARED_INSET_OUTER_RADIUS);
gl_FragColor = gl_Color * vec4(white, white, white, alpha);
}

View file

@ -0,0 +1,25 @@
#version 120
//
// metavoxel_voxel_cursor.vert
// vertex shader
//
// Created by Andrzej Kapolka on 10/10/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
void main(void) {
// compute the view space coordinates
vec4 viewPosition = gl_ModelViewMatrix * gl_Vertex;
gl_Position = gl_ProjectionMatrix * viewPosition;
// generate the texture coordinates from the view position
gl_TexCoord[0] = vec4(dot(viewPosition, gl_EyePlaneS[4]), dot(viewPosition, gl_EyePlaneT[4]),
dot(viewPosition, gl_EyePlaneR[4]), 1.0);
// copy the color for interpolation
gl_FrontColor = gl_Color;
}

View file

@ -454,10 +454,10 @@ float MetavoxelSystem::getHeightfieldHeight(const glm::vec3& location) {
return visitor.height;
}
class HeightfieldCursorRenderVisitor : public MetavoxelVisitor {
class CursorRenderVisitor : public MetavoxelVisitor {
public:
HeightfieldCursorRenderVisitor(const Box& bounds);
CursorRenderVisitor(const AttributePointer& attribute, const Box& bounds);
virtual int visit(MetavoxelInfo& info);
@ -466,13 +466,12 @@ private:
Box _bounds;
};
HeightfieldCursorRenderVisitor::HeightfieldCursorRenderVisitor(const Box& bounds) :
MetavoxelVisitor(QVector<AttributePointer>() <<
Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()),
CursorRenderVisitor::CursorRenderVisitor(const AttributePointer& attribute, const Box& bounds) :
MetavoxelVisitor(QVector<AttributePointer>() << attribute),
_bounds(bounds) {
}
int HeightfieldCursorRenderVisitor::visit(MetavoxelInfo& info) {
int CursorRenderVisitor::visit(MetavoxelInfo& info) {
if (!info.getBounds().intersects(_bounds)) {
return STOP_RECURSION;
}
@ -508,7 +507,8 @@ void MetavoxelSystem::renderHeightfieldCursor(const glm::vec3& position, float r
glActiveTexture(GL_TEXTURE0);
glm::vec3 extents(radius, radius, radius);
HeightfieldCursorRenderVisitor visitor(Box(position - extents, position + extents));
CursorRenderVisitor visitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(),
Box(position - extents, position + extents));
guideToAugmented(visitor);
DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().release();
@ -521,6 +521,42 @@ void MetavoxelSystem::renderHeightfieldCursor(const glm::vec3& position, float r
glDepthFunc(GL_LESS);
}
void MetavoxelSystem::renderVoxelCursor(const glm::vec3& position, float radius) {
glDepthFunc(GL_LEQUAL);
glEnable(GL_CULL_FACE);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(-1.0f, -1.0f);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glEnableClientState(GL_VERTEX_ARRAY);
DefaultMetavoxelRendererImplementation::getVoxelCursorProgram().bind();
glActiveTexture(GL_TEXTURE4);
float scale = 1.0f / radius;
glm::vec4 sCoefficients(scale, 0.0f, 0.0f, -scale * position.x);
glm::vec4 tCoefficients(0.0f, scale, 0.0f, -scale * position.y);
glm::vec4 rCoefficients(0.0f, 0.0f, scale, -scale * position.z);
glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&sCoefficients);
glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&tCoefficients);
glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&rCoefficients);
glActiveTexture(GL_TEXTURE0);
glm::vec3 extents(radius, radius, radius);
CursorRenderVisitor visitor(Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute(),
Box(position - extents, position + extents));
guideToAugmented(visitor);
DefaultMetavoxelRendererImplementation::getVoxelCursorProgram().release();
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_CULL_FACE);
glDepthFunc(GL_LESS);
}
void MetavoxelSystem::deleteTextures(int heightID, int colorID, int textureID) {
glDeleteTextures(1, (GLuint*)&heightID);
glDeleteTextures(1, (GLuint*)&colorID);
@ -1170,7 +1206,7 @@ void VoxelBuffer::render(bool cursor) {
glDrawRangeElements(GL_QUADS, 0, _vertexCount - 1, _indexCount, GL_UNSIGNED_INT, 0);
if (!_materials.isEmpty()) {
if (!(_materials.isEmpty() || cursor)) {
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
glDepthFunc(GL_LEQUAL);
@ -1252,7 +1288,7 @@ void VoxelBuffer::render(bool cursor) {
_vertexBuffer.release();
_indexBuffer.release();
if (_hermiteCount > 0 && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHermiteData)) {
if (_hermiteCount > 0 && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHermiteData) && !cursor) {
if (!_hermiteBuffer.isCreated()) {
_hermiteBuffer.create();
_hermiteBuffer.bind();
@ -1348,6 +1384,12 @@ void DefaultMetavoxelRendererImplementation::init() {
_baseVoxelProgram.link();
loadSplatProgram("voxel", _splatVoxelProgram, _splatVoxelLocations);
_voxelCursorProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() +
"shaders/metavoxel_voxel_cursor.vert");
_voxelCursorProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() +
"shaders/metavoxel_voxel_cursor.frag");
_voxelCursorProgram.link();
}
}
@ -2577,6 +2619,7 @@ ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldCursorProgram;
ProgramObject DefaultMetavoxelRendererImplementation::_baseVoxelProgram;
ProgramObject DefaultMetavoxelRendererImplementation::_splatVoxelProgram;
DefaultMetavoxelRendererImplementation::SplatLocations DefaultMetavoxelRendererImplementation::_splatVoxelLocations;
ProgramObject DefaultMetavoxelRendererImplementation::_voxelCursorProgram;
static void enableClipPlane(GLenum plane, float x, float y, float z, float w) {
GLdouble coefficients[] = { x, y, z, w };

View file

@ -46,6 +46,8 @@ public:
void renderHeightfieldCursor(const glm::vec3& position, float radius);
void renderVoxelCursor(const glm::vec3& position, float radius);
bool findFirstRayHeightfieldIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance);
bool findFirstRayVoxelIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance);
@ -321,6 +323,8 @@ public:
static ProgramObject& getSplatVoxelProgram() { return _splatVoxelProgram; }
static const SplatLocations& getSplatVoxelLocations() { return _splatVoxelLocations; }
static ProgramObject& getVoxelCursorProgram() { return _voxelCursorProgram; }
Q_INVOKABLE DefaultMetavoxelRendererImplementation();
virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod);
@ -354,6 +358,8 @@ private:
static ProgramObject _baseVoxelProgram;
static ProgramObject _splatVoxelProgram;
static SplatLocations _splatVoxelLocations;
static ProgramObject _voxelCursorProgram;
};
/// Base class for spanner renderers; provides clipping.

View file

@ -1529,6 +1529,15 @@ void VoxelMaterialSpannerTool::textureLoaded() {
VoxelBrushTool::VoxelBrushTool(MetavoxelEditor* editor, const QString& name) :
MetavoxelTool(editor, name, false, true) {
QWidget* widget = new QWidget();
widget->setLayout(_form = new QFormLayout());
layout()->addWidget(widget);
_form->addRow("Radius:", _radius = new QDoubleSpinBox());
_radius->setSingleStep(0.01);
_radius->setMaximum(FLT_MAX);
_radius->setValue(0.25);
}
bool VoxelBrushTool::appliesTo(const AttributePointer& attribute) const {
@ -1548,24 +1557,71 @@ void VoxelBrushTool::render() {
if (!Application::getInstance()->getMetavoxels()->findFirstRayVoxelIntersection(origin, direction, distance)) {
return;
}
_position = origin + distance * direction;
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glPushMatrix();
glTranslatef(_position.x, _position.y, _position.z);
Application::getInstance()->getGeometryCache()->renderSphere(0.1f, 16, 16);
glPopMatrix();
Application::getInstance()->getMetavoxels()->renderVoxelCursor(
_position = origin + distance * direction, _radius->value());
}
bool VoxelBrushTool::eventFilter(QObject* watched, QEvent* event) {
if (event->type() == QEvent::Wheel) {
float angle = static_cast<QWheelEvent*>(event)->angleDelta().y();
const float ANGLE_SCALE = 1.0f / 1000.0f;
_radius->setValue(_radius->value() * glm::pow(2.0f, angle * ANGLE_SCALE));
return true;
} else if (event->type() == QEvent::MouseButtonPress) {
MetavoxelEditMessage message = { createEdit(static_cast<QMouseEvent*>(event)->button() == Qt::RightButton) };
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
return true;
}
return false;
}
VoxelMaterialBrushTool::VoxelMaterialBrushTool(MetavoxelEditor* editor) :
VoxelBrushTool(editor, "Material Brush") {
_form->addRow("Color:", _color = new QColorEditor(this));
connect(_color, &QColorEditor::colorChanged, this, &VoxelMaterialBrushTool::clearTexture);
_form->addRow(_materialEditor = new SharedObjectEditor(&MaterialObject::staticMetaObject, false));
connect(_materialEditor, &SharedObjectEditor::objectChanged, this, &VoxelMaterialBrushTool::updateTexture);
}
QVariant VoxelMaterialBrushTool::createEdit(bool alternate) {
if (alternate) {
return QVariant::fromValue(PaintVoxelMaterialEdit(_position, _radius->value(), SharedObjectPointer(), QColor()));
} else {
SharedObjectPointer material = _materialEditor->getObject();
if (static_cast<MaterialObject*>(material.data())->getDiffuse().isValid()) {
_materialEditor->detachObject();
} else {
material = SharedObjectPointer();
}
return QVariant::fromValue(PaintVoxelMaterialEdit(_position, _radius->value(), material, _color->getColor()));
}
}
void VoxelMaterialBrushTool::clearTexture() {
_materialEditor->setObject(new MaterialObject());
}
void VoxelMaterialBrushTool::updateTexture() {
if (_texture) {
_texture->disconnect(this);
}
MaterialObject* material = static_cast<MaterialObject*>(_materialEditor->getObject().data());
if (!material->getDiffuse().isValid()) {
_texture.clear();
return;
}
_texture = Application::getInstance()->getTextureCache()->getTexture(material->getDiffuse(), SPLAT_TEXTURE);
if (_texture) {
if (_texture->isLoaded()) {
textureLoaded();
} else {
connect(_texture.data(), &Resource::loaded, this, &VoxelMaterialBrushTool::textureLoaded);
}
}
}
void VoxelMaterialBrushTool::textureLoaded() {
_color->setColor(_texture->getAverageColor());
}

View file

@ -485,6 +485,11 @@ public:
protected:
virtual QVariant createEdit(bool alternate) = 0;
QFormLayout* _form;
QDoubleSpinBox* _radius;
glm::vec3 _position;
};
@ -495,6 +500,22 @@ class VoxelMaterialBrushTool : public VoxelBrushTool {
public:
VoxelMaterialBrushTool(MetavoxelEditor* editor);
protected:
virtual QVariant createEdit(bool alternate);
private slots:
void clearTexture();
void updateTexture();
void textureLoaded();
private:
QColorEditor* _color;
SharedObjectEditor* _materialEditor;
QSharedPointer<NetworkTexture> _texture;
};
#endif // hifi_MetavoxelEditor_h

View file

@ -848,3 +848,108 @@ void VoxelMaterialSpannerEdit::apply(MetavoxelData& data, const WeakSharedObject
VoxelMaterialSpannerEditVisitor visitor(spanner, material, averageColor);
data.guide(visitor);
}
PaintVoxelMaterialEdit::PaintVoxelMaterialEdit(const glm::vec3& position, float radius,
const SharedObjectPointer& material, const QColor& averageColor) :
position(position),
radius(radius),
material(material),
averageColor(averageColor) {
}
class PaintVoxelMaterialEditVisitor : public MetavoxelVisitor {
public:
PaintVoxelMaterialEditVisitor(const glm::vec3& position, float radius,
const SharedObjectPointer& material, const QColor& color);
virtual int visit(MetavoxelInfo& info);
private:
glm::vec3 _position;
float _radius;
SharedObjectPointer _material;
QColor _color;
Box _bounds;
};
PaintVoxelMaterialEditVisitor::PaintVoxelMaterialEditVisitor(const glm::vec3& position, float radius,
const SharedObjectPointer& material, const QColor& color) :
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getVoxelColorAttribute() <<
AttributeRegistry::getInstance()->getVoxelMaterialAttribute(), QVector<AttributePointer>() <<
AttributeRegistry::getInstance()->getVoxelColorAttribute() <<
AttributeRegistry::getInstance()->getVoxelMaterialAttribute()),
_position(position),
_radius(radius),
_material(material),
_color(color) {
glm::vec3 extents(_radius, _radius, _radius);
_bounds = Box(_position - extents, _position + extents);
}
int PaintVoxelMaterialEditVisitor::visit(MetavoxelInfo& info) {
if (!info.getBounds().intersects(_bounds)) {
return STOP_RECURSION;
}
if (!info.isLeaf) {
return DEFAULT_ORDER;
}
VoxelColorDataPointer colorPointer = info.inputValues.at(0).getInlineValue<VoxelColorDataPointer>();
VoxelMaterialDataPointer materialPointer = info.inputValues.at(1).getInlineValue<VoxelMaterialDataPointer>();
if (!(colorPointer && materialPointer && colorPointer->getSize() == materialPointer->getSize())) {
return STOP_RECURSION;
}
QVector<QRgb> colorContents = colorPointer->getContents();
QByteArray materialContents = materialPointer->getContents();
QVector<SharedObjectPointer> materials = materialPointer->getMaterials();
Box overlap = info.getBounds().getIntersection(_bounds);
int size = colorPointer->getSize();
int area = size * size;
float scale = (size - 1.0f) / info.size;
overlap.minimum = (overlap.minimum - info.minimum) * scale;
overlap.maximum = (overlap.maximum - info.minimum) * scale;
int minX = glm::ceil(overlap.minimum.x);
int minY = glm::ceil(overlap.minimum.y);
int minZ = glm::ceil(overlap.minimum.z);
int sizeX = (int)overlap.maximum.x - minX + 1;
int sizeY = (int)overlap.maximum.y - minY + 1;
int sizeZ = (int)overlap.maximum.z - minZ + 1;
QRgb rgb = _color.rgba();
float step = 1.0f / scale;
glm::vec3 position(0.0f, 0.0f, info.minimum.z + minZ * step);
uchar materialIndex = getMaterialIndex(_material, materials, materialContents);
QRgb* colorData = colorContents.data();
uchar* materialData = (uchar*)materialContents.data();
for (int destZ = minZ * area + minY * size + minX, endZ = destZ + sizeZ * area; destZ != endZ;
destZ += area, position.z += step) {
position.y = info.minimum.y + minY * step;
for (int destY = destZ, endY = destY + sizeY * size; destY != endY; destY += size, position.y += step) {
position.x = info.minimum.x + minX * step;
for (int destX = destY, endX = destX + sizeX; destX != endX; destX++, position.x += step) {
QRgb& color = colorData[destX];
if (qAlpha(color) != 0 && glm::distance(position, _position) <= _radius) {
color = rgb;
materialData[destX] = materialIndex;
}
}
}
}
VoxelColorDataPointer newColorPointer(new VoxelColorData(colorContents, size));
info.outputValues[0] = AttributeValue(info.inputValues.at(0).getAttribute(),
encodeInline<VoxelColorDataPointer>(newColorPointer));
clearUnusedMaterials(materials, materialContents);
VoxelMaterialDataPointer newMaterialPointer(new VoxelMaterialData(materialContents, size, materials));
info.outputValues[1] = AttributeValue(_inputs.at(1), encodeInline<VoxelMaterialDataPointer>(newMaterialPointer));
return STOP_RECURSION;
}
void PaintVoxelMaterialEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
PaintVoxelMaterialEditVisitor visitor(position, radius, material, averageColor);
data.guide(visitor);
}

View file

@ -261,4 +261,23 @@ public:
DECLARE_STREAMABLE_METATYPE(VoxelMaterialSpannerEdit)
/// An edit that sets a region of a voxel material.
class PaintVoxelMaterialEdit : public MetavoxelEdit {
STREAMABLE
public:
STREAM glm::vec3 position;
STREAM float radius;
STREAM SharedObjectPointer material;
STREAM QColor averageColor;
PaintVoxelMaterialEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f,
const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor());
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
};
DECLARE_STREAMABLE_METATYPE(PaintVoxelMaterialEdit)
#endif // hifi_MetavoxelMessages_h