Files
filament/samples/app/Sphere.cpp
Mathias Agopian 7a14aadb28 sample clean-up and new sphere object (#134)
* Add missing method to query the type of a light

* IcoSphere now generates front facing triangles

* Add a fairly generic sphere object to use in samples

it provides an ico sphere with normal, and reuses
the same vertex/index buffer for each new instance.
Each instance can have its own material, size and
position.

currently it’s not possible to change the # of
subdivisions.

* FilamentApp now provides a “default” pbr material

this makes it easier to create renderables for
testing.

* clean-up lightbulb and add spheres for each light

lightbulb now has less hardcoded things and it
spawns a small sphere for each light.
2018-08-23 21:12:46 -07:00

133 lines
4.5 KiB
C++

/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Sphere.h"
#include <filament/Engine.h>
#include <filament/IndexBuffer.h>
#include <filament/RenderableManager.h>
#include <filament/TransformManager.h>
#include <filament/VertexBuffer.h>
#include <utils/EntityManager.h>
#include <math/norm.h>
#include "IcoSphere.h"
using namespace filament;
using namespace math;
using namespace utils;
struct Geometry {
IcoSphere sphere = IcoSphere{ 2 };
std::vector<math::short4> tangents;
filament::VertexBuffer* vertexBuffer = nullptr;
filament::IndexBuffer* indexBuffer = nullptr;
};
// note: this will be leaked since we don't have a good time to free it.
// this should be a cache indexed on the sphere's subdivisions
static Geometry* gGeometry = nullptr;
Sphere::Sphere(Engine& engine, Material const* material, bool culling)
: mEngine(engine) {
Geometry* geometry = gGeometry;
static_assert(sizeof(IcoSphere::Triangle) == sizeof(IcoSphere::Index) * 3,
"indices are not packed");
if (geometry == nullptr) {
geometry = gGeometry = new Geometry;
auto const& indices = geometry->sphere.getIndices();
auto const& vertices = geometry->sphere.getVertices();
uint32_t indexCount = (uint32_t)(indices.size() * 3);
for (auto const& vertice : vertices) {
float3 n = vertice;
// todo produce correct u,v
float3 b = cross(n, float3{ 1, 0, 0 });
float3 t = cross(b, n);
quatf q = mat3f::packTangentFrame({ t, b, n });
geometry->tangents.push_back(packSnorm16(q.xyzw));
}
geometry->vertexBuffer = VertexBuffer::Builder()
.vertexCount((uint32_t)vertices.size())
.bufferCount(2)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.attribute(VertexAttribute::TANGENTS, 1, VertexBuffer::AttributeType::SHORT4)
.normalized(VertexAttribute::TANGENTS)
.build(engine);
geometry->vertexBuffer->setBufferAt(engine, 0,
VertexBuffer::BufferDescriptor(vertices.data(), vertices.size() * sizeof(float3)));
geometry->vertexBuffer->setBufferAt(engine, 1,
VertexBuffer::BufferDescriptor(geometry->tangents.data(), geometry->tangents.size() * sizeof(math::short4)));
geometry->indexBuffer = IndexBuffer::Builder()
.bufferType(IndexBuffer::IndexType::USHORT)
.indexCount(indexCount)
.build(engine);
geometry->indexBuffer->setBuffer(engine,
IndexBuffer::BufferDescriptor(indices.data(), indexCount * sizeof(IcoSphere::Index)));
}
if (material) {
mMaterialInstance = material->createInstance();
}
utils::EntityManager& em = utils::EntityManager::get();
mRenderable = em.create();
RenderableManager::Builder(1)
.boundingBox({{0}, {1}})
.material(0, mMaterialInstance)
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, geometry->vertexBuffer, geometry->indexBuffer)
.culling(culling)
.build(engine, mRenderable);
}
Sphere::~Sphere() {
mEngine.destroy(mMaterialInstance);
mEngine.destroy(mRenderable);
utils::EntityManager& em = utils::EntityManager::get();
em.destroy(mRenderable);
}
Sphere& Sphere::setPosition(math::float3 const& position) noexcept {
auto& tcm = mEngine.getTransformManager();
auto ci = tcm.getInstance(mRenderable);
mat4f model = tcm.getTransform(ci);
model[3].xyz = position;
tcm.setTransform(ci, model);
return *this;
}
Sphere& Sphere::setRadius(float radius) noexcept {
auto& tcm = mEngine.getTransformManager();
auto ci = tcm.getInstance(mRenderable);
mat4f model = tcm.getTransform(ci);
model[0].x = radius;
model[1].y = radius;
model[2].z = radius;
tcm.setTransform(ci, model);
return *this;
}