Draw lines in models with triangles

pull/905/head
Levin Li 2020-12-11 21:38:12 +08:00
parent b21a5fd404
commit 0c6ef0d0d6
5 changed files with 272 additions and 34 deletions

View File

@ -37,14 +37,14 @@ public:
{
for (auto vboId : vbos)
{
if (vboId != 0)
if (vboId.second)
{
glDeleteBuffers(1, &vboId);
glDeleteBuffers(1, &vboId.second);
}
}
}
std::vector<GLuint> vbos; // vertex buffer objects
std::map<const void*, GLuint> vbos; // vertex buffer objects
};
@ -99,10 +99,27 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
mesh->getVertexData(),
GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_glData->vbos[mesh->getVertexData()] = vboId;
}
}
m_glData->vbos.push_back(vboId);
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
{
const Mesh::PrimitiveGroup* group = mesh->getGroup(groupIndex);
if (group->vertexOverride != nullptr && group->vertexCountOverride * group->vertexDescriptionOverride.stride > MinVBOSize)
{
glGenBuffers(1, &vboId);
if (vboId != 0)
{
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER,
group->vertexCountOverride * group->vertexDescriptionOverride.stride,
group->vertexOverride, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_glData->vbos[group->vertexOverride] = vboId;
}
}
}
}
}
@ -113,30 +130,42 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
for (unsigned int meshIndex = 0; meshIndex < m_model->getMeshCount(); ++meshIndex)
{
Mesh* mesh = m_model->getMesh(meshIndex);
GLuint vboId = 0;
if (meshIndex < m_glData->vbos.size())
{
vboId = m_glData->vbos[meshIndex];
}
if (vboId != 0)
{
// Bind the vertex buffer object.
glBindBuffer(GL_ARRAY_BUFFER, vboId);
rc.setVertexArrays(mesh->getVertexDescription(), nullptr);
}
else
{
// No vertex buffer object; just use normal vertex arrays
rc.setVertexArrays(mesh->getVertexDescription(), mesh->getVertexData());
}
const void* currentData = nullptr;
GLuint currentVboId = 0;
// Iterate over all primitive groups in the mesh
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
{
const Mesh::PrimitiveGroup* group = mesh->getGroup(groupIndex);
rc.updateShader(mesh->getVertexDescription(), group->prim);
bool useOverrideValue = group->vertexOverride != nullptr && rc.shouldDrawLineAsTriangles();
const void* data = useOverrideValue ? group->vertexOverride : mesh->getVertexData();
auto vertexDescription = useOverrideValue ? group->vertexDescriptionOverride : mesh->getVertexDescription();
if (currentData != data)
{
GLuint vboId = m_glData->vbos[data];
if (vboId != 0)
{
// Bind the vertex buffer object.
glBindBuffer(GL_ARRAY_BUFFER, vboId);
rc.setVertexArrays(vertexDescription, nullptr);
}
else
{
if (currentVboId != 0)
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// No vertex buffer object; just use normal vertex arrays
rc.setVertexArrays(vertexDescription, data);
}
currentData = data;
currentVboId = vboId;
}
rc.updateShader(vertexDescription, group->prim);
// Set up the material
const Material* material = nullptr;
@ -147,11 +176,11 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
}
rc.setMaterial(material);
rc.drawGroup(*group);
rc.drawGroup(*group, useOverrideValue);
}
// If we set a VBO, unbind it.
if (vboId != 0)
if (currentVboId != 0)
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
}

View File

@ -122,6 +122,13 @@ RenderContext::setMaterial(const Material* newMaterial)
}
bool
RenderContext::shouldDrawLineAsTriangles() const
{
return renderer->shouldDrawLineAsTriangles();
}
void
RenderContext::setPointScale(float _pointScale)
{
@ -151,7 +158,7 @@ RenderContext::getCameraOrientation() const
void
RenderContext::drawGroup(const Mesh::PrimitiveGroup& group)
RenderContext::drawGroup(const Mesh::PrimitiveGroup& group, bool useOverride)
{
// Skip rendering if this is the emissive pass but there's no
// emissive texture.
@ -175,10 +182,10 @@ RenderContext::drawGroup(const Mesh::PrimitiveGroup& group)
glActiveTexture(GL_TEXTURE0);
}
glDrawElements(GLPrimitiveModes[(int) group.prim],
group.nIndices,
glDrawElements(GLPrimitiveModes[(int)(useOverride ? group.primOverride : group.prim)],
useOverride ? group.nIndicesOverride : group.nIndices,
GL_UNSIGNED_INT,
group.indices);
useOverride ? group.indicesOverride : group.indices);
#ifndef GL_ES
if (drawPoints)
{
@ -208,19 +215,22 @@ RenderContext::updateShader(const cmod::Mesh::VertexDescription& desc, Mesh::Pri
bool useNormalsNow = (desc.getAttribute(Mesh::Normal).format == Mesh::Float3);
bool useColorsNow = (desc.getAttribute(Mesh::Color0).format != Mesh::InvalidFormat);
bool useTexCoordsNow = (desc.getAttribute(Mesh::Texture0).format != Mesh::InvalidFormat);
bool drawLineNow = (desc.getAttribute(Mesh::NextPosition).format == Mesh::Float3);
bool useStaticPointSizeNow = primType == Mesh::PointList;
if (usePointSizeNow != usePointSize ||
useStaticPointSizeNow != useStaticPointSize ||
useNormalsNow != useNormals ||
useColorsNow != useColors ||
useTexCoordsNow != useTexCoords)
useTexCoordsNow != useTexCoords ||
drawLineNow != drawLine)
{
usePointSize = usePointSizeNow;
useStaticPointSize = useStaticPointSizeNow;
useNormals = useNormalsNow;
useColors = useColorsNow;
useTexCoords = useTexCoordsNow;
drawLine = drawLineNow;
if (getMaterial() != nullptr)
makeCurrent(*getMaterial());
}
@ -353,6 +363,40 @@ setExtendedVertexArrays(const Mesh::VertexDescription& desc,
glDisableVertexAttribArray(CelestiaGLProgram::PointSizeAttributeIndex);
break;
}
const Mesh::VertexAttribute& nextPos = desc.getAttribute(Mesh::NextPosition);
switch (nextPos.format)
{
case Mesh::Float3:
glEnableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::NextVCoordAttributeIndex,
GLComponentCounts[(int) nextPos.format],
GLComponentTypes[(int) nextPos.format],
GL_FALSE,
desc.stride,
vertices + nextPos.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex);
break;
}
const Mesh::VertexAttribute& scaleFac = desc.getAttribute(Mesh::ScaleFactor);
switch (scaleFac.format)
{
case Mesh::Float1:
glEnableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::ScaleFactorAttributeIndex,
GLComponentCounts[(int) scaleFac.format],
GLComponentTypes[(int) scaleFac.format],
GL_FALSE,
desc.stride,
vertices + scaleFac.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex);
break;
}
}
@ -551,6 +595,9 @@ GLSL_RenderContext::makeCurrent(const Material& m)
else if (useStaticPointSize)
shaderProps.texUsage |= ShaderProperties::StaticPointSize;
if (drawLine)
shaderProps.texUsage |= ShaderProperties::LineAsTriangles;
if (useColors)
shaderProps.texUsage |= ShaderProperties::VertexColors;
@ -638,6 +685,12 @@ GLSL_RenderContext::makeCurrent(const Material& m)
prog->pointScale = renderer->getScreenDpi() / 96.0f;
}
if (drawLine)
{
prog->lineWidthX = renderer->getLineWidthX();
prog->lineWidthY = renderer->getLineWidthY();
}
// Ring shadow parameters
if ((shaderProps.texUsage & ShaderProperties::RingShadowTexture) != 0)
{
@ -783,6 +836,9 @@ GLSLUnlit_RenderContext::makeCurrent(const Material& m)
else if (useStaticPointSize)
shaderProps.texUsage |= ShaderProperties::StaticPointSize;
if (drawLine)
shaderProps.texUsage |= ShaderProperties::LineAsTriangles;
if (useColors)
shaderProps.texUsage |= ShaderProperties::VertexColors;
@ -817,6 +873,12 @@ GLSLUnlit_RenderContext::makeCurrent(const Material& m)
prog->pointScale = renderer->getScreenDpi() / 96.0f;
}
if (drawLine)
{
prog->lineWidthX = renderer->getLineWidthX();
prog->lineWidthY = renderer->getLineWidthY();
}
Material::BlendMode newBlendMode = Material::InvalidBlend;
if (m.opacity != 1.0f ||
m.blend == Material::AdditiveBlend ||

View File

@ -30,13 +30,14 @@ class RenderContext
virtual void setVertexArrays(const cmod::Mesh::VertexDescription& desc,
const void* vertexData);
virtual void updateShader(const cmod::Mesh::VertexDescription& desc, cmod::Mesh::PrimitiveGroupType primType);
virtual void drawGroup(const cmod::Mesh::PrimitiveGroup& group);
virtual void drawGroup(const cmod::Mesh::PrimitiveGroup& group, bool useOverride);
const cmod::Material* getMaterial() const;
void setMaterial(const cmod::Material*);
void lock() { locked = true; }
void unlock() { locked = false; }
bool isLocked() const { return locked; }
bool shouldDrawLineAsTriangles() const;
enum RenderPass
{
@ -70,6 +71,7 @@ class RenderContext
bool useNormals{ true };
bool useColors{ false };
bool useTexCoords{ true };
bool drawLine { false };
const Eigen::Matrix4f *modelViewMatrix;
const Eigen::Matrix4f *projectionMatrix;
};

View File

@ -109,6 +109,23 @@ Mesh::VertexDescription::validate() const
return true;
}
Mesh::VertexDescription Mesh::VertexDescription::appendingAttributes(const VertexAttribute* newAttributes, int count) const
{
unsigned int totalAttributeCount = nAttributes + count;
VertexAttribute* allAttributes = new VertexAttribute[totalAttributeCount];
memcpy(allAttributes, attributes, sizeof(VertexAttribute) * nAttributes);
unsigned int newStride = stride;
for (int i = 0; i < count; ++i)
{
VertexAttribute attribute = newAttributes[i];
allAttributes[nAttributes + i] = attribute;
newStride += Mesh::getVertexAttributeSize(attribute.format);
}
memcpy(allAttributes + nAttributes, newAttributes, sizeof(VertexAttribute) * count);
VertexDescription desc = VertexDescription(newStride, totalAttributeCount, allAttributes);
delete[] allAttributes;
return desc;
}
Mesh::VertexDescription::~VertexDescription()
{
@ -236,17 +253,113 @@ Mesh::addGroup(PrimitiveGroup* group)
}
Mesh::PrimitiveGroup* Mesh::createLinePrimitiveGroup(bool lineStrip, unsigned int nIndices, index32* indices)
{
// Transform LINE_STRIP/LINES to triangle vertices
int transformedVertCount = lineStrip ? (nIndices - 1) * 4 : nIndices * 2;
// Get information of the position attributes
auto positionAttributes = vertexDesc.getAttribute(Position);
int positionSize = getVertexAttributeSize(positionAttributes.format);
int positionOffset = positionAttributes.offset;
int originalStride = vertexDesc.stride;
// Add another position (next line end), and scale factor
// ORIGINAL ATTRIBUTES | NextVCoordAttributeIndex | ScaleFactorAttributeIndex
int stride = originalStride + positionSize + sizeof(float);
// Get line count
int lineCount = lineStrip ? nIndices - 1 : nIndices / 2;
int lineIndexCount = 6 * lineCount;
int lineVertexCount = 4 * lineCount;
// Create buffer to hold the transformed vertices/indices
unsigned char* data = new unsigned char[stride * lineVertexCount];
index32* newIndices = new index32[lineIndexCount];
unsigned char* originalData = (unsigned char *)vertices;
auto ptr = data;
for (int i = 0; i < lineCount; ++i)
{
int thisIndex = indices[lineStrip ? i : i * 2];
int nextIndex = indices[lineStrip ? i + 1 : i * 2 + 1];
unsigned char* origThisVertLoc = originalData + thisIndex * originalStride;
unsigned char* origNextVertLoc = originalData + nextIndex * originalStride;
float *ff = (float *)origThisVertLoc;
float *ffn = (float *)origNextVertLoc;
// Fill the info for the 4 vertices
memcpy(ptr, origThisVertLoc, originalStride);
memcpy(ptr + originalStride, origNextVertLoc + positionOffset, positionSize);
*(float *)&ptr[originalStride + positionSize] = -0.5f;
ptr += stride;
memcpy(ptr, origThisVertLoc, originalStride);
memcpy(ptr + originalStride, origNextVertLoc + positionOffset, positionSize);
*(float *)&ptr[originalStride + positionSize] = 0.5f;
ptr += stride;
memcpy(ptr, origNextVertLoc, originalStride);
memcpy(ptr + originalStride, origThisVertLoc + positionOffset, positionSize);
*(float *)&ptr[originalStride + positionSize] = -0.5f;
ptr += stride;
memcpy(ptr, origNextVertLoc, originalStride);
memcpy(ptr + originalStride, origThisVertLoc + positionOffset, positionSize);
*(float *)&ptr[originalStride + positionSize] = 0.5f;
ptr += stride;
int lineIndex = 6 * i;
index32 newIndex = 4 * i;
// Fill info for the 6 indices
newIndices[lineIndex] = newIndex;
newIndices[lineIndex + 1] = newIndex + 1;
newIndices[lineIndex + 2] = newIndex + 2;
newIndices[lineIndex + 3] = newIndex + 2;
newIndices[lineIndex + 4] = newIndex + 3;
newIndices[lineIndex + 5] = newIndex;
}
array<VertexAttribute, 2> newAttributes = {
VertexAttribute(NextPosition, positionAttributes.format, originalStride),
VertexAttribute(ScaleFactor, Float1, originalStride + positionSize),
};
auto* g = new PrimitiveGroup();
g->vertexOverride = data;
g->vertexCountOverride = lineVertexCount;
g->vertexDescriptionOverride = vertexDesc.appendingAttributes(newAttributes.data(), 2);
g->indicesOverride = newIndices;
g->nIndicesOverride = lineIndexCount;
g->primOverride = PrimitiveGroupType::TriList;
return g;
}
unsigned int
Mesh::addGroup(PrimitiveGroupType prim,
unsigned int materialIndex,
unsigned int nIndices,
index32* indices)
{
auto* g = new PrimitiveGroup();
g->prim = prim;
g->materialIndex = materialIndex;
PrimitiveGroup* g;
if (prim == LineStrip || prim == LineList)
{
g = createLinePrimitiveGroup(prim == LineStrip, nIndices, indices);
}
else
{
g = new PrimitiveGroup;
g->vertexOverride = nullptr;
g->vertexCountOverride = 0;
g->indicesOverride = nullptr;
g->nIndicesOverride = 0;
g->primOverride = prim;
}
g->nIndices = nIndices;
g->indices = indices;
g->prim = prim;
g->materialIndex = materialIndex;
return addGroup(g);
}
@ -518,6 +631,27 @@ Mesh::transform(const Vector3f& translation, float scale)
Map<Vector3f>(reinterpret_cast<float*>(vdata)) = tv;
}
// Scale and translate the overriden vertex values
for (i = 0; i < getGroupCount(); i++)
{
PrimitiveGroup* group = getGroup(i);
char* vdata = reinterpret_cast<char*>(group->vertexOverride);
if (!vdata)
return;
auto vertexDesc = group->vertexDescriptionOverride;
int positionOffset = vertexDesc.getAttribute(Position).offset;
int nextPositionOffset = vertexDesc.getAttribute(NextPosition).offset;
for (int j = 0; j < group->vertexCountOverride; j++, vdata += vertexDesc.stride)
{
Vector3f tv = (Map<Vector3f>(reinterpret_cast<float*>(vdata + positionOffset)) + translation) * scale;
Map<Vector3f>(reinterpret_cast<float*>(vdata + positionOffset)) = tv;
tv = (Map<Vector3f>(reinterpret_cast<float*>(vdata + nextPositionOffset)) + translation) * scale;
Map<Vector3f>(reinterpret_cast<float*>(vdata + nextPositionOffset)) = tv;
}
}
// Point sizes need to be scaled as well
if (vertexDesc.getAttribute(PointSize).format == Float1)
{

View File

@ -42,7 +42,9 @@ class Mesh
Texture2 = 7,
Texture3 = 8,
PointSize = 9,
SemanticMax = 10,
NextPosition = 10,
ScaleFactor = 11,
SemanticMax = 12,
InvalidSemantic = -1,
};
@ -93,6 +95,8 @@ class Mesh
return semanticMap[semantic];
}
VertexDescription appendingAttributes(const VertexAttribute* newAttributes, int count) const;
bool validate() const;
VertexDescription& operator=(const VertexDescription&);
@ -134,6 +138,12 @@ class Mesh
unsigned int materialIndex;
index32* indices;
unsigned int nIndices;
PrimitiveGroupType primOverride;
void* vertexOverride;
unsigned int vertexCountOverride;
index32* indicesOverride;
unsigned int nIndicesOverride;
VertexDescription vertexDescriptionOverride { 0, 0, nullptr };
};
class PickResult
@ -154,6 +164,7 @@ class Mesh
bool setVertexDescription(const VertexDescription& desc);
const VertexDescription& getVertexDescription() const;
PrimitiveGroup* createLinePrimitiveGroup(bool lineStrip, unsigned int nIndices, Mesh::index32* indices);
const PrimitiveGroup* getGroup(unsigned int index) const;
PrimitiveGroup* getGroup(unsigned int index);
unsigned int addGroup(PrimitiveGroup* group);