diff --git a/.github/workflows/BlenderMalt.yml b/.github/workflows/BlenderMalt.yml
index 6e815e81..5d0fde79 100644
--- a/.github/workflows/BlenderMalt.yml
+++ b/.github/workflows/BlenderMalt.yml
@@ -22,13 +22,24 @@ jobs:
- uses: ncipollo/release-action@v1
id: create_release
+ if: ${{ github.ref_type == 'branch' }}
with:
token: ${{ secrets.GITHUB_TOKEN }}
allowUpdates: true
tag: ${{ env.BRANCH_NAME }}-latest
+ commit: ${{ github.sha }}
prerelease: ${{ env.BRANCH_NAME != 'Release' }}
- bodyFile: ".github/download.md"
- if: ${{ github.ref_type == 'branch' }}
+ body: |
+ ### Sponsored by
+ ## Creative Shrimp
+ ## オリトイツキ - Orito Itsuki
+ ---
+ [**BlenderMalt-Windows.zip**](https://github.com/${{github.repository}}/releases/download/${{env.BRANCH_NAME}}-latest/BlenderMalt-Windows.zip)
+ [**BlenderMalt-Linux.zip**](https://github.com/${{github.repository}}/releases/download/${{env.BRANCH_NAME}}-latest/BlenderMalt-Linux.zip)
+
+ *(Requires Blender 3.2)*
+ ---
+
- name: Rollback Tagged Release
uses: author/action-rollback@stable
@@ -41,12 +52,23 @@ jobs:
- uses: ncipollo/release-action@v1
id: create_tagged_release
+ if: ${{ github.ref_type == 'tag' }}
with:
token: ${{ secrets.GITHUB_TOKEN }}
+ commit: ${{ github.sha }}
allowUpdates: true
prerelease: ${{ env.BRANCH_NAME != 'Release' }}
- bodyFile: ".github/download.md"
- if: ${{ github.ref_type == 'tag' }}
+ body: |
+ ### Sponsored by
+ ## Creative Shrimp
+ ## オリトイツキ - Orito Itsuki
+ ---
+ [**BlenderMalt-Windows.zip**](https://github.com/${{github.repository}}/releases/download/${{github.ref_name}}/BlenderMalt-Windows.zip)
+ [**BlenderMalt-Linux.zip**](https://github.com/${{github.repository}}/releases/download/${{github.ref_name}}/BlenderMalt-Linux.zip)
+
+ *(Requires Blender 3.2)*
+ ---
+
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
@@ -60,7 +82,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- os: [windows-latest, ubuntu-18.04]
+ os: [windows-latest, ubuntu-latest]
steps:
- uses: actions/checkout@v2
diff --git a/BlenderMalt/MaltNodes/MaltNodeTree.py b/BlenderMalt/MaltNodes/MaltNodeTree.py
index a5e810e2..5bd0833c 100644
--- a/BlenderMalt/MaltNodes/MaltNodeTree.py
+++ b/BlenderMalt/MaltNodes/MaltNodeTree.py
@@ -151,12 +151,15 @@ def get_generated_source(self, force_update=False):
output_nodes.append(node)
linked_nodes.append(node)
- def add_node_inputs(node, list):
+ def add_node_inputs(node, list, io_type):
for input in node.inputs:
if input.get_linked():
new_node = input.get_linked().node
+ if new_node.bl_idname == 'MaltIONode' and new_node.io_type != io_type:
+ input.links[0].is_muted = True
+ continue
if new_node not in list:
- add_node_inputs(new_node, list)
+ add_node_inputs(new_node, list, io_type)
list.append(new_node)
if new_node not in linked_nodes:
linked_nodes.append(new_node)
@@ -164,7 +167,7 @@ def add_node_inputs(node, list):
transpiler = self.get_transpiler()
def get_source(output):
nodes = []
- add_node_inputs(output, nodes)
+ add_node_inputs(output, nodes, output.io_type)
code = ''
for node in nodes:
if isinstance(node, MaltNode):
@@ -219,11 +222,12 @@ def update_ext(self, force_track_shader_changes=True):
try:
for link in self.links:
try:
- if (link.from_socket.array_size != link.to_socket.array_size or
- (link.from_socket.data_type != link.to_socket.data_type and
- self.cast(link.from_socket.data_type, link.to_socket.data_type) is None)):
- #TODO: handle reroute nodes
- self.links.remove(link)
+ b = link.to_socket
+ a = b.get_linked()
+ if (a.array_size != b.array_size or
+ (a.data_type != b.data_type and
+ self.cast(a.data_type, b.data_type) is None)):
+ link.is_muted = True
except:
pass
@@ -557,7 +561,7 @@ def node_header_ui(self, context):
if context.space_data.tree_type != 'MaltTree' or node_tree is None:
return
def duplicate():
- node_tree = node_tree.copy()
+ context.space_data.node_tree = node_tree.copy()
self.layout.operator('wm.malt_callback', text='', icon='DUPLICATE').callback.set(duplicate, 'Duplicate')
def recompile():
node_tree.update()
diff --git a/BlenderMalt/MaltNodes/MaltSocket.py b/BlenderMalt/MaltNodes/MaltSocket.py
index 6a81c812..be891686 100644
--- a/BlenderMalt/MaltNodes/MaltSocket.py
+++ b/BlenderMalt/MaltNodes/MaltSocket.py
@@ -26,8 +26,9 @@ def on_type_update(self, context):
default_initialization: bpy.props.StringProperty(default='',
options={'LIBRARY_EDITABLE'}, override={'LIBRARY_OVERRIDABLE'})
- show_in_material_panel: bpy.props.BoolProperty(default=True,
- options={'LIBRARY_EDITABLE'}, override={'LIBRARY_OVERRIDABLE'})
+ # Declared below, in register()
+ #show_in_material_panel: bpy.props.BoolProperty(default=True,
+ # options={'LIBRARY_EDITABLE'}, override={'LIBRARY_OVERRIDABLE'})
active: bpy.props.BoolProperty(default=True,
options={'LIBRARY_EDITABLE'}, override={'LIBRARY_OVERRIDABLE'})
@@ -80,6 +81,8 @@ def get_linked_internal(socket):
return None
else:
link = socket.links[0]
+ if link.is_muted == True:
+ return None
linked = link.to_socket if socket.is_output else link.from_socket
if isinstance(linked.node, bpy.types.NodeReroute):
sockets = linked.node.inputs if linked.is_output else linked.node.outputs
@@ -144,6 +147,11 @@ def draw_color(self, context, node):
def register():
for _class in classes: bpy.utils.register_class(_class)
+
+ #Declare MaltSocket.show_in_material_panel
+ preferences = bpy.context.preferences.addons['BlenderMalt'].preferences
+ preferences.update_show_sockets(None)
+
def unregister():
for _class in reversed(classes): bpy.utils.unregister_class(_class)
diff --git a/BlenderMalt/MaltPipeline.py b/BlenderMalt/MaltPipeline.py
index b5bdf8d8..2bd52bb1 100644
--- a/BlenderMalt/MaltPipeline.py
+++ b/BlenderMalt/MaltPipeline.py
@@ -112,7 +112,7 @@ def update_pipeline_settings(self, context):
set=malt_path_setter('plugins_dir'), get=malt_path_getter('plugins_dir'),
options={'LIBRARY_EDITABLE'}, override={'LIBRARY_OVERRIDABLE'})
- viewport_bit_depth : bpy.props.EnumProperty(items=[('8', '8', ''),('32', '32', '')],
+ viewport_bit_depth : bpy.props.EnumProperty(items=[('8', '8', ''),('16', '16', ''),('32', '32', '')],
name="Bit Depth (Viewport)", update=update_pipeline_settings,
options={'LIBRARY_EDITABLE'}, override={'LIBRARY_OVERRIDABLE'})
graph_types : bpy.props.CollectionProperty(type=bpy.types.PropertyGroup,
diff --git a/BlenderMalt/MaltRenderEngine.py b/BlenderMalt/MaltRenderEngine.py
index 35e3cd5e..8329a102 100644
--- a/BlenderMalt/MaltRenderEngine.py
+++ b/BlenderMalt/MaltRenderEngine.py
@@ -1,4 +1,5 @@
import ctypes, time, platform
+import xxhash
import bpy
from mathutils import Vector, Matrix, Quaternion
from Malt import Scene
@@ -187,7 +188,7 @@ def add_object(obj, matrix, id):
for obj in depsgraph.objects:
if is_f12 or obj.visible_in_viewport_get(context.space_data):
- id = abs(hash(obj.name_full)) % (2**16)
+ id = xxhash.xxh3_64_intdigest(obj.name_full.encode()) % (2**16)
add_object(obj, obj.matrix_world, id)
for instance in depsgraph.object_instances:
@@ -354,6 +355,9 @@ def view_draw(self, context, depsgraph):
texture_format = GL.GL_RGBA8
if GL.glGetInternalformativ(GL.GL_TEXTURE_2D, texture_format, GL.GL_READ_PIXELS, 1) != GL.GL_ZERO:
data_format = GL.glGetInternalformativ(GL.GL_TEXTURE_2D, texture_format, GL.GL_TEXTURE_IMAGE_TYPE, 1)
+ elif self.bridge.viewport_bit_depth == 16:
+ data_format = GL.GL_HALF_FLOAT
+ texture_format = GL.GL_RGBA16F
render_texture = Texture(resolution, texture_format, data_format, pixels.buffer(), mag_filter=mag_filter)
diff --git a/BlenderMalt/MaltTextures.py b/BlenderMalt/MaltTextures.py
index abac8fa1..cc1e0a4a 100644
--- a/BlenderMalt/MaltTextures.py
+++ b/BlenderMalt/MaltTextures.py
@@ -14,7 +14,7 @@ def __load_texture(texture):
w,h = texture.size
channels = int(texture.channels)
size = w*h*channels
- sRGB = texture.colorspace_settings.name == 'sRGB' and texture.use_generated_float == False
+ sRGB = texture.colorspace_settings.name == 'sRGB' and texture.is_float == False
if size == 0:
return True
diff --git a/BlenderMalt/__init__.py b/BlenderMalt/__init__.py
index cf959a7d..64a06d04 100644
--- a/BlenderMalt/__init__.py
+++ b/BlenderMalt/__init__.py
@@ -2,7 +2,7 @@
"name": "BlenderMalt",
"description" : "Extensible Python Render Engine",
"author" : "Miguel Pozo",
- "version": (1,0,0,'beta.2','Release'),
+ "version": (1,0,0,'beta.3','Release'),
"blender" : (3, 2, 0),
"doc_url": "https://malt3d.com",
"tracker_url": "https://github.com/bnpr/Malt/issues/new/choose",
@@ -34,7 +34,8 @@ class Preferences(bpy.types.AddonPreferences):
# this must match the addon name
bl_idname = __package__
- setup_vs_code : bpy.props.BoolProperty(name="Auto setup VSCode", default=True, description="Setups a VSCode project on your .blend file folder")
+ setup_vs_code : bpy.props.BoolProperty(name="Auto setup VSCode", default=True,
+ description="Setups a VSCode project on your .blend file folder")
renderdoc_path : bpy.props.StringProperty(name="RenderDoc Path", subtype='FILE_PATH',
set=malt_path_setter('renderdoc_path'), get=malt_path_getter('renderdoc_path'))
@@ -47,11 +48,20 @@ class Preferences(bpy.types.AddonPreferences):
render_fps_cap : bpy.props.IntProperty(name="Max Viewport Render Framerate", default=30)
+ def update_show_sockets(self, context):
+ from BlenderMalt.MaltNodes.MaltSocket import MaltSocket
+ MaltSocket.show_in_material_panel = bpy.props.BoolProperty(default=self.show_sockets,
+ options={'LIBRARY_EDITABLE'}, override={'LIBRARY_OVERRIDABLE'})
+
+ show_sockets : bpy.props.BoolProperty(name="Show sockets in Material Panel", default=True,
+ update=update_show_sockets, description="Show node socket properties in the Material Panel by default")
+
def update_debug_mode(self, context):
if context.scene.render.engine == 'MALT':
context.scene.world.malt.update_pipeline(context)
- debug_mode : bpy.props.BoolProperty(name="Debug Mode", default=False, update=update_debug_mode, description="Developers only. Do not touch !!!")
+ debug_mode : bpy.props.BoolProperty(name="Debug Mode", default=False, update=update_debug_mode,
+ description="Developers only. Do not touch !!!")
def draw(self, context):
layout = self.layout
@@ -68,9 +78,10 @@ def draw(self, context):
row.operator('wm.path_open', text="Open Session Log")
layout.prop(self, "plugins_dir")
+ layout.prop(self, "show_sockets")
+ layout.prop(self, "render_fps_cap")
layout.prop(self, "setup_vs_code")
layout.prop(self, "renderdoc_path")
- layout.prop(self, "render_fps_cap")
layout.label(text='Developer Settings :')
layout.prop(self, "debug_mode")
layout.prop(self, "docs_path")
diff --git a/Bridge/Client_API.py b/Bridge/Client_API.py
index ddaddd33..135d926b 100644
--- a/Bridge/Client_API.py
+++ b/Bridge/Client_API.py
@@ -259,8 +259,11 @@ def render(self, viewport_id, resolution, scene, scene_update, renderdoc_capture
from itertools import chain
for key, texture_format in chain(self.render_outputs.items(), AOVs.items()):
buffer_type = ctypes.c_float
- if viewport_id != 0 and self.viewport_bit_depth == 8:
- buffer_type = ctypes.c_byte
+ if viewport_id != 0:
+ if self.viewport_bit_depth == 8:
+ buffer_type = ctypes.c_byte
+ elif self.viewport_bit_depth == 16:
+ buffer_type = ctypes.c_ushort
w,h = resolution
self.render_buffers[viewport_id][key] = self.get_shared_buffer(buffer_type, w*h*4)
if viewport_id != 0: #viewport render
diff --git a/Bridge/Server.py b/Bridge/Server.py
index 4c99d848..f3a49db6 100644
--- a/Bridge/Server.py
+++ b/Bridge/Server.py
@@ -169,6 +169,12 @@ def setup(self, new_buffers, resolution, scene, scene_update, renderdoc_capture)
self.final_texture = Texture(resolution, GL_RGBA8, GL_UNSIGNED_BYTE, pixel_format=GL_RGBA)
self.final_texture.channel_size = 1
self.final_target = RenderTarget([self.final_texture])
+ elif self.bit_depth == 16:
+ self.final_texture = Texture(resolution, GL_RGBA16F)
+ self.final_target = RenderTarget([self.final_texture])
+ elif self.bit_depth == 32:
+ self.final_texture = Texture(resolution, GL_RGBA32F)
+ self.final_target = RenderTarget([self.final_texture])
if new_buffers:
self.buffers = new_buffers
@@ -202,7 +208,7 @@ def render(self):
if self.needs_more_samples:
result = self.pipeline.render(self.resolution, self.scene, self.is_final_render, self.is_new_frame)
- if self.final_texture:
+ if self.final_texture.internal_format != result['COLOR'].internal_format:
self.pipeline.copy_textures(self.final_target, [result['COLOR']])
result = { 'COLOR' : self.final_texture }
self.is_new_frame = False
diff --git a/Malt/GL/GL.py b/Malt/GL/GL.py
index 4708ee52..807f1960 100644
--- a/Malt/GL/GL.py
+++ b/Malt/GL/GL.py
@@ -11,8 +11,17 @@
#For some reason PyOpenGL doesnt support the most common depth/stencil buffer by default ???
#https://sourceforge.net/p/pyopengl/bugs/223/
from OpenGL import images
- images.TYPE_TO_ARRAYTYPE[ GL_UNSIGNED_INT_24_8 ] = GL_UNSIGNED_INT
- images.TIGHT_PACK_FORMATS[ GL_UNSIGNED_INT_24_8 ] = 4
+ images.TYPE_TO_ARRAYTYPE[GL_UNSIGNED_INT_24_8] = GL_UNSIGNED_INT
+ images.TIGHT_PACK_FORMATS[GL_UNSIGNED_INT_24_8] = 4
+ images.TYPE_TO_ARRAYTYPE[GL_HALF_FLOAT] = GL_HALF_FLOAT
+ from OpenGL import arrays
+ if arrays.ADT:
+ arrays.GL_CONSTANT_TO_ARRAY_TYPE[GL_HALF_FLOAT] = arrays.ADT(GL_HALF_FLOAT, GLhalfARB)
+ else:
+ class GLhalfFloatArray(ArrayDatatype, ctypes.POINTER(GLhalfARB)):
+ baseType = GLhalfARB
+ typeConstant = GL_HALF_FLOAT
+ arrays.GL_CONSTANT_TO_ARRAY_TYPE[GL_HALF_FLOAT] = GLhalfFloatArray
NULL = None
GL_ENUMS = {}
@@ -56,6 +65,8 @@ def gl_buffer(type, size, data=None):
GL_UNSIGNED_SHORT : GLushort,
GL_INT : GLint,
GL_UNSIGNED_INT : GLuint,
+ #GL_HALF_FLOAT : GLhalfARB,
+ GL_HALF_FLOAT : GLfloat,
GL_FLOAT : GLfloat,
GL_DOUBLE : GLdouble,
GL_BOOL : GLboolean,
diff --git a/Malt/GL/RenderTarget.py b/Malt/GL/RenderTarget.py
index 9c8f5672..a0d2abe5 100644
--- a/Malt/GL/RenderTarget.py
+++ b/Malt/GL/RenderTarget.py
@@ -59,6 +59,7 @@ def clear(self, colors=[], depth=None, stencil=None):
GL_INT : glClearBufferiv,
GL_UNSIGNED_INT : glClearBufferuiv,
GL_FLOAT : glClearBufferfv,
+ GL_HALF_FLOAT : glClearBufferfv,
GL_UNSIGNED_BYTE : glClearBufferfv,
}
target = self.targets[i]
diff --git a/Malt/GL/Shader.py b/Malt/GL/Shader.py
index a8241639..d3122aa4 100644
--- a/Malt/GL/Shader.py
+++ b/Malt/GL/Shader.py
@@ -526,9 +526,12 @@ def glsl_reflection(code, root_paths=[]):
except:
pass
- def fix_paths(dic):
+ def handle_paths(dic):
for e in dic.values():
path = e['file']
+ if '.internal.' in path or '__internal__' in path:
+ if 'internal' not in e['meta'].keys():
+ e['meta']['internal'] = True
path = os.path.normpath(path)
for root_path in root_paths:
try:
@@ -538,8 +541,8 @@ def fix_paths(dic):
except: pass
e['file'] = path.replace('\\','/')
- fix_paths(reflection['structs'])
- fix_paths(reflection['functions'])
+ handle_paths(reflection['structs'])
+ handle_paths(reflection['functions'])
functions = {}
for key, function in reflection['functions'].items():
diff --git a/Malt/GL/Texture.py b/Malt/GL/Texture.py
index c8dd8bd9..86eef3bd 100644
--- a/Malt/GL/Texture.py
+++ b/Malt/GL/Texture.py
@@ -172,7 +172,8 @@ def __del__(self):
def internal_format_to_data_format(internal_format):
name = GL_ENUMS[internal_format]
table = {
- 'F' : GL_FLOAT,
+ '32F' : GL_FLOAT,
+ '16F' : GL_HALF_FLOAT,
'UI' : GL_UNSIGNED_INT,
'I' : GL_INT,
}
@@ -197,6 +198,7 @@ def internal_format_to_sampler_type(internal_format):
table = {
GL_UNSIGNED_BYTE : 'sampler2D',
GL_FLOAT : 'sampler2D',
+ GL_HALF_FLOAT : 'sampler2D',
GL_INT : 'isampler2D',
GL_UNSIGNED_INT : 'usampler2D'
}
diff --git a/Malt/Nodes/Unpack8bitTextures.py b/Malt/Nodes/Unpack8bitTextures.py
deleted file mode 100644
index 3887e428..00000000
--- a/Malt/Nodes/Unpack8bitTextures.py
+++ /dev/null
@@ -1,64 +0,0 @@
-from Malt.PipelineNode import PipelineNode
-from Malt.PipelineParameters import Parameter, Type, MaterialParameter
-
-_UNPACK_SRC = """
-#include "Passes/Unpack8bitTextures.glsl"
-"""
-_UNPACK_SHADER = None
-
-class Unpack8bitTextures(PipelineNode):
-
- """
- Unpacks up to 4 textures packed into a single one using the *pack_8bit* shader function.
- *(Useful when a shader needs to output more than 8 textures)*
- """
-
- def __init__(self, pipeline):
- self.pipeline = pipeline
- self.resolution = None
- self.texture_targets = [None]*4
- self.render_target = None
-
- @classmethod
- def reflect_inputs(cls):
- return {
- 'Packed Texture' : Parameter('usampler2D', Type.OTHER)
- }
-
- @classmethod
- def reflect_outputs(cls):
- return {
- 'A' : Parameter('', Type.TEXTURE),
- 'B' : Parameter('', Type.TEXTURE),
- 'C' : Parameter('', Type.TEXTURE),
- 'D' : Parameter('', Type.TEXTURE),
- }
-
- def execute(self, parameters):
- from Malt.GL import GL
- from Malt.GL.Texture import Texture
- from Malt.GL.RenderTarget import RenderTarget
-
- if self.pipeline.resolution != self.resolution:
- for i in range(4):
- #TODO: Doesn't work with GL_RGBA?
- self.texture_targets[i] = Texture(self.pipeline.resolution, GL.GL_RGBA16F)
- self.render_target = RenderTarget(self.texture_targets)
- self.resolution = self.pipeline.resolution
-
- self.render_target.clear([(0,0,0,0)]*4)
-
- global _UNPACK_SHADER
- if _UNPACK_SHADER is None:
- _UNPACK_SHADER = self.pipeline.compile_shader_from_source(_UNPACK_SRC)
-
- _UNPACK_SHADER.textures['IN_PACKED'] = parameters['Packed Texture']
- self.pipeline.draw_screen_pass(_UNPACK_SHADER, self.render_target, blend = False)
-
- parameters['A'] = self.texture_targets[0]
- parameters['B'] = self.texture_targets[1]
- parameters['C'] = self.texture_targets[2]
- parameters['D'] = self.texture_targets[3]
-
-
-NODE = Unpack8bitTextures
diff --git a/Malt/Pipeline.py b/Malt/Pipeline.py
index 662cdc3e..fcc9c767 100644
--- a/Malt/Pipeline.py
+++ b/Malt/Pipeline.py
@@ -1,6 +1,5 @@
-import os
+import math, os, ctypes
from os import path
-import ctypes
from Malt.Utils import LOG
@@ -305,7 +304,10 @@ def build_scene_batches(self, objects):
if i == batch_length or instances_count == max_instances:
local_models = ((ctypes.c_float * 16) * instances_count).from_address(ctypes.addressof(models))
- local_ids = (ctypes.c_uint * instances_count).from_address(ctypes.addressof(ids))
+ # IDs are stored as uvec4, so we make sure the buffer count is a multiple of 4,
+ # since some drivers will only bind a full uvec4 (see issue #319)
+ id_buffer_count = math.ceil(instances_count/4)*4
+ local_ids = (ctypes.c_uint * id_buffer_count).from_address(ctypes.addressof(ids))
models_UBO = UBO()
ids_UBO = UBO()
diff --git a/Malt/PipelineGraph.py b/Malt/PipelineGraph.py
index 1f1f7acf..6213fef0 100644
--- a/Malt/PipelineGraph.py
+++ b/Malt/PipelineGraph.py
@@ -71,12 +71,8 @@ def get_serializable_copy(self):
class GLSLGraphIO(PipelineGraphIO):
- COMMON_INPUT_TYPES = ['sampler2D', 'usampler2D', 'isampler2D']
- COMMON_OUTPUT_TYPES = [
- 'float','vec2','vec3','vec4',
- 'uint','uvec2','uvec3','uvec4',
- 'int','ivec2','ivec3','ivec4',
- ]
+ COMMON_INPUT_TYPES = ['sampler2D']
+ COMMON_OUTPUT_TYPES = ['float','vec2','vec3','vec4']
def __init__(self, name, define = None, io_wrap=None, dynamic_input_types = [], dynamic_output_types = [],
default_dynamic_inputs = {}, default_dynamic_outputs = {}, shader_type=None, custom_output_start_index=0):
diff --git a/Malt/Pipelines/NPR_Pipeline/NPR_Pipeline.py b/Malt/Pipelines/NPR_Pipeline/NPR_Pipeline.py
index e4fff924..d063a4fb 100644
--- a/Malt/Pipelines/NPR_Pipeline/NPR_Pipeline.py
+++ b/Malt/Pipelines/NPR_Pipeline/NPR_Pipeline.py
@@ -177,7 +177,7 @@ def setup_graphs(self):
name='Light',
graph_type=GLSLPipelineGraph.INTERNAL_GRAPH,
default_global_scope=_LIGHT_SHADER_HEADER,
- default_shader_src="void LIGHT_SHADER(LightShaderInput I, inout LightShaderOutput O) { }",
+ default_shader_src="void LIGHT_SHADER(vec3 relative_coordinates, vec3 uvw, inout vec3 color, inout float attenuation) { }",
graph_io=[
GLSLGraphIO(
name='LIGHT_SHADER',
diff --git a/Malt/Pipelines/NPR_Pipeline/Nodes/Render/SceneLighting.py b/Malt/Pipelines/NPR_Pipeline/Nodes/Render/SceneLighting.py
index 58fbc138..0208e716 100644
--- a/Malt/Pipelines/NPR_Pipeline/Nodes/Render/SceneLighting.py
+++ b/Malt/Pipelines/NPR_Pipeline/Nodes/Render/SceneLighting.py
@@ -66,6 +66,11 @@ def execute(self, parameters):
sample_offset = self.pipeline.get_sample(scene.world_parameters['Samples.Width'])
opaque_batches, transparent_batches = self.pipeline.get_scene_batches(scene)
+ inputs['Spot Resolution'] = max(8, inputs['Spot Resolution'])
+ inputs['Sun Resolution'] = max(8, inputs['Sun Resolution'])
+ inputs['Point Resolution'] = max(8, inputs['Point Resolution'])
+ inputs['Sun CSM Count'] = max(1, inputs['Sun CSM Count'])
+
self.lights_buffer.load(scene,
inputs['Spot Resolution'],
inputs['Sun Resolution'],
diff --git a/Malt/Pipelines/NPR_Pipeline/Shaders/NPR_LightShader.glsl b/Malt/Pipelines/NPR_Pipeline/Shaders/NPR_LightShader.glsl
index 0712079e..9d05a4ea 100644
--- a/Malt/Pipelines/NPR_Pipeline/Shaders/NPR_LightShader.glsl
+++ b/Malt/Pipelines/NPR_Pipeline/Shaders/NPR_LightShader.glsl
@@ -4,19 +4,6 @@
uniform int LIGHT_INDEX;
-struct LightShaderInput
-{
- Light L;
- LitSurface LS;
- vec3 light_space_position;
- vec3 light_uv;
-};
-
-struct LightShaderOutput
-{
- vec3 color;
-};
-
#ifdef VERTEX_SHADER
void main()
{
@@ -30,7 +17,7 @@ uniform sampler2D IN_DEPTH;
layout (location = 0) out vec3 RESULT;
-void LIGHT_SHADER(LightShaderInput I, inout LightShaderOutput O);
+void LIGHT_SHADER(vec3 relative_coordinates, vec3 uvw, inout vec3 color, inout float attenuation);
void main()
{
@@ -43,39 +30,50 @@ void main()
Light L = LIGHTS.lights[LIGHT_INDEX];
LitSurface LS = lit_surface(POSITION, vec3(0), L, false);
- vec3 light_space;
- vec3 light_uv;
+ vec3 light_space = vec3(0);
+ vec3 uvw = vec3(0);
if(L.type == LIGHT_SPOT)
{
- light_space = project_point(LIGHTS.spot_matrices[L.type_index], POSITION);
- light_uv = light_space * 0.5 + 0.5;
+ light_space = project_point(LIGHTS.spot_matrices[L.type_index], POSITION);
+ uvw.xy = light_space.xy * 0.5 + 0.5;
}
if(L.type == LIGHT_SUN)
{
- mat4 matrix = LIGHTS.sun_matrices[L.type_index*LIGHTS.cascades_count];
- matrix[3] = vec4(L.position, 1);
- light_space = project_point(matrix, POSITION);
- light_uv = light_space;
+ vec3 z = L.direction;
+ vec3 c = vec3(0,0,1);
+ if(abs(dot(z, c)) < 1.0)
+ {
+ vec3 x = normalize(cross(c, z));
+ vec3 y = normalize(cross(x, z));
+ mat3 rotation = mat3(x,y,z);
+ mat4 m = mat4_translation(L.position) * mat4(rotation);
+ m = inverse(m);
+
+ light_space = transform_point(m, POSITION);
+ }
+ else
+ {
+ light_space = POSITION;
+ light_space -= L.position;
+ }
+
+ uvw.xy = light_space.xy;
}
if(L.type == LIGHT_POINT)
{
- light_space = POSITION - L.position;
- light_uv = normalize(POSITION - L.position);
+ light_space = POSITION - L.position;
+ light_space /= L.radius;
+
+ uvw = normalize(light_space);
}
- LightShaderInput I;
- I.L = L;
- I.LS = LS;
- I.light_space_position = light_space;
- I.light_uv = light_uv;
-
- LightShaderOutput O;
- O.color = LS.light_color;
+ vec3 color = L.color;
+ float attenuation = LS.P;
- LIGHT_SHADER(I,O);
+ LIGHT_SHADER(light_space, uvw, color, attenuation);
- RESULT = O.color;
+ RESULT = color * attenuation;
}
#endif //PIXEL_SHADER
diff --git a/Malt/Shaders/Node Utils/vec2.glsl b/Malt/Shaders/Node Utils/vec2.glsl
index 5568efd0..dc8f05df 100644
--- a/Malt/Shaders/Node Utils/vec2.glsl
+++ b/Malt/Shaders/Node Utils/vec2.glsl
@@ -25,6 +25,8 @@ vec2 vec2_max(vec2 a, vec2 b){ return max(a,b); }
vec2 vec2_mix(vec2 a, vec2 b, vec2 factor){ return mix(a,b,factor); }
vec2 vec2_mix_float(vec2 a, vec2 b, float factor){ return mix(a,b,factor); }
+vec2 vec2_normalize(vec2 v){ return normalize(v); }
+
float vec2_length(vec2 v){ return length(v); }
float vec2_distance(vec2 a, vec2 b){ return distance(a,b); }
float vec2_dot_product(vec2 a, vec2 b){ return dot(a,b); }
diff --git a/Malt/Shaders/Node Utils/vec3.glsl b/Malt/Shaders/Node Utils/vec3.glsl
index f29069c0..4ddd4b6c 100644
--- a/Malt/Shaders/Node Utils/vec3.glsl
+++ b/Malt/Shaders/Node Utils/vec3.glsl
@@ -44,6 +44,9 @@ vec3 vec3_mix(vec3 a, vec3 b, vec3 factor){ return mix(a,b,factor); }
/*META @a: subtype=Vector; @b: subtype=Vector;*/
vec3 vec3_mix_float(vec3 a, vec3 b, float factor){ return mix(a,b,factor); }
+/*META @v: subtype=Vector;*/
+vec3 vec3_normalize(vec3 v){ return normalize(v); }
+
/*META @v: subtype=Vector;*/
float vec3_length(vec3 v){ return length(v); }
/*META @a: subtype=Vector; @b: subtype=Vector;*/
diff --git a/Malt/Shaders/Node Utils/vec4.glsl b/Malt/Shaders/Node Utils/vec4.glsl
index 2c08ec0c..ba64c341 100644
--- a/Malt/Shaders/Node Utils/vec4.glsl
+++ b/Malt/Shaders/Node Utils/vec4.glsl
@@ -44,6 +44,9 @@ vec4 vec4_mix(vec4 a, vec4 b, vec4 factor){ return mix(a,b,factor); }
/*META @a: subtype=Vector; @b: subtype=Vector;*/
vec4 vec4_mix_float(vec4 a, vec4 b, float factor){ return mix(a,b,factor); }
+/*META @v: subtype=Vector;*/
+vec4 vec4_normalize(vec4 v){ return normalize(v); }
+
/*META @v: subtype=Vector;*/
float vec4_length(vec4 v){ return length(v); }
/*META @a: subtype=Vector; @b: subtype=Vector;*/
diff --git a/Malt/Shaders/Procedural/Fractal_Noise.glsl b/Malt/Shaders/Procedural/Fractal_Noise.glsl
index f3d19ea4..f9796664 100644
--- a/Malt/Shaders/Procedural/Fractal_Noise.glsl
+++ b/Malt/Shaders/Procedural/Fractal_Noise.glsl
@@ -11,16 +11,19 @@
vec4 fractal_noise_ex(vec4 coord, int octaves, bool tile, vec4 tile_size)
{
vec4 result = vec4(0);
- float strength = 0.5;
+ float strength = 1.0;
+ float total_strength = 0.0;
for (int i = 0; i < octaves; i++)
- {
- result += strength * noise_ex(coord, tile, tile_size);
+ {
+ vec4 noise = noise_ex(coord, tile, tile_size);
+ result += strength * noise;
+ total_strength += strength;
+ strength *= 0.5;
coord *= 2.0;
tile_size *= 2.0;
- strength *= 0.5;
}
- return result;
+ return result / total_strength;
}
diff --git a/README.md b/README.md
index e085418f..07bd8478 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
Malt is a fully customizable real-time rendering framework for animation and illustration.
It's aimed at advanced users and technical artists who want more control over their workflow and/or their art style, with special care put into the needs of stylized non photorealistic rendering.
-[Docs](https://malt3d.com) | [Forums & Support](https://github.com/bnpr/Malt/discussions) | [Bug Reports](https://github.com/bnpr/Malt/issues) | [Twitter](https://twitter.com/pragma37) | [Patreon](https://patreon.com/pragma37)
+[Download](#install) | [Docs](https://malt3d.com) | [Forums & Support](https://github.com/bnpr/Malt/discussions) | [Bug Reports](https://github.com/bnpr/Malt/issues) | [Twitter](https://twitter.com/pragma37) | [Patreon](https://patreon.com/pragma37)
## Features
@@ -20,7 +20,8 @@ It's aimed at advanced users and technical artists who want more control over th
## Current State
-The 1.0 Release is almost ready, take a look at the [1.0 Preview](https://github.com/bnpr/Malt/discussions/231) and leave your feedback.
+We've been working on a full redesign of the default nodes before the 1.0 Release.
+[Give it try and leave your feedback](https://github.com/bnpr/Malt/discussions/382).
Malt is software agnostic, but Blender is the only integration planned right now.
@@ -28,6 +29,7 @@ Malt is software agnostic, but Blender is the only integration planned right now
- OpenGL 4.1+
- Blender 3.2
+- Windows or Linux
> A dedicated Nvidia or AMD graphics card is highly recomended.
@@ -48,10 +50,8 @@ Malt is software agnostic, but Blender is the only integration planned right now
## First steps
-To learn how to use *Malt*, check [this playlist](https://www.youtube.com/playlist?list=PLiN2BGdwwlLqbks8h5MohvH0Xd0Zql_Sg) and the [Sample Files](https://github.com/bnpr/Malt/discussions/94).
-
-> Malt allows to use different settings for *Viewport Preview*, *Viewport Render* and *F12 Render*.
-> By default, the *Viewport Preview* should be faster than the *Viewport Render* mode.
+To learn how to use *Malt*, check the [Docs](https://malt3d.com/Documentation/Getting%20Started/), this [playlist](https://www.youtube.com/playlist?list=PLiN2BGdwwlLqbks8h5MohvH0Xd0Zql_Sg) and the [Sample Files](https://github.com/bnpr/Malt/discussions/94).
+The [Q&A section](https://github.com/bnpr/Malt/discussions/categories/q-a) is full of info as well.
## Developer Documentation
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 00000000..c07b0c6b
--- /dev/null
+++ b/__init__.py
@@ -0,0 +1,20 @@
+# Some people are used to download the zipped repo from Github to install Blender addons.
+# This file is just to redirect those users to the right path. It's not distributed in the actual addon.
+
+bl_info = {
+ "name": "Oops! You downloaded the wrong BlenderMalt file.",
+ "description" : "Please, read the install intructions on Github or malt3d.com",
+ "author" : "Miguel Pozo",
+ "version": (1,0,0),
+ "blender" : (3, 0, 0),
+ "doc_url": "https://malt3d.com/documentation/getting started/#install",
+ "tracker_url": "https://github.com/bnpr/Malt#install",
+ "category": "Render"
+}
+
+def register():
+ pass
+
+def unregister():
+ pass
+
diff --git a/docs/Documentation/Plugins.md b/docs/Documentation/Plugins.md
index f2d21b11..e6ecddc9 100644
--- a/docs/Documentation/Plugins.md
+++ b/docs/Documentation/Plugins.md
@@ -2,6 +2,7 @@
Render pipelines can be customized through plugins.
Plugins can:
+
- Add new node libraries to *Pipeline Graphs*.
- Add new *Pipeline Parameters*.
- Add new *PipelineGraph types*.
diff --git a/docs/Documentation/Settings.md b/docs/Documentation/Settings.md
index 45b75a0a..62c8a43e 100644
--- a/docs/Documentation/Settings.md
+++ b/docs/Documentation/Settings.md
@@ -8,12 +8,14 @@
>Opens the current session log in a text editor.
- **Global Plugins**
>The path to the *plugins* folder. See [Plugins](../Plugins) for more info.
+- **Show sockets in Material Panel**
+>Show node socket properties in the Material Panel by default.
+- **Max Viewport Render Framerate**
+>Framerate cap for the viewport. Limiting *Blender* framerate can improve *Malt* performance and animation playback stability. Set it to 0 to disable it.
- **Auto setup VSCode**
>On file save, setups a VSCode project on your *.blend* file folder.
- **RenderDoc Path**
>Path to the **renderdoccmd** executable, for [RenderDoc](https://renderdoc.org/) debugging.
-- **Max Viewport Render Framerate**
->Framerate cap for the viewport. Limiting *Blender* framerate can improve *Malt* performance and animation playback stability. Set it to 0 to disable it.
- **Debug Mode**
>Include debug info in the *Session Logs*. Enabling it increases the log sizes and can negatively affect performance, don't enable it unless a developer asks you for it in a bug report.
diff --git a/docs/reference/Light-graph.md b/docs/reference/Light-graph.md
index f59b3e4a..86ebeb00 100644
--- a/docs/reference/Light-graph.md
+++ b/docs/reference/Light-graph.md
@@ -1438,6 +1438,14 @@ Blends the blend color as a layer over the base color.
- **Outputs**
- **result** *: ( vec2 )*
---
+### **vec2_normalize**
+>vec2 vec2_normalize(vec2 v)
+
+- **Inputs**
+ - **v** *: ( vec2 )*
+- **Outputs**
+ - **result** *: ( vec2 )*
+---
### **vec2_length**
>float vec2_length(vec2 v)
@@ -1679,6 +1687,14 @@ Blends the blend color as a layer over the base color.
- **Outputs**
- **result** *: ( vec3 )*
---
+### **vec3_normalize**
+>vec3 vec3_normalize(vec3 v)
+
+- **Inputs**
+ - **v** *: ( vec3 | Vector )*
+- **Outputs**
+ - **result** *: ( vec3 )*
+---
### **vec3_length**
>float vec3_length(vec3 v)
@@ -1931,6 +1947,14 @@ Blends the blend color as a layer over the base color.
- **Outputs**
- **result** *: ( vec4 )*
---
+### **vec4_normalize**
+>vec4 vec4_normalize(vec4 v)
+
+- **Inputs**
+ - **v** *: ( vec4 | Vector )*
+- **Outputs**
+ - **result** *: ( vec4 )*
+---
### **vec4_length**
>float vec4_length(vec4 v)
diff --git a/docs/reference/Mesh-graph.md b/docs/reference/Mesh-graph.md
index 26eb04b7..4e65db13 100644
--- a/docs/reference/Mesh-graph.md
+++ b/docs/reference/Mesh-graph.md
@@ -1741,6 +1741,14 @@ Blends the blend color as a layer over the base color.
- **Outputs**
- **result** *: ( vec2 )*
---
+### **vec2_normalize**
+>vec2 vec2_normalize(vec2 v)
+
+- **Inputs**
+ - **v** *: ( vec2 )*
+- **Outputs**
+ - **result** *: ( vec2 )*
+---
### **vec2_length**
>float vec2_length(vec2 v)
@@ -1982,6 +1990,14 @@ Blends the blend color as a layer over the base color.
- **Outputs**
- **result** *: ( vec3 )*
---
+### **vec3_normalize**
+>vec3 vec3_normalize(vec3 v)
+
+- **Inputs**
+ - **v** *: ( vec3 | Vector )*
+- **Outputs**
+ - **result** *: ( vec3 )*
+---
### **vec3_length**
>float vec3_length(vec3 v)
@@ -2234,6 +2250,14 @@ Blends the blend color as a layer over the base color.
- **Outputs**
- **result** *: ( vec4 )*
---
+### **vec4_normalize**
+>vec4 vec4_normalize(vec4 v)
+
+- **Inputs**
+ - **v** *: ( vec4 | Vector )*
+- **Outputs**
+ - **result** *: ( vec4 )*
+---
### **vec4_length**
>float vec4_length(vec4 v)
diff --git a/docs/reference/Render Layer-graph.md b/docs/reference/Render Layer-graph.md
index 7893f31a..01646ccc 100644
--- a/docs/reference/Render Layer-graph.md
+++ b/docs/reference/Render Layer-graph.md
@@ -27,18 +27,6 @@ Performs anti-aliasing by accumulating multiple render samples into a single tex
- **Outputs**
- **Color** *: ( Texture )*
---
-### **Unpack8bitTextures**
-Unpacks up to 4 textures packed into a single one using the *pack_8bit* shader function.
-*(Useful when a shader needs to output more than 8 textures)*
-
-- **Inputs**
- - **Packed Texture** *: ( usampler2D )*
-- **Outputs**
- - **A** *: ( Texture )*
- - **B** *: ( Texture )*
- - **C** *: ( Texture )*
- - **D** *: ( Texture )*
----
### **MainPass**
>Graph Type / Pass : *Mesh / MAIN_PASS_PIXEL_SHADER*
diff --git a/docs/reference/Render-graph.md b/docs/reference/Render-graph.md
index 3f7e30de..453cfa50 100644
--- a/docs/reference/Render-graph.md
+++ b/docs/reference/Render-graph.md
@@ -27,18 +27,6 @@ Performs anti-aliasing by accumulating multiple render samples into a single tex
- **Outputs**
- **Color** *: ( Texture )*
---
-### **Unpack8bitTextures**
-Unpacks up to 4 textures packed into a single one using the *pack_8bit* shader function.
-*(Useful when a shader needs to output more than 8 textures)*
-
-- **Inputs**
- - **Packed Texture** *: ( usampler2D )*
-- **Outputs**
- - **A** *: ( Texture )*
- - **B** *: ( Texture )*
- - **C** *: ( Texture )*
- - **D** *: ( Texture )*
----
### **RenderLayers**
>Graph Type / Pass : *Render Layer / Render Layer*
diff --git a/docs/reference/Screen-graph.md b/docs/reference/Screen-graph.md
index 996ca7f5..e21d247e 100644
--- a/docs/reference/Screen-graph.md
+++ b/docs/reference/Screen-graph.md
@@ -1652,6 +1652,14 @@ Blends the blend color as a layer over the base color.
- **Outputs**
- **result** *: ( vec2 )*
---
+### **vec2_normalize**
+>vec2 vec2_normalize(vec2 v)
+
+- **Inputs**
+ - **v** *: ( vec2 )*
+- **Outputs**
+ - **result** *: ( vec2 )*
+---
### **vec2_length**
>float vec2_length(vec2 v)
@@ -1893,6 +1901,14 @@ Blends the blend color as a layer over the base color.
- **Outputs**
- **result** *: ( vec3 )*
---
+### **vec3_normalize**
+>vec3 vec3_normalize(vec3 v)
+
+- **Inputs**
+ - **v** *: ( vec3 | Vector )*
+- **Outputs**
+ - **result** *: ( vec3 )*
+---
### **vec3_length**
>float vec3_length(vec3 v)
@@ -2145,6 +2161,14 @@ Blends the blend color as a layer over the base color.
- **Outputs**
- **result** *: ( vec4 )*
---
+### **vec4_normalize**
+>vec4 vec4_normalize(vec4 v)
+
+- **Inputs**
+ - **v** *: ( vec4 | Vector )*
+- **Outputs**
+ - **result** *: ( vec4 )*
+---
### **vec4_length**
>float vec4_length(vec4 v)
diff --git a/scripts/install_dependencies.py b/scripts/install_dependencies.py
index 5306296c..de7849c8 100644
--- a/scripts/install_dependencies.py
+++ b/scripts/install_dependencies.py
@@ -12,10 +12,10 @@
py_version = str(sys.version_info[0])+str(sys.version_info[1])
malt_dependencies_path = os.path.join(malt_folder, '.Dependencies-{}'.format(py_version))
-dependencies = ['glfw', 'PyOpenGL==3.1.5', 'PyOpenGL_accelerate==3.1.5', 'Pyrr', 'psutil']
+dependencies = ['glfw', 'PyOpenGL', 'PyOpenGL_accelerate', 'Pyrr', 'psutil', 'xxhash']
for dependency in dependencies:
try:
- subprocess.check_call([sys.executable, '-m', 'pip', 'install', dependency, '--target', malt_dependencies_path])
+ subprocess.check_call([sys.executable, '-m', 'pip', 'install', '--upgrade', dependency, '--target', malt_dependencies_path])
except:
print('ERROR: pip install {} failed.'.format(dependency))
import traceback