Files
filament/samples/app/Sphere.cpp
Philip Rideout 91abaf575b Add tangents utility to fix #532.
I tested this by writing a quick-and-dirty Sphere demo.
2018-11-28 11:27:37 -08:00

135 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);
geometry->tangents.resize(vertices.size());
VertexBuffer::populateTangentQuaternions(VertexBuffer::QuatTangentContext {
.quatType = VertexBuffer::SHORT4,
.quatCount = vertices.size(),
.outBuffer = geometry->tangents.data(),
.outStride = sizeof(math::short4),
.normals = vertices.data()
});
// todo produce correct u,v
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;
}