OverviewFilesCommitsIssuesDocsReleasesPeers

proc-nodes / src / core / proc_volume.h

91 lines · c ref:
#ifndef PROC_NODES_PROC_VOLUME_H
#define PROC_NODES_PROC_VOLUME_H

#include <godot_cpp/classes/material.hpp>
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/variant/packed_float32_array.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/vector3.hpp>
#include <godot_cpp/variant/vector3i.hpp>

namespace godot {

// Volume data for SDF/density field evaluation.
// Holds either a compiled GLSL function (for GPU evaluation) or a pre-computed
// density grid (for CPU evaluation), or both.
class ProcVolume : public RefCounted {
	GDCLASS(ProcVolume, RefCounted);

protected:
	static void _bind_methods();

public:
	// Compiled GLSL density function source.
	// Expected signature: float proc_density(vec3 pos) { ... }
	String glsl_source;

	// Pre-computed density grid (optional, for CPU path or caching).
	// Layout: density[z * res.x * res.y + y * res.x + x]
	PackedFloat32Array density_grid;

	// Grid parameters
	Vector3 grid_origin;
	Vector3 grid_size = Vector3(64, 64, 64);
	Vector3i grid_resolution = Vector3i(64, 64, 64);

	// Getters/setters
	String get_glsl_source() const { return glsl_source; }
	void set_glsl_source(const String &p_src) { glsl_source = p_src; }

	PackedFloat32Array get_density_grid() const { return density_grid; }
	void set_density_grid(const PackedFloat32Array &p_grid) { density_grid = p_grid; }

	Vector3 get_grid_origin() const { return grid_origin; }
	void set_grid_origin(const Vector3 &p_origin) { grid_origin = p_origin; }

	Vector3 get_grid_size() const { return grid_size; }
	void set_grid_size(const Vector3 &p_size) { grid_size = p_size; }

	Vector3i get_grid_resolution() const { return grid_resolution; }
	void set_grid_resolution(const Vector3i &p_res) { grid_resolution = p_res; }

	bool has_glsl() const { return !glsl_source.is_empty(); }
	bool has_grid() const { return density_grid.size() > 0; }

	// ── THE GPU CONSUMER ─────────────────────────────────────────────────────
	//
	// A Godot `shader_type fog` material wrapping this volume's proc_density,
	// for a FogVolume to raymarch. That is dc-terrain-nubis Layer 3 -- the
	// artist-placed local effects layer -- and it is the whole reason
	// glsl_source exists: an authored cloud formation, a fog body, a blob, made
	// in the graph editor and rendered by the engine's own froxel pass. No
	// custom compute pipeline.
	//
	// ⚠ THE EMITTED TEXT MUST BE GODOT SHADING LANGUAGE, NOT GLSL 450. They are
	// close but not the same: no `#version`, and Godot rejects a mutable global
	// at file scope. compile_to_glsl_function's output for an SDF graph is
	// already portable (measured: 469 characters of vec3/float/max/length, all
	// of which Godot has). A graph pulling in a noise prelude is the case to
	// check, not to assume -- see demo/fog_shader_gate.gd, which compiles the
	// result for real rather than eyeballing it.
	String build_fog_shader_code() const;

	// The same thing as a ready ShaderMaterial, so a scene is two lines:
	//   fog_volume.material = volume.make_fog_material()
	//   fog_volume.size = ...
	Ref<Material> make_fog_material() const;

	// Sample density from pre-computed grid (trilinear interpolation)
	float sample_density(const Vector3 &p_world_pos) const;

	// Deep copy
	Ref<ProcVolume> duplicate_volume() const;

	ProcVolume() = default;
};

} // namespace godot

#endif // PROC_NODES_PROC_VOLUME_H