diff --git a/CMakeLists.txt b/CMakeLists.txt index 02cf566..e284d38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ file(GLOB libcoreSource src/core/*.cpp src/core/shapes/*.* src/core/cameras/*.* src/core/bsdfs/*.* + src/core/lights/*.* src/core/integrators/*.* src/core/samplers/*.* external/tinyobjloader/tiny_obj_loader.cc diff --git a/src/api/light.h b/src/api/light.h index 5ac043e..ae7c85c 100644 --- a/src/api/light.h +++ b/src/api/light.h @@ -56,10 +56,12 @@ namespace miyuki::core { virtual void sampleLe(const Point2f &u1, const Point2f &u2, LightRaySample &sample) = 0; }; + class Scene; + struct VisibilityTester { + Ray shadowRay; - class AreaLight : public Light { - public: - virtual void setShape(Shape *shape) = 0; + bool visible(Scene &scene) ; }; + } #endif //MIYUKIRENDERER_LIGHT_H diff --git a/src/api/mesh.h b/src/api/mesh.h index d85909a..4638953 100644 --- a/src/api/mesh.h +++ b/src/api/mesh.h @@ -27,9 +27,11 @@ #include #include #include +#include namespace miyuki::core { class Mesh; + class AreaLight; /// SOA @@ -42,18 +44,25 @@ namespace miyuki::core { struct MeshTriangle { - AreaLight * light = nullptr; + AreaLight *light = nullptr; Mesh *mesh = nullptr; uint16_t name_id = -1; uint32_t primID = -1; MeshTriangle() = default; - const Point3f &vertex(size_t) const; + [[nodiscard]] const Point3f &vertex(size_t) const; + + [[nodiscard]] const Normal3f &normal(size_t) const; + + [[nodiscard]] const Point2f &texCoord(size_t) const; - const Normal3f &normal(size_t) const; - const Point2f &texCoord(size_t) const; + [[nodiscard]] const Vec3f Ng() const { + Vec3f e1 = (vertex(1) - vertex(0)); + Vec3f e2 = (vertex(2) - vertex(0)); + return e1.cross(e2).normalized(); + } bool intersect(const Ray &ray, Intersection &isct) const { float u, v; @@ -101,6 +110,7 @@ namespace miyuki::core { uv.x = 1.0f - uv.x; uv.y = 1.0f - uv.y; } + sample.uv = uv; sample.pdf = 1 / area(); sample.p = (1 - uv.x - uv.y) * vertex(0) + uv.x * vertex(1) + uv.y * vertex(1); Vec3f e1 = (vertex(1) - vertex(0)); @@ -108,15 +118,27 @@ namespace miyuki::core { sample.normal = e1.cross(e2).normalized(); } - Float area() const { + [[nodiscard]] Float area() const { return Vec3f(vertex(1) - vertex(0)).cross(vertex(2) - vertex(0)).length(); } - BSDF *getBSDF() const { + [[nodiscard]] BSDF *getBSDF() const { return nullptr; } - Material * getMaterial()const; + [[nodiscard]] Material *getMaterial() const; + + [[nodiscard]] Vec3f positionAt(const Point2f &uv) const { + return lerp3(vertex(0), vertex(1), vertex(2), uv[0], uv[1]); + } + + [[nodiscard]] Normal3f normalAt(const Point2f &uv) const { + return lerp3(normal(0), normal(1), normal(2), uv[0], uv[1]); + } + + [[nodiscard]] Point2f texCoordAt(const Point2f &uv) const { + return lerp3(texCoord(0), texCoord(1), texCoord(2), uv[0], uv[1]); + } }; @@ -128,14 +150,15 @@ namespace miyuki::core { VertexData _vertex_data; std::vector _indices; std::vector _names; - std::vector> materials; + std::vector> _materials; + std::unordered_map> materials; std::string filename; MYK_DECL_CLASS(Mesh, "Mesh", interface = "Shape") - MYK_AUTO_SER(filename) + MYK_AUTO_SER(filename, materials) - MYK_AUTO_INIT(filename) + MYK_AUTO_INIT(filename, materials) bool intersect(const Ray &ray, Intersection &isct) const { return accelerator->intersect(ray, isct); diff --git a/src/api/shader.h b/src/api/shader.h index 9620dd3..c6fd86a 100644 --- a/src/api/shader.h +++ b/src/api/shader.h @@ -28,7 +28,7 @@ namespace miyuki::core { struct ShadingPoint { - Point2f uv; + Point2f texCoord; Normal3f Ns; Normal3f Ng; }; diff --git a/src/api/shape.h b/src/api/shape.h index 1d63c71..db304d7 100644 --- a/src/api/shape.h +++ b/src/api/shape.h @@ -35,6 +35,7 @@ namespace miyuki::core { Point3f p; Float pdf; Normal3f normal; + Point2f uv; }; diff --git a/src/core/graph.cpp b/src/core/graph.cpp index 7d672b0..6950781 100644 --- a/src/core/graph.cpp +++ b/src/core/graph.cpp @@ -13,9 +13,6 @@ namespace miyuki::core { camera->preprocess(); integrator->preprocess(); sampler->preprocess(); - for (auto &i:shapes) { - i->preprocess(); - } Film film(filmDimension[0], filmDimension[1]); auto scene = std::make_shared(); for (const auto& i: shapes) { diff --git a/src/core/integrators/rtao.cpp b/src/core/integrators/rtao.cpp index 9b44438..6c91ac7 100644 --- a/src/core/integrators/rtao.cpp +++ b/src/core/integrators/rtao.cpp @@ -41,8 +41,8 @@ namespace miyuki::core { for (int s = 0; s < spp; s++) { CameraSample sample; sampler->startNextSample(); - camera->generateRay(sampler->next2D(), sampler->next2D(), Point2i{i, j}, - Point2i{film.width, film.height}, + camera->generateRay(sampler->next2D(), sampler->next2D(), Point2i(i, j), + Point2i(film.width, film.height), sample); Intersection isct; diff --git a/src/core/lights/arealight.cpp b/src/core/lights/arealight.cpp new file mode 100644 index 0000000..8ba1703 --- /dev/null +++ b/src/core/lights/arealight.cpp @@ -0,0 +1,65 @@ +// MIT License +// +// Copyright (c) 2019 椎名深雪 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "arealight.h" +#include + + +namespace miyuki::core { + void AreaLight::setTriangle(MeshTriangle *shape) { + this->triangle = shape; + emission = triangle->getMaterial()->emission; + } + + Spectrum AreaLight::Li(ShadingPoint &sp) const { + return emission->evaluate(sp); + } + + void + AreaLight::sampleLi(const Point2f &u, Intersection &isct, LightSample &sample, VisibilityTester &tester) const { + SurfaceSample surfaceSample; + triangle->sample(u, surfaceSample); + auto wi = surfaceSample.p - isct.p; + tester.shadowRay = Ray(isct.p, wi, RayBias, 1); + ShadingPoint sp; + sp.Ng = triangle->Ng(); + sp.Ns = triangle->normalAt(surfaceSample.uv); + sp.texCoord = triangle->texCoordAt(surfaceSample.uv); + sample.Li = Li(sp); + sample.wi = wi.normalized(); + sample.pdf = wi.lengthSquared() / sample.wi.absDot(surfaceSample.normal) * surfaceSample.pdf; + } + + Float AreaLight::pdfLi(const Intersection &intersection, const Vec3f &wi) const { + Intersection _isct; + Ray ray(intersection.p, wi, RayBias); + if (!triangle->intersect(ray, _isct)) { + return 0.0f; + } + Float SA = triangle->area() * wi.absDot(_isct.Ng) / (_isct.distance * _isct.distance); + return 1.0f / SA; + } + + void AreaLight::sampleLe(const Point2f &u1, const Point2f &u2, LightRaySample &sample) { + MIYUKI_NOT_IMPLEMENTED(); + } +} \ No newline at end of file diff --git a/src/core/lights/arealight.h b/src/core/lights/arealight.h new file mode 100644 index 0000000..bb8686b --- /dev/null +++ b/src/core/lights/arealight.h @@ -0,0 +1,49 @@ +// MIT License +// +// Copyright (c) 2019 椎名深雪 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef MIYUKIRENDERER_AREALIGHT_H +#define MIYUKIRENDERER_AREALIGHT_H + +#include +#include +#include + +namespace miyuki::core { + class AreaLight final: public Light { + MeshTriangle *triangle = nullptr; + std::shared_ptr emission; + public: + MYK_DECL_CLASS(AreaLight, "AreaLight", interface = "Light") + + Spectrum Li(ShadingPoint &sp) const override; + + void + sampleLi(const Point2f &u, Intersection &isct, LightSample &sample, VisibilityTester &tester) const override; + + Float pdfLi(const Intersection &intersection, const Vec3f &wi) const override; + + void sampleLe(const Point2f &u1, const Point2f &u2, LightRaySample &sample) override; + + void setTriangle(MeshTriangle *shape); + }; +} +#endif //MIYUKIRENDERER_AREALIGHT_H diff --git a/src/core/scene.cpp b/src/core/scene.cpp index cf1140e..c1be326 100644 --- a/src/core/scene.cpp +++ b/src/core/scene.cpp @@ -22,18 +22,25 @@ #include #include +#include namespace miyuki::core { void Scene::preprocess() { accelerator = std::make_shared(); - auto setLight = [](MeshTriangle *triangle) { - + auto setLight = [=](MeshTriangle *triangle) { + auto mat = triangle->getMaterial(); + if (mat->emission != nullptr) { + auto light = std::make_shared(); + light->setTriangle(triangle); + lights.emplace_back(light); + } }; std::vector v; for (auto &i:shapes) { + i->preprocess(); v.push_back(i.get()); - + i->foreach(setLight); } accelerator->build(v); } diff --git a/src/core/shapes/mesh.cpp b/src/core/shapes/mesh.cpp index 8849707..35d5b31 100644 --- a/src/core/shapes/mesh.cpp +++ b/src/core/shapes/mesh.cpp @@ -81,6 +81,11 @@ namespace miyuki::core { for (int i = 0; i < triangles.size(); i++) { triangles[i].primID = i; } + _materials.clear(); + for (const auto &name : _names) { + auto mat = materials.at(name); + _materials.emplace_back(mat); + } accelerator = std::dynamic_pointer_cast(CreateEntity("BVHAccelerator")); accelerator->build(this); } @@ -339,7 +344,7 @@ namespace miyuki::core { } Material *MeshTriangle::getMaterial() const { - return mesh->materials[name_id].get(); + return mesh->_materials[name_id].get(); } } diff --git a/src/core/visibility.cpp b/src/core/visibility.cpp new file mode 100644 index 0000000..5cdf1a1 --- /dev/null +++ b/src/core/visibility.cpp @@ -0,0 +1,34 @@ +// MIT License +// +// Copyright (c) 2019 椎名深雪 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include + +namespace miyuki::core{ + bool VisibilityTester::visible(miyuki::core::Scene &scene) { + Intersection isct; + if (!scene.intersect(shadowRay, isct) || isct.distance >= shadowRay.tMax - RayBias) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/src/mesh-importer/importer.cpp b/src/mesh-importer/importer.cpp index 5644898..c20e274 100644 --- a/src/mesh-importer/importer.cpp +++ b/src/mesh-importer/importer.cpp @@ -19,17 +19,18 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include +#include int main(int argc, char **argv) { if (argc != 3) { - printf("Usage: mesh-importer src dst\n"); + printf("Usage: mesh-importer scene-file src dst\n"); return 0; } miyuki::core::Mesh mesh; - mesh.importFromFile(argv[1]); - mesh.writeToFile(argv[2]); + // + mesh.importFromFile(argv[2]); + mesh.writeToFile(argv[3]); return 0; }