feat: re-implement grid overlay
This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.app-sandbox</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.cs.allow-jit</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.network.server</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -1,57 +1,118 @@
|
|||||||
|
|
||||||
material {
|
material {
|
||||||
name : Grid,
|
name : Grid,
|
||||||
parameters : [
|
parameters : [
|
||||||
{
|
{
|
||||||
type : float,
|
type: float,
|
||||||
name : maxDistance
|
name: distance
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type : float3,
|
type: float,
|
||||||
name : color
|
name: lineSize
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
depthWrite : false,
|
depthWrite : true,
|
||||||
depthCulling : true,
|
depthCulling : true,
|
||||||
|
doubleSided: false,
|
||||||
shadingModel : unlit,
|
shadingModel : unlit,
|
||||||
blending: opaque,
|
blending : transparent,
|
||||||
variantFilter : [ skinning, shadowReceiver, vsm ],
|
variantFilter : [ dynamicLighting, directionalLighting, shadowReceiver, skinning, ssr, stereo ],
|
||||||
culling: none,
|
culling : none,
|
||||||
instanced: false,
|
instanced : false,
|
||||||
vertexDomain: object
|
vertexDomain : object
|
||||||
}
|
}
|
||||||
|
|
||||||
vertex {
|
vertex {
|
||||||
|
|
||||||
void materialVertex(inout MaterialVertexInputs material) {
|
void materialVertex(inout MaterialVertexInputs material) {
|
||||||
vec4 modelSpace = getPosition();
|
vec3 position = getPosition().xyz;
|
||||||
vec4 worldSpace = getWorldFromModelMatrix() * modelSpace;
|
position.xz *= materialParams.distance;
|
||||||
vec4 clipSpace = getClipFromWorldMatrix() * worldSpace;
|
material.worldPosition.xz = position.xz;
|
||||||
clipSpace.z = 0.02f;
|
|
||||||
material.worldPosition = getWorldFromClipMatrix() * clipSpace;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment {
|
fragment {
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
|
||||||
|
/* the below has been adapted from Blender's overlay_grid_frag.glsl */
|
||||||
|
|
||||||
|
#define _1_DIV_SQRTPI 0.5641895835477563
|
||||||
|
#define RADIUS (_1_DIV_SQRTPI * 1.05)
|
||||||
|
#define GRID_START (0.5 + RADIUS)
|
||||||
|
#define GRID_END (0.5 - RADIUS)
|
||||||
|
#define GRID_STEP(dist) smoothstep(GRID_START, GRID_END, dist)
|
||||||
|
|
||||||
|
float getGrid(vec2 point, vec2 fwidthCos, vec2 gridScale, float lineSize) {
|
||||||
|
vec2 halfSize = gridScale / 2.0;
|
||||||
|
vec2 gridDomain = abs(mod(point + halfSize, gridScale) - halfSize);
|
||||||
|
gridDomain /= fwidthCos;
|
||||||
|
float lineDist = min(gridDomain.x, gridDomain.y);
|
||||||
|
return GRID_STEP(lineDist - lineSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getAxes(vec3 point, vec3 fwidthCos, float line_size)
|
||||||
|
{
|
||||||
|
vec3 axes_domain = abs(point);
|
||||||
|
axes_domain /= fwidthCos;
|
||||||
|
return GRID_STEP(axes_domain - (line_size + materialParams.lineSize));
|
||||||
|
}
|
||||||
|
|
||||||
void material(inout MaterialInputs material) {
|
void material(inout MaterialInputs material) {
|
||||||
prepareMaterial(material);
|
prepareMaterial(material);
|
||||||
|
|
||||||
|
vec3 P = getWorldPosition().xyz;
|
||||||
|
vec3 dFdxPos = dFdx(P);
|
||||||
|
vec3 dFdyPos = dFdy(P);
|
||||||
|
vec3 fwidthPos = abs(dFdxPos) + abs(dFdyPos);
|
||||||
|
|
||||||
|
P += mulMat4x4Float3(getUserWorldFromWorldMatrix(), getWorldCameraPosition()).xyz;
|
||||||
|
|
||||||
|
vec3 V = getWorldPosition().xyz;
|
||||||
|
float dist = length(V);
|
||||||
|
V /= dist;
|
||||||
|
|
||||||
// Convert world position to view space
|
float angle = V.y;
|
||||||
float4 viewPos = getViewFromWorldMatrix() * float4(getWorldPosition(), 1.0);
|
|
||||||
|
angle = 1.0 - abs(angle);
|
||||||
|
angle *= angle;
|
||||||
|
float fade = 1.0 - angle;
|
||||||
|
fade *= 0.5 - smoothstep(0.0, materialParams.distance, dist - materialParams.distance);
|
||||||
|
|
||||||
|
float gridA = getGrid(P.xz, fwidthPos.xz, vec2(1.0, 1.0), materialParams.lineSize);
|
||||||
|
|
||||||
|
vec3 planeAxes = vec3(1.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
vec3 distanceToAxes = vec3(
|
||||||
|
dot(P.yz, planeAxes.yz),
|
||||||
|
0.0f,
|
||||||
|
dot(P.xy, planeAxes.xy)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec3 dAxes = vec3(
|
||||||
|
dot(fwidthPos.yz, planeAxes.yz),
|
||||||
|
0.0f,
|
||||||
|
dot(fwidthPos.xy, planeAxes.xy)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec3 axes = getAxes(distanceToAxes, dAxes, 0.1);
|
||||||
|
|
||||||
|
vec4 color = vec4(
|
||||||
|
0.1f,
|
||||||
|
0.1f,
|
||||||
|
0.1f,
|
||||||
|
gridA
|
||||||
|
);
|
||||||
|
|
||||||
|
color.a = max(color.a, axes.x);
|
||||||
|
color.rgb = (axes.x < 1e-8) ? color.rgb : AXIS_COLOR_X;
|
||||||
|
|
||||||
|
color.a = max(color.a, axes.z);
|
||||||
|
color.rgb = (axes.z < 1e-8) ? color.rgb : AXIS_COLOR_Z;
|
||||||
|
|
||||||
|
color.a *= fade;
|
||||||
|
|
||||||
|
material.baseColor = color;
|
||||||
|
|
||||||
// Calculate distance in view space (camera is at 0,0,0 in view space)
|
|
||||||
float distance = length(viewPos.xz);
|
|
||||||
|
|
||||||
// Discard fragment if it's too far from the camera
|
|
||||||
if (distance > materialParams.maxDistance) {
|
|
||||||
material.baseColor = float4(0.0);
|
|
||||||
} else {
|
|
||||||
material.baseColor = float4(materialParams.color, 1.0);
|
|
||||||
|
|
||||||
// Optional: fade out as we approach maxDistance
|
|
||||||
float fadeStart = materialParams.maxDistance * 0.8;
|
|
||||||
if (distance > fadeStart) {
|
|
||||||
float fade = 1.0 - (distance - fadeStart) / (materialParams.maxDistance - fadeStart);
|
|
||||||
material.baseColor.a = fade;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
4
materials/shared.h
Normal file
4
materials/shared.h
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0, 1.0))
|
||||||
|
#define AXIS_COLOR_X vec3(1.0f, 0.0f, 0.0f)
|
||||||
|
#define AXIS_COLOR_Y vec3(0.0f, 1.0f, 0.0f)
|
||||||
|
#define AXIS_COLOR_Z vec3(0.0f, 0.0f, 1.0f)
|
||||||
@@ -8,5 +8,5 @@ GRID_PACKAGE:
|
|||||||
GRID_GRID_OFFSET:
|
GRID_GRID_OFFSET:
|
||||||
.int 0
|
.int 0
|
||||||
GRID_GRID_SIZE:
|
GRID_GRID_SIZE:
|
||||||
.int 44564
|
.int 47596
|
||||||
|
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ _GRID_PACKAGE:
|
|||||||
_GRID_GRID_OFFSET:
|
_GRID_GRID_OFFSET:
|
||||||
.int 0
|
.int 0
|
||||||
_GRID_GRID_SIZE:
|
_GRID_GRID_SIZE:
|
||||||
.int 44564
|
.int 47596
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,8 @@
|
|||||||
#include <filament/MaterialInstance.h>
|
#include <filament/MaterialInstance.h>
|
||||||
#include <utils/Entity.h>
|
#include <utils/Entity.h>
|
||||||
#include "scene/SceneAsset.hpp"
|
#include "scene/SceneAsset.hpp"
|
||||||
|
#include "material/grid.h"
|
||||||
|
|
||||||
|
|
||||||
namespace thermion {
|
namespace thermion {
|
||||||
|
|
||||||
@@ -15,7 +17,7 @@ using namespace filament;
|
|||||||
|
|
||||||
class GridOverlay : public SceneAsset {
|
class GridOverlay : public SceneAsset {
|
||||||
public:
|
public:
|
||||||
GridOverlay(Engine& engine);
|
GridOverlay(Engine& engine, Material* material);
|
||||||
~GridOverlay();
|
~GridOverlay();
|
||||||
|
|
||||||
SceneAssetType getType() override { return SceneAsset::SceneAssetType::Gizmo; }
|
SceneAssetType getType() override { return SceneAsset::SceneAssetType::Gizmo; }
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
#include "scene/GridOverlay.hpp"
|
#include "scene/GridOverlay.hpp"
|
||||||
#include "scene/SceneManager.hpp"
|
#include "scene/SceneManager.hpp"
|
||||||
#include "material/grid.h"
|
|
||||||
#include "Log.hpp"
|
#include "Log.hpp"
|
||||||
|
|
||||||
namespace thermion
|
namespace thermion
|
||||||
{
|
{
|
||||||
|
|
||||||
GridOverlay::GridOverlay(Engine &engine) : _engine(engine)
|
GridOverlay::GridOverlay(Engine &engine, Material *material) : _engine(engine), _material(material)
|
||||||
{
|
{
|
||||||
createGrid();
|
createGrid();
|
||||||
createSphere();
|
createSphere();
|
||||||
_childEntities[0] = _gridEntity;
|
|
||||||
_childEntities[1] = _sphereEntity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GridOverlay::~GridOverlay()
|
GridOverlay::~GridOverlay()
|
||||||
@@ -31,88 +28,98 @@ namespace thermion
|
|||||||
|
|
||||||
void GridOverlay::createGrid()
|
void GridOverlay::createGrid()
|
||||||
{
|
{
|
||||||
const int gridSize = 100;
|
const float stepSize = 0.25f;
|
||||||
const float gridSpacing = 1.0f;
|
const int gridSize = 8; // Number of grid cells in each direction (-1 to 1 with 0.25 step = 8 cells)
|
||||||
int vertexCount = (gridSize + 1) * 4; // 2 axes, 2 vertices per line
|
const int vertexCount = gridSize * gridSize * 4; // 4 vertices per grid cell
|
||||||
|
const int indexCount = gridSize * gridSize * 6; // 6 indices (2 triangles) per grid cell
|
||||||
|
|
||||||
float *gridVertices = new float[vertexCount * 3];
|
std::vector<math::float3> *vertices = new std::vector<math::float3>();
|
||||||
int index = 0;
|
std::vector<uint32_t> *indices = new std::vector<uint32_t>();
|
||||||
|
vertices->reserve(vertexCount);
|
||||||
|
indices->reserve(indexCount);
|
||||||
|
|
||||||
// Create grid lines
|
// Generate grid vertices and indices
|
||||||
for (int i = 0; i <= gridSize; ++i)
|
for (float x = -1.0f; x < 1.0f; x += stepSize)
|
||||||
{
|
{
|
||||||
float pos = i * gridSpacing - (gridSize * gridSpacing / 2);
|
for (float z = -1.0f; z < 1.0f; z += stepSize)
|
||||||
|
{
|
||||||
|
uint32_t baseIndex = vertices->size();
|
||||||
|
|
||||||
// X-axis lines
|
// Add four vertices for this grid cell
|
||||||
gridVertices[index++] = pos;
|
vertices->push_back({x, 0.0f, z}); // Bottom-left
|
||||||
gridVertices[index++] = 0;
|
vertices->push_back({x, 0.0f, z + stepSize}); // Top-left
|
||||||
gridVertices[index++] = -(gridSize * gridSpacing / 2);
|
vertices->push_back({x + stepSize, 0.0f, z + stepSize}); // Top-right
|
||||||
|
vertices->push_back({x + stepSize, 0.0f, z}); // Bottom-right
|
||||||
|
|
||||||
gridVertices[index++] = pos;
|
// Add indices for two triangles
|
||||||
gridVertices[index++] = 0;
|
indices->push_back(baseIndex);
|
||||||
gridVertices[index++] = (gridSize * gridSpacing / 2);
|
indices->push_back(baseIndex + 1);
|
||||||
|
indices->push_back(baseIndex + 2);
|
||||||
// Z-axis lines
|
indices->push_back(baseIndex + 2);
|
||||||
gridVertices[index++] = -(gridSize * gridSpacing / 2);
|
indices->push_back(baseIndex + 3);
|
||||||
gridVertices[index++] = 0;
|
indices->push_back(baseIndex);
|
||||||
gridVertices[index++] = pos;
|
}
|
||||||
|
|
||||||
gridVertices[index++] = (gridSize * gridSpacing / 2);
|
|
||||||
gridVertices[index++] = 0;
|
|
||||||
gridVertices[index++] = pos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto vb = VertexBuffer::Builder()
|
auto vb = VertexBuffer::Builder()
|
||||||
.vertexCount(vertexCount)
|
.vertexCount(vertices->size())
|
||||||
.bufferCount(1)
|
.bufferCount(1)
|
||||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||||
.build(_engine);
|
.build(_engine);
|
||||||
|
|
||||||
vb->setBufferAt(_engine, 0, VertexBuffer::BufferDescriptor(gridVertices, vertexCount * sizeof(math::float3), [](void *buffer, size_t size, void *)
|
vb->setBufferAt(_engine, 0,
|
||||||
{ delete[] static_cast<float *>(buffer); }));
|
VertexBuffer::BufferDescriptor(
|
||||||
|
vertices->data(),
|
||||||
uint32_t *gridIndices = new uint32_t[vertexCount];
|
vertices->size() * sizeof(math::float3),
|
||||||
for (uint32_t i = 0; i < vertexCount; ++i)
|
[](void *buffer, size_t size, void *user) {
|
||||||
{
|
delete static_cast<std::vector<math::float3>*>(user);
|
||||||
gridIndices[i] = i;
|
}, vertices));
|
||||||
}
|
|
||||||
|
|
||||||
auto ib = IndexBuffer::Builder()
|
auto ib = IndexBuffer::Builder()
|
||||||
.indexCount(vertexCount)
|
.indexCount(indices->size())
|
||||||
.bufferType(IndexBuffer::IndexType::UINT)
|
.bufferType(IndexBuffer::IndexType::UINT)
|
||||||
.build(_engine);
|
.build(_engine);
|
||||||
|
|
||||||
ib->setBuffer(_engine, IndexBuffer::BufferDescriptor(
|
ib->setBuffer(_engine,
|
||||||
gridIndices,
|
IndexBuffer::BufferDescriptor(
|
||||||
vertexCount * sizeof(uint32_t),
|
indices->data(),
|
||||||
[](void *buffer, size_t size, void *)
|
indices->size() * sizeof(uint32_t),
|
||||||
{ delete[] static_cast<uint32_t *>(buffer); }));
|
[](void *buffer, size_t size, void *user) {
|
||||||
|
delete static_cast<std::vector<uint32_t>*>(user);
|
||||||
|
}, indices));
|
||||||
|
|
||||||
_gridEntity = utils::EntityManager::get().create();
|
_gridEntity = utils::EntityManager::get().create();
|
||||||
_material = Material::Builder()
|
|
||||||
.package(GRID_PACKAGE, GRID_GRID_SIZE)
|
|
||||||
.build(_engine);
|
|
||||||
|
|
||||||
_materialInstance = _material->createInstance();
|
_materialInstance = _material->createInstance();
|
||||||
_materialInstance->setParameter("maxDistance", 50.0f);
|
|
||||||
_materialInstance->setParameter("color", math::float3{0.05f, 0.05f, 0.05f});
|
// Set material parameters to match Dart implementation
|
||||||
|
_materialInstance->setParameter("distance", 10000.0f);
|
||||||
|
_materialInstance->setParameter("lineSize", 0.01f);
|
||||||
|
_materialInstance->setCullingMode(MaterialInstance::CullingMode::NONE);
|
||||||
|
|
||||||
RenderableManager::Builder(1)
|
RenderableManager::Builder(1)
|
||||||
.boundingBox({{-gridSize * gridSpacing / 2, 0, -gridSize * gridSpacing / 2},
|
.boundingBox({{-1.0f, -1.0f, -1.0f}, // Min point
|
||||||
{gridSize * gridSpacing / 2, 0, gridSize * gridSpacing / 2}})
|
{1.0f, 1.0f, 1.0f}}) // Max point
|
||||||
|
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb, ib, 0, indices->size())
|
||||||
.material(0, _materialInstance)
|
.material(0, _materialInstance)
|
||||||
.geometry(0, RenderableManager::PrimitiveType::LINES, vb, ib, 0, vertexCount)
|
.priority(1)
|
||||||
.priority(7)
|
|
||||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||||
.culling(true)
|
/*
|
||||||
|
We disable culling here because we calculate the quad's world-space coordinates
|
||||||
|
manually in the shader (see grid.mat). Without this, the quad would be culled before
|
||||||
|
rendered.
|
||||||
|
*/
|
||||||
|
.culling(false)
|
||||||
.receiveShadows(false)
|
.receiveShadows(false)
|
||||||
.castShadows(false)
|
.castShadows(false)
|
||||||
.build(_engine, _gridEntity);
|
.build(_engine, _gridEntity);
|
||||||
|
|
||||||
|
_childEntities[0] = _gridEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridOverlay::createSphere()
|
void GridOverlay::createSphere()
|
||||||
{
|
{
|
||||||
const float sphereRadius = 0.05f;
|
const float sphereRadius = 1.05f;
|
||||||
const int sphereSegments = 16;
|
const int sphereSegments = 16;
|
||||||
const int sphereRings = 16;
|
const int sphereRings = 16;
|
||||||
|
|
||||||
@@ -195,14 +202,15 @@ namespace thermion
|
|||||||
.receiveShadows(false)
|
.receiveShadows(false)
|
||||||
.castShadows(false)
|
.castShadows(false)
|
||||||
.build(_engine, _sphereEntity);
|
.build(_engine, _sphereEntity);
|
||||||
|
_childEntities[1] = _sphereEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneAsset *GridOverlay::createInstance(MaterialInstance **materialInstances, size_t materialInstanceCount)
|
SceneAsset *GridOverlay::createInstance(MaterialInstance **materialInstances, size_t materialInstanceCount)
|
||||||
{
|
{
|
||||||
auto instance = std::make_unique<GridOverlay>(_engine);
|
auto instance = std::make_unique<GridOverlay>(_engine, _material);
|
||||||
auto *raw = instance.get();
|
auto *raw = instance.get();
|
||||||
_instances.push_back(std::move(instance));
|
_instances.push_back(std::move(instance));
|
||||||
return reinterpret_cast<SceneAsset*>(raw);
|
return reinterpret_cast<SceneAsset *>(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridOverlay::addAllEntities(Scene *scene)
|
void GridOverlay::addAllEntities(Scene *scene)
|
||||||
|
|||||||
Reference in New Issue
Block a user