/* This file is part of Mitsuba, a physically based rendering system. Copyright (c) 2007-2011 by Wenzel Jakob and others. Mitsuba is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License Version 3 as published by the Free Software Foundation. Mitsuba is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include MTS_NAMESPACE_BEGIN /*!\plugin{wireframe}{Wireframe texture} * \parameters{ * \parameter{interiorColor}{\Spectrum}{ * Color value of the interior of triangles * \default{0.5} * } * \parameter{color1}{\Spectrum}{ * Edge color value * \default{0.1} * } * \parameter{lineWidth}{\Float}{ * World-space width of the mesh edges * \default{automatic} * } * } * * This plugin implements a simple two-color wireframe texture map * that reveals the structure of a triangular mesh. */ class WireFrame : public Texture { public: WireFrame(const Properties &props) : Texture(props) { m_edgeColor = props.getSpectrum("edgeColor", Spectrum(0.1f)); m_interiorColor = props.getSpectrum("interiorColor", Spectrum(.5f)); m_lineWidth = props.getFloat("lineWidth", 0.0f); m_mutex = new Mutex(); } WireFrame(Stream *stream, InstanceManager *manager) : Texture(stream, manager) { m_mutex = new Mutex(); m_edgeColor = Spectrum(stream); m_interiorColor = Spectrum(stream); m_lineWidth = stream->readFloat(); } void serialize(Stream *stream, InstanceManager *manager) const { Texture::serialize(stream, manager); m_edgeColor.serialize(stream); m_interiorColor.serialize(stream); stream->writeFloat(m_lineWidth); } Spectrum getValue(const Intersection &its) const { if (!its.shape->getClass()->derivesFrom(MTS_CLASS(TriMesh))) return m_interiorColor; const TriMesh *triMesh = static_cast(its.shape); const Point *positions = triMesh->getVertexPositions(); if (its.primIndex >= triMesh->getTriangleCount()) return m_interiorColor; if (m_lineWidth == 0) { /* Somewhat hacky but probably helpful in many cases. This tries to find a suitable line width, which is set to 10% of the average average edge length */ m_mutex->lock(); if (m_lineWidth == 0) { for (size_t i=0; igetTriangleCount(); ++i) { const Triangle &tri = triMesh->getTriangles()[i]; for (int j=0; j<3; ++j) m_lineWidth += (positions[tri.idx[j]] - positions[tri.idx[j+1%3]]).length(); } m_lineWidth = 0.1f * m_lineWidth / (3 * triMesh->getTriangleCount()); } m_mutex->unlock(); } const Triangle &tri = triMesh->getTriangles()[its.primIndex]; Point pos[] = { positions[tri.idx[0]], positions[tri.idx[1]], positions[tri.idx[2]] }; Float minDist = std::numeric_limits::infinity(); for (int i=0; i<3; ++i) { Point cur = pos[i], next = pos[(i+1)%3]; Vector d1 = normalize(next - cur), d2 = its.p - cur; minDist = std::min(minDist, (cur + d1 * dot(d1, d2) - its.p).lengthSquared()); } Float value = 1-smoothStep(0, m_lineWidth, std::sqrt(minDist)); return m_edgeColor * value + m_interiorColor * (1-value); } bool usesRayDifferentials() const { return false; } Spectrum getAverage() const { Spectrum value; /* Approximate ... */ for (size_t i=0; i m_mutex; Spectrum m_edgeColor; Spectrum m_interiorColor; }; // ================ Hardware shader implementation ================ class WireFrameShader : public Shader { public: WireFrameShader(Renderer *renderer, const Spectrum &value) : Shader(renderer, ETextureShader), m_value(value) { } void generateCode(std::ostringstream &oss, const std::string &evalName, const std::vector &depNames) const { oss << "uniform vec3 " << evalName << "_value;" << endl << endl << "vec3 " << evalName << "(vec2 uv) {" << endl << " return " << evalName << "_value;" << endl << "}" << endl; } void resolve(const GPUProgram *program, const std::string &evalName, std::vector ¶meterIDs) const { parameterIDs.push_back(program->getParameterID(evalName + "_value", false)); } void bind(GPUProgram *program, const std::vector ¶meterIDs, int &textureUnitOffset) const { program->setParameter(parameterIDs[0], m_value); } MTS_DECLARE_CLASS() private: Spectrum m_value; }; Shader *WireFrame::createShader(Renderer *renderer) const { return new WireFrameShader(renderer, m_interiorColor); } MTS_IMPLEMENT_CLASS(WireFrameShader, false, Shader) MTS_IMPLEMENT_CLASS_S(WireFrame, false, Texture) MTS_EXPORT_PLUGIN(WireFrame, "Vertex color texture"); MTS_NAMESPACE_END