Skip to content

Commit

Permalink
WIP: grid volume and RGB heterogeneous estimator
Browse files Browse the repository at this point in the history
  • Loading branch information
Enigmatisms committed Jun 21, 2024
1 parent 8c883b2 commit b50e7e1
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 6 deletions.
3 changes: 3 additions & 0 deletions bxdf/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*egg-info/
dist/
build/
27 changes: 27 additions & 0 deletions bxdf/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from pybind11.setup_helpers import Pybind11Extension
from setuptools import setup

__version__ = "0.1.0"
cxx_std=11

ext_modules = [
Pybind11Extension("vol_loader",
["vol_loader/vol2numpy.cpp"],
# Example: passing in the version to the compiled code
define_macros = [('VERSION_INFO', __version__)],
extra_compile_args= ['-g', '-O3'],
),
]

setup(
name="vol_loader",
version=__version__,
author="Qianyue He",
description="Volume grid loader",
include_dirs="/usr/include/eigen3/",
long_description="",
ext_modules=ext_modules,
extras_require={"test": "pytest"},
zip_safe=False,
python_requires=">=3.7",
)
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,14 @@ auto loadVol2Numpy(const std::string& filename) {
readVolumeData(filename, volume);

py::array_t<float> vol_numpy(volume.size());
float* const data_ptr = vol_numpy.mutable_data(0);
if (volume.channels == 1) {
for (int z = 0; z < volume.zres; ++z) {
int zy_base = z * volume.yres;
for (int y = 0; y < volume.yres; ++y) {
int zyx_base = (zy_base + y) * volume.xres;
for (int x = 0; x < volume.xres; ++x) {
vol_numpy[zyx_base + x] = volume.data[zyx_base + x];
data_ptr[zyx_base + x] = volume.data[zyx_base + x];
}
}
}
Expand All @@ -93,9 +94,9 @@ auto loadVol2Numpy(const std::string& filename) {
int zyx_base = (zy_base + y) * volume.xres;
for (int x = 0; x < volume.xres; ++x) {
int index = (zyx_base + x) * 3;
vol_numpy[index] = volume.data[index];
vol_numpy[index + 1] = volume.data[index + 1];
vol_numpy[index + 2] = volume.data[index + 2];
data_ptr[index] = volume.data[index];
data_ptr[index + 1] = volume.data[index + 1];
data_ptr[index + 2] = volume.data[index + 2];
}
}
}
Expand All @@ -107,7 +108,6 @@ auto loadVol2Numpy(const std::string& filename) {
}

PYBIND11_MODULE(vol_loader, m) {

m.doc() = "Volume grid (.vol / .vdb) loader (to numpy)\n";

m.def("vol_file_to_numpy", &loadVol2Numpy, "Load volume grid from mitsuba3 .vol file (return numpy)\n"
Expand Down
89 changes: 89 additions & 0 deletions bxdf/volume.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"""
Grid Volume Scattering Medium (RGB / Float)
@author: Qianyue He
@date: 2024-6-22
"""

import numpy as np
import taichi as ti
import xml.etree.ElementTree as xet

from taichi.math import vec3

from bxdf.phase import PhaseFunction
from bxdf.medium import Medium_np
from la.cam_transform import delocalize_rotate
from parsers.general_parser import get, rgb_parse
from sampler.general_sampling import random_rgb
from rich.console import Console
CONSOLE = Console(width = 128)

try:
from vol_loader import vol_file_to_numpy
except ImportError:
CONSOLE.log("[red]:skeleton: Error [/red]: vol_loader is not found, possible reason:")
CONSOLE.log(f"module not installed. Use 'python ./setup.py install --user' in {'./bxdf/'}")
raise ImportError("vol_loader not found")

""" TODO: add transform parsing
"""
class GridVolume_np:
__type_mapping = {"none": 0, "mono": 1, "rgb": 2}
def __init__(self, elem: xet.Element, is_world = False):
self.albedo = np.ones(3, np.float32)
self.par = np.zeros(3, np.float32)
self.pdf = np.float32([1., 0., 0.])
self.phase_type_id = -1
self.phase_type = "hg"
self.type_id = -1
self.type_name = "none"

self.xres = 0
self.yres = 0
self.zres = 0
self.channel = 0
self.grids = None

elem_to_query = {"rgb": rgb_parse, "float": lambda el: get(el, "value"), "string": lambda path: vol_file_to_numpy(path)}
if elem is not None:
type_name = elem.get("type")
if type_name in GridVolume_np.__type_mapping:
self.type_id = GridVolume_np.__type_mapping[type_name]
else:
raise NotImplementedError(f"GridVolume type '{type_name}' is not supported.")
self.type_name = type_name

phase_type = elem.get("phase_type")
if type_name in Medium_np.__type_mapping:
self.type_id = Medium_np.__type_mapping[phase_type]
else:
raise NotImplementedError(f"Phase function type '{phase_type}' is not supported.")

for tag, query_func in elem_to_query.items():
tag_elems = elem.findall(tag)
for tag_elem in tag_elems:
name = tag_elem.get("name")
if hasattr(self, name):
self.__setattr__(name, query_func(tag_elem))
else:
if not is_world:
CONSOLE.log("[yellow]:warning: Warning: default initialization yields <transparent>, which is a trivial medium.")
self.u_e = self.u_a + self.u_s

def setup_volume(self, path:str):
self.grids, (self.xres, self.yres, self.zres, self.channel) = vol_file_to_numpy(path)
CONSOLE.log(f"Volume grid loaded, type {self.type_name},\n \
shape: (x = {self.xres}, y = {self.yres}, z = {self.zres}, c = {self.channel})")

def export(self):
pass

def __repr__(self):
return f"<Volume grid {self.type_name.upper()} with phase {self.phase_type}, albedo: {self.albedo},\n \
shape: (x = {self.xres}, y = {self.yres}, z = {self.zres}, c = {self.channel})>"

@ti.dataclass
class GridVolume:
_type: int
albedo: vec3 # scattering

7 changes: 6 additions & 1 deletion parsers/xml_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ def parse_emitters(em_elem: list):
raise ValueError(f"Source [{emitter_type}] is not implemented.")
return sources, source_id_dict

def parse_volume(directory: str, vol_list: List[xet.Element]):

pass

def parse_wavefront(
directory: str, obj_list: List[xet.Element],
bsdf_dict: dict, emitter_dict: dict, texture_dict: List[Texture_np]) -> List[Arr]:
Expand Down Expand Up @@ -255,6 +259,7 @@ def scene_parsing(directory: str, file: str):
shape_nodes = root_node.findall("shape")
sensor_node = root_node.find("sensor")
world_node = root_node.find("world")
volume_node = root_node.find("volume")
assert(sensor_node)
emitter_configs, \
emitter_dict = parse_emitters(emitter_nodes)
Expand All @@ -268,7 +273,7 @@ def scene_parsing(directory: str, file: str):
Each mapping might needs a different packing, therefore we need different image packaging and texture info block
For normal mapping, non-bidirectional renderers will be simple but not for BDPT
roughness is of lower priority
- [ ] Speed up python->taichi conversion
- [x] Speed up python->taichi conversion
"""
array_info, all_objs, area_lut, has_vertex_normal \
= parse_wavefront(directory, shape_nodes, bsdf_dict, emitter_dict, textures)
Expand Down

0 comments on commit b50e7e1

Please sign in to comment.