Full Code of PKU-EPIC/GraspNeRF for AI

main 946e12a11fa2 cached
61 files
657.5 KB
179.1k tokens
727 symbols
1 requests
Download .txt
Showing preview only (684K chars total). Download the full file or copy to clipboard to get everything.
Repository: PKU-EPIC/GraspNeRF
Branch: main
Commit: 946e12a11fa2
Files: 61
Total size: 657.5 KB

Directory structure:
gitextract_hto38wet/

├── .gitignore
├── README.md
├── data_generator/
│   ├── modify_material.py
│   ├── render_pile_STD_rand.py
│   └── run_pile_rand.sh
├── requirements.txt
├── run_simgrasp.sh
├── scripts/
│   ├── sim_grasp.py
│   └── stat_expresult.py
├── src/
│   ├── gd/
│   │   ├── __init__.py
│   │   ├── baselines.py
│   │   ├── dataset.py
│   │   ├── detection.py
│   │   ├── experiments/
│   │   │   ├── __init__.py
│   │   │   └── clutter_removal.py
│   │   ├── grasp.py
│   │   ├── io.py
│   │   ├── networks.py
│   │   ├── perception.py
│   │   ├── simulation.py
│   │   ├── utils/
│   │   │   ├── __init__.py
│   │   │   ├── btsim.py
│   │   │   ├── panda_control.py
│   │   │   ├── ros_utils.py
│   │   │   └── transform.py
│   │   └── vis.py
│   ├── nr/
│   │   ├── asset.py
│   │   ├── configs/
│   │   │   └── nrvgn_sdf.yaml
│   │   ├── dataset/
│   │   │   ├── database.py
│   │   │   ├── name2dataset.py
│   │   │   └── train_dataset.py
│   │   ├── main.py
│   │   ├── network/
│   │   │   ├── aggregate_net.py
│   │   │   ├── dist_decoder.py
│   │   │   ├── ibrnet.py
│   │   │   ├── init_net.py
│   │   │   ├── loss.py
│   │   │   ├── metrics.py
│   │   │   ├── mvsnet/
│   │   │   │   ├── modules.py
│   │   │   │   └── mvsnet.py
│   │   │   ├── neus.py
│   │   │   ├── ops.py
│   │   │   ├── render_ops.py
│   │   │   ├── renderer.py
│   │   │   └── vis_encoder.py
│   │   ├── run_training.py
│   │   ├── train/
│   │   │   ├── lr_common_manager.py
│   │   │   ├── train_tools.py
│   │   │   ├── train_valid.py
│   │   │   └── trainer.py
│   │   └── utils/
│   │       ├── base_utils.py
│   │       ├── dataset_utils.py
│   │       ├── draw_utils.py
│   │       ├── field_utils.py
│   │       ├── grasp_utils.py
│   │       ├── imgs_info.py
│   │       └── view_select.py
│   └── rd/
│       ├── modify_material.py
│       ├── render.py
│       └── render_utils.py
└── train.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
.venv-py2
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/

# vscode
.vscode

# data
data

__pycache__

*.log
log/

output/
ckpt/

*.pth

================================================
FILE: README.md
================================================
# GraspNeRF: Multiview-based 6-DoF Grasp Detection for Transparent and Specular Objects Using Generalizable NeRF (ICRA 2023)

This is the official repository of [**GraspNeRF: Multiview-based 6-DoF Grasp Detection for Transparent and Specular Objects Using Generalizable NeRF**](https://arxiv.org/abs/2210.06575).

For more information, please visit our [**project page**](https://pku-epic.github.io/GraspNeRF/).

## Introduction
<img src="images/teaser.png" width="640">

In this work, we propose a multiview RGB-based 6-DoF grasp detection network, **GraspNeRF**, 
that leverages the **generalizable neural radiance field (NeRF)** to achieve material-agnostic object grasping in clutter. 
Compared to the existing NeRF-based 3-DoF grasp detection methods that rely on densely captured input images and time-consuming per-scene optimization, 
our system can perform zero-shot NeRF construction with **sparse RGB inputs** and reliably detect **6-DoF grasps**, both in **real-time**. 
The proposed framework jointly learns generalizable NeRF and grasp detection in an **end-to-end** manner, optimizing the scene representation construction for the grasping. 
For training data, we generate a large-scale photorealistic **domain-randomized synthetic dataset** of grasping in cluttered tabletop scenes that enables direct transfer to the real world. 
Experiments in synthetic and real-world environments demonstrate that our method significantly outperforms all the baselines in all the experiments.

## Overview
This repository provides:
- PyTorch code, and weights of GraspNeRF.
- Grasp Simulator based on blender and pybullet.
- Multiview 6-DoF Grasping Dataset Generator and Examples.

## Dependency
1. Please run 
```
pip install -r requirements.txt
```
to install dependency.

2. (optional) Please install [blender 2.93.3--Ubuntu](https://www.blender.org/) if you need simulation.

## Data & Checkpoints
1. Please generate or download and uncompress the [example data](https://drive.google.com/file/d/1Ku-EotayUhfv5DtXAvFitGzzdMF84Ve2/view?usp=share_link) to `data/` for training, and [rendering assets](https://drive.google.com/file/d/1Udvi2QQ6AtYDLUWY0oH-PO2R6kZBxJLT/view?usp=share_link) to `data/assets` for simulation. 
Specifically, download [imagenet valset](https://image-net.org/data/ILSVRC/2010/ILSVRC2010_images_val.tar) to `data/assets/imagenet/images/val` which is used as random texture in simulation. 
2. We provide pretrained weights for testing. Please download the [checkpoint](https://drive.google.com/file/d/1k-Cy4NO2isCBYc3az-34HEdcNxDptDgU/view?usp=share_link) to `src/nr/ckpt/test`. 

## Testing
Our grasp simulation pipeline is depend on blender and pybullet. Please verify the installation before running simulation.

After the dependency and assets are ready, please run 
```
bash run_simgrasp.sh
```

## Training
After the training data is ready, please run
```
bash train.sh GPU_ID
```
e.g. `bash train.sh 0`.

## Data Generator
1. Download the scene descriptor files from [GIGA](https://github.com/UT-Austin-RPL/GIGA#pre-generated-data) and [assets](https://drive.google.com/file/d/1-59zcQ8h5esT_ogjaDjtzQ6sG70WNWzU/view?usp=share_link).
2. For example, run 
```
bash run_pile_rand.sh 
```
in ./data_generator for pile data generation.

## Citation
If you find our work useful in your research, please consider citing:

```
@article{Dai2023GraspNeRF,
  title={GraspNeRF: Multiview-based 6-DoF Grasp Detection for Transparent and Specular Objects Using Generalizable NeRF},
  author={Qiyu Dai and Yan Zhu and Yiran Geng and Ciyu Ruan and Jiazhao Zhang and He Wang},
  booktitle={IEEE International Conference on Robotics and Automation (ICRA)},
  year={2023}
```

## License

 This work and the dataset are licensed under [CC BY-NC 4.0][cc-by-nc].

 [![CC BY-NC 4.0][cc-by-nc-image]][cc-by-nc]

 [cc-by-nc]: https://creativecommons.org/licenses/by-nc/4.0/
 [cc-by-nc-image]: https://licensebuttons.net/l/by-nc/4.0/88x31.png

## Contact
If you have any questions, please open a github issue or contact us:

Qiyu Dai: qiyudai@pku.edu.cn, Yan Zhu: zhuyan_@stu.pku.edu.cn, He Wang: hewang@pku.edu.cn


================================================
FILE: data_generator/modify_material.py
================================================
from mathutils import Vector
import bpy
import random
import math

def modify_material(mat_links, mat_nodes, material_name, mat_randomize_mode, is_texture=False, orign_base_color=None, tex_node=None, is_transfer=True, is_arm=False):
    if is_transfer:
        if material_name.split("_")[0] == "metal" or material_name.split("_")[0] == "porcelain" or material_name.split("_")[0] == "plasticsp" or material_name.split("_")[0] == "paintsp":
            tex_mix_prop = random.uniform(0.85, 0.98)
        else:
            tex_mix_prop = random.uniform(0.7, 0.95)
        mix_prop = random.uniform(0.6, 0.9)


        if mat_randomize_mode == "specular_texmix" or mat_randomize_mode == "mixed" \
            or material_name.split("_")[0] == "metal" or material_name.split("_")[0] == "porcelain" \
            or material_name.split("_")[0] == "plasticsp" or material_name.split("_")[0] == "paintsp":
            transfer_rand = random.randint(0,2)
        else:
            transfer_rand = 1

        if transfer_rand == 1:
            transfer_flag = True
        else:
            transfer_flag = False
            tex_mix_prop = 1
            mix_prop = 1
            if not is_arm:
                bs_color_rand = random.uniform(-0.2, 0.2)
            else:
                bs_color_rand = 0
            r_rand = bs_color_rand
            g_rand = bs_color_rand
            b_rand = bs_color_rand


    else:
        tex_mix_prop = 1
        mix_prop = 1
        transfer_flag = False
        if not is_arm:
            bs_color_rand = random.uniform(-0.2, 0.2)
        else:
            bs_color_rand = 0
        r_rand = bs_color_rand
        g_rand = bs_color_rand
        b_rand = bs_color_rand
    
    bsdfnode_list = [n for n in mat_nodes if isinstance(n, bpy.types.ShaderNodeBsdfPrincipled)]
    if bsdfnode_list != []:
        for bsdfnode in bsdfnode_list:
            if not bsdfnode.inputs[4].links:    # metallic
                src_value = bsdfnode.inputs[4].default_value
                if material_name.split("_")[0] == "metal":
                    new_value = src_value + random.uniform(-0.05, 0.05)
                elif material_name.split("_")[0] == "porcelain":
                    new_value = src_value + random.uniform(-0.05, 0.1)
                elif material_name.split("_")[0] == "plasticsp":
                    new_value = src_value + random.uniform(-0.05, 0.1)
                else:
                    new_value = src_value + random.uniform(-0.05, 0.05)
                if new_value > 1.0: new_value = 1.0
                elif new_value < 0: new_value = 0.0
                bsdfnode.inputs[4].default_value = new_value 
            if not bsdfnode.inputs[5].links:    # specular
                src_value = bsdfnode.inputs[5].default_value
                #if material_name.split("_")[0] == "metal":
                new_value = src_value + random.uniform(0, 0.3)
                if new_value > 1.0: new_value = 1.0
                elif new_value < 0: new_value = 0.0
                bsdfnode.inputs[5].default_value = new_value
            if not bsdfnode.inputs[6].links:    # specularTint
                src_value = bsdfnode.inputs[6].default_value
                new_value = src_value + random.uniform(-1, 1)
                if new_value > 1.0: new_value = 1.0
                elif new_value < 0: new_value = 0.0
                bsdfnode.inputs[6].default_value = new_value
            if not bsdfnode.inputs[7].links:    # roughness
                src_value = bsdfnode.inputs[7].default_value
                if material_name.split("_")[0] == "metal" or material_name.split("_")[0] == "porcelain" or material_name.split("_")[0] == "plasticsp" or material_name.split("_")[0] == "paintsp":
                    new_value = src_value + random.uniform(-0.2, 0.01)
                else:
                    new_value = src_value + random.uniform(-0.03, 0.1)
                if new_value > 1.0: new_value = 1.0
                elif new_value < 0: new_value = 0.0
                bsdfnode.inputs[7].default_value = new_value
            if not bsdfnode.inputs[8].links:    # anisotropic
                src_value = bsdfnode.inputs[8].default_value
                new_value = src_value + random.uniform(-0.1, 0.1)
                if new_value > 1.0: new_value = 1.0
                elif new_value < 0: new_value = 0.0
                bsdfnode.inputs[8].default_value = new_value
            if not bsdfnode.inputs[9].links:    # anisotropicRotation
                src_value = bsdfnode.inputs[9].default_value
                new_value = src_value + random.uniform(-0.3, 0.3)
                if new_value > 1.0: new_value = 1.0
                elif new_value < 0: new_value = 0.0
                bsdfnode.inputs[9].default_value = new_value
            if not bsdfnode.inputs[10].links:    # sheen
                src_value = bsdfnode.inputs[10].default_value
                new_value = src_value + random.uniform(-0.1, 0.1)
                if new_value > 1.0: new_value = 1.0
                elif new_value < 0: new_value = 0.0
                bsdfnode.inputs[10].default_value = new_value
            if not bsdfnode.inputs[11].links:    # sheenTint
                src_value = bsdfnode.inputs[11].default_value
                new_value = src_value + random.uniform(-0.2, 0.2)
                if new_value > 1.0: new_value = 1.0
                elif new_value < 0: new_value = 0.0
                bsdfnode.inputs[11].default_value = new_value
            if not bsdfnode.inputs[12].links:    # clearcoat
                src_value = bsdfnode.inputs[12].default_value
                new_value = src_value + random.uniform(-0.2, 0.2)
                if new_value > 1.0: new_value = 1.0
                elif new_value < 0: new_value = 0.0
                bsdfnode.inputs[12].default_value = new_value
            if not bsdfnode.inputs[13].links:    # clearcoatGloss
                src_value = bsdfnode.inputs[13].default_value
                new_value = src_value + random.uniform(-0.2, 0.2)
                if new_value > 1.0: new_value = 1.0
                elif new_value < 0: new_value = 0.0
                bsdfnode.inputs[13].default_value = new_value

    ## metal
    if material_name == "metal_0":
        # mat_nodes["Principled BSDF"].inputs[4].default_value = random.uniform(0.95, 1.00)       # metallic
        # mat_nodes["Principled BSDF"].inputs[5].default_value = random.uniform(0.3, 1.0)         # specular
        # mat_nodes["Principled BSDF"].inputs[6].default_value = random.uniform(0.0, 1.0)         # specularTint
        mat_nodes["Principled BSDF"].inputs[8].default_value = random.uniform(0.0, 1.0)         # anisotropic
        # mat_nodes["Principled BSDF"].inputs[9].default_value = random.uniform(0.0, 1.0)         # anisotropicRotation
        # mat_nodes["Principled BSDF"].inputs[12].default_value = random.uniform(0.0, 1.0)         # clearcoat
        # mat_nodes["Principled BSDF"].inputs[13].default_value = random.uniform(0.3, 1.0)         # clearcoatGloss

        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9  
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.7  

            mat_links.new(mat_nodes["Normal Map"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])
            mat_links.new(mat_nodes["Image Texture.002"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])

            mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])
    elif material_name == "metal_1":
        # mat_nodes["Principled BSDF"].inputs[4].default_value = random.uniform(0.9, 1.00)        # metallic
        # mat_nodes["Principled BSDF"].inputs[5].default_value = random.uniform(0.5, 1.0)         # specular
        # mat_nodes["Principled BSDF"].inputs[6].default_value = random.uniform(0.5, 1.0)         # specularTint
        mat_nodes["Principled BSDF"].inputs[7].default_value = random.uniform(0.08, 0.25)         # roughness
        mat_nodes["Principled BSDF"].inputs[8].default_value = random.uniform(0.04, 0.5)         # anisotropic
        # mat_nodes["Principled BSDF"].inputs[9].default_value = random.uniform(0.3, 0.7)         # anisotropicRotation
        # mat_nodes["Principled BSDF"].inputs[12].default_value = random.uniform(0.8, 1.0)         # clearcoat
        # mat_nodes["Principled BSDF"].inputs[13].default_value = random.uniform(0.0, 1.0)         # clearcoatGloss
        
        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9  
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.7  

            mat_links.new(mat_nodes["Tangent"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[22]) 

            mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])
        else:
            bs_color = mat_nodes["Principled BSDF"].inputs[0].default_value
            
            new_bs_color_r = bs_color[0] + r_rand
            new_bs_color_g = bs_color[1] + g_rand
            new_bs_color_b = bs_color[2] + b_rand
            if new_bs_color_r < 0:
                new_bs_color_r = 0
            if new_bs_color_g < 0:
                new_bs_color_g = 0
            if new_bs_color_b < 0:
                new_bs_color_b = 0
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(new_bs_color)
    elif material_name == "metal_10":
        
        # mat_nodes["Principled BSDF"].inputs[5].default_value = random.uniform(0.5, 1.0)         # specular
        # mat_nodes["Principled BSDF"].inputs[6].default_value = random.uniform(0.0, 1.0)         # specularTint
        mat_nodes["Principled BSDF"].inputs[8].default_value = random.uniform(0.0, 0.5)         # anisotropic
        # mat_nodes["Principled BSDF"].inputs[9].default_value = random.uniform(0.3, 0.7)         # anisotropicRotation
        # mat_nodes["Principled BSDF"].inputs[12].default_value = random.uniform(0.0, 1.0)         # clearcoat
        # mat_nodes["Principled BSDF"].inputs[13].default_value = random.uniform(0.0, 1.0)         # clearcoatGloss
        
        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            bsdf_new.location = Vector((-800, 0))
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'
            mix_new.location = Vector((-800, 0))

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.7

            mat_links.new(mat_nodes["Image Texture"].outputs[1], mat_nodes["Principled BSDF-new"].inputs[19])
            mat_links.new(mat_nodes["Image Texture.001"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[4])
            mat_links.new(mat_nodes["Normal Map"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])
            mat_links.new(mat_nodes["ColorRamp"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])

            mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])
    elif material_name == "metal_11":
        
        # mat_nodes["Principled BSDF"].inputs[5].default_value = random.uniform(0.5, 1.0)         # specular
        # mat_nodes["Principled BSDF"].inputs[6].default_value = random.uniform(0.0, 1.0)         # specularTint
        mat_nodes["Principled BSDF"].inputs[8].default_value = random.uniform(0.0, 0.8)         # anisotropic
        # mat_nodes["Principled BSDF"].inputs[9].default_value = random.uniform(0.0, 0.8)         # anisotropicRotation
        # mat_nodes["Principled BSDF"].inputs[12].default_value = random.uniform(0.0, 1.0)         # clearcoat
        # mat_nodes["Principled BSDF"].inputs[13].default_value = random.uniform(0.0, 1.0)         # clearcoatGloss
        
        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9  
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.7  

            mat_links.new(mat_nodes["Image Texture.001"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[4])    
            mat_links.new(mat_nodes["Image Texture.002"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])  
            mat_links.new(mat_nodes["Normal Map"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])

            mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])                  
    elif material_name == "metal_12":
        
        # mat_nodes["Principled BSDF"].inputs[4].default_value = random.uniform(0.95, 1.00)       # metallic
        # mat_nodes["Principled BSDF"].inputs[5].default_value = random.uniform(0.5, 1.0)         # specular
        # mat_nodes["Principled BSDF"].inputs[6].default_value = random.uniform(0.0, 1.0)         # specularTint
        mat_nodes["Principled BSDF"].inputs[8].default_value = random.uniform(0.0, 0.8)         # anisotropic
        # mat_nodes["Principled BSDF"].inputs[9].default_value = random.uniform(0.0, 0.8)         # anisotropicRotation
        # mat_nodes["Principled BSDF"].inputs[12].default_value = random.uniform(0.0, 1.0)         # clearcoat
        # mat_nodes["Principled BSDF"].inputs[13].default_value = random.uniform(0.0, 1.0)         # clearcoatGloss
        
        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9  
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.7  

            mat_links.new(mat_nodes["ColorRamp"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])    
            mat_links.new(mat_nodes["Reroute.006"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])  

            mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])
        else:
            bs_color = mat_nodes["Principled BSDF"].inputs[0].default_value
            
            new_bs_color_r = bs_color[0] + r_rand
            new_bs_color_g = bs_color[1] + g_rand
            new_bs_color_b = bs_color[2] + b_rand
            if new_bs_color_r < 0:
                new_bs_color_r = 0
            if new_bs_color_g < 0:
                new_bs_color_g = 0
            if new_bs_color_b < 0:
                new_bs_color_b = 0
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(new_bs_color)
    elif material_name == "metal_13":
        
        # mat_nodes["Principled BSDF.001"].inputs[4].default_value = random.uniform(0.95, 1.00)       # metallic
        # mat_nodes["Principled BSDF.001"].inputs[5].default_value = random.uniform(0.5, 1.0)         # specular
        # mat_nodes["Principled BSDF.001"].inputs[6].default_value = random.uniform(0.0, 1.0)         # specularTint
        mat_nodes["Principled BSDF.001"].inputs[8].default_value = random.uniform(0.3, 0.7)         # anisotropic
        # mat_nodes["Principled BSDF.001"].inputs[9].default_value = random.uniform(0.0, 0.8)         # anisotropicRotation
        # mat_nodes["Principled BSDF.001"].inputs[12].default_value = random.uniform(0.0, 1.0)         # clearcoat
        # mat_nodes["Principled BSDF.001"].inputs[13].default_value = random.uniform(0.0, 1.0)         # clearcoatGloss

        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF.001"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = 1.0  
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.7  

            mat_links.new(mat_nodes["Bump"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20]) 
            mat_links.new(mat_nodes["Mix.001"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])  

            mat_links.new(mat_nodes["Principled BSDF.001"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output.001"].inputs["Surface"])  
        else:
            bs_color = mat_nodes["Principled BSDF.001"].inputs[0].default_value
            new_bs_color_r = bs_color[0] + r_rand
            new_bs_color_g = bs_color[1] + g_rand
            new_bs_color_b = bs_color[2] + b_rand
            if new_bs_color_r < 0:
                new_bs_color_r = 0
            if new_bs_color_g < 0:
                new_bs_color_g = 0
            if new_bs_color_b < 0:
                new_bs_color_b = 0
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["Principled BSDF.001"].inputs[0].default_value = list(new_bs_color)
    elif material_name == "metal_14":
        
        # mat_nodes["Principled BSDF"].inputs[4].default_value = random.uniform(0.95, 1.00)       # metallic
        # mat_nodes["Principled BSDF"].inputs[5].default_value = random.uniform(0.5, 1.0)         # specular
        # mat_nodes["Principled BSDF"].inputs[6].default_value = random.uniform(0.0, 1.0)         # specularTint
        mat_nodes["Principled BSDF"].inputs[8].default_value = random.uniform(0.0, 0.5)         # anisotropic
        # mat_nodes["Principled BSDF"].inputs[9].default_value = random.uniform(0.0, 0.5)         # anisotropicRotation
        # mat_nodes["Principled BSDF"].inputs[12].default_value = random.uniform(0.0, 1.0)         # clearcoat
        # mat_nodes["Principled BSDF"].inputs[13].default_value = random.uniform(0.0, 1.0)         # clearcoatGloss
        
        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.85 
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.7 
            
            mat_links.new(mat_nodes["Group"].outputs[1], mat_nodes["Principled BSDF-new"].inputs[7])  
            mat_links.new(mat_nodes["Group"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])   

            mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])
        else:
            bs_color = mat_nodes["Principled BSDF"].inputs[0].default_value
            
            new_bs_color_r = bs_color[0] + r_rand
            new_bs_color_g = bs_color[1] + g_rand
            new_bs_color_b = bs_color[2] + b_rand
            if new_bs_color_r < 0:
                new_bs_color_r = 0
            if new_bs_color_g < 0:
                new_bs_color_g = 0
            if new_bs_color_b < 0:
                new_bs_color_b = 0
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(new_bs_color)
    elif material_name == "metal_2":
        
        # mat_nodes["Principled BSDF"].inputs[4].default_value = random.uniform(0.95, 1.00)       # metallic
        # mat_nodes["Principled BSDF"].inputs[5].default_value = random.uniform(0.5, 1.0)         # specular
        # mat_nodes["Principled BSDF"].inputs[6].default_value = random.uniform(0.5, 1.0)         # specularTint
        mat_nodes["Principled BSDF"].inputs[8].default_value = random.uniform(0.0, 0.95)        # anisotropic
        # mat_nodes["Principled BSDF"].inputs[9].default_value = random.uniform(0.0, 1.0)         # anisotropicRotation
        # mat_nodes["Principled BSDF"].inputs[12].default_value = random.uniform(0.0, 1.0)        # clearcoat
        # mat_nodes["Principled BSDF"].inputs[13].default_value = random.uniform(0.0, 1.0)        # clearcoatGloss

        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9  
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.7  

            mat_links.new(mat_nodes["Image Texture.003"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7]) 
            mat_links.new(mat_nodes["Normal Map"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])  

            mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])       
    elif material_name == "metal_3":
        
        # mat_nodes["Principled BSDF"].inputs[4].default_value = random.uniform(0.95, 1.00)       # metallic
        # mat_nodes["Principled BSDF"].inputs[5].default_value = random.uniform(0.5, 1.0)         # specular
        # mat_nodes["Principled BSDF"].inputs[6].default_value = random.uniform(0.5, 1.0)         # specularTint
        mat_nodes["Principled BSDF"].inputs[8].default_value = random.uniform(0.0, 0.2)        # anisotropic
        # mat_nodes["Principled BSDF"].inputs[9].default_value = random.uniform(0.0, 1.0)         # anisotropicRotation
        # mat_nodes["Principled BSDF"].inputs[12].default_value = random.uniform(0.0, 1.0)        # clearcoat
        # mat_nodes["Principled BSDF"].inputs[13].default_value = random.uniform(0.0, 1.0)        # clearcoatGloss
        mat_nodes["Gamma"].inputs[1].default_value = random.uniform(3.0, 4.0)

        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9  
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.7  

            mat_links.new(mat_nodes["Gamma"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7]) 
            mat_links.new(mat_nodes["Normal Map"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])  

            mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])       
    elif material_name == "metal_4":
        
        # mat_nodes["Principled BSDF"].inputs[4].default_value = random.uniform(0.95, 1.00)       # metallic
        # mat_nodes["Principled BSDF"].inputs[5].default_value = random.uniform(0.1, 0.5)         # specular
        # mat_nodes["Principled BSDF"].inputs[6].default_value = random.uniform(0.0, 1.0)         # specularTint
        mat_nodes["Principled BSDF"].inputs[8].default_value = random.uniform(0.0, 0.2)        # anisotropic
        # mat_nodes["Principled BSDF"].inputs[9].default_value = random.uniform(0.0, 1.0)         # anisotropicRotation
        # mat_nodes["Principled BSDF"].inputs[12].default_value = random.uniform(0.0, 0.5)        # clearcoat
        # mat_nodes["Principled BSDF"].inputs[13].default_value = random.uniform(0.0, 0.5)        # clearcoatGloss
 
        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9  
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.7  

            mat_links.new(mat_nodes["ColorRamp"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7]) 
            mat_links.new(mat_nodes["Bump"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])  

            mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])  
    elif material_name == "metal_5":
        
        # mat_nodes["Principled BSDF"].inputs[4].default_value = random.uniform(0.98, 1.00)       # metallic
        # mat_nodes["Principled BSDF"].inputs[5].default_value = random.uniform(0.2, 0.4)         # specular
        # mat_nodes["Principled BSDF"].inputs[6].default_value = random.uniform(0.0, 1.0)         # specularTint
        mat_nodes["Principled BSDF"].inputs[8].default_value = random.uniform(0.6, 0.9)        # anisotropic
        # mat_nodes["Principled BSDF"].inputs[9].default_value = random.uniform(0.0, 1.0)         # anisotropicRotation
        # mat_nodes["Principled BSDF"].inputs[12].default_value = random.uniform(0.8, 1.0)        # clearcoat
        # mat_nodes["Principled BSDF"].inputs[13].default_value = random.uniform(0.0, 0.3)        # clearcoatGloss

        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9  
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.7  

            mat_links.new(mat_nodes["Voronoi Texture"].outputs[1], mat_nodes["Principled BSDF-new"].inputs[7]) 
            mat_links.new(mat_nodes["Tangent"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[22])   
            mat_links.new(mat_nodes["Bump"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[21])  

            mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])  
        else:
            bs_color = mat_nodes["Principled BSDF"].inputs[0].default_value
            
            new_bs_color_r = bs_color[0] + r_rand
            new_bs_color_g = bs_color[1] + g_rand
            new_bs_color_b = bs_color[2] + b_rand
            if new_bs_color_r < 0:
                new_bs_color_r = 0
            if new_bs_color_g < 0:
                new_bs_color_g = 0
            if new_bs_color_b < 0:
                new_bs_color_b = 0
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(new_bs_color)
    elif material_name == "metal_6":
        
        # mat_nodes["BSDF guidé"].inputs[4].default_value = random.uniform(0.98, 1.00)       # metallic
        # mat_nodes["BSDF guidé"].inputs[5].default_value = random.uniform(0.5, 1.0)         # specular
        # mat_nodes["BSDF guidé"].inputs[6].default_value = random.uniform(0.0, 1.0)         # specularTint
        mat_nodes["BSDF guidé"].inputs[8].default_value = random.uniform(0.0, 0.2)        # anisotropic
        # mat_nodes["BSDF guidé"].inputs[9].default_value = random.uniform(0.0, 1.0)         # anisotropicRotation
        # mat_nodes["BSDF guidé"].inputs[12].default_value = random.uniform(0.0, 0.3)        # clearcoat
        # mat_nodes["BSDF guidé"].inputs[13].default_value = random.uniform(0.0, 0.3)        # clearcoatGloss
        mat_nodes["Valeur"].outputs[0].default_value = random.uniform(0.1, 0.3)

        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            bsdf_new.location = Vector((-800, 0))
            for key, input in enumerate(mat_nodes["BSDF guidé"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'
            mix_new.location = Vector((-800, 0))

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9  
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.7 

            mat_links.new(mat_nodes["Mélanger.002"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])

            mat_links.new(mat_nodes["BSDF guidé"].outputs[0], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs[0], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Sortie de matériau"].inputs[0])
    elif material_name == "metal_7":
        
        # mat_nodes["Principled BSDF"].inputs[4].default_value = random.uniform(0.98, 1.00)       # metallic
        # mat_nodes["Principled BSDF"].inputs[5].default_value = random.uniform(0.5, 1.0)         # specular
        # mat_nodes["Principled BSDF"].inputs[6].default_value = random.uniform(0.0, 1.0)         # specularTint
        mat_nodes["Principled BSDF"].inputs[8].default_value = random.uniform(0.7, 0.9)        # anisotropic
        # mat_nodes["Principled BSDF"].inputs[9].default_value = random.uniform(0.0, 1.0)         # anisotropicRotation
        # mat_nodes["Principled BSDF"].inputs[12].default_value = random.uniform(0.0, 0.3)        # clearcoat
        # mat_nodes["Principled BSDF"].inputs[13].default_value = random.uniform(0.0, 0.3)        # clearcoatGloss
        
        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            #bsdf_new.location = Vector((-800, 0))
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'
            #mix_new.location = Vector((-800, 0))

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9 
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.7

            mat_links.new(mat_nodes["Reroute.001"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])
            mat_links.new(mat_nodes["Bump"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])
            mat_links.new(mat_nodes["Tangent"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[22])

            mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])
        else:
            bs_color = mat_nodes["Principled BSDF"].inputs[0].default_value
            
            new_bs_color_r = bs_color[0] + r_rand
            new_bs_color_g = bs_color[1] + g_rand
            new_bs_color_b = bs_color[2] + b_rand
            if new_bs_color_r < 0:
                new_bs_color_r = 0
            if new_bs_color_g < 0:
                new_bs_color_g = 0
            if new_bs_color_b < 0:
                new_bs_color_b = 0
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(new_bs_color)
    elif material_name == "metal_8":
        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value
            bsdf_1_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_1_new.name = 'Principled BSDF-1-new'
            for key, input in enumerate(mat_nodes["Principled BSDF.001"].inputs):
                bsdf_1_new.inputs[key].default_value = input.default_value
            bsdf_2_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_2_new.name = 'Principled BSDF-2-new'
            for key, input in enumerate(mat_nodes["Principled BSDF.002"].inputs):
                bsdf_2_new.inputs[key].default_value = input.default_value
            bsdf_3_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_3_new.name = 'Principled BSDF-3-new'
            for key, input in enumerate(mat_nodes["Principled BSDF.003"].inputs):
                bsdf_3_new.inputs[key].default_value = input.default_value
            
            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'
            mix_1_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_1_new.name = 'Mix Shader-1-new'
            mix_2_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_2_new.name = 'Mix Shader-2-new'
            mix_3_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_3_new.name = 'Mix Shader-3-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs[0])
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-1-new"].inputs[0])
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-2-new"].inputs[0])
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-3-new"].inputs[0])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.6
                mat_nodes["Mix Shader-1-new"].inputs[0].default_value = 0.6
                mat_nodes["Mix Shader-2-new"].inputs[0].default_value = 0.6
                mat_nodes["Mix Shader-3-new"].inputs[0].default_value = 0.6
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Principled BSDF-1-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Principled BSDF-2-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Principled BSDF-3-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.5
                mat_nodes["Mix Shader-1-new"].inputs[0].default_value = 0.5
                mat_nodes["Mix Shader-2-new"].inputs[0].default_value = 0.5
                mat_nodes["Mix Shader-3-new"].inputs[0].default_value = 0.5

            mat_links.new(mat_nodes["ColorRamp"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])
            mat_links.new(mat_nodes["Bump"].outputs[0], mat_nodes["Principled BSDF-1-new"].inputs[20]) 
            mat_links.new(mat_nodes["Bump.001"].outputs[0], mat_nodes["Principled BSDF-2-new"].inputs[20])   

            mat_links.new(mat_nodes["Principled BSDF"].outputs[0], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs[0], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Mix Shader"].inputs[1])

            mat_links.new(mat_nodes["Principled BSDF.001"].outputs[0], mat_nodes["Mix Shader-1-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-1-new"].outputs[0], mat_nodes["Mix Shader-1-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-1-new"].outputs[0], mat_nodes["Mix Shader"].inputs[2])

            mat_links.new(mat_nodes["Principled BSDF.002"].outputs[0], mat_nodes["Mix Shader-2-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-2-new"].outputs[0], mat_nodes["Mix Shader-2-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-2-new"].outputs[0], mat_nodes["Mix Shader.001"].inputs[1])

            mat_links.new(mat_nodes["Principled BSDF.003"].outputs[0], mat_nodes["Mix Shader-3-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-3-new"].outputs[0], mat_nodes["Mix Shader-3-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-3-new"].outputs[0], mat_nodes["Mix Shader.001"].inputs[2])        
    elif material_name == "metal_9":
        
        # mat_nodes["Principled BSDF"].inputs[4].default_value = random.uniform(0.98, 1.00)       # metallic
        # mat_nodes["Principled BSDF"].inputs[5].default_value = random.uniform(0.5, 1.0)         # specular
        # mat_nodes["Principled BSDF"].inputs[6].default_value = random.uniform(0.0, 1.0)         # specularTint
        mat_nodes["Principled BSDF"].inputs[7].default_value = random.uniform(0.01, 0.3)         # roughness
        # mat_nodes["Principled BSDF"].inputs[12].default_value = random.uniform(0.0, 0.3)        # clearcoat
        # mat_nodes["Principled BSDF"].inputs[13].default_value = random.uniform(0.0, 0.3)        # clearcoatGloss
        mat_nodes["Anisotropic BSDF"].inputs[1].default_value = random.uniform(0.11, 0.25)
        mat_nodes["Anisotropic BSDF"].inputs[2].default_value = random.uniform(0.4, 0.6)

        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9
                mat_links.new(tex_node.outputs[0], mat_nodes["Anisotropic BSDF"].inputs[0])
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.9
                mat_nodes["Anisotropic BSDF"].inputs[0].default_value = list(orign_base_color)

            mat_links.new(mat_nodes["Principled BSDF-new"].outputs[0], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Principled BSDF"].outputs[0], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Mix Shader"].inputs[1])

    ## porcelain
    elif material_name == "porcelain_0":
        if transfer_flag == True:
            # if is_texture:
            #     mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
            # else:
            #     mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color)
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9   
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = mix_prop#0.8   

            mat_links.new(mat_nodes["Normal Map"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])
            mat_links.new(mat_nodes["Image Texture.001"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])

            mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])    
    elif material_name == "porcelain_1":
        if transfer_flag == True:
            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Mix"].inputs[1])
            else:
                mat_nodes["Mix"].inputs[1].default_value = list(orign_base_color)  
        else: 
            bs_color = mat_nodes["Mix"].inputs[1].default_value
        
            new_bs_color_r = bs_color[0] + random.uniform(-0.3, 0.3)
            new_bs_color_g = bs_color[1] + random.uniform(-0.3, 0.3)
            new_bs_color_b = bs_color[2] + random.uniform(-0.3, 0.3)
            if new_bs_color_r < 0:
                new_bs_color_r = 0.2
            if new_bs_color_g < 0:
                new_bs_color_g = 0.2
            if new_bs_color_b < 0:
                new_bs_color_b = 0.2
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["Mix"].inputs[1].default_value = list(new_bs_color)
    elif material_name == "porcelain_2":
        if transfer_flag == True:
            bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
            bsdf_new.name = 'Principled BSDF-new'
            for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
                bsdf_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = tex_mix_prop#0.9   
            else:
                mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.8   

            mat_links.new(mat_nodes["Normal Map"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])
            mat_links.new(mat_nodes["Image Texture.001"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])

            mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])    
    elif material_name == "porcelain_3":
        if transfer_flag == True:
            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Mix.001"].inputs[1])
            else:
                mat_nodes["Mix.001"].inputs[1].default_value = list(orign_base_color)   
        else: 
            bs_color = mat_nodes["Mix.001"].inputs[1].default_value
        
            new_bs_color_r = bs_color[0] + random.uniform(-0.3, 0.3)
            new_bs_color_g = bs_color[1] + random.uniform(-0.3, 0.3)
            new_bs_color_b = bs_color[2] + random.uniform(-0.3, 0.3)
            if new_bs_color_r < 0:
                new_bs_color_r = 0.2
            if new_bs_color_g < 0:
                new_bs_color_g = 0.2
            if new_bs_color_b < 0:
                new_bs_color_b = 0.2
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["Mix.001"].inputs[1].default_value = list(new_bs_color)
    elif material_name == "porcelain_4":
        if transfer_flag == True:
            # if is_texture:
            #     mat_links.new(tex_node.outputs[0], mat_nodes["Diffuse BSDF"].inputs[0])
            #     mat_links.new(tex_node.outputs[0], mat_nodes["Glossy BSDF"].inputs[0])
            # else:
            #     mat_nodes["Diffuse BSDF"].inputs[0].default_value = list(orign_base_color)
            #     mat_nodes["Glossy BSDF"].inputs[0].default_value = list(orign_base_color)
            mat_nodes["Glossy BSDF"].inputs[1].default_value = random.uniform(0.05, 0.15)

            diff_new = mat_nodes.new(type='ShaderNodeBsdfDiffuse')
            diff_new.name = 'Diffuse BSDF-new'
            for key, input in enumerate(mat_nodes["Diffuse BSDF"].inputs):
                diff_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Diffuse BSDF-new"].inputs[0])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = 1.0   
            else:
                mat_nodes["Diffuse BSDF"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.9   

            mat_links.new(mat_nodes["Diffuse BSDF"].outputs[0], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Diffuse BSDF-new"].outputs[0], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Mix Shader"].inputs[1])
    elif material_name == "porcelain_5":
        if transfer_flag == True:
            # if is_texture:
            #     mat_links.new(tex_node.outputs[0], mat_nodes["Diffuse BSDF"].inputs[0])
            #     mat_links.new(tex_node.outputs[0], mat_nodes["Glossy BSDF"].inputs[0])
            # else:
            #     mat_nodes["Diffuse BSDF"].inputs[0].default_value = list(orign_base_color)
            #     mat_nodes["Glossy BSDF"].inputs[0].default_value = list(orign_base_color)
            diff_new = mat_nodes.new(type='ShaderNodeBsdfDiffuse')
            diff_new.name = 'Diffuse BSDF-new'
            for key, input in enumerate(mat_nodes["Diffuse BSDF"].inputs):
                diff_new.inputs[key].default_value = input.default_value

            mix_new = mat_nodes.new(type='ShaderNodeMixShader')
            mix_new.name = 'Mix Shader-new'

            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Diffuse BSDF-new"].inputs[0])
                mat_nodes["Mix Shader-new"].inputs[0].default_value = 1.0   
            else:
                mat_nodes["Diffuse BSDF"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.9   

            mat_links.new(mat_nodes["Diffuse BSDF"].outputs[0], mat_nodes["Mix Shader-new"].inputs[1])
            mat_links.new(mat_nodes["Diffuse BSDF-new"].outputs[0], mat_nodes["Mix Shader-new"].inputs[2])
            mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Mix Shader"].inputs[1])
    elif material_name == "porcelain_6":
        if transfer_flag == True:
            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Diffuse BSDF"].inputs[0])
            else:
                mat_nodes["Diffuse BSDF"].inputs[0].default_value = list(orign_base_color)  
        else: 
            bs_color = mat_nodes["Diffuse BSDF"].inputs[0].default_value
        
            new_bs_color_r = bs_color[0] + random.uniform(-0.3, 0.3)
            new_bs_color_g = bs_color[1] + random.uniform(-0.3, 0.3)
            new_bs_color_b = bs_color[2] + random.uniform(-0.3, 0.3)
            if new_bs_color_r < 0:
                new_bs_color_r = 0.2
            if new_bs_color_g < 0:
                new_bs_color_g = 0.2
            if new_bs_color_b < 0:
                new_bs_color_b = 0.2
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["Diffuse BSDF"].inputs[0].default_value = list(new_bs_color)
    
    ## plastic
    elif material_name == "plastic_1":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF.001"].inputs[0])
        else:
            mat_nodes["Principled BSDF.001"].inputs[0].default_value = list(orign_base_color)            
    elif material_name == "plastic_2":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF.001"].inputs[0])
        else:
            mat_nodes["Principled BSDF.001"].inputs[0].default_value = list(orign_base_color)    
    elif material_name == "plastic_3":
        mat_nodes["值(明度)"].outputs[0].default_value = random.uniform(0.05, 0.25)

        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Diffuse BSDF"].inputs[0])
        else:
            mat_nodes["Diffuse BSDF"].inputs[0].default_value = list(orign_base_color)  
    elif material_name == "plastic_5":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color)    
    elif material_name == "plastic_6":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Reroute.012"].inputs[0])    
            mat_links.new(tex_node.outputs[0], mat_nodes["Reroute.021"].inputs[0])    
            mat_links.new(tex_node.outputs[0], mat_nodes["Reroute.022"].inputs[0])    
            mat_links.new(tex_node.outputs[0], mat_nodes["Reroute.033"].inputs[0])  
        else:
            mat_nodes["RGB"].outputs[0].default_value = list(orign_base_color)
            mat_nodes["RGB.001"].outputs[0].default_value = list(orign_base_color)
            """
            mat_nodes["RGB.002"].outputs[0].default_value = list(orign_base_color)
            mat_nodes["RGB.003"].outputs[0].default_value = list(orign_base_color)
            """

    ## rubber
    elif material_name == "rubber_0":
        diff_new = mat_nodes.new(type='ShaderNodeBsdfDiffuse')
        diff_new.name = 'Diffuse BSDF-new'
        for key, input in enumerate(mat_nodes["Diffuse BSDF"].inputs):
            diff_new.inputs[key].default_value = input.default_value

        mix_new = mat_nodes.new(type='ShaderNodeMixShader')
        mix_new.name = 'Mix Shader-new'

        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Diffuse BSDF-new"].inputs[0])
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 1.0   
        else:
            mat_nodes["Diffuse BSDF"].inputs[0].default_value = list(orign_base_color)
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.9   

        mat_links.new(mat_nodes["Diffuse BSDF"].outputs[0], mat_nodes["Mix Shader-new"].inputs[1])
        mat_links.new(mat_nodes["Diffuse BSDF-new"].outputs[0], mat_nodes["Mix Shader-new"].inputs[2])
        mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Mix Shader"].inputs[1])
    elif material_name == "rubber_1":
        bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
        bsdf_new.name = 'Principled BSDF-new'
        for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
            bsdf_new.inputs[key].default_value = input.default_value

        mix_new = mat_nodes.new(type='ShaderNodeMixShader')
        mix_new.name = 'Mix Shader-new'

        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 1.0  
        else:
            mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.9  

        mat_links.new(mat_nodes["Bump"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])
        mat_links.new(mat_nodes["RGB Curves"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])

        mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
        mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
        mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])
    elif material_name == "rubber_2":
        bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
        bsdf_new.name = 'Principled BSDF-new'
        for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
            bsdf_new.inputs[key].default_value = input.default_value

        mix_new = mat_nodes.new(type='ShaderNodeMixShader')
        mix_new.name = 'Mix Shader-new'

        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 1.0  
        else:
            mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.9  

        mat_links.new(mat_nodes["Normal Map"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])
        mat_links.new(mat_nodes["RGB Curves"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])

        mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
        mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
        mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])
    elif material_name == "rubber_3":
        bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
        bsdf_new.name = 'Principled BSDF-new'
        for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
            bsdf_new.inputs[key].default_value = input.default_value

        mix_new = mat_nodes.new(type='ShaderNodeMixShader')
        mix_new.name = 'Mix Shader-new'

        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 1.0  
        else:
            mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.9  

        mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
        mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
        mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])
    elif material_name == "rubber_4":
        bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
        bsdf_new.name = 'Principled BSDF-new'
        for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
            bsdf_new.inputs[key].default_value = input.default_value

        mix_new = mat_nodes.new(type='ShaderNodeMixShader')
        mix_new.name = 'Mix Shader-new'

        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 1.0  
        else:
            mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.9  

        mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
        mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
        mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])
    
    ######################## 2022.02.04
    ## plastic_specular
    elif material_name == "plasticsp_0":
        if transfer_flag == True:
            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Reroute.001"].inputs[0])
                mat_links.new(tex_node.outputs[0], mat_nodes["Reroute"].inputs[0])
            else:
                mat_nodes["RGB.001"].outputs[0].default_value = list(orign_base_color)
        else:
            bs_color = mat_nodes["RGB.001"].outputs[0].default_value
            
            new_bs_color_r = bs_color[0] + r_rand
            new_bs_color_g = bs_color[1] + g_rand
            new_bs_color_b = bs_color[2] + b_rand
            if new_bs_color_r < 0:
                new_bs_color_r = 0
            if new_bs_color_g < 0:
                new_bs_color_g = 0
            if new_bs_color_b < 0:
                new_bs_color_b = 0
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["RGB.001"].outputs[0].default_value = list(new_bs_color)
    elif material_name == "plasticsp_1":
        if transfer_flag == True:
            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
            else:
                mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color)
        else:
            bs_color = mat_nodes["Principled BSDF"].inputs[0].default_value
            
            new_bs_color_r = bs_color[0] + r_rand
            new_bs_color_g = bs_color[1] + g_rand
            new_bs_color_b = bs_color[2] + b_rand
            if new_bs_color_r < 0:
                new_bs_color_r = 0
            if new_bs_color_g < 0:
                new_bs_color_g = 0
            if new_bs_color_b < 0:
                new_bs_color_b = 0
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(new_bs_color)
    
    ## paint_specular
    elif material_name == "paintsp_0":
        if transfer_flag == True:
            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
                mat_links.new(tex_node.outputs[0], mat_nodes["Diffuse BSDF"].inputs[0])
            else:
                mat_nodes["RGB"].outputs[0].default_value = list(orign_base_color)
        else:
            bs_color = mat_nodes["RGB"].outputs[0].default_value
            
            new_bs_color_r = bs_color[0] + r_rand
            new_bs_color_g = bs_color[1] + g_rand
            new_bs_color_b = bs_color[2] + b_rand
            if new_bs_color_r < 0:
                new_bs_color_r = 0
            if new_bs_color_g < 0:
                new_bs_color_g = 0
            if new_bs_color_b < 0:
                new_bs_color_b = 0
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["RGB"].outputs[0].default_value = list(new_bs_color)
    elif material_name == "paintsp_1":
        if transfer_flag == True:
            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Glossy BSDF"].inputs[0])
                mat_links.new(tex_node.outputs[0], mat_nodes["Mix"].inputs[2])
                mat_links.new(tex_node.outputs[0], mat_nodes["Mix.001"].inputs[1])
                mat_links.new(tex_node.outputs[0], mat_nodes["Hue Saturation Value"].inputs[4])
            else:
                mat_nodes["RGB"].outputs[0].default_value = list(orign_base_color)
        else:
            bs_color = mat_nodes["RGB"].outputs[0].default_value
            
            new_bs_color_r = bs_color[0] + r_rand
            new_bs_color_g = bs_color[1] + g_rand
            new_bs_color_b = bs_color[2] + b_rand
            if new_bs_color_r < 0:
                new_bs_color_r = 0
            if new_bs_color_g < 0:
                new_bs_color_g = 0
            if new_bs_color_b < 0:
                new_bs_color_b = 0
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["RGB"].outputs[0].default_value = list(new_bs_color)
    elif material_name == "paintsp_2":
        if transfer_flag == True:
            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Group"].inputs[0])
            else:
                mat_nodes["Group"].inputs[0].default_value = list(orign_base_color)
        else:
            bs_color = mat_nodes["Group"].inputs[0].default_value
            
            new_bs_color_r = bs_color[0] + r_rand
            new_bs_color_g = bs_color[1] + g_rand
            new_bs_color_b = bs_color[2] + b_rand
            if new_bs_color_r < 0:
                new_bs_color_r = 0
            if new_bs_color_g < 0:
                new_bs_color_g = 0
            if new_bs_color_b < 0:
                new_bs_color_b = 0
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["Group"].inputs[0].default_value = list(new_bs_color)
    elif material_name == "paintsp_3":
        if transfer_flag == True:
            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
            else:
                mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color)
        else:
            #bs_color = mat_nodes["Principled BSDF"].inputs[0].default_value
            new_bs_color = [random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1), 1]
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(new_bs_color)
    elif material_name == "paintsp_4":
        if transfer_flag == True:
            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
                mat_links.new(tex_node.outputs[0], mat_nodes["Glossy BSDF"].inputs[0])
                mat_links.new(tex_node.outputs[0], mat_nodes["Glossy BSDF.001"].inputs[0])
            else:
                mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Glossy BSDF"].inputs[0].default_value = list(orign_base_color)
                mat_nodes["Glossy BSDF.001"].inputs[0].default_value = list(orign_base_color)
        else:
            bs_color = mat_nodes["Principled BSDF"].inputs[0].default_value
            
            new_bs_color_r = bs_color[0] + r_rand
            new_bs_color_g = bs_color[1] + g_rand
            new_bs_color_b = bs_color[2] + b_rand
            if new_bs_color_r < 0:
                new_bs_color_r = 0
            if new_bs_color_g < 0:
                new_bs_color_g = 0
            if new_bs_color_b < 0:
                new_bs_color_b = 0
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(new_bs_color)
            mat_nodes["Glossy BSDF"].inputs[0].default_value = list(new_bs_color)
            mat_nodes["Glossy BSDF.001"].inputs[0].default_value = list(new_bs_color)
    elif material_name == "paintsp_5":
        if transfer_flag == True:
            if is_texture:
                mat_links.new(tex_node.outputs[0], mat_nodes["Invert"].inputs[1])
                mat_links.new(tex_node.outputs[0], mat_nodes["Reroute.002"].inputs[0])
            else:
                mat_nodes["RGB"].outputs[0].default_value = list(orign_base_color)
        else:
            bs_color = mat_nodes["RGB"].outputs[0].default_value
            
            new_bs_color_r = bs_color[0] + r_rand
            new_bs_color_g = bs_color[1] + g_rand
            new_bs_color_b = bs_color[2] + b_rand
            if new_bs_color_r < 0:
                new_bs_color_r = 0
            if new_bs_color_g < 0:
                new_bs_color_g = 0
            if new_bs_color_b < 0:
                new_bs_color_b = 0
                
            if new_bs_color_r > 1:
                new_bs_color_r = 1
            if new_bs_color_g > 1:
                new_bs_color_g = 1
            if new_bs_color_b > 1:
                new_bs_color_b = 1

            new_bs_color = [new_bs_color_r, new_bs_color_g, new_bs_color_b, 1]
            mat_nodes["RGB"].outputs[0].default_value = list(new_bs_color)

    ## rubber
    elif material_name == "rubber_5":
        bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
        bsdf_new.name = 'Principled BSDF-new'
        for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
            bsdf_new.inputs[key].default_value = input.default_value

        mix_new = mat_nodes.new(type='ShaderNodeMixShader')
        mix_new.name = 'Mix Shader-new'

        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 1.0  
        else:
            mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.9  

        mat_links.new(mat_nodes["Mix.005"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7]) 
        mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
        mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
        mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])

    ## plastic
    elif material_name == "plastic_0":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF.001"].inputs[0])
        else:
            mat_nodes["Principled BSDF.001"].inputs[0].default_value = list(orign_base_color)
    elif material_name == "plastic_4":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color) 
    elif material_name == "plastic_7":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF.001"].inputs[0])    
        else:
            mat_nodes["RGB"].outputs[0].default_value = list(orign_base_color)
    elif material_name == "plastic_8":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Group"].inputs[0])    
        else:
            mat_nodes["Group"].inputs[0].default_value = list(orign_base_color)
    elif material_name == "plastic_9":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color)            
    elif material_name == "plastic_10":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color)            
    elif material_name == "plastic_11":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color)
    elif material_name == "plastic_12":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Mix"].inputs[2])    
        else:
            mat_nodes["RGB"].outputs[0].default_value = list(orign_base_color)
    elif material_name == "plastic_13":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color)
    elif material_name == "plastic_14":
        mat_nodes["Math.005"].inputs[1].default_value = random.uniform(0.05, 0.3)

        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color)
    
    ## paper
    elif material_name == "paper_0":
        bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
        bsdf_new.name = 'Principled BSDF-new'
        for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
            bsdf_new.inputs[key].default_value = input.default_value

        mix_new = mat_nodes.new(type='ShaderNodeMixShader')
        mix_new.name = 'Mix Shader-new'

        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.9  
        else:
            mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
            mat_nodes["Mix Shader-new"].inputs[0].default_value = 0.9  

        mat_links.new(mat_nodes["Bump"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])
        mat_links.new(mat_nodes["Mix.002"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])

        mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
        mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
        mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])
    elif material_name == "paper_1":
        bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
        bsdf_new.name = 'Principled BSDF-new'
        for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
            bsdf_new.inputs[key].default_value = input.default_value

        mix_new = mat_nodes.new(type='ShaderNodeMixShader')
        mix_new.name = 'Mix Shader-new'

        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
            mat_nodes["Mix Shader-new"].inputs[0].default_value = random.uniform(0.8, 0.95)  
        else:
            mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
            mat_nodes["Mix Shader-new"].inputs[0].default_value = random.uniform(0.8, 0.9)  

        mat_links.new(mat_nodes["Normal Map"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])
        mat_links.new(mat_nodes["Image Texture.001"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])

        mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
        mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
        mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])
    elif material_name == "paper_2":
        bsdf_new = mat_nodes.new(type='ShaderNodeBsdfPrincipled')
        bsdf_new.name = 'Principled BSDF-new'
        for key, input in enumerate(mat_nodes["Principled BSDF"].inputs):
            bsdf_new.inputs[key].default_value = input.default_value

        mix_new = mat_nodes.new(type='ShaderNodeMixShader')
        mix_new.name = 'Mix Shader-new'

        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF-new"].inputs["Base Color"])
            mat_nodes["Mix Shader-new"].inputs[0].default_value = random.uniform(0.9, 0.95)  
        else:
            mat_nodes["Principled BSDF-new"].inputs[0].default_value = list(orign_base_color)
            mat_nodes["Mix Shader-new"].inputs[0].default_value = random.uniform(0.9, 0.95)  

        mat_links.new(mat_nodes["Bump"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[20])
        mat_links.new(mat_nodes["Bright/Contrast"].outputs[0], mat_nodes["Principled BSDF-new"].inputs[7])

        mat_links.new(mat_nodes["Principled BSDF"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[1])
        mat_links.new(mat_nodes["Principled BSDF-new"].outputs["BSDF"], mat_nodes["Mix Shader-new"].inputs[2])
        mat_links.new(mat_nodes["Mix Shader-new"].outputs[0], mat_nodes["Material Output"].inputs["Surface"])
    
    ## leather
    elif material_name == "leather_0":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color) 
    elif material_name == "leather_1":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color)
    elif material_name == "leather_2":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Mix"].inputs[1])
        else:
            mat_nodes["Mix"].inputs[1].default_value = list(orign_base_color)
    elif material_name == "leather_3":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color)
    elif material_name == "leather_4":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color)
    elif material_name == "leather_5":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["lether"].inputs[0])
        else:
            mat_nodes["lether"].inputs[0].default_value = list(orign_base_color)

    ## wood (全部不作处理,保留原始材质)
    elif material_name == "wood_0":
        pass
    elif material_name == "wood_1":
        pass
    elif material_name == "wood_2":
        pass
    elif material_name == "wood_3":
        pass
    elif material_name == "wood_4":
        pass
    elif material_name == "wood_5":
        pass
    elif material_name == "wood_6":
        pass
    elif material_name == "wood_7":
        pass
    elif material_name == "wood_8":
        pass
    elif material_name == "wood_9":
        pass

    ## fabric
    elif material_name == "fabric_0":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color) 
    elif material_name == "fabric_1":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color) 
    elif material_name == "fabric_2":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Mix"].inputs[1])
        else:
            mat_nodes["Mix"].inputs[1].default_value = list(orign_base_color) 

    ## clay
    elif material_name == "clay_0":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color) 
    elif material_name == "clay_1":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color) 
    elif material_name == "clay_2":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color) 
    elif material_name == "clay_3":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Mix"].inputs[1])
        else:
            mat_nodes["Mix"].inputs[1].default_value = list(orign_base_color) 
    elif material_name == "clay_4":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
        else:
            mat_nodes["Principled BSDF"].inputs[0].default_value = list(orign_base_color) 
    elif material_name == "clay_5":
        if is_texture:
            mat_links.new(tex_node.outputs[0], mat_nodes["Mix"].inputs[1])
        else:
            mat_nodes["Mix"].inputs[1].default_value = list(orign_base_color) 

    ## glass
    elif material_name == "glass_0":
        mat_nodes["Mix Shader"].inputs[0].default_value = random.uniform(0.1, 0.3)
        mat_nodes["Glossy BSDF"].inputs[1].default_value = random.uniform(0.1, 0.3)
    elif material_name == "glass_4":
        mat_nodes["Layer Weight"].inputs[0].default_value = random.uniform(0.3, 0.7)
        mat_nodes["Glossy BSDF"].inputs[1].default_value = random.uniform(0.05, 0.2)
    elif material_name == "glass_5":
        mat_nodes["Layer Weight"].inputs[0].default_value = random.uniform(0.2, 0.4)
        mat_nodes["Glossy BSDF"].inputs[1].default_value = random.uniform(0.0, 0.1)
    elif material_name == "glass_14":
        mat_nodes["Glass BSDF.005"].inputs[1].default_value = random.uniform(0.0, 0.1)
        mat_nodes["Glass BSDF.006"].inputs[1].default_value = random.uniform(0.0, 0.1)
        mat_nodes["Glass BSDF.007"].inputs[1].default_value = random.uniform(0.0, 0.1)
        mat_nodes["Glass BSDF.008"].inputs[1].default_value = random.uniform(0.0, 0.1)
        mat_nodes["Layer Weight"].inputs[0].default_value = random.uniform(0.81, 0.87)
        mat_nodes["Layer Weight.001"].inputs[0].default_value = random.uniform(0.65, 0.71)
        mat_nodes["Layer Weight.002"].inputs[0].default_value = random.uniform(0.81, 0.87)
        color_value = random.uniform(0.599459, 0.70)
        mat_nodes["Transparent BSDF"].inputs[0].default_value = list([color_value, color_value, color_value, 1])

    # elif material_name == "glass_15":
    #     mat_nodes["Glass BSDF"].inputs[1].default_value = random.uniform(0.0, 0.1)
    #     mat_nodes["Glass BSDF"].inputs[2].default_value = random.uniform(1.325, 1.335)
    #     color_value = random.uniform(0.297, 0.35)
    #     mat_nodes["Transparent BSDF"].inputs[0].default_value = list([color_value, color_value, color_value, 1])

    ########################
    else:
        print(material_name + " no change")



def set_modify_material(obj, material, obj_texture_img_list, mat_randomize_mode, is_transfer=True):
    for mat_slot in obj.material_slots:
        if mat_slot.material:
            if mat_slot.material.node_tree:
                srcmat = material
                mat = srcmat.copy()
                mat.name = mat_slot.material.name   # rename
                mat_links = mat.node_tree.links
                mat_nodes = mat.node_tree.nodes
                bsdf_node = mat_slot.material.node_tree.nodes.get("Principled BSDF", None)
                if bsdf_node is not None:
                    tex_node = mat_slot.material.node_tree.nodes.new(type='ShaderNodeTexImage')
                    tex_node.name = 'objtexture_tex'
                    tex_node.extension = 'EXTEND'
                    flag = random.randint(0, len(obj_texture_img_list)-1)
                    tex_node.image = obj_texture_img_list[flag]

                    tex_node_orign = mat_slot.material.node_tree.nodes.get('objtexture_tex', None)
                    if tex_node_orign is not None:
                        #mat = mat_slot.material.copy() 
                        # Get the bl_idname to create a new node of the same type
                        tex_node = mat_nodes.new(tex_node_orign.bl_idname)
                        texture_img = bpy.data.images[tex_node_orign.image.name]
                        # Assign the default values from the old node to the new node
                        tex_node.image = texture_img
                        tex_node.projection = 'SPHERE'
                        #tex_node.location = Vector((-800, 0))
                        mapping_node = mat_nodes.new(type='ShaderNodeMapping')
                        mapping_node.name = 'objtexture_mapping'
                        texcoord_node = mat_nodes.new(type='ShaderNodeTexCoord')
                        texcoord_node.name = 'objtexture_texcoord'
                        mat_links.new(mapping_node.outputs[0], tex_node.inputs[0])
                        mat_links.new(texcoord_node.outputs[0], mapping_node.inputs[0])

                        modify_material(mat_links, mat_nodes, srcmat.name, mat_randomize_mode, is_texture=True, tex_node=tex_node, is_transfer=is_transfer)

                    else:

                        orign_base_color = mat_slot.material.node_tree.nodes["Principled BSDF"].inputs[0].default_value
                        if orign_base_color[0] == 0.0 and orign_base_color[1] == 0.0 and orign_base_color[2] == 0.0:
                            orign_base_color = [0.05, 0.05, 0.05, 1]

                        modify_material(mat_links, mat_nodes, srcmat.name, mat_randomize_mode, is_texture=False, orign_base_color=orign_base_color, is_transfer=is_transfer)


                bpy.data.materials.remove(mat_slot.material)
                mat_slot.material = mat


def set_modify_raw_material(obj):
    for mat_slot in obj.material_slots:
        if mat_slot.material:
            if mat_slot.material.node_tree:
                bsdf_node = mat_slot.material.node_tree.nodes.get("Principled BSDF", None)
                if bsdf_node is not None:
                    tex_node_orign = mat_slot.material.node_tree.nodes.get("Image Texture", None)
                    if tex_node_orign is None:
                            orign_base_color = mat_slot.material.node_tree.nodes["Principled BSDF"].inputs[0].default_value
                            if orign_base_color[0] == 0.0 and orign_base_color[1] == 0.0 and orign_base_color[2] == 0.0:
                                mat = mat_slot.material.copy()
                                mat.name = mat_slot.material.name   # rename
                                mat_nodes = mat.node_tree.nodes   
                                mat_nodes["Principled BSDF"].inputs[0].default_value = list([0.05, 0.05, 0.05, 1])

                                bpy.data.materials.remove(mat_slot.material)
                                mat_slot.material = mat


def set_modify_table_material(obj, material, selected_realtable_img):

    srcmat = material
    #print(srcmat.name)
    mat = srcmat.copy()
    mat_links = mat.node_tree.links
    mat_nodes = mat.node_tree.nodes

    tex_node = mat_nodes.new(type='ShaderNodeTexImage')
    tex_node.name = 'realtable_tex'
    tex_node.extension = 'EXTEND'
    tex_node.image = selected_realtable_img
    mapping_node = mat_nodes.new(type='ShaderNodeMapping')
    mapping_node.name = 'realtable_mapping'
    texcoord_node = mat_nodes.new(type='ShaderNodeTexCoord')
    texcoord_node.name = 'realtable_texcoord'

    mat_links.new(tex_node.outputs[0], mat_nodes["Principled BSDF"].inputs[0])
    mat_links.new(mapping_node.outputs[0], tex_node.inputs[0])
    mat_links.new(texcoord_node.outputs[2], mapping_node.inputs[0])

    obj.active_material = mat


def set_modify_floor_material(obj, material, selected_realfloor_img):

    srcmat = material
    mat = srcmat.copy()
    mat_links = mat.node_tree.links
    mat_nodes = mat.node_tree.nodes

    bsdfnode_list = [n for n in mat_nodes if isinstance(n, bpy.types.ShaderNodeBsdfPrincipled)]
    if bsdfnode_list == []:
        obj.active_material = material
    else:
        for bsdfnode in bsdfnode_list:
            tex_node = mat_nodes.new(type='ShaderNodeTexImage')
            tex_node.name = 'realfloor_tex'
            tex_node.extension = 'REPEAT'
            tex_node.image = selected_realfloor_img
            mapping_node = mat_nodes.new(type='ShaderNodeMapping')
            mapping_node.name = 'realfloor_mapping'
            texcoord_node = mat_nodes.new(type='ShaderNodeTexCoord')
            texcoord_node.name = 'realfloor_texcoord'


            mat_links.new(tex_node.outputs[0], bsdfnode.inputs[0])
            mat_links.new(mapping_node.outputs[0], tex_node.inputs[0])
            mat_links.new(texcoord_node.outputs[2], mapping_node.inputs[0])


            obj.active_material = mat


def set_modify_arm_material(obj, material):
    for mat_slot in obj.material_slots:

        if mat_slot.material:
            if mat_slot.material.node_tree:
                
                srcmat = material

                mat = srcmat.copy()
                mat.name = mat_slot.material.name   # rename
                mat_links = mat.node_tree.links
                mat_nodes = mat.node_tree.nodes

                rgb = random.uniform(0.50, 1.00)
                orign_base_color = [rgb, rgb, rgb, 1]

                modify_material(mat_links, mat_nodes, srcmat.name, mat_randomize_mode="diffuse", is_texture=False, orign_base_color=orign_base_color, is_transfer=False, is_arm=True)

                bpy.data.materials.remove(mat_slot.material)
                mat_slot.material = mat



================================================
FILE: data_generator/render_pile_STD_rand.py
================================================
import os
import random
import bpy
import math
import numpy as np
from mathutils import Vector, Matrix
import copy
import sys
import time
import argparse
from scipy.spatial.transform import Rotation
from bpy_extras.object_utils import world_to_camera_view

sys.path.append(os.getcwd())
from modify_material import set_modify_material, set_modify_raw_material, set_modify_table_material, set_modify_floor_material, set_modify_arm_material


argv = sys.argv
argv = argv[argv.index("--") + 1:]  # get all args after "--"

RENDERING_PATH = os.getcwd()
LIGHT_EMITTER_ENERGY = 5
LIGHT_ENV_MAP_ENERGY_IR = 0.035
LIGHT_ENV_MAP_ENERGY_RGB = 1.0
CYCLES_SAMPLE = 32
DEVICE_LIST = [6]

SCENE_NUM = int(argv[0]) if len(argv) > 0 else 0
CAMERA_TYPE = "realsense"
NUM_FRAME_PER_SCENE = 24

RENDER_START_FRAME = 0
RENDER_END_FRAME = 24
RENDER_FRAMES_LIST = list(range(RENDER_START_FRAME, RENDER_END_FRAME))


look_at_shift = np.array([0,0,0])
num_point_ver = 6
num_point_hor = 4
beta_range = (random.uniform(12, 16)*math.pi/180, random.uniform(41, 45)*math.pi/180)
r = random.uniform(0.40, 0.50)


code_root = "/data/InterNeRF/renderer/renderer_giga_GPU6-0_rand_M"
emitter_pattern_path = os.path.join(code_root, "pattern", "test_pattern.png")
env_map_path =  os.path.join(code_root, "envmap_lib")
default_background_texture_path = os.path.join(code_root, "texture", "texture_0.jpg")
table_CAD_model_path = os.path.join(code_root, "table_obj", "table.obj")
table_plane_CAD_model_path = os.path.join(code_root, "table_obj", "table_plane.obj")
arm_CAD_model_path = os.path.join(code_root, "table_obj", "arm.obj")
TABLE_CAD_MODEL_HEIGHT = 0.75
real_table_image_root_path = os.path.join(code_root, "realtable")
real_floor_image_root_path = os.path.join(code_root, "realfloor")
obj_texture_image_root_path = "/data/InterNeRF/data/imagenet"
obj_texture_image_idxfile = "train_paths.txt"

output_root_path = "/data/InterNeRF/data/giga_hemisphere_train_0827/pile_full/6_M_rand/pile_%d-%d"%(830*(SCENE_NUM//830), 830*(SCENE_NUM//830)+830)

raw_urdfs_and_poses_dir_path = "/data/InterNeRF/data/GIGA/data_pile_train_raw/mesh_pose_list"


# render mode
render_mode_list = {'RGB': 1,
                    'IR': 0,
                    'NOCS': 0,
                    'Mask': 1, 
                    'Normal': 1}

# material randomization mode (diffuse, transparent, specular, specular_tex, specular_texmix, mixed)
my_material_randomize_mode = 'mixed'

# set depth sensor parameter
camera_width = 640
camera_height = 360
camera_fov = 69.75 / 180 * math.pi
baseline_distance = 0.055

# set background parameter
background_size = 3.
background_position = (0., 0., 0.)
background_scale = (1., 1., 1.)


# set camera randomize paramater
# start_point_range: (range_r, range_vector),   range_r: (r_min, r_max),    range_vector: (x_min, x_max, y_min, y_max)
# look_at_range: (x_min, x_max, y_min, y_max, z_min, z_max)
# up_range: (x_min, x_max, y_min, y_max)
start_point_range = ((0.5, 0.95), (-0.6, 0.6, -0.6, 0.6))
up_range = (-0.18, -0.18, -0.18, 0.18)
look_at_range = (background_position[0] - 0.05, background_position[0] + 0.05, 
                 background_position[1] - 0.05, background_position[1] + 0.05,
                 background_position[2] - 0.05, background_position[2] + 0.05)


g_syn_light_num_lowbound = 4
g_syn_light_num_highbound = 6
g_syn_light_dist_lowbound = 8
g_syn_light_dist_highbound = 12
g_syn_light_azimuth_degree_lowbound = 0
g_syn_light_azimuth_degree_highbound = 360
g_syn_light_elevation_degree_lowbound = 0
g_syn_light_elevation_degree_highbound = 90
g_syn_light_energy_mean = 3
g_syn_light_energy_std = 0.5
g_syn_light_environment_energy_lowbound = 0
g_syn_light_environment_energy_highbound = 1

def obj_centered_camera_pos(dist, azimuth_deg, elevation_deg):
    phi = float(elevation_deg) / 180 * math.pi
    theta = float(azimuth_deg) / 180 * math.pi
    x = (dist * math.cos(theta) * math.cos(phi))
    y = (dist * math.sin(theta) * math.cos(phi))
    z = (dist * math.sin(phi))
    return (x, y, z)

def quaternionFromYawPitchRoll(yaw, pitch, roll):
    c1 = math.cos(yaw / 2.0)
    c2 = math.cos(pitch / 2.0)
    c3 = math.cos(roll / 2.0)    
    s1 = math.sin(yaw / 2.0)
    s2 = math.sin(pitch / 2.0)
    s3 = math.sin(roll / 2.0)    
    q1 = c1 * c2 * c3 + s1 * s2 * s3
    q2 = c1 * c2 * s3 - s1 * s2 * c3
    q3 = c1 * s2 * c3 + s1 * c2 * s3
    q4 = s1 * c2 * c3 - c1 * s2 * s3
    return (q1, q2, q3, q4)

def camPosToQuaternion(cx, cy, cz):
    q1a = 0
    q1b = 0
    q1c = math.sqrt(2) / 2
    q1d = math.sqrt(2) / 2
    camDist = math.sqrt(cx * cx + cy * cy + cz * cz)
    cx = cx / camDist
    cy = cy / camDist
    cz = cz / camDist    
    t = math.sqrt(cx * cx + cy * cy) 
    tx = cx / t
    ty = cy / t
    yaw = math.acos(ty)
    if tx > 0:
        yaw = 2 * math.pi - yaw
    pitch = 0
    tmp = min(max(tx*cx + ty*cy, -1),1)
    #roll = math.acos(tx * cx + ty * cy)
    roll = math.acos(tmp)
    if cz < 0:
        roll = -roll    
    print("%f %f %f" % (yaw, pitch, roll))
    q2a, q2b, q2c, q2d = quaternionFromYawPitchRoll(yaw, pitch, roll)    
    q1 = q1a * q2a - q1b * q2b - q1c * q2c - q1d * q2d
    q2 = q1b * q2a + q1a * q2b + q1d * q2c - q1c * q2d
    q3 = q1c * q2a - q1d * q2b + q1a * q2c + q1b * q2d
    q4 = q1d * q2a + q1c * q2b - q1b * q2c + q1a * q2d
    return (q1, q2, q3, q4)

def camRotQuaternion(cx, cy, cz, theta): 
    theta = theta / 180.0 * math.pi
    camDist = math.sqrt(cx * cx + cy * cy + cz * cz)
    cx = -cx / camDist
    cy = -cy / camDist
    cz = -cz / camDist
    q1 = math.cos(theta * 0.5)
    q2 = -cx * math.sin(theta * 0.5)
    q3 = -cy * math.sin(theta * 0.5)
    q4 = -cz * math.sin(theta * 0.5)
    return (q1, q2, q3, q4)

def quaternionProduct(qx, qy): 
    a = qx[0]
    b = qx[1]
    c = qx[2]
    d = qx[3]
    e = qy[0]
    f = qy[1]
    g = qy[2]
    h = qy[3]
    q1 = a * e - b * f - c * g - d * h
    q2 = a * f + b * e + c * h - d * g
    q3 = a * g - b * h + c * e + d * f
    q4 = a * h + b * g - c * f + d * e    
    return (q1, q2, q3, q4)

def quaternionToRotation(q):
    w, x, y, z = q
    r00 = 1 - 2 * y ** 2 - 2 * z ** 2
    r01 = 2 * x * y + 2 * w * z
    r02 = 2 * x * z - 2 * w * y

    r10 = 2 * x * y - 2 * w * z
    r11 = 1 - 2 * x ** 2 - 2 * z ** 2
    r12 = 2 * y * z + 2 * w * x

    r20 = 2 * x * z + 2 * w * y
    r21 = 2 * y * z - 2 * w * x
    r22 = 1 - 2 * x ** 2 - 2 * y ** 2
    r = [[r00, r01, r02], [r10, r11, r12], [r20, r21, r22]]
    return r

def quaternionToRotation_xyzw(q):
    x, y, z, w = q
    r00 = 1 - 2 * y ** 2 - 2 * z ** 2
    r01 = 2 * x * y + 2 * w * z
    r02 = 2 * x * z - 2 * w * y

    r10 = 2 * x * y - 2 * w * z
    r11 = 1 - 2 * x ** 2 - 2 * z ** 2
    r12 = 2 * y * z + 2 * w * x

    r20 = 2 * x * z + 2 * w * y
    r21 = 2 * y * z - 2 * w * x
    r22 = 1 - 2 * x ** 2 - 2 * y ** 2
    r = [[r00, r01, r02], [r10, r11, r12], [r20, r21, r22]]
    return r

def quaternionFromRotMat(rotation_matrix):
    rotation_matrix = np.reshape(rotation_matrix, (1, 9))[0]
    w = math.sqrt(rotation_matrix[0]+rotation_matrix[4]+rotation_matrix[8]+1 + 1e-6)/2
    x = math.sqrt(rotation_matrix[0]-rotation_matrix[4]-rotation_matrix[8]+1 + 1e-6)/2
    y = math.sqrt(-rotation_matrix[0]+rotation_matrix[4]-rotation_matrix[8]+1 + 1e-6)/2
    z = math.sqrt(-rotation_matrix[0]-rotation_matrix[4]+rotation_matrix[8]+1 + 1e-6)/2
    a = [w,x,y,z]
    m = a.index(max(a))
    if m == 0:
        x = (rotation_matrix[7]-rotation_matrix[5])/(4*w)
        y = (rotation_matrix[2]-rotation_matrix[6])/(4*w)
        z = (rotation_matrix[3]-rotation_matrix[1])/(4*w)
    if m == 1:
        w = (rotation_matrix[7]-rotation_matrix[5])/(4*x)
        y = (rotation_matrix[1]+rotation_matrix[3])/(4*x)
        z = (rotation_matrix[6]+rotation_matrix[2])/(4*x)
    if m == 2:
        w = (rotation_matrix[2]-rotation_matrix[6])/(4*y)
        x = (rotation_matrix[1]+rotation_matrix[3])/(4*y)
        z = (rotation_matrix[5]+rotation_matrix[7])/(4*y)
    if m == 3:
        w = (rotation_matrix[3]-rotation_matrix[1])/(4*z)
        x = (rotation_matrix[6]+rotation_matrix[2])/(4*z)
        y = (rotation_matrix[5]+rotation_matrix[7])/(4*z)
    quaternion = (w,x,y,z)
    return quaternion

def quaternionFromRotMat_xyzw(rotation_matrix):
    rotation_matrix = np.reshape(rotation_matrix, (1, 9))[0]
    w = math.sqrt(rotation_matrix[0]+rotation_matrix[4]+rotation_matrix[8]+1 + 1e-6)/2
    x = math.sqrt(rotation_matrix[0]-rotation_matrix[4]-rotation_matrix[8]+1 + 1e-6)/2
    y = math.sqrt(-rotation_matrix[0]+rotation_matrix[4]-rotation_matrix[8]+1 + 1e-6)/2
    z = math.sqrt(-rotation_matrix[0]-rotation_matrix[4]+rotation_matrix[8]+1 + 1e-6)/2
    a = [x,y,z,w]
    m = a.index(max(a))
    if m == 0:
        x = (rotation_matrix[7]-rotation_matrix[5])/(4*w)
        y = (rotation_matrix[2]-rotation_matrix[6])/(4*w)
        z = (rotation_matrix[3]-rotation_matrix[1])/(4*w)
    if m == 1:
        w = (rotation_matrix[7]-rotation_matrix[5])/(4*x)
        y = (rotation_matrix[1]+rotation_matrix[3])/(4*x)
        z = (rotation_matrix[6]+rotation_matrix[2])/(4*x)
    if m == 2:
        w = (rotation_matrix[2]-rotation_matrix[6])/(4*y)
        x = (rotation_matrix[1]+rotation_matrix[3])/(4*y)
        z = (rotation_matrix[5]+rotation_matrix[7])/(4*y)
    if m == 3:
        w = (rotation_matrix[3]-rotation_matrix[1])/(4*z)
        x = (rotation_matrix[6]+rotation_matrix[2])/(4*z)
        y = (rotation_matrix[5]+rotation_matrix[7])/(4*z)
    quaternion = (x,y,z,w)
    return quaternion

def rotVector(q, vector_ori):
    r = quaternionToRotation(q)
    x_ori = vector_ori[0]
    y_ori = vector_ori[1]
    z_ori = vector_ori[2]
    x_rot = r[0][0] * x_ori + r[1][0] * y_ori + r[2][0] * z_ori
    y_rot = r[0][1] * x_ori + r[1][1] * y_ori + r[2][1] * z_ori
    z_rot = r[0][2] * x_ori + r[1][2] * y_ori + r[2][2] * z_ori
    return (x_rot, y_rot, z_rot)

def cameraLPosToCameraRPos(q_l, pos_l, baseline_dis):
    vector_camera_l_y = (1, 0, 0)
    vector_rot = rotVector(q_l, vector_camera_l_y)
    pos_r = (pos_l[0] + vector_rot[0] * baseline_dis,
             pos_l[1] + vector_rot[1] * baseline_dis,
             pos_l[2] + vector_rot[2] * baseline_dis)
    return pos_r

def getRTFromAToB(pointCloudA, pointCloudB):

    muA = np.mean(pointCloudA, axis=0)
    muB = np.mean(pointCloudB, axis=0)

    zeroMeanA = pointCloudA - muA
    zeroMeanB = pointCloudB - muB

    covMat = np.matmul(np.transpose(zeroMeanA), zeroMeanB)
    U, S, Vt = np.linalg.svd(covMat)
    R = np.matmul(Vt.T, U.T)

    if np.linalg.det(R) < 0:
        print("Reflection detected")
        Vt[2, :] *= -1
        R = Vt.T * U.T
    T = (-np.matmul(R, muA.T) + muB.T).reshape(3, 1)
    return R, T

def cameraPositionRandomize(start_point_range, look_at_range, up_range):
    r_range, vector_range = start_point_range
    r_min, r_max = r_range
    x_min, x_max, y_min, y_max = vector_range
    r = random.uniform(r_min, r_max)
    x = random.uniform(x_min, x_max)
    y = random.uniform(y_min, y_max)
    z = math.sqrt(1 - x**2 - y**2)
    vector_camera_axis = np.array([x, y, z])

    x_min, x_max, y_min, y_max = up_range
    x = random.uniform(x_min, x_max)
    y = random.uniform(y_min, y_max)    
    z = math.sqrt(1 - x**2 - y**2)
    up = np.array([x, y, z])

    x_min, x_max, y_min, y_max, z_min, z_max = look_at_range
    look_at = np.array([random.uniform(x_min, x_max),
                        random.uniform(y_min, y_max),
                        random.uniform(z_min, z_max)])
    position = look_at + r * vector_camera_axis

    vectorZ = - (look_at - position)/np.linalg.norm(look_at - position)
    vectorX = np.cross(up, vectorZ)/np.linalg.norm(np.cross(up, vectorZ))
    vectorY = np.cross(vectorZ, vectorX)/np.linalg.norm(np.cross(vectorX, vectorZ))

    # points in camera coordinates
    pointSensor= np.array([[0., 0., 0.], [1., 0., 0.], [0., 2., 0.], [0., 0., 3.]])

    # points in world coordinates 
    pointWorld = np.array([position,
                            position + vectorX,
                            position + vectorY * 2,
                            position + vectorZ * 3])

    resR, resT = getRTFromAToB(pointSensor, pointWorld)
    resQ = quaternionFromRotMat(resR)
    return resQ, resT    

def add_noise_to_transformation_matrix(Rot, Trans, angle_std=2, translation_std=0.01):
    axis = np.random.rand(3)
    axis /= np.linalg.norm(axis)
    angle = np.random.uniform(0, angle_std) / 180 * np.pi
    Rot = Rotation.from_rotvec(angle * axis).as_matrix() @ Rot
    direction = np.random.rand(3)
    direction /= np.linalg.norm(direction)
    length = np.random.uniform(0, translation_std)
    Trans += direction.reshape(Trans.shape) * length
    return Rot, Trans

def genCameraPosition(look_at):
    quat_list = []
    rot_list = []
    trans_list = []
    position_list = []
    
    alpha = 0
    alpha_delta = (2 * math.pi) / num_point_ver
    for i in range(num_point_ver):
        alpha = alpha + alpha_delta
        flag_x = 1
        flag_y = 1
        alpha1 = alpha
        if alpha > math.pi/2 and alpha <= math.pi: 
            alpha1 = math.pi - alpha #alpha - math.pi/2
            flag_x = -1
            flag_y = 1
        elif alpha > math.pi and alpha <= math.pi*(3/2):
            alpha1 = alpha - math.pi #math.pi*(3/2) - alpha
            flag_x = -1
            flag_y = -1
        elif alpha > math.pi*(3/2):
            alpha1 = math.pi*2 - alpha #alpha - math.pi*(3/2)
            flag_x = 1
            flag_y = -1
    
        beta = beta_range[0]
        beta_delta = (beta_range[1]-beta_range[0])/(num_point_hor-1)
        for j in range(num_point_hor):
            if j != 0:
                beta = beta + beta_delta 
            x = flag_x * (r * math.sin(beta)) * math.cos(alpha1)
            y = flag_y * (r * math.sin(beta)) * math.sin(alpha1)
            z = r * math.cos(beta)
            position = np.array([x, y, z]) + look_at
            look_at = look_at
            up = np.array([0, 0, 1])

            vectorZ = - (look_at - position)/np.linalg.norm(look_at - position)
            vectorX = np.cross(up, vectorZ)/np.linalg.norm(np.cross(up, vectorZ))
            vectorY = np.cross(vectorZ, vectorX)/np.linalg.norm(np.cross(vectorX, vectorZ))

            # points in camera coordinates
            pointSensor= np.array([[0., 0., 0.], [1., 0., 0.], [0., 2., 0.], [0., 0., 3.]])

            # points in world coordinates 
            pointWorld = np.array([position,
                                   position + vectorX,
                                   position + vectorY * 2,
                                   position + vectorZ * 3])

            # get R and T
            resR, resT = getRTFromAToB(pointSensor, pointWorld)
            
            # add noise
            resR, resT = add_noise_to_transformation_matrix(resR, resT)

            # add to list
            resQ = quaternionFromRotMat(resR)
            quat_list.append(resQ)
            rot_list.append(resR)
            trans_list.append(resT)
            #position_list.append(position)
            position_list.append(resT.reshape(3))
    return quat_list, trans_list, rot_list, position_list

def quanternion_mul(q1, q2):
    s1 = q1[0]
    v1 = np.array(q1[1:])
    s2 = q2[0]
    v2 = np.array(q2[1:])
    s = s1 * s2 - np.dot(v1, v2)
    v = s1 * v2 + s2 * v1 + np.cross(v1, v2)
    return (s, v[0], v[1], v[2])


class BlenderRenderer(object):

    def __init__(self, viewport_size_x=640, viewport_size_y=360):
        '''
        viewport_size_x, viewport_size_y: rendering viewport resolution
        '''

        # remove all objects, cameras and lights
        for obj in bpy.data.meshes:
            bpy.data.meshes.remove(obj)

        for cam in bpy.data.cameras:
            bpy.data.cameras.remove(cam)

        for light in bpy.data.lights:
            bpy.data.lights.remove(light)

        for obj in bpy.data.objects:
            bpy.data.objects.remove(obj, do_unlink=True)

        # remove all materials
        # for item in bpy.data.materials:
        #     bpy.data.materials.remove(item)

        render_context = bpy.context.scene.render

        # add left camera
        camera_l_data = bpy.data.cameras.new(name="camera_l")
        camera_l_object = bpy.data.objects.new(name="camera_l", object_data=camera_l_data)
        bpy.context.collection.objects.link(camera_l_object)

        # add right camera
        camera_r_data = bpy.data.cameras.new(name="camera_r")
        camera_r_object = bpy.data.objects.new(name="camera_r", object_data=camera_r_data)
        bpy.context.collection.objects.link(camera_r_object)

        camera_l = bpy.data.objects["camera_l"]
        camera_r = bpy.data.objects["camera_r"]

        # set the camera postion and orientation so that it is in
        # the front of the object
        camera_l.location = (1, 0, 0)
        camera_r.location = (1, 0, 0)

        # add emitter light
        light_emitter_data = bpy.data.lights.new(name="light_emitter", type='SPOT')
        light_emitter_object = bpy.data.objects.new(name="light_emitter", object_data=light_emitter_data)
        bpy.context.collection.objects.link(light_emitter_object)

        light_emitter = bpy.data.objects["light_emitter"]
        light_emitter.location = (1, 0, 0)
        light_emitter.data.energy = LIGHT_EMITTER_ENERGY

        # render setting
        render_context.resolution_percentage = 100
        self.render_context = render_context

        self.camera_l = camera_l
        self.camera_r = camera_r

        self.light_emitter = light_emitter

        self.model_loaded = False
        self.background_added = None

        self.render_context.resolution_x = viewport_size_x
        self.render_context.resolution_y = viewport_size_y

        self.my_material = {}
        self.render_mode = 'IR'

        # output setting 
        self.render_context.image_settings.file_format = 'PNG'
        self.render_context.image_settings.compression = 0
        self.render_context.image_settings.color_mode = 'BW'
        self.render_context.image_settings.color_depth = '8'

        # cycles setting
        self.render_context.engine = 'CYCLES'
        bpy.context.scene.cycles.progressive = 'BRANCHED_PATH'
        bpy.context.scene.cycles.use_denoising = True
        bpy.context.scene.cycles.denoiser = 'NLM'
        bpy.context.scene.cycles.film_exposure = 0.5

        # self.render_context.use_antialiasing = False
        ##########
        bpy.context.scene.view_layers["View Layer"].use_sky = True
        ##########

        # switch on nodes
        bpy.context.scene.use_nodes = True
        tree = bpy.context.scene.node_tree
        links = tree.links
  
        # clear default nodes
        for n in tree.nodes:
            tree.nodes.remove(n)
  
        # create input render layer node
        rl = tree.nodes.new('CompositorNodeRLayers')

        # create output node
        self.fileOutput = tree.nodes.new(type="CompositorNodeOutputFile")
        self.fileOutput.base_path = "./new_data/0000"
        self.fileOutput.format.file_format = 'OPEN_EXR'
        self.fileOutput.format.color_depth= '32'
        self.fileOutput.file_slots[0].path = 'depth#'
        # links.new(map.outputs[0], fileOutput.inputs[0])
        links.new(rl.outputs[2], self.fileOutput.inputs[0])
        # links.new(gamma.outputs[0], fileOutput.inputs[0])

        # depth sensor pattern
        self.pattern = []
        # environment map
        self.env_map = []
        ###
        self.realtable_img_list = []
        self.realfloor_img_list = []
        self.obj_texture_img_list = []
        ###

    def loadImages(self, pattern_path, env_map_path, real_table_image_root_path, real_floor_image_root_path):
        # load pattern image
        self.pattern = bpy.data.images.load(filepath=pattern_path)
        # load env map
        for item in os.listdir(env_map_path):
            if item.split('.')[-1] == 'hdr':
                self.env_map.append(bpy.data.images.load(filepath=os.path.join(env_map_path, item)))
        ###
        # load real table images
        for item in os.listdir(real_table_image_root_path):
            if item.split('.')[-1] == 'jpg':
                self.realtable_img_list.append(bpy.data.images.load(filepath=os.path.join(real_table_image_root_path, item)))
        # load real floor images
        for item in os.listdir(real_floor_image_root_path):
            if item.split('.')[-1] == 'jpg':
                self.realfloor_img_list.append(bpy.data.images.load(filepath=os.path.join(real_floor_image_root_path, item)))
        # load obj texture images
        f_teximg_idx = open(os.path.join(obj_texture_image_root_path,obj_texture_image_idxfile),"r")  
        lines = f_teximg_idx.readlines() 
        # for item in lines:
        #     item = item[:-1]      # 去掉"\n"  
        # #for item in os.listdir(obj_texture_image_root_path):
        #     #if item.split('.')[-1] == 'jpg':
        #     self.obj_texture_img_list.append(bpy.data.images.load(filepath=os.path.join(obj_texture_image_root_path, "images", item)))

        start = random.randint(0,99900)
        end = start+100
        for item in lines[start:end]:
            item = item[:-1]      # 去掉"\n"  
            self.obj_texture_img_list.append(bpy.data.images.load(filepath=os.path.join(obj_texture_image_root_path, "images", item)))
        ###

    def addEnvMap(self):
        # Get the environment node tree of the current scene
        node_tree = bpy.context.scene.world.node_tree
        tree_nodes = node_tree.nodes

        # Clear all nodes
        tree_nodes.clear()

        # Add Background node
        node_background = tree_nodes.new(type='ShaderNodeBackground')

        # Add Environment Texture node
        node_environment = tree_nodes.new('ShaderNodeTexEnvironment')
        # Load and assign the image to the node property
        # node_environment.image = bpy.data.images.load("/Users/zhangjiyao/Desktop/test_addon/envmap_lib/autoshop_01_1k.hdr") # Relative path
        node_environment.location = -300,0

        node_tex_coord = tree_nodes.new(type='ShaderNodeTexCoord')
        node_tex_coord.location = -700,0

        node_mapping = tree_nodes.new(type='ShaderNodeMapping')
        node_mapping.location = -500,0

        # Add Output node
        node_output = tree_nodes.new(type='ShaderNodeOutputWorld')   
        node_output.location = 200,0

        # Link all nodes
        links = node_tree.links
        links.new(node_environment.outputs["Color"], node_background.inputs["Color"])
        links.new(node_background.outputs["Background"], node_output.inputs["Surface"])
        links.new(node_tex_coord.outputs["Generated"], node_mapping.inputs["Vector"])
        links.new(node_mapping.outputs["Vector"], node_environment.inputs["Vector"])

        #### bpy.data.worlds["World"].node_tree.nodes["Background"].inputs[1].default_value = 1.0
        random_energy = random.uniform(LIGHT_ENV_MAP_ENERGY_RGB * 0.8, LIGHT_ENV_MAP_ENERGY_RGB * 1.2)
        bpy.data.worlds["World"].node_tree.nodes["Background"].inputs[1].default_value = random_energy
        ####

    def setEnvMap(self, env_map_id, rotation_elur_z):
        # Get the environment node tree of the current scene
        node_tree = bpy.context.scene.world.node_tree

        # Get Environment Texture node
        node_environment = node_tree.nodes['Environment Texture']
        # Load and assign the image to the node property
        node_environment.image = self.env_map[env_map_id]

        node_mapping = node_tree.nodes['Mapping']
        node_mapping.inputs[2].default_value[2] = rotation_elur_z

    def addMaskMaterial(self, num=20):
        background_material_name_list = ["mask_background", "mask_table", "mask_tableplane", "mask_arm"]
        for material_name in background_material_name_list:
            material_class = (bpy.data.materials.get(material_name) or bpy.data.materials.new(material_name))         # test if material exists, if it does not exist, create it:

            # enable 'Use nodes'
            material_class.use_nodes = True
            node_tree = material_class.node_tree

            # remove default nodes
            material_class.node_tree.nodes.clear()

            # add new nodes  
            node_1 = node_tree.nodes.new('ShaderNodeOutputMaterial')
            node_2= node_tree.nodes.new('ShaderNodeBrightContrast')

            # link nodes
            node_tree.links.new(node_1.inputs[0], node_2.outputs[0])
            node_2.inputs[0].default_value = (1, 1, 1, 1)
            self.my_material[material_name] =  material_class

        #print("##############################", self.my_material)

        for i in range(num):
            class_name = str(i + 1)
            # set the material of background    
            material_name = "mask_" + class_name

            # test if material exists
            # if it does not exist, create it:
            material_class = (bpy.data.materials.get(material_name) or 
                bpy.data.materials.new(material_name))

            # enable 'Use nodes'
            material_class.use_nodes = True
            node_tree = material_class.node_tree

            # remove default nodes
            material_class.node_tree.nodes.clear()

            # add new nodes  
            node_1 = node_tree.nodes.new('ShaderNodeOutputMaterial')
            node_2= node_tree.nodes.new('ShaderNodeBrightContrast')

            # link nodes
            node_tree.links.new(node_1.inputs[0], node_2.outputs[0])

            if class_name.split('_')[0] == 'background' or class_name.split('_')[0] == 'table' or class_name.split('_')[0] == 'tableplane' or class_name.split('_')[0] == 'arm':
                node_2.inputs[0].default_value = (1, 1, 1, 1)
            else:
                node_2.inputs[0].default_value = ((i + 1)/255., 0., 0., 1)

            self.my_material[material_name] =  material_class

    def addNOCSMaterial(self):
        material_name = 'coord_color'
        mat = (bpy.data.materials.get(material_name) or bpy.data.materials.new(material_name))

        mat.use_nodes = True
        node_tree = mat.node_tree
        nodes = node_tree.nodes
        nodes.clear()        

        links = node_tree.links
        links.clear()

        vcol_R = nodes.new(type="ShaderNodeVertexColor")
        vcol_R.layer_name = "Col_R" # the vertex color layer name
        vcol_G = nodes.new(type="ShaderNodeVertexColor")
        vcol_G.layer_name = "Col_G" # the vertex color layer name
        vcol_B = nodes.new(type="ShaderNodeVertexColor")
        vcol_B.layer_name = "Col_B" # the vertex color layer name

        node_Output = node_tree.nodes.new('ShaderNodeOutputMaterial')
        node_Emission = node_tree.nodes.new('ShaderNodeEmission')
        node_LightPath = node_tree.nodes.new('ShaderNodeLightPath')
        node_Mix = node_tree.nodes.new('ShaderNodeMixShader')
        node_Combine = node_tree.nodes.new(type="ShaderNodeCombineRGB")


        # make links
        node_tree.links.new(vcol_R.outputs[1], node_Combine.inputs[0])
        node_tree.links.new(vcol_G.outputs[1], node_Combine.inputs[1])
        node_tree.links.new(vcol_B.outputs[1], node_Combine.inputs[2])
        node_tree.links.new(node_Combine.outputs[0], node_Emission.inputs[0])

        node_tree.links.new(node_LightPath.outputs[0], node_Mix.inputs[0])
        node_tree.links.new(node_Emission.outputs[0], node_Mix.inputs[2])
        node_tree.links.new(node_Mix.outputs[0], node_Output.inputs[0])

        self.my_material[material_name] = mat

    def addNormalMaterial(self):
        material_name = 'normal'
        mat = (bpy.data.materials.get(material_name) or bpy.data.materials.new(material_name))
        mat.use_nodes = True
        node_tree = mat.node_tree
        nodes = node_tree.nodes
        nodes.clear()
            
        links = node_tree.links
        links.clear()
            
        # Nodes :
        new_node = nodes.new(type='ShaderNodeMath')
        new_node.active_preview = False
        new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
        new_node.location = (151.59744262695312, 854.5482177734375)
        new_node.name = 'Math'
        new_node.operation = 'MULTIPLY'
        new_node.select = False
        new_node.use_clamp = False
        new_node.width = 140.0
        new_node.inputs[0].default_value = 0.5
        new_node.inputs[1].default_value = 1.0
        new_node.inputs[2].default_value = 0.0
        new_node.outputs[0].default_value = 0.0

        new_node = nodes.new(type='ShaderNodeLightPath')
        new_node.active_preview = False
        new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
        new_node.location = (602.9912719726562, 1046.660888671875)
        new_node.name = 'Light Path'
        new_node.select = False
        new_node.width = 140.0
        new_node.outputs[0].default_value = 0.0
        new_node.outputs[1].default_value = 0.0
        new_node.outputs[2].default_value = 0.0
        new_node.outputs[3].default_value = 0.0
        new_node.outputs[4].default_value = 0.0
        new_node.outputs[5].default_value = 0.0
        new_node.outputs[6].default_value = 0.0
        new_node.outputs[7].default_value = 0.0
        new_node.outputs[8].default_value = 0.0
        new_node.outputs[9].default_value = 0.0
        new_node.outputs[10].default_value = 0.0
        new_node.outputs[11].default_value = 0.0
        new_node.outputs[12].default_value = 0.0

        new_node = nodes.new(type='ShaderNodeOutputMaterial')
        new_node.active_preview = False
        new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
        new_node.is_active_output = True
        new_node.location = (1168.93017578125, 701.84033203125)
        new_node.name = 'Material Output'
        new_node.select = False
        new_node.target = 'ALL'
        new_node.width = 140.0
        new_node.inputs[2].default_value = [0.0, 0.0, 0.0]

        new_node = nodes.new(type='ShaderNodeBsdfTransparent')
        new_node.active_preview = False
        new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
        new_node.location = (731.72900390625, 721.4832763671875)
        new_node.name = 'Transparent BSDF'
        new_node.select = False
        new_node.width = 140.0
        new_node.inputs[0].default_value = [1.0, 1.0, 1.0, 1.0]

        new_node = nodes.new(type='ShaderNodeCombineXYZ')
        new_node.active_preview = False
        new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
        new_node.location = (594.4229736328125, 602.9271240234375)
        new_node.name = 'Combine XYZ'
        new_node.select = False
        new_node.width = 140.0
        new_node.inputs[0].default_value = 0.0
        new_node.inputs[1].default_value = 0.0
        new_node.inputs[2].default_value = 0.0
        new_node.outputs[0].default_value = [0.0, 0.0, 0.0]

        new_node = nodes.new(type='ShaderNodeMixShader')
        new_node.active_preview = False
        new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
        new_node.location = (992.7239990234375, 707.2142333984375)
        new_node.name = 'Mix Shader'
        new_node.select = False
        new_node.width = 140.0
        new_node.inputs[0].default_value = 0.5

        new_node = nodes.new(type='ShaderNodeEmission')
        new_node.active_preview = False
        new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
        new_node.location = (774.0802612304688, 608.2547607421875)
        new_node.name = 'Emission'
        new_node.select = False
        new_node.width = 140.0
        new_node.inputs[0].default_value = [1.0, 1.0, 1.0, 1.0]
        new_node.inputs[1].default_value = 1.0

        new_node = nodes.new(type='ShaderNodeSeparateXYZ')
        new_node.active_preview = False
        new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
        new_node.location = (-130.12167358398438, 558.1497802734375)
        new_node.name = 'Separate XYZ'
        new_node.select = False
        new_node.width = 140.0
        new_node.inputs[0].default_value = [0.0, 0.0, 0.0]
        new_node.outputs[0].default_value = 0.0
        new_node.outputs[1].default_value = 0.0
        new_node.outputs[2].default_value = 0.0

        new_node = nodes.new(type='ShaderNodeMath')
        new_node.active_preview = False
        new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
        new_node.location = (162.43240356445312, 618.8094482421875)
        new_node.name = 'Math.002'
        new_node.operation = 'MULTIPLY'
        new_node.select = False
        new_node.use_clamp = False
        new_node.width = 140.0
        new_node.inputs[0].default_value = 0.5
        new_node.inputs[1].default_value = 1.0
        new_node.inputs[2].default_value = 0.0
        new_node.outputs[0].default_value = 0.0

        new_node = nodes.new(type='ShaderNodeMath')
        new_node.active_preview = False
        new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
        new_node.location = (126.8158187866211, 364.5539855957031)
        new_node.name = 'Math.001'
        new_node.operation = 'MULTIPLY'
        new_node.select = False
        new_node.use_clamp = False
        new_node.width = 140.0
        new_node.inputs[0].default_value = 0.5
        new_node.inputs[1].default_value = -1.0
        new_node.inputs[2].default_value = 0.0
        new_node.outputs[0].default_value = 0.0

        new_node = nodes.new(type='ShaderNodeVectorTransform')
        new_node.active_preview = False
        new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
        new_node.convert_from = 'WORLD'
        new_node.convert_to = 'CAMERA'
        new_node.location = (-397.0209045410156, 594.7037353515625)
        new_node.name = 'Vector Transform'
        new_node.select = False
        new_node.vector_type = 'VECTOR'
        new_node.width = 140.0
        new_node.inputs[0].default_value = [0.5, 0.5, 0.5]
        new_node.outputs[0].default_value = [0.0, 0.0, 0.0]

        new_node = nodes.new(type='ShaderNodeNewGeometry')
        new_node.active_preview = False
        new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
        new_node.location = (-651.8067016601562, 593.0455932617188)
        new_node.name = 'Geometry'
        new_node.width = 140.0
        new_node.outputs[0].default_value = [0.0, 0.0, 0.0]
        new_node.outputs[1].default_value = [0.0, 0.0, 0.0]
        new_node.outputs[2].default_value = [0.0, 0.0, 0.0]
        new_node.outputs[3].default_value = [0.0, 0.0, 0.0]
        new_node.outputs[4].default_value = [0.0, 0.0, 0.0]
        new_node.outputs[5].default_value = [0.0, 0.0, 0.0]
        new_node.outputs[6].default_value = 0.0
        new_node.outputs[7].default_value = 0.0
        new_node.outputs[8].default_value = 0.0

        # Links :

        links.new(nodes["Light Path"].outputs[0], nodes["Mix Shader"].inputs[0])    
        links.new(nodes["Separate XYZ"].outputs[0], nodes["Math"].inputs[0])    
        links.new(nodes["Separate XYZ"].outputs[1], nodes["Math.002"].inputs[0])    
        links.new(nodes["Separate XYZ"].outputs[2], nodes["Math.001"].inputs[0])    
        links.new(nodes["Vector Transform"].outputs[0], nodes["Separate XYZ"].inputs[0])    
        links.new(nodes["Combine XYZ"].outputs[0], nodes["Emission"].inputs[0])    
        links.new(nodes["Math"].outputs[0], nodes["Combine XYZ"].inputs[0])    
        links.new(nodes["Math.002"].outputs[0], nodes["Combine XYZ"].inputs[1])    
        links.new(nodes["Math.001"].outputs[0], nodes["Combine XYZ"].inputs[2])    
        links.new(nodes["Transparent BSDF"].outputs[0], nodes["Mix Shader"].inputs[1])    
        links.new(nodes["Emission"].outputs[0], nodes["Mix Shader"].inputs[2])    
        links.new(nodes["Mix Shader"].outputs[0], nodes["Material Output"].inputs[0])    
        links.new(nodes["Geometry"].outputs[1], nodes["Vector Transform"].inputs[0])    

        self.my_material[material_name] = mat

    def addMaterialLib(self, material_class_instance_pairs):
        for mat in bpy.data.materials:
            name = mat.name
            name_class = str(name.split('_')[0])
            if name_class != 'Dots Stroke' and name_class != 'default':
                #print(name)
                if name_class not in self.my_material:
                    self.my_material[name_class] = [mat]
                else:
                    self.my_material[name_class].append(mat)    # e.g. self.my_material['metal'] = [.....]

    def setCamera(self, quaternion, translation, fov, baseline_distance):
        self.camera_l.data.angle = fov
        self.camera_r.data.angle = self.camera_l.data.angle
        cx = translation[0]
        cy = translation[1]
        cz = translation[2]

        self.camera_l.location[0] = cx
        self.camera_l.location[1] = cy 
        self.camera_l.location[2] = cz

        self.camera_l.rotation_mode = 'QUATERNION'
        self.camera_l.rotation_quaternion[0] = quaternion[0]
        self.camera_l.rotation_quaternion[1] = quaternion[1]
        self.camera_l.rotation_quaternion[2] = quaternion[2]
        self.camera_l.rotation_quaternion[3] = quaternion[3]

        self.camera_r.rotation_mode = 'QUATERNION'
        self.camera_r.rotation_quaternion[0] = quaternion[0]
        self.camera_r.rotation_quaternion[1] = quaternion[1]
        self.camera_r.rotation_quaternion[2] = quaternion[2]
        self.camera_r.rotation_quaternion[3] = quaternion[3]
        cx, cy, cz = cameraLPosToCameraRPos(quaternion, (cx, cy, cz), baseline_distance)
        self.camera_r.location[0] = cx
        self.camera_r.location[1] = cy 
        self.camera_r.location[2] = cz

    def setLighting(self):
        # emitter        
        #self.light_emitter.location = self.camera_r.location
        self.light_emitter.location = self.camera_l.location + 0.51 * (self.camera_r.location - self.camera_l.location)
        self.light_emitter.rotation_mode = 'QUATERNION'
        self.light_emitter.rotation_quaternion = self.camera_r.rotation_quaternion

        # emitter setting
        bpy.context.view_layer.objects.active = None
        # bpy.ops.object.select_all(action="DESELECT")
        self.render_context.engine = 'CYCLES'
        self.light_emitter.select_set(True)
        self.light_emitter.data.use_nodes = True
        self.light_emitter.data.type = "POINT"
        self.light_emitter.data.shadow_soft_size = 0.001
        random_energy = random.uniform(LIGHT_EMITTER_ENERGY * 0.9, LIGHT_EMITTER_ENERGY * 1.1)
        self.light_emitter.data.energy = random_energy

        # remove default node
        light_emitter = bpy.data.objects["light_emitter"].data
        light_emitter.node_tree.nodes.clear()
        # light_projector.node_tree.nodes.remove(light_projector.node_tree.nodes.get('光输出')) #title of the existing node when materials.new
        # light_projector.node_tree.nodes.remove(light_projector.node_tree.nodes.get('自发光(发射)')) #title of the existing node when materials.new

        # add new nodes
        light_output = light_emitter.node_tree.nodes.new("ShaderNodeOutputLight")
        node_1 = light_emitter.node_tree.nodes.new("ShaderNodeEmission")
        node_2 = light_emitter.node_tree.nodes.new("ShaderNodeTexImage")
        node_3 = light_emitter.node_tree.nodes.new("ShaderNodeMapping")
        node_4 = light_emitter.node_tree.nodes.new("ShaderNodeVectorMath")
        node_5 = light_emitter.node_tree.nodes.new("ShaderNodeSeparateXYZ")
        node_6 = light_emitter.node_tree.nodes.new("ShaderNodeTexCoord")

        # link nodes
        light_emitter.node_tree.links.new(light_output.inputs[0], node_1.outputs[0])
        light_emitter.node_tree.links.new(node_1.inputs[0], node_2.outputs[0])
        light_emitter.node_tree.links.new(node_2.inputs[0], node_3.outputs[0])
        light_emitter.node_tree.links.new(node_3.inputs[0], node_4.outputs[0])
        light_emitter.node_tree.links.new(node_4.inputs[0], node_6.outputs[1])
        light_emitter.node_tree.links.new(node_4.inputs[1], node_5.outputs[2])
        light_emitter.node_tree.links.new(node_5.inputs[0], node_6.outputs[1])

        # set parameter of nodes
        node_1.inputs[1].default_value = 1.0        # scale
        node_2.extension = 'CLIP'
        # node_2.interpolation = 'Cubic'

        node_3.inputs[1].default_value[0] = 0.5
        node_3.inputs[1].default_value[1] = 0.5
        node_3.inputs[1].default_value[2] = 0
        node_3.inputs[2].default_value[0] = 0
        node_3.inputs[2].default_value[1] = 0
        node_3.inputs[2].default_value[2] = 0.05

        # scale of pattern
        node_3.inputs[3].default_value[0] = 0.6
        node_3.inputs[3].default_value[1] = 0.85
        node_3.inputs[3].default_value[2] = 0
        node_4.operation = 'DIVIDE'

        # pattern path
        node_2.image = self.pattern

    def lightModeSelect(self, light_mode):
        if light_mode == "RGB":
            self.light_emitter.hide_render = True
            # set the environment map energy
            #### random_energy = random.uniform(LIGHT_ENV_MAP_ENERGY_RGB * 0.8, LIGHT_ENV_MAP_ENERGY_RGB * 1.2)
            #### bpy.data.worlds["World"].node_tree.nodes["Background"].inputs[1].default_value = random_energy

        elif light_mode == "IR":
            self.light_emitter.hide_render = False
            # set the environment map energy
            random_energy = random.uniform(LIGHT_ENV_MAP_ENERGY_IR * 0.8, LIGHT_ENV_MAP_ENERGY_IR * 1.2)
            bpy.data.worlds["World"].node_tree.nodes["Background"].inputs[1].default_value = random_energy
        
        elif light_mode == "Mask" or light_mode == "NOCS" or light_mode == "Normal":
            self.light_emitter.hide_render = True
            bpy.data.worlds["World"].node_tree.nodes["Background"].inputs[1].default_value = 0


        else:
            print("Not support the mode!")    

    def outputModeSelect(self, output_mode):
        if output_mode == "RGB":
            self.render_context.image_settings.file_format = 'PNG'
            self.render_context.image_settings.compression = 0
            self.render_context.image_settings.color_mode = 'RGB'
            self.render_context.image_settings.color_depth = '8'
            bpy.context.scene.view_settings.view_transform = 'Filmic'
            bpy.context.scene.render.filter_size = 1.5
            self.render_context.resolution_x = 640 ### 1280
            self.render_context.resolution_y = 360 ### 720
        elif output_mode == "IR":
            self.render_context.image_settings.file_format = 'PNG'
            self.render_context.image_settings.compression = 0
            self.render_context.image_settings.color_mode = 'BW'
            self.render_context.image_settings.color_depth = '8'
            bpy.context.scene.view_settings.view_transform = 'Filmic'
            bpy.context.scene.render.filter_size = 1.5
            self.render_context.resolution_x = 640 ### 1280
            self.render_context.resolution_y = 360 ### 720
        elif output_mode == "Mask":
            self.render_context.image_settings.file_format = 'OPEN_EXR'
            self.render_context.image_settings.color_mode = 'RGB'
            bpy.context.scene.view_settings.view_transform = 'Raw'
            bpy.context.scene.render.filter_size = 0
            self.render_context.resolution_x = 640
            self.render_context.resolution_y = 360
        elif output_mode == "NOCS":
            # self.render_context.image_settings.file_format = 'OPEN_EXR'
            self.render_context.image_settings.file_format = 'PNG'            
            self.render_context.image_settings.color_mode = 'RGB'
            self.render_context.image_settings.color_depth = '8'
            bpy.context.scene.view_settings.view_transform = 'Raw'
            bpy.context.scene.render.filter_size = 0
            self.render_context.resolution_x = 640
            self.render_context.resolution_y = 360
        elif output_mode == "Normal":
            self.render_context.image_settings.file_format = 'OPEN_EXR'
            self.render_context.image_settings.color_mode = 'RGB'
            bpy.context.scene.view_settings.view_transform = 'Raw'
            bpy.context.scene.render.filter_size = 1.5
            self.render_context.resolution_x = 640
            self.render_context.resolution_y = 360
        else:
            print("Not support the mode!")    

    def renderEngineSelect(self, engine_mode):

        if engine_mode == "CYCLES":
            self.render_context.engine = 'CYCLES'
            bpy.context.scene.cycles.progressive = 'BRANCHED_PATH'
            bpy.context.scene.cycles.use_denoising = True
            bpy.context.scene.cycles.denoiser = 'NLM'
            bpy.context.scene.cycles.film_exposure = 1.0
            bpy.context.scene.cycles.aa_samples = CYCLES_SAMPLE

            ## Set the device_type
            bpy.context.preferences.addons["cycles"].preferences.compute_device_type = "CUDA" # or "OPENCL"
            ## Set the device and feature set
            # bpy.context.scene.cycles.device = "CPU"

            ## get_devices() to let Blender detects GPU device
            cuda_devices, _ = bpy.context.preferences.addons["cycles"].preferences.get_devices()
            print(bpy.context.preferences.addons["cycles"].preferences.compute_device_type)
            for d in bpy.context.preferences.addons["cycles"].preferences.devices:
                d["use"] = 1 # Using all devices, include GPU and CPU
                print(d["name"], d["use"])
            '''
            '''
            device_list = DEVICE_LIST
            activated_gpus = []
            for i, device in enumerate(cuda_devices):
                if (i in device_list):
                    device.use = True
                    activated_gpus.append(device.name)
                else:
                    device.use = False


        elif engine_mode == "EEVEE":
            bpy.context.scene.render.engine = 'BLENDER_EEVEE'
        else:
            print("Not support the mode!")    

    def addBackground(self, size, position, scale):
        # set the material of background    
        material_name = "default_background"

        # test if material exists
        # if it does not exist, create it:
        material_background = (bpy.data.materials.get(material_name) or 
            bpy.data.materials.new(material_name))

        # enable 'Use nodes'
        material_background.use_nodes = True
        node_tree = material_background.node_tree

        # remove default nodes
        material_background.node_tree.nodes.clear()
        # material_background.node_tree.nodes.remove(material_background.node_tree.nodes.get('Principled BSDF')) #title of the existing node when materials.new
        # material_background.node_tree.nodes.remove(material_background.node_tree.nodes.get('Material Output')) #title of the existing node when materials.new

        # add new nodes  
        node_1 = node_tree.nodes.new('ShaderNodeOutputMaterial')
        node_2 = node_tree.nodes.new('ShaderNodeBsdfPrincipled')
        node_3 = node_tree.nodes.new('ShaderNodeTexImage')

        # link nodes
        node_tree.links.new(node_1.inputs[0], node_2.outputs[0])
        node_tree.links.new(node_2.inputs[0], node_3.outputs[0])

        # add texture image
        node_3.image = bpy.data.images.load(filepath=default_background_texture_path)
        self.my_material['default_background'] = material_background

        # add background plane
        for i in range(-2, 3, 1):
            for j in range(-2, 3, 1):
                position_i_j = (i * size + position[0], j * size + position[1], position[2] - TABLE_CAD_MODEL_HEIGHT)
                bpy.ops.mesh.primitive_plane_add(size=size, enter_editmode=False, align='WORLD', location=position_i_j, scale=scale)
                bpy.ops.rigidbody.object_add()
                bpy.context.object.rigid_body.type = 'PASSIVE'
                bpy.context.object.rigid_body.collision_shape = 'BOX'
        for i in range(-2, 3, 1):
            for j in [-2, 2]:
                position_i_j = (i * size + position[0], j * size + position[1], position[2] - 0.25)# - TABLE_CAD_MODEL_HEIGHT)
                rotation_elur = (math.pi / 2., 0., 0.)
                bpy.ops.mesh.primitive_plane_add(size=size, enter_editmode=False, align='WORLD', location=position_i_j, rotation = rotation_elur)
                bpy.ops.rigidbody.object_add()
                bpy.context.object.rigid_body.type = 'PASSIVE'
                bpy.context.object.rigid_body.collision_shape = 'BOX'    
        for j in range(-2, 3, 1):
            for i in [-2, 2]:
                position_i_j = (i * size + position[0], j * size + position[1], position[2] - 0.25)# - TABLE_CAD_MODEL_HEIGHT)
                rotation_elur = (0, math.pi / 2, 0)
                bpy.ops.mesh.primitive_plane_add(size=size, enter_editmode=False, align='WORLD', location=position_i_j, rotation = rotation_elur)
                bpy.ops.rigidbody.object_add()
                bpy.context.object.rigid_body.type = 'PASSIVE'
                bpy.context.object.rigid_body.collision_shape = 'BOX'        
        count = 0
        for obj in bpy.data.objects:
            if obj.type == "MESH":
                obj.name = "background_" + str(count)
                obj.data.name = "background_" + str(count)
                obj.active_material = material_background
                count += 1

        self.background_added = True

    def clearModel(self):
        '''
        # delete all meshes
        for item in bpy.data.meshes:
            bpy.data.meshes.remove(item)
        for item in bpy.data.materials:
            bpy.data.materials.remove(item)
        '''

        # remove all objects except background
        for obj in bpy.data.objects:
            if obj.type == 'MESH' and not obj.name.split('_')[0] == 'background':
                bpy.data.meshes.remove(obj.data)
        for obj in bpy.data.objects:
            if obj.type == 'MESH' and not obj.name.split('_')[0] == 'background':
                bpy.data.objects.remove(obj, do_unlink=True)

        # remove all default material
        for mat in bpy.data.materials:
            name = mat.name.split('.')
            if name[0] == 'Material':
                bpy.data.materials.remove(mat)

    def loadModel(self, file_path):
        self.model_loaded = True
        try:
            if file_path.endswith('obj'):
                bpy.ops.import_scene.obj(filepath=file_path)
            elif file_path.endswith('3ds'):
                bpy.ops.import_scene.autodesk_3ds(filepath=file_path)
            elif file_path.endswith('dae'):
                # Must install OpenCollada. Please read README.md
                bpy.ops.wm.collada_import(filepath=file_path)
            else:
                self.model_loaded = False
                raise Exception("Loading failed: %s" % (file_path))
        except Exception:
            self.model_loaded = False

    def render(self, image_name="tmp", image_path=RENDERING_PATH):
        # Render the object
        if not self.model_loaded:
            print("Model not loaded.")
            return      

        if self.render_mode == "IR":
            bpy.context.scene.use_nodes = False
            # set light and render mode
            self.lightModeSelect("IR")
            self.outputModeSelect("IR")
            self.renderEngineSelect("CYCLES")

        elif self.render_mode == 'RGB':
            bpy.context.scene.use_nodes = False
            # set light and render mode
            self.lightModeSelect("RGB")
            self.outputModeSelect("RGB")
            self.renderEngineSelect("CYCLES")

        elif self.render_mode == "Mask":
            bpy.context.scene.use_nodes = False
            # set light and render mode
            self.lightModeSelect("Mask")
            self.outputModeSelect("Mask")
            # self.renderEngineSelect("EEVEE")
            self.renderEngineSelect("CYCLES")
            bpy.context.scene.cycles.use_denoising = False
            bpy.context.scene.cycles.aa_samples = 1

        elif self.render_mode == "NOCS":
            bpy.context.scene.use_nodes = False
            # set light and render mode
            self.lightModeSelect("NOCS")
            self.outputModeSelect("NOCS")
            # self.renderEngineSelect("EEVEE")
            self.renderEngineSelect("CYCLES")
            bpy.context.scene.cycles.use_denoising = False
            bpy.context.scene.cycles.aa_samples = 1

        elif self.render_mode == "Normal":
            bpy.context.scene.use_nodes = True
            self.fileOutput.base_path = image_path.replace("normal","depth")
            self.fileOutput.file_slots[0].path = image_name[:4]+"_#"# + 'depth_#'

            # set light and render mode
            self.lightModeSelect("Normal")
            self.outputModeSelect("Normal")
            # self.renderEngineSelect("EEVEE")
            self.renderEngineSelect("CYCLES")
            bpy.context.scene.cycles.use_denoising = False
            bpy.context.scene.cycles.aa_samples = 32

        else:
            print("The render mode is not supported")
            return 

        bpy.context.scene.render.filepath = os.path.join(image_path, image_name)
        bpy.ops.render.render(write_still=True)  # save straight to file

    def set_material_randomize_mode(self, class_material_pairs, mat_randomize_mode, instance, material_type_in_mixed_mode):
        if mat_randomize_mode in ['mixed','diffuse','transparent','specular_tex','specular_texmix']:
            if material_type_in_mixed_mode == 'raw':
                print(instance.name, 'material type: raw')
                set_modify_raw_material(instance)
            else:
                print(instance.name, 'material type: ', material_type_in_mixed_mode)
                material = random.sample(self.my_material[material_type_in_mixed_mode], 1)[0]
                set_modify_material(instance, material, self.obj_texture_img_list, mat_randomize_mode=mat_randomize_mode) 
        elif mat_randomize_mode == 'specular':
            material = random.sample(self.my_material[material_type_in_mixed_mode], 1)[0]
            print(instance.name, 'material type: ', material_type_in_mixed_mode)
            set_modify_material(instance, material, self.obj_texture_img_list, mat_randomize_mode=mat_randomize_mode, is_transfer=False) 
        else:
            print("No such mat_randomize_mode!")

    def get_instance_pose(self):
        instance_pose = {}
        bpy.context.view_layer.update()
        cam = self.camera_l
        mat_rot_x = Matrix.Rotation(math.radians(180.0), 4, 'X')
        for obj in bpy.data.objects:
            if obj.type == 'MESH' and not obj.name.split('_')[0] == 'background':
                instance_id = obj.name.split('_')[0]
                mat_rel = cam.matrix_world.inverted() @ obj.matrix_world
                # location
                relative_location = [mat_rel.translation[0],
                                     - mat_rel.translation[1],
                                     - mat_rel.translation[2]]
                # rotation
                # relative_rotation_euler = mat_rel.to_euler() # must be converted from radians to degrees
                relative_rotation_quat = [mat_rel.to_quaternion()[0],
                                          mat_rel.to_quaternion()[1],
                                          mat_rel.to_quaternion()[2],
                                          mat_rel.to_quaternion()[3]]
                quat_x = [0, 1, 0, 0]
                quat = quanternion_mul(quat_x, relative_rotation_quat)
                quat = [quat[0], - quat[1], - quat[2], - quat[3]]
                instance_pose[str(instance_id)] = [quat, relative_location]

        return instance_pose

    def check_visible(self, threshold=(0.1, 0.9, 0.1, 0.9)):
        w_min, x_max, h_min, h_max = threshold
        visible_objects_list = []
        bpy.context.view_layer.update()
        cs, ce = self.camera_l.data.clip_start, self.camera_l.data.clip_end
        for obj in bpy.data.objects:
            if obj.type == 'MESH' and not obj.name.split('_')[0] == 'background':
                obj_center = obj.matrix_world.translation
                co_ndc = world_to_camera_view(scene, self.camera_l, obj_center)
                if (w_min < co_ndc.x < x_max and
                    h_min < co_ndc.y < h_max and
                    cs < co_ndc.z <  ce):
                    obj.select_set(True)
                    visible_objects_list.append(obj)
                else:
                    obj.select_set(False)
        return visible_objects_list


def setModelPosition(instance, location, quaternion):
    instance.rotation_mode = 'QUATERNION'
    instance.rotation_quaternion[0] = quaternion[0]
    instance.rotation_quaternion[1] = quaternion[1]
    instance.rotation_quaternion[2] = quaternion[2]
    instance.rotation_quaternion[3] = quaternion[3]
    instance.location = location

def setRigidBody(instance):
    bpy.context.view_layer.objects.active = instance 
    object_single = bpy.context.active_object

    # add rigid body constraints to cube
    bpy.ops.rigidbody.object_add()
    bpy.context.object.rigid_body.mass = 1
    bpy.context.object.rigid_body.kinematic = True
    bpy.context.object.rigid_body.collision_shape = 'CONVEX_HULL'
    bpy.context.object.rigid_body.restitution = 0.01
    bpy.context.object.rigid_body.angular_damping = 0.8
    bpy.context.object.rigid_body.linear_damping = 0.99

    bpy.context.object.rigid_body.kinematic = False
    object_single.keyframe_insert(data_path='rigid_body.kinematic', frame=0)

def set_visiable_objects(visible_objects_list):
    for obj in bpy.data.objects:
        if obj.type == 'MESH' and not obj.name.split('_')[0] == 'background':
            if obj in visible_objects_list:
                obj.hide_render = False
            else:
                obj.hide_render = True

def generate_CAD_model_list(urdf_path_list):
    CAD_model_list = {}
    for instance_path in urdf_path_list:
        class_name = 'other'
        print(instance_path)
        class_list = []
        class_list.append([instance_path, class_name])
        if class_name == 'other' and 'other' in CAD_model_list:
            CAD_model_list[class_name] = CAD_model_list[class_name] + class_list
        else:
            CAD_model_list[class_name] = class_list
    return CAD_model_list

def generate_material_type(obj_name, class_material_pairs, instance_material_except_pairs, instance_material_include_pairs, material_class_instance_pairs, material_type):
    specular_type_for_ins_list = []
    transparent_type_for_ins_list = []
    diffuse_type_for_ins_list = []
    for key in instance_material_except_pairs:
            if key in material_class_instance_pairs['specular']:
                specular_type_for_ins_list.append(key)
            elif key in material_class_instance_pairs['transparent']:
                transparent_type_for_ins_list.append(key)
            elif key in material_class_instance_pairs['diffuse']:
                diffuse_type_for_ins_list.append(key)
    for key in instance_material_include_pairs:
        ### if ins_idx in instance_material_include_pairs[key]:
            if key in material_class_instance_pairs['specular']:
                specular_type_for_ins_list.append(key)
            elif key in material_class_instance_pairs['transparent']:
                transparent_type_for_ins_list.append(key)
            elif key in material_class_instance_pairs['diffuse']:
                diffuse_type_for_ins_list.append(key)
    
    if material_type == "transparent":
        return random.sample(transparent_type_for_ins_list, 1)[0]
    elif material_type == "diffuse":
        return random.sample(diffuse_type_for_ins_list, 1)[0]
    elif material_type == "specular" or material_type == "specular_tex" or material_type == "specular_texmix":
        return random.sample(specular_type_for_ins_list, 1)[0]
    elif material_type == "mixed":
        # randomly select one material class
        flag = random.randint(0, 2) # D:S:T=1:2:2
        # select the raw material
        if flag == 0:
            # flag = random.randint(0, 7) # 1:7
            # if flag == 0:
            #     return 'raw'
            # else:
            return random.sample(diffuse_type_for_ins_list, 1)[0] ### 'diffuse'
        # select one from specular and transparent
        elif flag == 1:
            return random.sample(specular_type_for_ins_list, 1)[0] ### 'specular'
        else:
            return random.sample(transparent_type_for_ins_list, 1)[0]  ### 'transparent'
    else:
        print("Material type error: ", material_type)
   


################################
#
#            Main
#
################################
### set random seed
random.seed(1143+SCENE_NUM) 

# load VGN obj path and tsdf pose
urdfs_and_poses_files_list = sorted(os.listdir(raw_urdfs_and_poses_dir_path))
urdfs_and_poses_dict = np.load(os.path.join(raw_urdfs_and_poses_dir_path, urdfs_and_poses_files_list[SCENE_NUM]), allow_pickle=True)['pc']
urdf_path_list = list(urdfs_and_poses_dict[:,0])
obj_scale_list = list(urdfs_and_poses_dict[:,1])
obj_RT_list = list(urdfs_and_poses_dict[:,2])

obj_quat_list = []
obj_trans_list = []
for RT in obj_RT_list:
    R = RT[:3,:3]
    T = RT[:3,3]
    T = T + np.array([-0.15,-0.15,-0.0503])
    quat = quaternionFromRotMat(R)
    obj_quat_list.append(quat)
    obj_trans_list.append(T)


g_synset_name_label_pairs = {'other': 0}   

material_class_instance_pairs = {'specular': ['metal','porcelain','plasticsp','paintsp'],
                                 'transparent': ['glass'],
                                 'diffuse': ['plastic','rubber','paper','leather','wood','clay','fabric'],
                                 'background': ['background']}


class_material_pairs = {'specular': ['other'],
                        'transparent': ['other'],
                        'diffuse': ['other']}

instance_material_except_pairs = {'metal': [],
                                  'porcelain': [],
                                  'plasticsp': [],
                                  'paintsp':[],

                                  'glass': [],
                                  
                                  'plastic': [],
                                  'rubber': [],     
                                  'leather': [],
                                  'wood':[],
                                  'paper':[],
                                  'fabric':[],
                                  'clay':[],   
                                  }

instance_material_include_pairs = {
                                  }

material_class_id_dict = {'raw': 0,
                        'diffuse': 1,
                        'transparent': 2,
                        'specular': 3}

material_type_id_dict = {'raw': 0,
                        'metal': 1,
                        'porcelain': 2,
                        'plasticsp': 3,
                        'paintsp':4,
                        'glass': 5, 
                        'plastic': 6,
                        'rubber': 7,     
                        'leather': 8,
                        'wood':9,
                        'paper':10,
                        'fabric':11,
                        'clay':12,               
                        }


max_instance_num = 20

if not os.path.exists(output_root_path):
    os.makedirs(output_root_path)

# generate CAD model list
CAD_model_list = generate_CAD_model_list(urdf_path_list)

renderer = BlenderRenderer(viewport_size_x=camera_width, viewport_size_y=camera_height)
renderer.loadImages(emitter_pattern_path, env_map_path, real_table_image_root_path, real_floor_image_root_path)
renderer.addEnvMap()
renderer.addBackground(background_size, background_position, background_scale)
renderer.addMaterialLib(material_class_instance_pairs)  ###
renderer.addMaskMaterial(max_instance_num)
renderer.addNOCSMaterial()
renderer.addNormalMaterial()


renderer.clearModel()
# set scene output path
path_scene = os.path.join(output_root_path, urdfs_and_poses_files_list[SCENE_NUM][:-4])### "scene_"+str(SCENE_NUM).zfill(4))
if os.path.exists(path_scene)==False:
    os.makedirs(path_scene)


# camera pose list, environment light list and background material_listz
quaternion_list = []
translation_list = []

# environment map list
env_map_id_list = []
rotation_elur_z_list = []

# background material list
background_material_list = []

# table material list
table_material_list = []


look_at = look_at_shift
quat_list, trans_list, rot_list, position_list = genCameraPosition(look_at)
np.savetxt(os.path.join(path_scene, "cam_pos_pc.txt"), np.array(position_list))

rot_array = np.array(rot_list)  # (256, 3, 3)
trans_array = np.array(trans_list)  #  (256, 3, 1)
cam_RT = np.concatenate([rot_array, trans_array], 2)
zero_one = np.expand_dims([[0, 0, 0, 1]],0).repeat(rot_array.shape[0],axis=0)
cam_RT = np.concatenate([cam_RT, zero_one], 1)  # (256, 4, 4)
np.save(os.path.join(path_scene, "camera_pose.npy"), cam_RT)


# generate camara pose list
for i in range(NUM_FRAME_PER_SCENE):
    
    quaternion = quat_list[i]
    translation = trans_list[i]
    quaternion_list.append(quaternion)
    translation_list.append(translation)

# generate environment map list
env_map_id_list.append(random.randint(0, len(renderer.env_map) - 1))
rotation_elur_z_list.append(random.uniform(-math.pi, math.pi))
    
# generate background material list 
if my_material_randomize_mode == 'raw':
    background_material_list.append(renderer.my_material['default_background'])
    # bpy.data.objects['background'].active_material = renderer.my_material['default_background']
else:
    material_selected = random.sample(renderer.my_material['background'], 2)[0]
    background_material_list.append(material_selected)
    # bpy.data.objects['background'].active_material = material_selected
    ###
    material_selected = random.sample(renderer.my_material['background'], 2)[1]
    table_material_list.append(material_selected)
    ###
    #print(background_material_list, table_material_list)

# read objects from floder
meta_output = {}
select_model_list = []
select_model_list_other = []
select_model_list_transparent = []
select_model_list_dis = []
select_number = 1


for item in CAD_model_list:
    if item in ['other']:
        test = CAD_model_list[item]
        for model in test:
            select_model_list.append(model)
    else:
        print("No such category!")
    

# load table obj
renderer.loadModel(table_CAD_model_path)
obj = bpy.data.objects['table']
table_scale = 0.001
obj.scale = (table_scale, table_scale, table_scale)
y_transform = np.array([[0,0,-1],[0,1,0],[1,0,0]])
transform = y_transform
obj_world_pose_quat = quaternionFromRotMat(transform)
obj_world_pose_T_shift = np.array([random.uniform(-0.02,0.02),random.uniform(-0.0843,-0.0243),-0.0751])
obj_world_pose_T = obj_world_pose_T_shift
setModelPosition(obj, obj_world_pose_T, obj_world_pose_quat)

# load table plane
obj_world_pose_T = obj_world_pose_T_shift
obj_world_pose_T[2] = 0
bpy.ops.mesh.primitive_plane_add(size=1., enter_editmode=False, align='WORLD', location=obj_world_pose_T)
bpy.ops.rigidbody.object_add()
bpy.context.object.rigid_body.type = 'PASSIVE'
bpy.context.object.rigid_body.collision_shape = 'BOX'
obj = bpy.data.objects['Plane']
obj.name = 'tableplane'
obj.data.name = 'tableplane'
obj.scale = (0.898, 1.3, 1.)

# load arm
renderer.loadModel(arm_CAD_model_path)
obj = bpy.data.objects['arm']
class_scale = 0.001
obj.scale = (class_scale, class_scale, class_scale)
x_transform = np.array([[1,0,0],[0,0,-1],[0,1,0]])
transform = x_transform
obj_world_pose_quat = quaternionFromRotMat(transform)
obj_world_pose_T_shift = np.array([0,random.uniform(-0.43,-0.41),0])
obj_world_pose_T = obj_world_pose_T_shift
setModelPosition(obj, obj_world_pose_T, obj_world_pose_quat)


instance_id = 1
imported_obj_name_list = []
for model in select_model_list:
    instance_path = model[0]
    class_name = model[1]
    instance_folder = model[0].split('/')[-1][:-4]
    instance_name = str(instance_id) + "_" + class_name + "_" + instance_folder

    material_type_in_mixed_mode = generate_material_type(instance_name, class_material_pairs, instance_material_except_pairs, instance_material_include_pairs, material_class_instance_pairs, my_material_randomize_mode)

    # download CAD model and rename
    renderer.loadModel(instance_path)
    import_obj_name = instance_folder
    obj = bpy.data.objects[import_obj_name]
    obj.name = instance_name
    obj.data.name = instance_name

    print(len(obj_trans_list), instance_id)
    obj_world_pose_T = obj_trans_list[instance_id-1]
    obj_world_pose_quat = obj_quat_list[instance_id-1]
    setModelPosition(obj, obj_world_pose_T, obj_world_pose_quat)

    # set object as rigid body
    setRigidBody(obj)

    # set material
    renderer.set_material_randomize_mode(class_material_pairs, my_material_randomize_mode, obj, material_type_in_mixed_mode)
    
    
    # generate meta file
    class_scale = obj_scale_list[instance_id-1]
    obj.scale = (class_scale, class_scale, class_scale)

    # material type
    material_class_id = None
    for key in material_class_instance_pairs:
        if material_type_in_mixed_mode == 'raw':
            material_class_id = material_class_id_dict[material_type_in_mixed_mode]
            break
        elif material_type_in_mixed_mode in material_class_instance_pairs[key]:
            material_class_id = material_class_id_dict[key]
            break
    if material_class_id == None:
        print("material_class_id error!")

    meta_output[str(instance_id)] = [str(instance_folder), 
                                     str(material_class_id),
                                     str(material_type_id_dict[material_type_in_mixed_mode])
                                     ]

    instance_id += 1

# set the key frame
scene = bpy.data.scenes['Scene']

# generate meta.txt
meta_dir_path = os.path.join(path_scene, 'meta')
if os.path.exists(meta_dir_path)==False:
    os.makedirs(meta_dir_path)

for i in RENDER_FRAMES_LIST: #range(RENDER_START_FRAME, RENDER_END_FRAME):
    # output the meta file
    path_meta = os.path.join(meta_dir_path, str(i).zfill(4) + ".txt")
    if os.path.exists(path_meta):
        os.remove(path_meta)
    
    file_write_obj = open(path_meta, 'w')
    for index in meta_output:
        file_write_obj.write(index)
        file_write_obj.write(' ')
        for item in meta_output[index]:
            file_write_obj.write(item)
            file_write_obj.write(' ')
        file_write_obj.write('\n')
    file_write_obj.close()


# render IR image and RGB image
if render_mode_list['IR'] or render_mode_list['RGB']:
    renderer.setEnvMap(env_map_id_list[0], rotation_elur_z_list[0])
    # 随机选一张real floor image
    flag = random.randint(0, len(renderer.realfloor_img_list)-1)
    selected_realfloor_img = renderer.realfloor_img_list[flag]

    # 随机选一张real table image
    flag = random.randint(0, len(renderer.realtable_img_list)-1)
    selected_realtable_img = renderer.realtable_img_list[flag] 

    arm_material_type_in_mixed_mode = generate_material_type(None, class_material_pairs, instance_material_except_pairs, instance_material_include_pairs, material_class_instance_pairs, material_type="diffuse")
    arm_material = random.sample(renderer.my_material[arm_material_type_in_mixed_mode], 1)[0]
    ###
    for i in RENDER_FRAMES_LIST:
        renderer.setCamera(quaternion_list[i], translation_list[i], camera_fov, baseline_distance)
        renderer.setLighting()
        for obj in bpy.data.objects:
            if obj.type == "MESH" and obj.name.split('_')[0] == 'background':
                if obj.name == 'background_0':
                    flag = random.randint(0, 3)
                    if flag == 0:
                        set_modify_floor_material(obj, background_material_list[0], selected_realfloor_img) ### renderer.realfloor_img_list)
                    else:
                        obj.active_material = background_material_list[0]
                else:
                    background_0_obj = bpy.data.objects['background_0']
                    obj.active_material = background_0_obj.material_slots[0].material
            elif obj.type == "MESH" and obj.name == 'table':
                flag = random.randint(0, 2)
                if flag == 0:
                    set_modify_table_material(obj, table_material_list[0], selected_realtable_img)### renderer.realtable_img_list)
                else:
                    obj.active_material = table_material_list[0]
            elif obj.type == "MESH" and obj.name == 'tableplane':
                    table_obj = bpy.data.objects['table']
                    obj.active_material = table_obj.material_slots[0].material
            elif obj.type == "MESH" and obj.name == 'arm':
                set_modify_arm_material(obj, arm_material)

        # render IR image            
        if render_mode_list['IR']:
            ir_l_dir_path = os.path.join(path_scene, 'ir_l')
            if os.path.exists(ir_l_dir_path)==False:
                os.makedirs(ir_l_dir_path)
            ir_r_dir_path = os.path.join(path_scene, 'ir_r')
            if os.path.exists(ir_r_dir_path)==False:
                os.makedirs(ir_r_dir_path)

            renderer.render_mode = "IR"
            camera = bpy.data.objects['camera_l']
            scene.camera = camera
            save_path = ir_l_dir_path
            save_name = str(i).zfill(4)
            renderer.render(save_name, save_path)

            camera = bpy.data.objects['camera_r']
            scene.camera = camera
            save_path = ir_r_dir_path
            save_name = str(i).zfill(4)
            renderer.render(save_name, save_path)
        
        # render RGB image
        if render_mode_list['RGB']:
            rgb_dir_path = os.path.join(path_scene, 'rgb')
            if os.path.exists(rgb_dir_path)==False:
                os.makedirs(rgb_dir_path)

            renderer.render_mode = "RGB"
            camera = bpy.data.objects['camera_l']
            scene.camera = camera
            save_path = rgb_dir_path
            save_name = str(i).zfill(4)
            renderer.render(save_name, save_path)
    
# render mask map and depth map
if render_mode_list['Mask']:
    # set instance mask as material
    for obj in bpy.data.objects:
        if obj.type == "MESH":
            obj.data.materials.clear()
            material_name = "mask_" + obj.name.split('_')[0]
            obj.active_material = renderer.my_material[material_name]
    
    # render mask map and depth map
    for i in RENDER_FRAMES_LIST:
        renderer.setCamera(quaternion_list[i], translation_list[i], camera_fov, baseline_distance)

        mask_dir_path = os.path.join(path_scene, 'mask')
        if os.path.exists(mask_dir_path)==False:
            os.makedirs(mask_dir_path)

        renderer.render_mode = "Mask"
        camera = bpy.data.objects['camera_l']
        scene.camera = camera
        save_path = mask_dir_path
        save_name = str(i).zfill(4)
        renderer.render(save_name, save_path)

# render normal map
if render_mode_list['Normal']:
    # set normal as material
    for obj in bpy.data.objects:
        if obj.type == 'MESH':
            obj.data.materials.clear()
            obj.active_material = renderer.my_material["normal"]

    # render normal map
    for i in RENDER_FRAMES_LIST:
        renderer.setCamera(quaternion_list[i], translation_list[i], camera_fov, baseline_distance)
        
        normal_dir_path = os.path.join(path_scene, 'normal')
        if os.path.exists(normal_dir_path)==False:
            os.makedirs(normal_dir_path)
        depth_dir_path = os.path.join(path_scene, 'depth')
        if os.path.exists(depth_dir_path)==False:
            os.makedirs(depth_dir_path)

        renderer.render_mode = "Normal"
        camera = bpy.data.objects['camera_l']
        scene.camera = camera
        save_path = normal_dir_path
        save_name = str(i).zfill(4)
        renderer.render(save_name, save_path)

context = bpy.context
for ob in context.selected_objects:
    ob.animation_data_clear()

print(bpy.data.materials) 
print(len(bpy.data.materials))

src_depth_list = os.listdir(os.path.join(output_root_path,urdfs_and_poses_files_list[SCENE_NUM][:-4],"depth"))
for src_depth in src_depth_list:
    source = os.path.join(output_root_path,urdfs_and_poses_files_list[SCENE_NUM][:-4],"depth",src_depth)
    target = source.replace("_0.exr",".exr")
    os.rename(source,target)

================================================
FILE: data_generator/run_pile_rand.sh
================================================
#!/bin/bash

cd /data/InterNeRF/renderer/renderer_giga_GPU6-0_rand_M

# 830*6
mycount=0;
while (( $mycount < 100 )); do
    /home/xxx/blender-2.93.3-linux-x64/blender material_lib_v2.blend --background -noaudio --python render_pile_STD_rand.py -- $mycount;
((mycount=$mycount+1));
done;

================================================
FILE: requirements.txt
================================================
torch
tensorflow
easydict
inplace-abn
plyfile
numpy
scikit-image
pyyaml
h5py
opencv-python
tqdm
matplotlib
scipy
lpips
transforms3d
kornia
sklearn
catkin_pkg
black
jupyterlab
pandas
mpi4py
open3d
pybullet==2.7.9
pytorch-ignite
tensorboard

================================================
FILE: run_simgrasp.sh
================================================
#!/bin/bash

GPUID=0
BLENDER_BIN=blender

RENDERER_ASSET_DIR=./data/assets
BLENDER_PROJ_PATH=./data/assets/material_lib_graspnet-v2.blend
SIM_LOG_DIR="./log/`date '+%Y%m%d-%H%M%S'`"

scene="pile"
object_set="pile_subdiv"
material_type="specular_and_transparent"
render_frame_list="2,6,10,14,18,22"
check_seen_scene=0
expname=0

NUM_TRIALS=200
METHOD='graspnerf'

mycount=0 
while (( $mycount < $NUM_TRIALS )); do
   $BLENDER_BIN $BLENDER_PROJ_PATH --background --python scripts/sim_grasp.py \
   -- $mycount $GPUID $expname $scene $object_set $check_seen_scene $material_type \
   $RENDERER_ASSET_DIR $SIM_LOG_DIR 0 $render_frame_list $METHOD

   python ./scripts/stat_expresult.py -- $SIM_LOG_DIR $expname
((mycount=$mycount+1));
done;

python ./scripts/stat_expresult.py -- $SIM_LOG_DIR $expname

================================================
FILE: scripts/sim_grasp.py
================================================
import argparse
import os
import sys
from pathlib import Path

def main(args, round_idx, gpuid, render_frame_list):
    os.environ["CUDA_VISIBLE_DEVICES"] = str(gpuid)
    
    sys.path.append("src")
    from nr.main import GraspNeRFPlanner 

    if args.method == "graspnerf":
        grasp_planner = GraspNeRFPlanner(args)
    else:
        print("No such method!")
        raise NotImplementedError
       
    from gd.experiments import clutter_removal
    clutter_removal.run(
        grasp_plan_fn=grasp_planner,
        logdir=args.logdir,
        description=args.description,
        scene=args.scene,
        object_set=args.object_set,
        num_objects=args.num_objects,
        num_rounds=args.num_rounds,
        seed=args.seed,
        sim_gui=args.sim_gui,
        rviz=args.rviz,
        round_idx = round_idx,
        renderer_root_dir = args.renderer_root_dir,
        gpuid = gpuid,
        args = args,
        render_frame_list = render_frame_list
    )
   
class ArgumentParserForBlender(argparse.ArgumentParser):
    """
    This class is identical to its superclass, except for the parse_args
    method (see docstring). It resolves the ambiguity generated when calling
    Blender from the CLI with a python script, and both Blender and the script
    have arguments. E.g., the following call will make Blender crash because
    it will try to process the script's -a and -b flags:
    >>> blender --python my_script.py -a 1 -b 2

    To bypass this issue this class uses the fact that Blender will ignore all
    arguments given after a double-dash ('--'). The approach is that all
    arguments before '--' go to Blender, arguments after go to the script.
    The following calls work fine:
    >>> blender --python my_script.py -- -a 1 -b 2
    >>> blender --python my_script.py --
    """

    def _get_argv_after_doubledash(self):
        """
        Given the sys.argv as a list of strings, this method returns the
        sublist right after the '--' element (if present, otherwise returns
        an empty list).
        """
        try:
            idx = sys.argv.index("---")
            return sys.argv[idx+1:] # the list after '--'
        except ValueError as e: # '--' not in the list:
            return []

    # overrides superclass
    def parse_args(self):
        """
        This method is expected to behave identically as in the superclass,
        except that the sys.argv list will be pre-processed using
        _get_argv_after_doubledash before. See the docstring of the class for
        usage examples and details.
        """
        return super().parse_args(args=self._get_argv_after_doubledash())

if __name__ == "__main__":
    argv = sys.argv
    argv = argv[argv.index("--") + 1:]  # get all args after "--"
    round_idx = int(argv[0])
    gpuid = int(argv[1])
    expname = str(argv[2])
    scene = str(argv[3])
    object_set = str(argv[4])
    check_seen_scene = bool(int(argv[5]))
    material_type = str(argv[6])
    blender_asset_dir = str(argv[7])
    log_root_dir = str(argv[8])
    use_gt_tsdf = bool(int(argv[9]))
    render_frame_list=[int(frame_id) for frame_id in str(argv[10]).replace(' ','').split(",")]
    method = str(argv[11])
    print("########## Simulation Start ##########")
    print("Round %d\nmethod: %s\nmaterial_type: %s\nviews: %s "%(round_idx, method, material_type, str(render_frame_list)))
    print("######################################")

    parser = ArgumentParserForBlender() ### argparse.ArgumentParser()
    parser.add_argument("---model", type=Path, default="")
    parser.add_argument("---logdir", type=Path, default=expname)
    parser.add_argument("---description", type=str, default="")
    parser.add_argument("---scene", type=str, choices=["pile", "packed", "single"], default=scene)
    parser.add_argument("---object-set", type=str, default=object_set)
    parser.add_argument("---num-objects", type=int, default=5)
    parser.add_argument("---num-rounds", type=int, default=200)
    parser.add_argument("---seed", type=int, default=42)
    parser.add_argument("---sim-gui", type=bool, default=False)
    parser.add_argument("---rviz", action="store_true")
    
    ###
    parser.add_argument("---renderer_root_dir", type=str, default=blender_asset_dir)
    parser.add_argument("---log_root_dir", type=str, default=log_root_dir)
    parser.add_argument("---obj_texture_image_root_path", type=str, default=blender_asset_dir+"/imagenet") #TODO   
    parser.add_argument("---cfg_fn", type=str, default="src/nr/configs/nrvgn_sdf.yaml")
    parser.add_argument('---database_name', type=str, default='vgn_syn/train/packed/packed_170-220/032cd891d9be4a16be5ea4be9f7eca2b/w_0.8', help='<dataset_name>/<scene_name>/<scene_setting>')

    parser.add_argument("---gen_scene_descriptor", type=bool, default=False)
    parser.add_argument("---load_scene_descriptor", type=bool, default=True)
    parser.add_argument("---material_type", type=str, default=material_type)
    parser.add_argument("---method", type=str, default=method)

    # pybullet camera parameter
    parser.add_argument("---camera_focal", type=float, default=446.31) #TODO 

    ###
    args = parser.parse_args()
    main(args, round_idx, gpuid, render_frame_list)

================================================
FILE: scripts/stat_expresult.py
================================================
from pathlib import Path
import sys
import pandas as pd
import os
import numpy as np

argv = sys.argv
argv = argv[argv.index("--") + 1:]  # get all args after "--"
log_root_dir = str(argv[0])
expname = str(argv[1])

class Data(object):
    """Object for loading and analyzing experimental data."""

    def __init__(self, logdir):
        self.logdir = logdir
        self.rounds = pd.read_csv(logdir / "rounds.csv")
        self.grasps = pd.read_csv(logdir / "grasps.csv")

    def num_rounds(self):
        return len(self.rounds.index)

    def num_grasps(self):
        return len(self.grasps.index)

    def success_rate(self):
        return self.grasps["label"].mean() * 100

    def percent_cleared(self):
        df = (
            self.grasps[["round_id", "label"]]
            .groupby("round_id")
            .sum()
            .rename(columns={"label": "cleared_count"})
            .merge(self.rounds, on="round_id")
        )
        return df["cleared_count"].sum() / df["object_count"].sum() * 100

    def avg_planning_time(self):
        return self.grasps["planning_time"].mean()

    def read_grasp(self, i):
        scene_id, grasp, label = io.read_grasp(self.grasps, i)
        score = self.grasps.loc[i, "score"]
        scene_data = np.load(self.logdir / "scenes" / (scene_id + ".npz"))

        return scene_data["points"], grasp, score, label

##############################
# Combine all trials
##############################
root_path = os.path.join(log_root_dir, "exp_results", expname)

round_dir_list = sorted(os.listdir(root_path))

if not os.path.exists(root_path + "_combine"):
    os.makedirs(root_path + "_combine")

df = pd.DataFrame()
for i in range(len(round_dir_list)):
    df_round = pd.read_csv(os.path.join(root_path, round_dir_list[i], "grasps.csv"))
    df_round["round_id"] = i
    df = pd.concat([df, df_round])
df = df.reset_index(drop=True)
df.to_csv(os.path.join(root_path + "_combine", "grasps.csv"), index=False)


df = pd.DataFrame()
for i in range(len(round_dir_list)):
    df_round = pd.read_csv(os.path.join(root_path, round_dir_list[i], "rounds.csv"))
    df_round["round_id"] = i
    df = pd.concat([df, df_round])
df = df.reset_index(drop=True)
df.to_csv(os.path.join(root_path + "_combine", "rounds.csv"), index=False)

##############################
# Print Stat
##############################
logdir = Path(os.path.join(log_root_dir, "exp_results", expname+"_combine"))
data = Data(logdir)

# First, we compute the following metrics for the experiment:
# * **Success rate**: the ratio of successful grasp executions,
# * **Percent cleared**: the percentage of objects removed during each round,
try:
    print("Path:              ",str(logdir))
    print("Num grasps:        ", data.num_grasps())
    print("Success rate:      ", data.success_rate())
    print("Percent cleared:   ", data.percent_cleared())
except:
    print("[W] Incomplete results, exit")
    exit()
##############################
# Calc first-time grasping SR
##############################

sum_label = 0
firstgrasp_fail_expidx_list = []
for i in range(len(round_dir_list)):
    #print(i)
    df_round = pd.read_csv(os.path.join(root_path, round_dir_list[i], "grasps.csv"))
    df = df_round.iloc[0:1,:]   
    
    label = df[["label"]].to_numpy(np.float32)
    if label.shape[0] == 0:
        firstgrasp_fail_expidx_list.append(i)
        continue
    sum_label += label[0,0]
    if label[0,0]==0:
        firstgrasp_fail_expidx_list.append(i)

print("First grasp success rate: ", sum_label / len(round_dir_list))
print("First grasp fail:", len(firstgrasp_fail_expidx_list),"/",len(round_dir_list), ", exp id: ", firstgrasp_fail_expidx_list)


================================================
FILE: src/gd/__init__.py
================================================


================================================
FILE: src/gd/baselines.py
================================================
import time

from gpd_ros.msg import GraspConfigList
import numpy as np
from sensor_msgs.msg import PointCloud2
import rospy

from gd.grasp import Grasp
from gd.utils import ros_utils
from gd.utils.transform import Rotation, Transform


class GPD(object):
    def __init__(self):
        self.input_topic = "/cloud_stitched"
        self.output_topic = "/detect_grasps/clustered_grasps"
        self.cloud_pub = rospy.Publisher(self.input_topic, PointCloud2, queue_size=1)

    def __call__(self, state):
        points = np.asarray(state.pc.points)
        msg = ros_utils.to_cloud_msg(points, frame="task")
        self.cloud_pub.publish(msg)

        tic = time.time()
        result = rospy.wait_for_message(self.output_topic, GraspConfigList)
        toc = time.time() - tic

        grasps, scores = self.to_grasp_list(result)

        return grasps, scores, toc

    def to_grasp_list(self, grasp_configs):
        grasps, scores = [], []
        for grasp_config in grasp_configs.grasps:
            # orientation
            x_axis = ros_utils.from_vector3_msg(grasp_config.axis)
            y_axis = -ros_utils.from_vector3_msg(grasp_config.binormal)
            z_axis = ros_utils.from_vector3_msg(grasp_config.approach)
            orientation = Rotation.from_matrix(np.vstack([x_axis, y_axis, z_axis]).T)
            # position
            position = ros_utils.from_point_msg(grasp_config.position)
            # width
            width = grasp_config.width.data
            # score
            score = grasp_config.score.data

            if score < 0.0:
                continue  # negative score is larger than positive score (https://github.com/atenpas/gpd/issues/32#issuecomment-387846534)

            grasps.append(Grasp(Transform(orientation, position), width))
            scores.append(score)

        return grasps, scores


================================================
FILE: src/gd/dataset.py
================================================
import numpy as np
from scipy import ndimage
import torch.utils.data

from gd.io import *
from gd.perception import *
from gd.utils.transform import Rotation, Transform


class Dataset(torch.utils.data.Dataset):
    def __init__(self, root, augment=False):
        self.root = root
        self.augment = augment
        self.df = read_df(root)

    def __len__(self):
        return len(self.df.index)

    def __getitem__(self, i):
        scene_id = self.df.loc[i, "scene_id"]
        ori = Rotation.from_quat(self.df.loc[i, "qx":"qw"].to_numpy(np.single))
        pos = self.df.loc[i, "i":"k"].to_numpy(np.single)
        width = self.df.loc[i, "width"].astype(np.single)
        label = self.df.loc[i, "label"].astype(np.long)
        voxel_grid = read_voxel_grid(self.root, scene_id)

        if self.augment:
            voxel_grid, ori, pos = apply_transform(voxel_grid, ori, pos)

        index = np.round(pos).astype(np.long)
        rotations = np.empty((2, 4), dtype=np.single)
        R = Rotation.from_rotvec(np.pi * np.r_[0.0, 0.0, 1.0])
        rotations[0] = ori.as_quat()
        rotations[1] = (ori * R).as_quat()

        x, y, index = voxel_grid, (label, rotations, width), index

        return x, y, index


def apply_transform(voxel_grid, orientation, position):
    angle = np.pi / 2.0 * np.random.choice(4)
    R_augment = Rotation.from_rotvec(np.r_[0.0, 0.0, angle])

    z_offset = np.random.uniform(6, 34) - position[2]

    t_augment = np.r_[0.0, 0.0, z_offset]
    T_augment = Transform(R_augment, t_augment)

    T_center = Transform(Rotation.identity(), np.r_[20.0, 20.0, 20.0])
    T = T_center * T_augment * T_center.inverse()

    # transform voxel grid
    T_inv = T.inverse()
    matrix, offset = T_inv.rotation.as_matrix(), T_inv.translation
    voxel_grid[0] = ndimage.affine_transform(voxel_grid[0], matrix, offset, order=0)

    # transform grasp pose
    position = T.transform_point(position)
    orientation = T.rotation * orientation

    return voxel_grid, orientation, position


================================================
FILE: src/gd/detection.py
================================================
import time

import numpy as np
from scipy import ndimage
import torch


from gd.grasp import *
from gd.utils.transform import Transform, Rotation
from gd.networks import load_network


class VGN(object):
    def __init__(self, model_path, rviz=False):
        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        self.net = load_network(model_path, self.device)
        self.rviz = rviz

    def __call__(self, state):
        tsdf_vol = state.tsdf.get_grid()
        voxel_size = state.tsdf.voxel_size

        tic = time.time()
        qual_vol, rot_vol, width_vol = predict(tsdf_vol, self.net, self.device)
        qual_vol, rot_vol, width_vol = process(tsdf_vol, qual_vol, rot_vol, width_vol)
        grasps, scores = select(qual_vol.copy(), rot_vol, width_vol)
        toc = time.time() - tic

        grasps, scores = np.asarray(grasps), np.asarray(scores)

        if len(grasps) > 0:
            p = np.random.permutation(len(grasps))
            grasps = [from_voxel_coordinates(g, voxel_size) for g in grasps[p]]
            scores = scores[p]

        if self.rviz:
            from gd import vis
            vis.draw_quality(qual_vol, state.tsdf.voxel_size, threshold=0.01)

        return grasps, scores, toc


def predict(tsdf_vol, net, device):
    assert tsdf_vol.shape == (1, 40, 40, 40)

    # move input to the GPU
    tsdf_vol = torch.from_numpy(tsdf_vol).unsqueeze(0).to(device)

    # forward pass
    with torch.no_grad():
        qual_vol, rot_vol, width_vol = net(tsdf_vol)

    # move output back to the CPU
    qual_vol = qual_vol.cpu().squeeze().numpy()
    rot_vol = rot_vol.cpu().squeeze().numpy()
    width_vol = width_vol.cpu().squeeze().numpy()
    return qual_vol, rot_vol, width_vol


def process(
    tsdf_vol,
    qual_vol,
    rot_vol,
    width_vol,
    gaussian_filter_sigma=1.0,
    min_width=1.33,
    max_width=9.33,
):
    tsdf_vol = tsdf_vol.squeeze()

    # smooth quality volume with a Gaussian
    qual_vol = ndimage.gaussian_filter(
        qual_vol, sigma=gaussian_filter_sigma, mode="nearest"
    )

    # mask out voxels too far away from the surface
    outside_voxels = tsdf_vol > 0.5
    inside_voxels = np.logical_and(1e-3 < tsdf_vol, tsdf_vol < 0.5)
    valid_voxels = ndimage.morphology.binary_dilation(
        outside_voxels, iterations=2, mask=np.logical_not(inside_voxels)
    )
    qual_vol[valid_voxels == False] = 0.0

    # reject voxels with predicted widths that are too small or too large
    qual_vol[np.logical_or(width_vol < min_width, width_vol > max_width)] = 0.0

    return qual_vol, rot_vol, width_vol


def select(qual_vol, rot_vol, width_vol, threshold=0.90, max_filter_size=4):
    # threshold on grasp quality
    qual_vol[qual_vol < threshold] = 0.0

    # non maximum suppression
    max_vol = ndimage.maximum_filter(qual_vol, size=max_filter_size)
    qual_vol = np.where(qual_vol == max_vol, qual_vol, 0.0)
    mask = np.where(qual_vol, 1.0, 0.0)

    # construct grasps
    grasps, scores = [], []
    for index in np.argwhere(mask):
        grasp, score = select_index(qual_vol, rot_vol, width_vol, index)
        grasps.append(grasp)
        scores.append(score)

    return grasps, scores


def select_index(qual_vol, rot_vol, width_vol, index):
    i, j, k = index
    score = qual_vol[i, j, k]
    ori = Rotation.from_quat(rot_vol[:, i, j, k])
    pos = np.array([i, j, k], dtype=np.float64)
    width = width_vol[i, j, k]
    return Grasp(Transform(ori, pos), width), score


================================================
FILE: src/gd/experiments/__init__.py
================================================


================================================
FILE: src/gd/experiments/clutter_removal.py
================================================
import collections
import uuid
import os
import numpy as np
import pandas as pd
import sys
import shutil
from pathlib import Path
from gd import io
from gd.grasp import *
from gd.simulation import ClutterRemovalSim
sys.path.append("./")
from rd.render import blender_init_scene, blender_render, blender_update_sceneobj

MAX_CONSECUTIVE_FAILURES = 2

State = collections.namedtuple("State", ["tsdf", "pc"])

def copydirs(from_file, to_file):
    if not os.path.exists(to_file):   
        os.makedirs(to_file)
    files = os.listdir(from_file)  
    for f in files:
        if os.path.isdir(from_file + '/' + f):  
            copydirs(from_file + '/' + f, to_file + '/' + f)  
        else:
            shutil.copy(from_file + '/' + f, to_file + '/' + f)  


def run(
    grasp_plan_fn,
    logdir,
    description,
    scene,
    object_set,
    num_objects=5,
    n=6,
    N=None,
    num_rounds=40,
    seed=1,
    sim_gui=False,
    rviz=False,
    round_idx=0,
    renderer_root_dir="",
    gpuid=None,
    args=None,
    render_frame_list=[]
):
    """Run several rounds of simulated clutter removal experiments.

    Each round, m objects are randomly placed in a tray. Then, the grasping pipeline is
    run until (a) no objects remain, (b) the planner failed to find a grasp hypothesis,
    or (c) maximum number of consecutive failed grasp attempts.
    """
    sim = ClutterRemovalSim(scene, object_set, gui=sim_gui, seed=seed, renderer_root_dir=renderer_root_dir, args=args)
    logger = Logger(args.log_root_dir, logdir, description, round_idx)

    # output modality
    output_modality_dict = {'RGB': 1,
                            'IR': 0,
                            'NOCS': 0,
                            'Mask': 0,
                            'Normal': 0}

    for n_round in range(round_idx, round_idx+1):
        urdfs_and_poses_dict = sim.reset(num_objects, round_idx)
        
Download .txt
gitextract_hto38wet/

├── .gitignore
├── README.md
├── data_generator/
│   ├── modify_material.py
│   ├── render_pile_STD_rand.py
│   └── run_pile_rand.sh
├── requirements.txt
├── run_simgrasp.sh
├── scripts/
│   ├── sim_grasp.py
│   └── stat_expresult.py
├── src/
│   ├── gd/
│   │   ├── __init__.py
│   │   ├── baselines.py
│   │   ├── dataset.py
│   │   ├── detection.py
│   │   ├── experiments/
│   │   │   ├── __init__.py
│   │   │   └── clutter_removal.py
│   │   ├── grasp.py
│   │   ├── io.py
│   │   ├── networks.py
│   │   ├── perception.py
│   │   ├── simulation.py
│   │   ├── utils/
│   │   │   ├── __init__.py
│   │   │   ├── btsim.py
│   │   │   ├── panda_control.py
│   │   │   ├── ros_utils.py
│   │   │   └── transform.py
│   │   └── vis.py
│   ├── nr/
│   │   ├── asset.py
│   │   ├── configs/
│   │   │   └── nrvgn_sdf.yaml
│   │   ├── dataset/
│   │   │   ├── database.py
│   │   │   ├── name2dataset.py
│   │   │   └── train_dataset.py
│   │   ├── main.py
│   │   ├── network/
│   │   │   ├── aggregate_net.py
│   │   │   ├── dist_decoder.py
│   │   │   ├── ibrnet.py
│   │   │   ├── init_net.py
│   │   │   ├── loss.py
│   │   │   ├── metrics.py
│   │   │   ├── mvsnet/
│   │   │   │   ├── modules.py
│   │   │   │   └── mvsnet.py
│   │   │   ├── neus.py
│   │   │   ├── ops.py
│   │   │   ├── render_ops.py
│   │   │   ├── renderer.py
│   │   │   └── vis_encoder.py
│   │   ├── run_training.py
│   │   ├── train/
│   │   │   ├── lr_common_manager.py
│   │   │   ├── train_tools.py
│   │   │   ├── train_valid.py
│   │   │   └── trainer.py
│   │   └── utils/
│   │       ├── base_utils.py
│   │       ├── dataset_utils.py
│   │       ├── draw_utils.py
│   │       ├── field_utils.py
│   │       ├── grasp_utils.py
│   │       ├── imgs_info.py
│   │       └── view_select.py
│   └── rd/
│       ├── modify_material.py
│       ├── render.py
│       └── render_utils.py
└── train.sh
Download .txt
SYMBOL INDEX (727 symbols across 50 files)

FILE: data_generator/modify_material.py
  function modify_material (line 6) | def modify_material(mat_links, mat_nodes, material_name, mat_randomize_m...
  function set_modify_material (line 1612) | def set_modify_material(obj, material, obj_texture_img_list, mat_randomi...
  function set_modify_raw_material (line 1661) | def set_modify_raw_material(obj):
  function set_modify_table_material (line 1680) | def set_modify_table_material(obj, material, selected_realtable_img):
  function set_modify_floor_material (line 1704) | def set_modify_floor_material(obj, material, selected_realfloor_img):
  function set_modify_arm_material (line 1734) | def set_modify_arm_material(obj, material):

FILE: data_generator/render_pile_STD_rand.py
  function obj_centered_camera_pos (line 108) | def obj_centered_camera_pos(dist, azimuth_deg, elevation_deg):
  function quaternionFromYawPitchRoll (line 116) | def quaternionFromYawPitchRoll(yaw, pitch, roll):
  function camPosToQuaternion (line 129) | def camPosToQuaternion(cx, cy, cz):
  function camRotQuaternion (line 158) | def camRotQuaternion(cx, cy, cz, theta):
  function quaternionProduct (line 170) | def quaternionProduct(qx, qy):
  function quaternionToRotation (line 185) | def quaternionToRotation(q):
  function quaternionToRotation_xyzw (line 201) | def quaternionToRotation_xyzw(q):
  function quaternionFromRotMat (line 217) | def quaternionFromRotMat(rotation_matrix):
  function quaternionFromRotMat_xyzw (line 244) | def quaternionFromRotMat_xyzw(rotation_matrix):
  function rotVector (line 271) | def rotVector(q, vector_ori):
  function cameraLPosToCameraRPos (line 281) | def cameraLPosToCameraRPos(q_l, pos_l, baseline_dis):
  function getRTFromAToB (line 289) | def getRTFromAToB(pointCloudA, pointCloudB):
  function cameraPositionRandomize (line 308) | def cameraPositionRandomize(start_point_range, look_at_range, up_range):
  function add_noise_to_transformation_matrix (line 347) | def add_noise_to_transformation_matrix(Rot, Trans, angle_std=2, translat...
  function genCameraPosition (line 358) | def genCameraPosition(look_at):
  function quanternion_mul (line 424) | def quanternion_mul(q1, q2):
  class BlenderRenderer (line 434) | class BlenderRenderer(object):
    method __init__ (line 436) | def __init__(self, viewport_size_x=640, viewport_size_y=360):
    method loadImages (line 555) | def loadImages(self, pattern_path, env_map_path, real_table_image_root...
    method addEnvMap (line 587) | def addEnvMap(self):
    method setEnvMap (line 626) | def setEnvMap(self, env_map_id, rotation_elur_z):
    method addMaskMaterial (line 638) | def addMaskMaterial(self, num=20):
    method addNOCSMaterial (line 692) | def addNOCSMaterial(self):
    method addNormalMaterial (line 730) | def addNormalMaterial(self):
    method addMaterialLib (line 915) | def addMaterialLib(self, material_class_instance_pairs):
    method setCamera (line 926) | def setCamera(self, quaternion, translation, fov, baseline_distance):
    method setLighting (line 953) | def setLighting(self):
    method lightModeSelect (line 1016) | def lightModeSelect(self, light_mode):
    method outputModeSelect (line 1037) | def outputModeSelect(self, output_mode):
    method renderEngineSelect (line 1082) | def renderEngineSelect(self, engine_mode):
    method addBackground (line 1120) | def addBackground(self, size, position, scale):
    method clearModel (line 1185) | def clearModel(self):
    method loadModel (line 1208) | def loadModel(self, file_path):
    method render (line 1224) | def render(self, image_name="tmp", image_path=RENDERING_PATH):
    method set_material_randomize_mode (line 1284) | def set_material_randomize_mode(self, class_material_pairs, mat_random...
    method get_instance_pose (line 1300) | def get_instance_pose(self):
    method check_visible (line 1326) | def check_visible(self, threshold=(0.1, 0.9, 0.1, 0.9)):
  function setModelPosition (line 1345) | def setModelPosition(instance, location, quaternion):
  function setRigidBody (line 1353) | def setRigidBody(instance):
  function set_visiable_objects (line 1369) | def set_visiable_objects(visible_objects_list):
  function generate_CAD_model_list (line 1377) | def generate_CAD_model_list(urdf_path_list):
  function generate_material_type (line 1390) | def generate_material_type(obj_name, class_material_pairs, instance_mate...

FILE: scripts/sim_grasp.py
  function main (line 6) | def main(args, round_idx, gpuid, render_frame_list):
  class ArgumentParserForBlender (line 37) | class ArgumentParserForBlender(argparse.ArgumentParser):
    method _get_argv_after_doubledash (line 54) | def _get_argv_after_doubledash(self):
    method parse_args (line 67) | def parse_args(self):

FILE: scripts/stat_expresult.py
  class Data (line 12) | class Data(object):
    method __init__ (line 15) | def __init__(self, logdir):
    method num_rounds (line 20) | def num_rounds(self):
    method num_grasps (line 23) | def num_grasps(self):
    method success_rate (line 26) | def success_rate(self):
    method percent_cleared (line 29) | def percent_cleared(self):
    method avg_planning_time (line 39) | def avg_planning_time(self):
    method read_grasp (line 42) | def read_grasp(self, i):

FILE: src/gd/baselines.py
  class GPD (line 13) | class GPD(object):
    method __init__ (line 14) | def __init__(self):
    method __call__ (line 19) | def __call__(self, state):
    method to_grasp_list (line 32) | def to_grasp_list(self, grasp_configs):

FILE: src/gd/dataset.py
  class Dataset (line 10) | class Dataset(torch.utils.data.Dataset):
    method __init__ (line 11) | def __init__(self, root, augment=False):
    method __len__ (line 16) | def __len__(self):
    method __getitem__ (line 19) | def __getitem__(self, i):
  function apply_transform (line 41) | def apply_transform(voxel_grid, orientation, position):

FILE: src/gd/detection.py
  class VGN (line 13) | class VGN(object):
    method __init__ (line 14) | def __init__(self, model_path, rviz=False):
    method __call__ (line 19) | def __call__(self, state):
  function predict (line 43) | def predict(tsdf_vol, net, device):
  function process (line 60) | def process(
  function select (line 90) | def select(qual_vol, rot_vol, width_vol, threshold=0.90, max_filter_size...
  function select_index (line 109) | def select_index(qual_vol, rot_vol, width_vol, index):

FILE: src/gd/experiments/clutter_removal.py
  function copydirs (line 19) | def copydirs(from_file, to_file):
  function run (line 30) | def run(
  class Logger (line 153) | class Logger(object):
    method __init__ (line 154) | def __init__(self, log_root_dir, expname, description, round_idx):
    method _create_csv_files_if_needed (line 163) | def _create_csv_files_if_needed(self):
    method last_round_id (line 186) | def last_round_id(self):
    method log_round (line 190) | def log_round(self, round_id, object_count):
    method log_grasp (line 193) | def log_grasp(self, round_id, timings, grasp, score, label):
  class Data (line 221) | class Data(object):
    method __init__ (line 224) | def __init__(self, logdir):
    method num_rounds (line 229) | def num_rounds(self):
    method num_grasps (line 232) | def num_grasps(self):
    method success_rate (line 235) | def success_rate(self):
    method percent_cleared (line 238) | def percent_cleared(self):
    method avg_planning_time (line 248) | def avg_planning_time(self):
    method read_grasp (line 251) | def read_grasp(self, i):

FILE: src/gd/grasp.py
  class Label (line 4) | class Label(enum.IntEnum):
  class Grasp (line 9) | class Grasp(object):
    method __init__ (line 15) | def __init__(self, pose, width):
  function to_voxel_coordinates (line 20) | def to_voxel_coordinates(grasp, voxel_size):
  function from_voxel_coordinates (line 27) | def from_voxel_coordinates(grasp, voxel_size):

FILE: src/gd/io.py
  function write_setup (line 12) | def write_setup(root, size, intrinsic, max_opening_width, finger_depth):
  function read_setup (line 22) | def read_setup(root):
  function write_sensor_data (line 31) | def write_sensor_data(root, depth_imgs, extrinsics):
  function read_sensor_data (line 38) | def read_sensor_data(root, scene_id):
  function write_grasp (line 43) | def write_grasp(root, scene_id, grasp, label):
  function read_grasp (line 57) | def read_grasp(df, i):
  function read_df (line 67) | def read_df(root):
  function write_df (line 71) | def write_df(df, root):
  function write_voxel_grid (line 75) | def write_voxel_grid(root, scene_id, voxel_grid):
  function read_voxel_grid (line 80) | def read_voxel_grid(root, scene_id):
  function read_json (line 85) | def read_json(path):
  function write_json (line 91) | def write_json(data, path):
  function create_csv (line 96) | def create_csv(path, columns):
  function append_csv (line 102) | def append_csv(path, *args):

FILE: src/gd/networks.py
  function get_network (line 9) | def get_network(name):
  function load_network (line 16) | def load_network(path, device):
  function conv (line 29) | def conv(in_channels, out_channels, kernel_size):
  function conv_stride (line 33) | def conv_stride(in_channels, out_channels, kernel_size):
  class ConvNet (line 39) | class ConvNet(nn.Module):
    method __init__ (line 40) | def __init__(self):
    method forward (line 48) | def forward(self, x):
  class Encoder (line 57) | class Encoder(nn.Module):
    method __init__ (line 58) | def __init__(self, in_channels, filters, kernels):
    method forward (line 64) | def forward(self, x):
  class Decoder (line 77) | class Decoder(nn.Module):
    method __init__ (line 78) | def __init__(self, in_channels, filters, kernels):
    method forward (line 84) | def forward(self, x):
  function count_num_trainable_parameters (line 100) | def count_num_trainable_parameters(net):

FILE: src/gd/perception.py
  class CameraIntrinsic (line 10) | class CameraIntrinsic(object):
    method __init__ (line 19) | def __init__(self, width, height, fx, fy, cx, cy, channel=1):
    method fx (line 26) | def fx(self):
    method fy (line 30) | def fy(self):
    method cx (line 34) | def cx(self):
    method cy (line 38) | def cy(self):
    method to_dict (line 41) | def to_dict(self):
    method from_dict (line 52) | def from_dict(cls, data):
  class TSDFVolume (line 66) | class TSDFVolume(object):
    method __init__ (line 69) | def __init__(self, size, resolution):
    method integrate (line 82) | def integrate(self, depth_img, intrinsic, extrinsic):
    method get_grid (line 109) | def get_grid(self):
    method get_cloud (line 119) | def get_cloud(self):
  function create_tsdf (line 123) | def create_tsdf(size, resolution, depth_imgs, intrinsic, extrinsics):
  function camera_on_sphere (line 131) | def camera_on_sphere(origin, radius, theta, phi):

FILE: src/gd/simulation.py
  class ClutterRemovalSim (line 13) | class ClutterRemovalSim(object):
    method __init__ (line 14) | def __init__(self, scene, object_set, gui=True, seed=None, renderer_ro...
    method num_objects (line 46) | def num_objects(self):
    method discover_objects (line 49) | def discover_objects(self):
    method save_state (line 53) | def save_state(self):
    method restore_state (line 56) | def restore_state(self):
    method reset (line 59) | def reset(self, object_count, n_round):
    method draw_workspace (line 100) | def draw_workspace(self):
    method place_table (line 108) | def place_table(self, height):
    method generate_seen_scene (line 120) | def generate_seen_scene(self, table_height, mesh_pose_npz):
    method generate_pile_scene (line 158) | def generate_pile_scene(self, object_count, table_height, scene_descri...
    method generate_packed_scene (line 205) | def generate_packed_scene(self, object_count, table_height, scene_desc...
    method generate_packedsingle_scene (line 273) | def generate_packedsingle_scene(self, object_count, table_height, scen...
    method acquire_tsdf (line 341) | def acquire_tsdf(self, n, N=None):
    method execute_grasp (line 369) | def execute_grasp(self, grasp, remove=True, allow_contact=False):
    method remove_and_wait (line 424) | def remove_and_wait(self):
    method wait_for_objects_to_rest (line 432) | def wait_for_objects_to_rest(self, timeout=2.0, tol=0.01):
    method remove_objects_outside_workspace (line 446) | def remove_objects_outside_workspace(self):
    method check_success (line 465) | def check_success(self, gripper):
  class Gripper (line 472) | class Gripper(object):
    method __init__ (line 475) | def __init__(self, world):
    method reset (line 483) | def reset(self, T_world_tcp):
    method update_tcp_constraint (line 514) | def update_tcp_constraint(self, T_world_tcp):
    method set_tcp (line 522) | def set_tcp(self, T_world_tcp):
    method move_tcp_xyz (line 527) | def move_tcp_xyz(self, target, eef_step=0.002, vel=0.10, abort_on_cont...
    method detect_contact (line 544) | def detect_contact(self, threshold=5):
    method move (line 550) | def move(self, width):
    method read (line 556) | def read(self):

FILE: src/gd/utils/__init__.py
  function workspace_lines (line 1) | def workspace_lines(size):

FILE: src/gd/utils/btsim.py
  class BtWorld (line 13) | class BtWorld(object):
    method __init__ (line 22) | def __init__(self, gui=True):
    method set_gravity (line 34) | def set_gravity(self, gravity):
    method load_urdf (line 37) | def load_urdf(self, urdf_path, pose, scale=1.0):
    method remove_body (line 44) | def remove_body(self, body, isRemoveObjPerGrasp=False):
    method add_constraint (line 50) | def add_constraint(self, *argv, **kwargs):
    method add_camera (line 55) | def add_camera(self, intrinsic, near, far):
    method get_contacts (line 59) | def get_contacts(self, bodyA):
    method reset (line 79) | def reset(self):
    method step (line 87) | def step(self):
    method save_state (line 93) | def save_state(self):
    method restore_state (line 96) | def restore_state(self, state_uid):
    method close (line 99) | def close(self):
  class Body (line 103) | class Body(object):
    method __init__ (line 113) | def __init__(self, physics_client, body_uid):
    method from_urdf (line 126) | def from_urdf(cls, physics_client, urdf_path, pose, scale):
    method get_pose (line 135) | def get_pose(self):
    method set_pose (line 139) | def set_pose(self, pose):
    method get_velocity (line 144) | def get_velocity(self):
  class Link (line 149) | class Link(object):
    method __init__ (line 156) | def __init__(self, physics_client, body_uid, link_index):
    method get_pose (line 161) | def get_pose(self):
  class Joint (line 167) | class Joint(object):
    method __init__ (line 177) | def __init__(self, physics_client, body_uid, joint_index):
    method get_position (line 187) | def get_position(self):
    method set_position (line 191) | def set_position(self, position, kinematics=False):
  class Constraint (line 203) | class Constraint(object):
    method __init__ (line 210) | def __init__(
    method change (line 250) | def change(self, **kwargs):
  class Contact (line 254) | class Contact(object):
    method __init__ (line 264) | def __init__(self, bodyA, bodyB, point, normal, depth, force):
  class Camera (line 273) | class Camera(object):
    method __init__ (line 280) | def __init__(self, physics_client, intrinsic, near, far):
    method render (line 287) | def render(self, extrinsic):
  function _build_projection_matrix (line 314) | def _build_projection_matrix(intrinsic, near, far):
  function _gl_ortho (line 327) | def _gl_ortho(left, right, bottom, top, near, far):

FILE: src/gd/utils/panda_control.py
  class PandaCommander (line 8) | class PandaCommander(object):
    method __init__ (line 9) | def __init__(self):
    method reset (line 15) | def reset(self):
    method clear (line 20) | def clear(self):
    method home (line 23) | def home(self):
    method goto_joints (line 29) | def goto_joints(self, joints):
    method get_joints (line 34) | def get_joints(self):
    method goto_pose (line 36) | def goto_pose(self, pose):
    method get_pose (line 54) | def get_pose(self):
    method grasp (line 57) | def grasp(self, width=0.0, force=10.0):
    method move_gripper (line 60) | def move_gripper(self, width):
    method get_gripper_width (line 63) | def get_gripper_width(self):

FILE: src/gd/utils/ros_utils.py
  function to_point_msg (line 11) | def to_point_msg(position):
  function from_point_msg (line 20) | def from_point_msg(msg):
  function to_vector3_msg (line 25) | def to_vector3_msg(vector3):
  function from_vector3_msg (line 34) | def from_vector3_msg(msg):
  function to_quat_msg (line 39) | def to_quat_msg(orientation):
  function from_quat_msg (line 50) | def from_quat_msg(msg):
  function to_pose_msg (line 55) | def to_pose_msg(transform):
  function to_transform_msg (line 63) | def to_transform_msg(transform):
  function from_transform_msg (line 71) | def from_transform_msg(msg):
  function to_color_msg (line 78) | def to_color_msg(color):
  function to_cloud_msg (line 88) | def to_cloud_msg(points, intensities=None, frame=None, stamp=None):
  class TransformTree (line 125) | class TransformTree(object):
    method __init__ (line 126) | def __init__(self):
    method lookup (line 133) | def lookup(self, target_frame, source_frame, time, timeout=rospy.Durat...
    method broadcast (line 137) | def broadcast(self, transform, target_frame, source_frame):
    method broadcast_static (line 145) | def broadcast_static(self, transform, target_frame, source_frame):

FILE: src/gd/utils/transform.py
  class Rotation (line 5) | class Rotation(scipy.spatial.transform.Rotation):
    method identity (line 7) | def identity(cls):
  class Transform (line 11) | class Transform(object):
    method __init__ (line 19) | def __init__(self, rotation, translation):
    method as_matrix (line 26) | def as_matrix(self):
    method to_dict (line 32) | def to_dict(self):
    method to_list (line 39) | def to_list(self):
    method __mul__ (line 42) | def __mul__(self, other):
    method transform_point (line 48) | def transform_point(self, point):
    method transform_vector (line 51) | def transform_vector(self, vector):
    method inverse (line 54) | def inverse(self):
    method from_matrix (line 61) | def from_matrix(cls, m):
    method from_dict (line 68) | def from_dict(cls, dictionary):
    method from_list (line 74) | def from_list(cls, list):
    method identity (line 80) | def identity(cls):
    method look_at (line 87) | def look_at(cls, eye, center, up):

FILE: src/gd/vis.py
  function draw_workspace (line 19) | def draw_workspace(size):
  function draw_tsdf (line 29) | def draw_tsdf(vol, voxel_size, threshold=0.01):
  function draw_points (line 34) | def draw_points(points):
  function draw_quality (line 39) | def draw_quality(vol, voxel_size, threshold=0.01):
  function draw_volume (line 44) | def draw_volume(vol, voxel_size, threshold=0.01):
  function draw_grasp (line 49) | def draw_grasp(grasp, score, finger_depth):
  function draw_grasps (line 89) | def draw_grasps(grasps, scores, finger_depth):
  function clear (line 99) | def clear():
  function clear_quality (line 109) | def clear_quality():
  function clear_grasps (line 113) | def clear_grasps():
  function _create_publishers (line 117) | def _create_publishers():
  function _create_marker_msg (line 129) | def _create_marker_msg(marker_type, frame, pose, scale, color):
  function _create_vol_msg (line 141) | def _create_vol_msg(vol, voxel_size, threshold):
  function _create_grasp_marker_msg (line 153) | def _create_grasp_marker_msg(grasp, score, finger_depth):
  function _gripper_lines (line 165) | def _gripper_lines(width, depth):

FILE: src/nr/asset.py
  function add_scenes (line 7) | def add_scenes(root, type, filter_list=None):

FILE: src/nr/dataset/database.py
  class BaseDatabase (line 21) | class BaseDatabase(abc.ABC):
    method __init__ (line 22) | def __init__(self, database_name):
    method get_image (line 26) | def get_image(self, img_id):
    method get_K (line 30) | def get_K(self, img_id):
    method get_pose (line 34) | def get_pose(self, img_id):
    method get_img_ids (line 38) | def get_img_ids(self,check_depth_exist=False):
    method get_bbox (line 42) | def get_bbox(self, img_id):
    method get_depth (line 46) | def get_depth(self,img_id):
    method get_mask (line 50) | def get_mask(self,img_id):
    method get_depth_range (line 54) | def get_depth_range(self,img_id):
  class GraspSynDatabase (line 57) | class GraspSynDatabase(BaseDatabase):
    method __init__ (line 58) | def __init__(self, database_name):
    method get_split (line 126) | def get_split(self):
    method get_image (line 129) | def get_image(self, img_id):
    method get_K (line 137) | def get_K(self, img_id):
    method get_pose (line 140) | def get_pose(self, img_id):
    method get_img_ids (line 143) | def get_img_ids(self,check_depth_exist=False):
    method get_bbox3d (line 147) | def get_bbox3d(self, vis=False):
    method get_bbox (line 160) | def get_bbox(self, img_id, vis=False):
    method _depth_existence (line 174) | def _depth_existence(self,img_id):
    method get_depth (line 177) | def get_depth(self, img_id):
    method get_mask (line 185) | def get_mask(self, img_id, tp='desk'):
    method get_depth_range (line 200) | def get_depth_range(self,img_id, fixed=True):
    method get_sdf (line 207) | def get_sdf(self):
  class VGNSynDatabase (line 211) | class VGNSynDatabase(GraspSynDatabase):
    method __init__ (line 212) | def __init__(self, database_name):
    method visualize_grasping (line 227) | def visualize_grasping(self, pos, rot, w, label=None, img_id=3,save_im...
    method visualize_grasping_3d (line 260) | def visualize_grasping_3d(self, pos, rot, w, label=None, voxel_size = ...
    method get_grasp_info (line 278) | def get_grasp_info(self):
  function parse_database_name (line 297) | def parse_database_name(database_name:str)->BaseDatabase:
  function get_database_split (line 307) | def get_database_split(database: BaseDatabase, split_type='val'):

FILE: src/nr/dataset/train_dataset.py
  function select_train_ids_for_real_estate (line 12) | def select_train_ids_for_real_estate(img_ids):
  function add_depth_offset (line 29) | def add_depth_offset(depth,mask,region_min,region_max,offset_min,offset_...
  function build_src_imgs_info_select (line 44) | def build_src_imgs_info_select(database, ref_ids, ref_ids_all, cost_volu...
  class GeneralRendererDataset (line 73) | class GeneralRendererDataset(Dataset):
    method __init__ (line 118) | def __init__(self, cfg, is_train):
    method get_database_ref_que_ids (line 145) | def get_database_ref_que_ids(self, index):
    method select_working_views_impl (line 166) | def select_working_views_impl(self, database_name, dist_idx, ref_num):
    method get_ref_que_ids (line 204) | def get_ref_que_ids(self, target_id):
    method select_working_views (line 211) | def select_working_views(self, database, que_id, ref_ids):
    method depth_range_aug_for_gso (line 242) | def depth_range_aug_for_gso(self, depth_range, depth, mask):
    method random_change_depth_range (line 270) | def random_change_depth_range(self, depth_range, depth, mask, database...
    method add_depth_noise (line 281) | def add_depth_noise(self,depths,masks,depth_ranges):
    method generate_coords_for_training (line 303) | def generate_coords_for_training(self, database, que_imgs_info):
    method consistent_depth_range (line 320) | def consistent_depth_range(self, ref_imgs_info, que_imgs_info):
    method __getitem__ (line 336) | def __getitem__(self, index):
    method __len__ (line 424) | def __len__(self):
  class FinetuningRendererDataset (line 428) | class FinetuningRendererDataset(Dataset):
    method __init__ (line 433) | def __init__(self,cfg, is_train):
    method __getitem__ (line 438) | def __getitem__(self, index):
    method __len__ (line 442) | def __len__(self):

FILE: src/nr/main.py
  function process (line 23) | def process(
  function select (line 58) | def select(qual_vol, rot_vol, width_vol, threshold=0.90, max_filter_size...
  function select_index (line 77) | def select_index(qual_vol, rot_vol, width_vol, index):
  class GraspNeRFPlanner (line 87) | class GraspNeRFPlanner(object):
    method set_params (line 88) | def set_params(self, args):
    method __init__ (line 132) | def __init__(self, args=None, cfg_fn=None, debug_dir=None) -> None:
    method get_image (line 167) | def get_image(self, img_id, round_idx):
    method get_pose (line 173) | def get_pose(self, img_id):
    method get_K (line 178) | def get_K(self, img_id):
    method get_depth_range (line 181) | def get_depth_range(self,img_id, round_idx, fixed=False):
    method __call__ (line 188) | def __call__(self, test_view_id, round_idx, n_grasp, gt_tsdf):
    method core (line 211) | def core(self,

FILE: src/nr/network/aggregate_net.py
  function get_dir_diff (line 11) | def get_dir_diff(prj_dir,que_dir):
  class BaseAggregationNet (line 19) | class BaseAggregationNet(nn.Module):
    method __init__ (line 25) | def __init__(self, cfg):
    method _get_embedding (line 35) | def _get_embedding(self, prj_dict, que_dir):
  class DefaultAggregationNet (line 72) | class DefaultAggregationNet(BaseAggregationNet):
    method __init__ (line 73) | def __init__(self,cfg):
    method forward (line 78) | def forward(self, prj_dict, que_dir, que_pts=None, que_dists=None):
  class NeusAggregationNet (line 87) | class NeusAggregationNet(BaseAggregationNet):
    method __init__ (line 93) | def __init__(self,cfg):
    method _update_cos_anneal_ratio (line 102) | def _update_cos_anneal_ratio(self):
    method _get_alpha_from_sdf (line 105) | def _get_alpha_from_sdf(self, sdf, grad, que_dir, que_dists):
    method forward (line 125) | def forward(self, prj_dict, que_dir, que_pts, que_dists, is_train):

FILE: src/nr/network/dist_decoder.py
  function get_near_far_points (line 6) | def get_near_far_points(depth, interval, depth_range, is_ref, fixed_inte...
  class MixtureLogisticsDistDecoder (line 53) | class MixtureLogisticsDistDecoder(nn.Module):
    method __init__ (line 59) | def __init__(self,cfg):
    method forward (line 99) | def forward(self, feats):
    method compute_prob (line 109) | def compute_prob(self, depth, interval, mean, var, vis, aw, is_ref, de...
    method decode_alpha_value (line 144) | def decode_alpha_value(self, alpha_value):
    method predict_mean (line 148) | def predict_mean(self,prj_ray_feats):
    method predict_aw (line 152) | def predict_aw(self,prj_ray_feats):

FILE: src/nr/network/ibrnet.py
  class ScaledDotProductAttention (line 7) | class ScaledDotProductAttention(nn.Module):
    method __init__ (line 10) | def __init__(self, temperature, attn_dropout=0.1):
    method forward (line 15) | def forward(self, q, k, v, mask=None):
  class PositionwiseFeedForward (line 30) | class PositionwiseFeedForward(nn.Module):
    method __init__ (line 33) | def __init__(self, d_in, d_hid, dropout=0.1):
    method forward (line 40) | def forward(self, x):
  class MultiHeadAttention (line 52) | class MultiHeadAttention(nn.Module):
    method __init__ (line 55) | def __init__(self, n_head, d_model, d_k, d_v, dropout=0.1):
    method forward (line 72) | def forward(self, q, k, v, mask=None):
  function weights_init (line 105) | def weights_init(m):
  function fused_mean_variance (line 113) | def fused_mean_variance(x, weight):
  class IBRNet (line 118) | class IBRNet(nn.Module):
    method __init__ (line 119) | def __init__(self, in_feat_ch=32, n_samples=64, **kwargs):
    method posenc (line 174) | def posenc(self, d_hid, n_samples):
    method forward (line 185) | def forward(self, rgb_feat, ray_diff, mask):
  class IBRNetWithNeuRay (line 240) | class IBRNetWithNeuRay(nn.Module):
    method __init__ (line 241) | def __init__(self, neuray_in_dim=32, in_feat_ch=32, n_samples=64, **kw...
    method change_pos_encoding (line 303) | def change_pos_encoding(self,n_samples):
    method posenc (line 306) | def posenc(self, d_hid, n_samples):
    method forward (line 316) | def forward(self, rgb_feat, neuray_feat, ray_diff, mask):
  class IBRNetWithNeuRayNeus (line 373) | class IBRNetWithNeuRayNeus(nn.Module):
    method __init__ (line 374) | def __init__(self, neuray_in_dim=32, in_feat_ch=32, n_samples=64, **kw...
    method change_pos_encoding (line 434) | def change_pos_encoding(self,n_samples):
    method posenc (line 437) | def posenc(self, d_hid, n_samples):
    method forward (line 447) | def forward(self, rgb_feat, neuray_feat, ray_diff, mask, que_pts):

FILE: src/nr/network/init_net.py
  class CostVolumeInitNet (line 8) | class CostVolumeInitNet(nn.Module):
    method __init__ (line 12) | def __init__(self,cfg):
    method forward (line 33) | def forward(self, ref_imgs_info, src_imgs_info, is_train):

FILE: src/nr/network/loss.py
  class Loss (line 11) | class Loss:
    method __init__ (line 12) | def __init__(self, keys):
    method __call__ (line 19) | def __call__(self, data_pr, data_gt, step, **kwargs):
  class ConsistencyLoss (line 22) | class ConsistencyLoss(Loss):
    method __init__ (line 29) | def __init__(self, cfg):
    method __call__ (line 33) | def __call__(self, data_pr, data_gt, step, **kwargs):
  class RenderLoss (line 50) | class RenderLoss(Loss):
    method __init__ (line 59) | def __init__(self, cfg):
    method __call__ (line 63) | def __call__(self, data_pr, data_gt, step, is_train=True, **kwargs):
  class DepthLoss (line 87) | class DepthLoss(Loss):
    method __init__ (line 95) | def __init__(self, cfg):
    method __call__ (line 101) | def __call__(self, data_pr, data_gt, step, is_train=True, **kwargs):
  function compute_mae (line 146) | def compute_mae(pr, gt, mask):
  class SDFLoss (line 149) | class SDFLoss(Loss):
    method __init__ (line 157) | def __init__(self, cfg):
    method __call__ (line 162) | def __call__(self, data_pr, data_gt, step, is_train=True, **kwargs):
  class VGNLoss (line 180) | class VGNLoss(Loss):
    method __init__ (line 184) | def __init__(self, cfg):
    method _loss_fn (line 188) | def _loss_fn(self, y_pred, y, is_train):
    method _qual_loss_fn (line 208) | def _qual_loss_fn(self, pred, target):
    method _acc_fn (line 211) | def _acc_fn(self, pred, target):
    method _pr_fn (line 214) | def _pr_fn(self, pred, target):
    method _rot_loss_fn (line 218) | def _rot_loss_fn(self, pred, target):
    method _angle_error_fn (line 223) | def _angle_error_fn(self, pred, target, method='torch'):
    method _quat_loss_fn (line 245) | def _quat_loss_fn(self, pred, target):
    method _width_loss_fn (line 248) | def _width_loss_fn(self, pred, target):
    method __call__ (line 251) | def __call__(self, data_pr, data_gt, step, is_train=True, **kwargs):

FILE: src/nr/network/metrics.py
  function compute_psnr (line 14) | def compute_psnr(img_gt, img_pr, use_vis_scores=False, vis_scores=None, ...
  function compute_mae (line 29) | def compute_mae(depth_pr, depth_gt):
  class PSNR_SSIM (line 32) | class PSNR_SSIM(Loss):
    method __init__ (line 36) | def __init__(self, cfg):
    method __call__ (line 40) | def __call__(self, data_pr, data_gt, step, **kwargs):
  class VisualizeImage (line 86) | class VisualizeImage(Loss):
    method __init__ (line 87) | def __init__(self, cfg):
    method __call__ (line 90) | def __call__(self, data_pr, data_gt, step, **kwargs):
  function psnr_nr (line 121) | def psnr_nr(results):
  function psnr_nr_fine (line 124) | def psnr_nr_fine(results):
  function depth_mae (line 127) | def depth_mae(results):
  function sdf_mae (line 130) | def sdf_mae(results):
  function loss_vgn (line 133) | def loss_vgn(results):

FILE: src/nr/network/mvsnet/modules.py
  class ConvBnReLU (line 7) | class ConvBnReLU(nn.Module):
    method __init__ (line 8) | def __init__(self, in_channels, out_channels, kernel_size=3, stride=1,...
    method forward (line 13) | def forward(self, x):
  class ConvBnReLU3D (line 16) | class ConvBnReLU3D(nn.Module):
    method __init__ (line 17) | def __init__(self, in_channels, out_channels, kernel_size=3, stride=1,...
    method forward (line 22) | def forward(self, x):
  function homo_warp (line 25) | def homo_warp(src_feat, src_proj, ref_proj_inv, depth_values):
  function depth_regression (line 66) | def depth_regression(p, depth_values):

FILE: src/nr/network/mvsnet/mvsnet.py
  class FeatureNet (line 7) | class FeatureNet(nn.Module):
    method __init__ (line 8) | def __init__(self, norm_act=InPlaceABN):
    method forward (line 23) | def forward(self, x):
  class CostRegNet (line 29) | class CostRegNet(nn.Module):
    method __init__ (line 30) | def __init__(self, norm_act=InPlaceABN):
    method forward (line 57) | def forward(self, x):
  class MVSNet (line 71) | class MVSNet(nn.Module):
    method __init__ (line 72) | def __init__(self, norm_act=InPlaceABN):
    method forward (line 77) | def forward(self, imgs, proj_mats, depth_values):
    method construct_cost_volume (line 133) | def construct_cost_volume(self, ref_imgs, ref_nn_idx, ref_prjs, depth_...
    method construct_cost_volume_with_src (line 160) | def construct_cost_volume_with_src(self, ref_imgs, src_imgs, ref_nn_id...
  function extract_model_state_dict (line 191) | def extract_model_state_dict(ckpt_path, prefixes_to_ignore=[]):
  function load_ckpt (line 215) | def load_ckpt(model, ckpt_path, prefixes_to_ignore=[]):

FILE: src/nr/network/neus.py
  class SingleVarianceNetwork (line 6) | class SingleVarianceNetwork(nn.Module):
    method __init__ (line 7) | def __init__(self, init_val, fix_s=-1):
    method set_step (line 13) | def set_step(self, step):
    method forward (line 16) | def forward(self, x):
  class Embedder (line 21) | class Embedder:
    method __init__ (line 22) | def __init__(self, **kwargs):
    method create_embedding_fn (line 26) | def create_embedding_fn(self):
    method embed (line 50) | def embed(self, inputs):
  function get_embedder (line 54) | def get_embedder(multires, input_dims=3):

FILE: src/nr/network/ops.py
  function conv3x3 (line 5) | def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):
  function conv1x1 (line 10) | def conv1x1(in_planes, out_planes, stride=1):
  function interpolate_feats (line 14) | def interpolate_feats(feats, points, h=None, w=None, padding_mode='zeros...
  function masked_mean_var (line 36) | def masked_mean_var(feats,mask,dim=2):
  class ResidualBlock (line 43) | class ResidualBlock(nn.Module):
    method __init__ (line 44) | def __init__(self, dim_in, dim_out, dim_inter=None, use_norm=True, nor...
    method forward (line 70) | def forward(self, feats):
  class AddBias (line 78) | class AddBias(nn.Module):
    method __init__ (line 79) | def __init__(self,val):
    method forward (line 83) | def forward(self,x):
  class BasicBlock (line 86) | class BasicBlock(nn.Module):
    method __init__ (line 89) | def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,
    method forward (line 107) | def forward(self, x):
  class conv (line 125) | class conv(nn.Module):
    method __init__ (line 126) | def __init__(self, num_in_layers, num_out_layers, kernel_size, stride):
    method forward (line 137) | def forward(self, x):
  class upconv (line 140) | class upconv(nn.Module):
    method __init__ (line 141) | def __init__(self, num_in_layers, num_out_layers, kernel_size, scale):
    method forward (line 146) | def forward(self, x):
  class ResUNetLight (line 150) | class ResUNetLight(nn.Module):
    method __init__ (line 151) | def __init__(self, in_dim=3, layers=(2, 3, 6, 3), out_dim=32, inplanes...
    method _make_layer (line 181) | def _make_layer(self, block, planes, blocks, stride=1, dilate=False):
    method skipconnect (line 205) | def skipconnect(self, x1, x2):
    method forward (line 214) | def forward(self, x):
  class ResEncoder (line 232) | class ResEncoder(nn.Module):
    method __init__ (line 233) | def __init__(self):
    method _make_layer (line 265) | def _make_layer(self, block, planes, blocks, stride=1, dilate=False):
    method skipconnect (line 289) | def skipconnect(self, x1, x2):
    method forward (line 303) | def forward(self, x):

FILE: src/nr/network/render_ops.py
  function coords2rays (line 4) | def coords2rays(coords, poses, Ks):
  function depth2points (line 27) | def depth2points(que_imgs_info, que_depth):
  function depth2dists (line 41) | def depth2dists(depth):
  function depth2inv_dists (line 46) | def depth2inv_dists(depth,depth_range):
  function interpolate_feature_map (line 54) | def interpolate_feature_map(ray_feats, coords, mask, h, w, border_type='...
  function alpha_values2hit_prob (line 72) | def alpha_values2hit_prob(alpha_values):
  function project_points_coords (line 82) | def project_points_coords(pts, Rt, K):
  function project_points_directions (line 106) | def project_points_directions(poses,points):
  function project_points_ref_views (line 117) | def project_points_ref_views(ref_imgs_info, que_points):
  function project_points_dict (line 132) | def project_points_dict(ref_imgs_info, que_pts):
  function sample_depth (line 146) | def sample_depth(depth_range, coords, sample_num, random_sample):
  function sample_fine_depth (line 172) | def sample_fine_depth(depth, hit_prob, depth_range, sample_num, random_s...

FILE: src/nr/network/renderer.py
  class NeuralRayRenderer (line 13) | class NeuralRayRenderer(nn.Module):
    method __init__ (line 48) | def __init__(self,cfg):
    method predict_proj_ray_prob (line 62) | def predict_proj_ray_prob(self, prj_dict, ref_imgs_info, que_dists, is...
    method get_img_feats (line 80) | def get_img_feats(self,ref_imgs_info, prj_dict):
    method network_rendering (line 90) | def network_rendering(self, prj_dict, que_dir, que_pts, que_depth, is_...
    method render_by_depth (line 110) | def render_by_depth(self, que_depth, que_imgs_info, ref_imgs_info, is_...
    method fine_render_impl (line 140) | def fine_render_impl(self, coarse_render_info, que_imgs_info, ref_imgs...
    method render_impl (line 152) | def render_impl(self, que_imgs_info, ref_imgs_info, is_train):
    method sample_volume (line 164) | def sample_volume(self, ref_imgs_info):
    method render (line 201) | def render(self, que_imgs_info, ref_imgs_info, is_train):
    method gen_depth_loss_coords (line 222) | def gen_depth_loss_coords(self,h,w,device):
    method predict_mean_for_depth_loss (line 230) | def predict_mean_for_depth_loss(self, ref_imgs_info):
    method forward (line 268) | def forward(self,data):
  class GraspNeRF (line 293) | class GraspNeRF(nn.Module):
    method __init__ (line 298) | def __init__(self, cfg):
    method select (line 305) | def select(self, out, index):
    method forward (line 313) | def forward(self, data):

FILE: src/nr/network/vis_encoder.py
  class DefaultVisEncoder (line 6) | class DefaultVisEncoder(nn.Module):
    method __init__ (line 8) | def __init__(self, cfg):
    method forward (line 19) | def forward(self, ray_feats, imgs_feats):

FILE: src/nr/train/lr_common_manager.py
  class LearningRateManager (line 3) | class LearningRateManager(abc.ABC):
    method set_lr_for_all (line 5) | def set_lr_for_all(optimizer, lr):
    method construct_optimizer (line 9) | def construct_optimizer(self, optimizer, network):
    method __call__ (line 16) | def __call__(self, optimizer, step, *args, **kwargs):
  class ExpDecayLR (line 19) | class ExpDecayLR(LearningRateManager):
    method __init__ (line 20) | def __init__(self,cfg):
    method __call__ (line 26) | def __call__(self, optimizer, step, *args, **kwargs):
  class ExpDecayLRRayFeats (line 31) | class ExpDecayLRRayFeats(ExpDecayLR):
    method construct_optimizer (line 32) | def construct_optimizer(self, optimizer, network):
  class WarmUpExpDecayLR (line 36) | class WarmUpExpDecayLR(LearningRateManager):
    method __init__ (line 37) | def __init__(self, cfg):
    method __call__ (line 45) | def __call__(self, optimizer, step, *args, **kwargs):

FILE: src/nr/train/train_tools.py
  function load_model (line 11) | def load_model(model, optim, model_dir, epoch=-1):
  function adjust_learning_rate (line 29) | def adjust_learning_rate(optimizer, epoch, lr_decay_rate, lr_decay_epoch...
  function reset_learning_rate (line 41) | def reset_learning_rate(optimizer, lr):
  function save_model (line 49) | def save_model(net, optim, epoch, model_dir):
  class Recorder (line 57) | class Recorder(object):
    method __init__ (line 58) | def __init__(self, rec_dir, rec_fn):
    method rec_loss (line 64) | def rec_loss(self, losses_batch, step, epoch, prefix='train', dump=Fal...
    method rec_msg (line 88) | def rec_msg(self, msg):
  class Logger (line 94) | class Logger:
    method __init__ (line 95) | def __init__(self, log_dir):
    method log (line 100) | def log(self,data, prefix='train',step=None,verbose=False):
  function print_shape (line 111) | def print_shape(obj):
  function overwrite_configs (line 118) | def overwrite_configs(cfg_base: dict, cfg: dict):
  function to_cuda (line 131) | def to_cuda(data):
  function dim_extend (line 147) | def dim_extend(data_list):
  class MultiGPUWrapper (line 153) | class MultiGPUWrapper(nn.Module):
    method __init__ (line 154) | def __init__(self,network,losses):
    method forward (line 159) | def forward(self, data_gt):
  class DummyLoss (line 167) | class DummyLoss:
    method __init__ (line 168) | def __init__(self,losses):
    method __call__ (line 173) | def __call__(self, data_pr, data_gt, step):

FILE: src/nr/train/train_valid.py
  class ValidationEvaluator (line 11) | class ValidationEvaluator:
    method __init__ (line 12) | def __init__(self,cfg):
    method __call__ (line 16) | def __call__(self, model, losses, eval_dataset, step, model_name, val_...

FILE: src/nr/train/trainer.py
  class Trainer (line 20) | class Trainer:
    method _init_dataset (line 37) | def _init_dataset(self):
    method _init_network (line 60) | def _init_network(self):
    method __init__ (line 97) | def __init__(self,cfg):
    method run (line 115) | def run(self):
    method _load_model (line 199) | def _load_model(self):
    method _save_model (line 211) | def _save_model(self, step, best_para, save_fn=None):
    method _init_logger (line 220) | def _init_logger(self):
    method _log_data (line 223) | def _log_data(self,results,step,prefix='train',verbose=False):

FILE: src/nr/utils/base_utils.py
  function read_pickle (line 20) | def read_pickle(pkl_path):
  function save_pickle (line 25) | def save_pickle(data, pkl_path):
  function mask_zbuffer_to_pts (line 33) | def mask_zbuffer_to_pts(mask, zbuffer, K):
  function mask_depth_to_pts (line 44) | def mask_depth_to_pts(mask, depth, K, rgb=None):
  function read_render_zbuffer (line 55) | def read_render_zbuffer(dpt_pth, max_depth, min_depth):
  function zbuffer_to_depth (line 62) | def zbuffer_to_depth(zbuffer, K):
  function project_points (line 75) | def project_points(pts, RT, K):
  function grey_repeats (line 89) | def grey_repeats(img_raw):
  function normalize_image (line 95) | def normalize_image(img, mask=None):
  function tensor_to_image (line 101) | def tensor_to_image(tensor):
  function equal_hist (line 105) | def equal_hist(img):
  function resize_large_image (line 116) | def resize_large_image(img, resize_max):
  function downsample_gaussian_blur (line 128) | def downsample_gaussian_blur(img, ratio):
  function resize_small_image (line 137) | def resize_small_image(img, resize_min):
  function round_coordinates (line 149) | def round_coordinates(coord, h, w):
  function get_img_patch (line 158) | def get_img_patch(img, pt, size):
  function perspective_transform (line 174) | def perspective_transform(pts, H):
  function get_rot_m (line 180) | def get_rot_m(angle):
  function get_rot_m_batch (line 184) | def get_rot_m_batch(angle):
  function compute_F (line 189) | def compute_F(K1, K2, R, t):
  function compute_relative_transformation (line 206) | def compute_relative_transformation(Rt0, Rt1):
  function compute_angle (line 219) | def compute_angle(rotation_diff):
  function load_h5 (line 226) | def load_h5(filename):
  function save_h5 (line 235) | def save_h5(dict_to_save, filename):
  function pts_to_hpts (line 241) | def pts_to_hpts(pts):
  function hpts_to_pts (line 245) | def hpts_to_pts(hpts):
  function np_skew_symmetric (line 249) | def np_skew_symmetric(v):
  function point_line_dist (line 259) | def point_line_dist(hpts, lines):
  function epipolar_distance (line 270) | def epipolar_distance(x0, x1, F):
  function epipolar_distance_mean (line 291) | def epipolar_distance_mean(x0, x1, F):
  function compute_dR_dt (line 295) | def compute_dR_dt(R0, t0, R1, t1):
  function compute_precision_recall_np (line 302) | def compute_precision_recall_np(pr, gt, eps=1e-5):
  function load_cfg (line 316) | def load_cfg(path):
  function get_stem (line 321) | def get_stem(path, suffix_len=5):
  function load_component (line 325) | def load_component(component_func, component_cfg_fn):
  function interpolate_image_points (line 330) | def interpolate_image_points(img, pts, interpolation=cv2.INTER_LINEAR):
  function transform_points_Rt (line 350) | def transform_points_Rt(pts, R, t):
  function transform_points_pose (line 355) | def transform_points_pose(pts, pose):
  function quaternion_from_matrix (line 360) | def quaternion_from_matrix(matrix, isprecise=False):
  function compute_rotation_angle_diff (line 446) | def compute_rotation_angle_diff(R_gt, R):
  function compute_translation_angle_diff (line 457) | def compute_translation_angle_diff(t_gt, t):
  function bbox2corners (line 466) | def bbox2corners(bbox):
  function get_identity_pose (line 475) | def get_identity_pose():
  function angular_difference (line 479) | def angular_difference(R0, R1):
  function load_ply_model (line 483) | def load_ply_model(model_path):
  function color_map_forward (line 492) | def color_map_forward(rgb):
  function color_map_backward (line 496) | def color_map_backward(rgb):
  function rotate_image (line 502) | def rotate_image(rot, pose, K, img, mask):
  function resize_img (line 535) | def resize_img(img, ratio):
  function pad_img (line 543) | def pad_img(img, padding_interval=8):
  function pad_img_end (line 552) | def pad_img_end(img, th, tw, padding_mode='edge', constant_values=0):
  function pad_img_target (line 564) | def pad_img_target(img, th, tw, K=np.eye(3), background_color=0):
  function get_coords_mask (line 585) | def get_coords_mask(que_mask, train_ray_num, foreground_ratio):
  function get_inverse_depth (line 607) | def get_inverse_depth(depth_range, depth_num):
  function pose_inverse (line 615) | def pose_inverse(pose):
  function pose_compose (line 621) | def pose_compose(pose0, pose1):
  function make_dir (line 633) | def make_dir(dir):
  function to_cuda (line 638) | def to_cuda(data):
  function to_cpu_numpy (line 655) | def to_cpu_numpy(data):
  function sample_fps_points (line 672) | def sample_fps_points(points, sample_num, init_center=True, index_model=...
  function pnp (line 704) | def pnp(points_3d, points_2d, camera_matrix, method=cv2.SOLVEPNP_ITERATI...
  function triangulate (line 725) | def triangulate(kps0, kps1, pose0, pose1, K0, K1):
  function transformation_compose_2d (line 734) | def transformation_compose_2d(trans0, trans1):
  function transformation_apply_2d (line 749) | def transformation_apply_2d(trans, points):
  function angle_to_rotation_2d (line 753) | def angle_to_rotation_2d(angle):
  function transformation_offset_2d (line 758) | def transformation_offset_2d(x, y):
  function transformation_scale_2d (line 762) | def transformation_scale_2d(scale):
  function transformation_rotation_2d (line 766) | def transformation_rotation_2d(ang):
  function look_at_rotation (line 770) | def look_at_rotation(point):
  function save_depth (line 782) | def save_depth(fn, depth, max_val=1000):
  function compute_geodesic_distance_from_two_matrices (line 791) | def compute_geodesic_distance_from_two_matrices(m1, m2):
  function compute_rotation_matrix_from_quaternion_xyzw (line 802) | def compute_rotation_matrix_from_quaternion_xyzw(quaternion, n_flag=True):
  function calc_rot_error_from_qxyzw (line 840) | def calc_rot_error_from_qxyzw(rotation_pred, rotations):

FILE: src/nr/utils/dataset_utils.py
  function dummy_collate_fn (line 6) | def dummy_collate_fn(data_list):
  function simple_collate_fn (line 9) | def simple_collate_fn(data_list):
  function set_seed (line 18) | def set_seed(index,is_train):

FILE: src/nr/utils/draw_utils.py
  function newline (line 17) | def newline(p1, p2):
  function draw_correspondence (line 32) | def draw_correspondence(img0, img1, kps0, kps1, matches=None, colors=Non...
  function draw_keypoints (line 99) | def draw_keypoints(img,kps,colors=None,radius=2):
  function draw_epipolar_line (line 110) | def draw_epipolar_line(F, img0, img1, pt0, color):
  function draw_epipolar_lines (line 123) | def draw_epipolar_lines(F, img0, img1,num=20):
  function gen_color_map (line 139) | def gen_color_map(error, clip_max=12.0, clip_min=2.0, cmap_name='viridis'):
  function scale_float_image (line 147) | def scale_float_image(image):
  function concat_images (line 152) | def concat_images(img0,img1,vert=False):
  function concat_images_list (line 167) | def concat_images_list(*args,vert=False):
  function get_colors_gt_pr (line 175) | def get_colors_gt_pr(gt,pr=None):
  function draw_hist (line 185) | def draw_hist(fn,vals,bins=100,hist_range=None,names=None):
  function draw_pr_curve (line 203) | def draw_pr_curve(fn,gt_sort):
  function draw_features_distribution (line 218) | def draw_features_distribution(fn,feats,colors,ds_type='pca'):
  function draw_points (line 245) | def draw_points(img,points):
  function draw_bbox (line 255) | def draw_bbox(img,bbox,color=None):
  function output_points (line 263) | def output_points(fn,pts,colors=None):
  function compute_axis_points (line 271) | def compute_axis_points(pose):
  function draw_epipolar_lines_func (line 279) | def draw_epipolar_lines_func(img0,img1,Rt0,Rt1,K0,K1):
  function draw_axis (line 284) | def draw_axis(img, R, t, K, length=0.1, width=3, with_text=False, dist=N...
  function draw_gripper (line 312) | def draw_gripper(img, R, t, K, width, thickness=2, dist=None):
  function draw_cube (line 328) | def draw_cube(img,  R, t, K, length=0.3, bias=[-0.15,-0.15,-0.], dist=No...
  function draw_world_points (line 346) | def draw_world_points(img, points, Rwc, twc, K, dist=None):
  function extract_surface_points_from_volume (line 355) | def extract_surface_points_from_volume(vol, rg, bound=(-1,1), color=(0,0...
  function draw_volume_surface (line 379) | def draw_volume_surface(logdir, vol, prefix='surface', rg=(-0.2,0.2)):
  function create_mesh_box (line 385) | def create_mesh_box(width, height, depth, dx=0, dy=0, dz=0):
  function draw_gripper_o3d (line 408) | def draw_gripper_o3d(R, t, width, score=1, color=None):
  function transform_points (line 482) | def transform_points(points, trans):

FILE: src/nr/utils/field_utils.py
  function generate_grid_points_old (line 4) | def generate_grid_points_old(bound_min, bound_max, resolution):
  function generate_grid_points (line 17) | def generate_grid_points():

FILE: src/nr/utils/grasp_utils.py
  class Grasp (line 15) | class Grasp(object):
    method __init__ (line 21) | def __init__(self, pose, width):
  function to_voxel_coordinates (line 26) | def to_voxel_coordinates(grasp, voxel_size):
  function from_voxel_coordinates (line 33) | def from_voxel_coordinates(grasp, voxel_size):
  function process (line 40) | def process(
  function select_index (line 70) | def select_index(qual_vol, rot_vol, width_vol, index):
  function select (line 78) | def select(qual_vol, rot_vol, width_vol, threshold=0.90, max_filter_size...
  function sim_grasp (line 97) | def sim_grasp(database,  alp_vol, qual_vol, rot_vol, width_vol, top_k=10):
  function run_real (line 119) | def run_real(run_id, model, images: list, extrinsics: list, intrinsic, s...

FILE: src/nr/utils/imgs_info.py
  function random_crop (line 6) | def random_crop(ref_imgs_info, que_imgs_info, target_size):
  function random_flip (line 37) | def random_flip(ref_imgs_info,que_imgs_info):
  function pad_imgs_info (line 60) | def pad_imgs_info(ref_imgs_info,pad_interval):
  function build_imgs_info (line 77) | def build_imgs_info(database, ref_ids, pad_interval=-1, is_aligned=True,...
  function build_render_imgs_info (line 126) | def build_render_imgs_info(que_pose,que_K,que_shape,que_depth_range):
  function build_canonical_info (line 137) | def build_canonical_info(bbox, resolution, que_pose, que_K):
  function imgs_info_to_torch (line 148) | def imgs_info_to_torch(imgs_info):
  function grasp_info_to_torch (line 154) | def grasp_info_to_torch(info):
  function imgs_info_slice (line 159) | def imgs_info_slice(imgs_info, indices):

FILE: src/nr/utils/view_select.py
  function compute_nearest_camera_indices (line 5) | def compute_nearest_camera_indices(database, que_ids, ref_ids=None):
  function select_working_views (line 16) | def select_working_views(ref_poses, que_poses, work_num, exclude_self=Fa...
  function select_working_views_db (line 27) | def select_working_views_db(database: BaseDatabase, ref_ids, que_poses, ...

FILE: src/rd/modify_material.py
  function modify_material (line 5) | def modify_material(mat_links, mat_nodes, material_name, mat_randomize_m...
  function set_modify_material (line 1604) | def set_modify_material(obj, material, obj_texture_img_list, mat_randomi...
  function set_modify_raw_material (line 1658) | def set_modify_raw_material(obj):
  function set_modify_table_material (line 1676) | def set_modify_table_material(obj, material, selected_realtable_img): ##...
  function set_modify_floor_material (line 1701) | def set_modify_floor_material(obj, material, selected_realfloor_img):###...

FILE: src/rd/render.py
  function blender_init_scene (line 9) | def blender_init_scene(code_root, log_root_dir, obj_texture_image_root_p...
  function blender_update_sceneobj (line 238) | def blender_update_sceneobj(obj_name_list, obj_trans_list, obj_quat_list...
  function blender_render (line 254) | def blender_render(renderer, quaternion_list, translation_list, path_sce...

FILE: src/rd/render_utils.py
  function obj_centered_camera_pos (line 181) | def obj_centered_camera_pos(dist, azimuth_deg, elevation_deg):
  function quaternionFromYawPitchRoll (line 189) | def quaternionFromYawPitchRoll(yaw, pitch, roll):
  function camPosToQuaternion (line 202) | def camPosToQuaternion(cx, cy, cz):
  function camRotQuaternion (line 231) | def camRotQuaternion(cx, cy, cz, theta):
  function quaternionProduct (line 243) | def quaternionProduct(qx, qy):
  function quaternionToRotation (line 258) | def quaternionToRotation(q):
  function quaternionToRotation_xyzw (line 274) | def quaternionToRotation_xyzw(q):
  function quaternionFromRotMat (line 290) | def quaternionFromRotMat(rotation_matrix):
  function quaternionFromRotMat_xyzw (line 317) | def quaternionFromRotMat_xyzw(rotation_matrix):
  function rotVector (line 344) | def rotVector(q, vector_ori):
  function cameraLPosToCameraRPos (line 354) | def cameraLPosToCameraRPos(q_l, pos_l, baseline_dis):
  function getRTFromAToB (line 362) | def getRTFromAToB(pointCloudA, pointCloudB):
  function cameraPositionRandomize (line 380) | def cameraPositionRandomize(start_point_range, look_at_range, up_range):
  function genCameraPosition (line 420) | def genCameraPosition(look_at):
  function quanternion_mul (line 483) | def quanternion_mul(q1, q2):
  class BlenderRenderer (line 492) | class BlenderRenderer(object):
    method __init__ (line 493) | def __init__(self, viewport_size_x=640, viewport_size_y=360, DEVICE_LI...
    method loadImages (line 608) | def loadImages(self, pattern_path, env_map_path, real_table_image_root...
    method addEnvMap (line 639) | def addEnvMap(self):
    method setEnvMap (line 679) | def setEnvMap(self, env_map_id, rotation_elur_z):
    method addMaskMaterial (line 692) | def addMaskMaterial(self, num=20):
    method addNOCSMaterial (line 746) | def addNOCSMaterial(self):
    method addNormalMaterial (line 785) | def addNormalMaterial(self):
    method addMaterialLib (line 970) | def addMaterialLib(self, material_class_instance_pairs):
    method setCamera (line 981) | def setCamera(self, quaternion, translation, fov, baseline_distance):
    method setLighting (line 1009) | def setLighting(self):
    method lightModeSelect (line 1071) | def lightModeSelect(self, light_mode):
    method outputModeSelect (line 1090) | def outputModeSelect(self, output_mode):
    method renderEngineSelect (line 1135) | def renderEngineSelect(self, engine_mode):
    method addBackground (line 1170) | def addBackground(self, size, position, scale, default_background_text...
    method clearModel (line 1234) | def clearModel(self):
    method loadModel (line 1258) | def loadModel(self, file_path):
    method render (line 1275) | def render(self, image_name="tmp", image_path=RENDERING_PATH):
    method set_material_randomize_mode (line 1336) | def set_material_randomize_mode(self, class_material_pairs, mat_random...
    method get_instance_pose (line 1355) | def get_instance_pose(self):
    method check_visible (line 1382) | def check_visible(self, threshold=(0.1, 0.9, 0.1, 0.9)):
  function setModelPosition (line 1401) | def setModelPosition(instance, location, quaternion):
  function setRigidBody (line 1410) | def setRigidBody(instance):
  function set_visiable_objects (line 1427) | def set_visiable_objects(visible_objects_list):
  function generate_CAD_model_list (line 1436) | def generate_CAD_model_list(scene_type, urdf_path_list, obj_uid_list):
  function generate_material_type (line 1458) | def generate_material_type(obj_name, class_material_pairs, instance_mate...
Condensed preview — 61 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (698K chars).
[
  {
    "path": ".gitignore",
    "chars": 1290,
    "preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
  },
  {
    "path": "README.md",
    "chars": 4126,
    "preview": "# GraspNeRF: Multiview-based 6-DoF Grasp Detection for Transparent and Specular Objects Using Generalizable NeRF (ICRA 2"
  },
  {
    "path": "data_generator/modify_material.py",
    "chars": 96076,
    "preview": "from mathutils import Vector\nimport bpy\nimport random\nimport math\n\ndef modify_material(mat_links, mat_nodes, material_na"
  },
  {
    "path": "data_generator/render_pile_STD_rand.py",
    "chars": 76949,
    "preview": "import os\nimport random\nimport bpy\nimport math\nimport numpy as np\nfrom mathutils import Vector, Matrix\nimport copy\nimpor"
  },
  {
    "path": "data_generator/run_pile_rand.sh",
    "chars": 286,
    "preview": "#!/bin/bash\n\ncd /data/InterNeRF/renderer/renderer_giga_GPU6-0_rand_M\n\n# 830*6\nmycount=0;\nwhile (( $mycount < 100 )); do\n"
  },
  {
    "path": "requirements.txt",
    "chars": 238,
    "preview": "torch\ntensorflow\neasydict\ninplace-abn\nplyfile\nnumpy\nscikit-image\npyyaml\nh5py\nopencv-python\ntqdm\nmatplotlib\nscipy\nlpips\nt"
  },
  {
    "path": "run_simgrasp.sh",
    "chars": 797,
    "preview": "#!/bin/bash\n\nGPUID=0\nBLENDER_BIN=blender\n\nRENDERER_ASSET_DIR=./data/assets\nBLENDER_PROJ_PATH=./data/assets/material_lib_"
  },
  {
    "path": "scripts/sim_grasp.py",
    "chars": 5238,
    "preview": "import argparse\nimport os\nimport sys\nfrom pathlib import Path\n\ndef main(args, round_idx, gpuid, render_frame_list):\n    "
  },
  {
    "path": "scripts/stat_expresult.py",
    "chars": 3791,
    "preview": "from pathlib import Path\r\nimport sys\r\nimport pandas as pd\r\nimport os\r\nimport numpy as np\r\n\r\nargv = sys.argv\r\nargv = argv"
  },
  {
    "path": "src/gd/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/gd/baselines.py",
    "chars": 1847,
    "preview": "import time\n\nfrom gpd_ros.msg import GraspConfigList\nimport numpy as np\nfrom sensor_msgs.msg import PointCloud2\nimport r"
  },
  {
    "path": "src/gd/dataset.py",
    "chars": 2026,
    "preview": "import numpy as np\nfrom scipy import ndimage\nimport torch.utils.data\n\nfrom gd.io import *\nfrom gd.perception import *\nfr"
  },
  {
    "path": "src/gd/detection.py",
    "chars": 3497,
    "preview": "import time\n\nimport numpy as np\nfrom scipy import ndimage\nimport torch\n\n\nfrom gd.grasp import *\nfrom gd.utils.transform "
  },
  {
    "path": "src/gd/experiments/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/gd/experiments/clutter_removal.py",
    "chars": 8721,
    "preview": "import collections\nimport uuid\nimport os\nimport numpy as np\nimport pandas as pd\nimport sys\nimport shutil\nfrom pathlib im"
  },
  {
    "path": "src/gd/grasp.py",
    "chars": 747,
    "preview": "import enum\n\n\nclass Label(enum.IntEnum):\n    FAILURE = 0  # grasp execution failed due to collision or slippage\n    SUCC"
  },
  {
    "path": "src/gd/io.py",
    "chars": 2843,
    "preview": "import json\nimport uuid\n\nimport numpy as np\nimport pandas as pd\n\nfrom gd.grasp import Grasp\nfrom gd.perception import *\n"
  },
  {
    "path": "src/gd/networks.py",
    "chars": 2723,
    "preview": "from builtins import super\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom scipy import ndimage"
  },
  {
    "path": "src/gd/perception.py",
    "chars": 4132,
    "preview": "from math import cos, sin\nimport time\n\nimport numpy as np\nimport open3d as o3d\n\nfrom gd.utils.transform import Transform"
  },
  {
    "path": "src/gd/simulation.py",
    "chars": 24800,
    "preview": "from pathlib import Path\nimport time\nimport os\nimport numpy as np\nimport pybullet\n\nfrom gd.grasp import Label\nfrom gd.pe"
  },
  {
    "path": "src/gd/utils/__init__.py",
    "chars": 683,
    "preview": "def workspace_lines(size):\n    return [\n        [0.0, 0.0, 0.0],\n        [size, 0.0, 0.0],\n        [size, 0.0, 0.0],\n   "
  },
  {
    "path": "src/gd/utils/btsim.py",
    "chars": 10231,
    "preview": "import time\n\nimport numpy as np\nimport pybullet\nfrom pybullet_utils import bullet_client\n\n\nfrom vgn.utils.transform impo"
  },
  {
    "path": "src/gd/utils/panda_control.py",
    "chars": 2046,
    "preview": "from panda_robot import PandaArm\nimport rospy\nimport numpy as np\nimport quaternion\nfrom gd.utils.transform import Transf"
  },
  {
    "path": "src/gd/utils/ros_utils.py",
    "chars": 4489,
    "preview": "import geometry_msgs.msg\nimport numpy as np\nimport rospy\nfrom sensor_msgs.msg import PointCloud2, PointField\nimport std_"
  },
  {
    "path": "src/gd/utils/transform.py",
    "chars": 3440,
    "preview": "import numpy as np\nimport scipy.spatial.transform\n\n\nclass Rotation(scipy.spatial.transform.Rotation):\n    @classmethod\n "
  },
  {
    "path": "src/gd/vis.py",
    "chars": 5661,
    "preview": "\"\"\"Render volumes, point clouds, and grasp detections in rviz.\"\"\"\n\nimport matplotlib.colors\nimport numpy as np\nfrom sens"
  },
  {
    "path": "src/nr/asset.py",
    "chars": 2373,
    "preview": "import os\nimport numpy as np\n\nDATA_ROOT_DIR = '../../data/traindata_example/'\nVGN_TRAIN_ROOT = DATA_ROOT_DIR + 'giga_hem"
  },
  {
    "path": "src/nr/configs/nrvgn_sdf.yaml",
    "chars": 1485,
    "preview": "name: test\ngroup_name: \"\"\n# network\nfix_seed: true\nnetwork:  grasp_nerf\ninit_net_type: cost_volume\nagg_net_type: neus\nus"
  },
  {
    "path": "src/nr/dataset/database.py",
    "chars": 11278,
    "preview": "import abc\nimport glob\nimport json\nimport os\nimport re\nfrom pathlib import Path\nimport sys\nimport open3d as o3d\nfrom uti"
  },
  {
    "path": "src/nr/dataset/name2dataset.py",
    "chars": 173,
    "preview": "from dataset.train_dataset import GeneralRendererDataset, FinetuningRendererDataset\n\nname2dataset={\n    'gen': GeneralRe"
  },
  {
    "path": "src/nr/dataset/train_dataset.py",
    "chars": 22388,
    "preview": "from torch.utils.data import Dataset\nfrom asset import *\nfrom dataset.database import parse_database_name, get_database_"
  },
  {
    "path": "src/nr/main.py",
    "chars": 10384,
    "preview": "import sys, os\nimport time\n\nsys.path.append(\"./src/nr\")\nfrom pathlib import Path\nimport numpy as np\n\nimport torch\nfrom s"
  },
  {
    "path": "src/nr/network/aggregate_net.py",
    "chars": 6289,
    "preview": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom easydict import EasyDict\nimport numpy as np\n\nfro"
  },
  {
    "path": "src/nr/network/dist_decoder.py",
    "chars": 5709,
    "preview": "import torch.nn as nn\nimport torch\n\nfrom network.ops import AddBias\n\ndef get_near_far_points(depth, interval, depth_rang"
  },
  {
    "path": "src/nr/network/ibrnet.py",
    "chars": 23093,
    "preview": "import numpy as np\nimport torch.nn.functional as F\nimport torch.nn as nn\nimport torch\nfrom network.neus import *\n\nclass "
  },
  {
    "path": "src/nr/network/init_net.py",
    "chars": 1316,
    "preview": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport numpy as np\n\nfrom network.ops import interpola"
  },
  {
    "path": "src/nr/network/loss.py",
    "chars": 10974,
    "preview": "import torch\nimport torch.nn as nn\nimport numpy as np\nimport pyquaternion as pyq\nimport math\nfrom network.ops import int"
  },
  {
    "path": "src/nr/network/metrics.py",
    "chars": 5176,
    "preview": "from pathlib import Path\n\nimport torch\nfrom skimage.io import imsave\n\nfrom network.loss import Loss\nfrom utils.base_util"
  },
  {
    "path": "src/nr/network/mvsnet/modules.py",
    "chars": 3005,
    "preview": "import torch\nfrom torch import nn\nimport torch.nn.functional as F\nfrom inplace_abn import InPlaceABN\nfrom kornia.utils i"
  },
  {
    "path": "src/nr/network/mvsnet/mvsnet.py",
    "chars": 9864,
    "preview": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom network.mvsnet.modules import ConvBnReLU, ConvBn"
  },
  {
    "path": "src/nr/network/neus.py",
    "chars": 2083,
    "preview": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport numpy as np\n\nclass SingleVarianceNetwork(nn.Mo"
  },
  {
    "path": "src/nr/network/ops.py",
    "chars": 12121,
    "preview": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\ndef conv3x3(in_planes, out_planes, stride=1, groups="
  },
  {
    "path": "src/nr/network/render_ops.py",
    "chars": 9237,
    "preview": "import torch\nfrom network.ops import interpolate_feats\n\ndef coords2rays(coords, poses, Ks):\n    \"\"\"\n    :param coords:  "
  },
  {
    "path": "src/nr/network/renderer.py",
    "chars": 15781,
    "preview": "import torch\nimport numpy as np\nimport torch.nn as nn\n\nfrom network.aggregate_net import name2agg_net\nfrom network.dist_"
  },
  {
    "path": "src/nr/network/vis_encoder.py",
    "chars": 754,
    "preview": "import torch.nn as nn\nimport torch\n\nfrom network.ops import conv3x3, ResidualBlock, conv1x1\n\nclass DefaultVisEncoder(nn."
  },
  {
    "path": "src/nr/run_training.py",
    "chars": 302,
    "preview": "import argparse\n\nfrom train.trainer import Trainer\nfrom utils.base_utils import load_cfg\n\nparser = argparse.ArgumentPars"
  },
  {
    "path": "src/nr/train/lr_common_manager.py",
    "chars": 1877,
    "preview": "import abc\n\nclass LearningRateManager(abc.ABC):\n    @staticmethod\n    def set_lr_for_all(optimizer, lr):\n        for par"
  },
  {
    "path": "src/nr/train/train_tools.py",
    "chars": 5437,
    "preview": "import datetime\nimport os\nfrom collections import OrderedDict\n\nimport torch\nimport numpy as np\nfrom torch.utils.tensorbo"
  },
  {
    "path": "src/nr/train/train_valid.py",
    "chars": 1716,
    "preview": "import time\n\nimport torch\nimport numpy as np\nfrom tqdm import tqdm\n\nfrom network.metrics import name2key_metrics\nfrom tr"
  },
  {
    "path": "src/nr/train/trainer.py",
    "chars": 9560,
    "preview": "import os\nimport random\nimport torch\nimport numpy as np\nfrom torch.nn import DataParallel\nfrom torch.optim import Adam, "
  },
  {
    "path": "src/nr/utils/base_utils.py",
    "chars": 26292,
    "preview": "import math\nimport os\n\nimport cv2\nimport h5py\nimport torch\n\nimport numpy as np\nimport pickle\n\nimport yaml\nfrom plyfile i"
  },
  {
    "path": "src/nr/utils/dataset_utils.py",
    "chars": 740,
    "preview": "import numpy as np\nimport time\nimport random\nimport torch\n\ndef dummy_collate_fn(data_list):\n    return data_list[0]\n\ndef"
  },
  {
    "path": "src/nr/utils/draw_utils.py",
    "chars": 17966,
    "preview": "import matplotlib\nmatplotlib.use('Agg')\nimport sys\nsys.path.append(\"./src/nr\")\n\nfrom utils.base_utils import compute_rel"
  },
  {
    "path": "src/nr/utils/field_utils.py",
    "chars": 1410,
    "preview": "import torch\nimport numpy as np\n\ndef generate_grid_points_old(bound_min, bound_max, resolution):\n    X = torch.linspace("
  },
  {
    "path": "src/nr/utils/grasp_utils.py",
    "chars": 5213,
    "preview": "import datetime\nfrom pathlib import Path\nimport numpy as np\nfrom scipy import ndimage\nimport sys\nsys.path.append(\"./src\""
  },
  {
    "path": "src/nr/utils/imgs_info.py",
    "chars": 7662,
    "preview": "import numpy as np\nimport torch\n\nfrom utils.base_utils import color_map_forward, pad_img_end\n\ndef random_crop(ref_imgs_i"
  },
  {
    "path": "src/nr/utils/view_select.py",
    "chars": 1524,
    "preview": "import numpy as np\n\nfrom dataset.database import BaseDatabase\n\ndef compute_nearest_camera_indices(database, que_ids, ref"
  },
  {
    "path": "src/rd/modify_material.py",
    "chars": 94017,
    "preview": "from mathutils import Vector\nimport bpy\nimport random\n\ndef modify_material(mat_links, mat_nodes, material_name, mat_rand"
  },
  {
    "path": "src/rd/render.py",
    "chars": 15096,
    "preview": "import os\nimport random\nimport bpy\nimport math\nimport numpy as np\nfrom rd.modify_material import  set_modify_table_mater"
  },
  {
    "path": "src/rd/render_utils.py",
    "chars": 64167,
    "preview": "import os\nimport random\nimport bpy\nimport math\nimport numpy as np\nfrom mathutils import Vector, Matrix\nfrom bpy_extras.o"
  },
  {
    "path": "train.sh",
    "chars": 90,
    "preview": "cd src/nr\nCUDA_VISIBLE_DEVICES=$1 python run_training.py --cfg configs/nrvgn_sdf.yaml\ncd -"
  }
]

About this extraction

This page contains the full source code of the PKU-EPIC/GraspNeRF GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 61 files (657.5 KB), approximately 179.1k tokens, and a symbol index with 727 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!