I would Like to access the position of the element of a color ramp and directly draw that in the panel as a Float Value Slider so whenever the value in that slider is changed it updates in the color ramp.
I have Created a color ramp with:
col_ramp = group.nodes.new(type="ShaderNodeValToRGB")
And then assigned a position to it:
col_ramp.color_ramp.elements.new(0.750)
col_ramp.color_ramp.elements[0].color = (0,0,0,1)
And I have defined and operator and that will only be executed when the button is pressed from the Panel, and What I don't know is how to access that color ramp element.
I have tried this:
position_control = context.Scene.node_tree.col_ramp.color_ramp.elements[0].position
And this:
position_control = bpy.data.materials["TestMat"].node_tree.nodes["col_ramp"].elements[0].position
But finally, this is giving an error in the console like this:
AttributeError: ramp_pos Error: Python script failed, check the message in the system console
And showing error in line:
del bpy.types.Scene.ramp_pos
Reference to the previously asked question by me relating this Drawing Float Property
class Col_ramp_Property(PropertyGroup):
ramp_pos : FloatProperty(
name = "Position",
description = "A float property",
default = 0.75,
min = 0.01,
max = 1.0
)
class TEST_MATERIAL_PT_layout_panel(Panel):
bl_label = "Test Material Node"
bl_category = "Test Material"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
def draw(self, context):
layout = self.layout
position_control = context.Scene.active_object.active_material.node_tree.nodes.col_ramp.color_ramp.elements[0].position
layout.operator("test_material.add_material", icon='IMPORT')
row = layout.row()
row.prop(position_control, "ramp_pos")
classes = (TEST_MATERIAL_OT_add_material, Col_ramp_Property, TEST_MATERIAL_PT_layout_panel)
def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.Scene.ramp_pos = PointerProperty(type=Col_ramp_Property)
def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
del bpy.types.Scene.ramp_pos
if __name__ == "__main__":
register()
Update: I tried doing as in the answer, but this is not working for me, when I tried running this script(written below), it gives this error
TypeError: must be real number, not str Traceback (most recent call last): File "\TEST_MATERIAL.py", line 181, in File "\TEST_MATERIAL.py", line 169, in register ValueError: bpy_struct "Col_ramp_Property" registration error: ramp_pos could not register
Error: Python script failed, check the message in the system console
for knowing the error I tried removing class Col_ramp_Property from classes and in the register and unregister also, and then I got this error -
Traceback (most recent call last): File "\TEST_MATERIAL.py", line 142, in draw AttributeError: 'Object' object has no attribute 'material'
location: :-1
location: :-1
I don't know what I did wrong, can you Please Show me the mistake I made in this -
bl_info = {
"name": "Add Test Material",
"author": "Rakesh Choudhary",
"version": (1, 0),
"blender": (2, 83, 0),
"location": "View3D > Sidebar > Test Material Node",
"description": "Click on the 'Test Material' button to add a material to your object.",
"warning": "",
"wiki_url": "",
"category": "3D View"
}
import bpy
from bpy.types import (
Operator,
Panel,
PropertyGroup,
)
from bpy.props import (
FloatProperty,
PointerProperty,
)
class TEST_MATERIAL_OT_add_material(Operator):
bl_idname = "test_material.add_material"
bl_label = "Add Test Material"
bl_description = "This button will add a material to your object"
def execute(self, context):
self.create_material()
return {'FINISHED'}
def create_material(self):
test_shader_mat = bpy.data.materials.new("TestMat")
mesh = bpy.context.object.data
mesh.materials.clear()
mesh.materials.append(test_shader_mat)
bpy.context.object.active_material.use_nodes = True
for mat in bpy.data.materials:
if "TestMat" in mat.name:
nodes = mat.node_tree.nodes
for node in nodes:
if node.type != 'OUTPUT_MATERIAL': # skip the material output node as we'll need it later
nodes.remove(node)
# Creating Node Group Test_Material
group = bpy.data.node_groups.new(type="ShaderNodeTree", name="Test_Material")
# Creating Group Input
group.inputs.new("NodeSocketColor", "Diffuse Color")
group.inputs.new("NodeSocketColor", "Glossy Color")
group.inputs.new("NodeSocketFloat", "Glossyness")
input_node = group.nodes.new("NodeGroupInput")
input_node.location = (-800, 0)
# Creating Group Output Node
group.outputs.new("NodeSocketShader", "Diffuse Color")
group.outputs.new("NodeSocketShader", "Glossy Color")
group.outputs.new("NodeSocketShader", "Mix Output")
output_node = group.nodes.new("NodeGroupOutput")
output_node.location = (1500, 0)
# Creating Diffuse Node
diffuse_node = group.nodes.new(type='ShaderNodeBsdfDiffuse')
diffuse_node.location = (150, 100)
# Creating Glossy Node
glossy_node = group.nodes.new(type='ShaderNodeBsdfGlossy')
glossy_node.location = (300, 250)
# Creating Mix Shader Node
mix_shader_node = group.nodes.new(type='ShaderNodeMixShader')
mix_shader_node.location = (450, 100)
#Creating Color Ramp ------------------------------------------------------
col_ramp = group.nodes.new(type="ShaderNodeValToRGB")
col_ramp.name = "col_ramp"
col_ramp.location = (400, -300)
col_ramp.color_ramp.elements.remove(col_ramp.color_ramp.elements[0])
col_ramp.color_ramp.elements.new(0.750)
col_ramp.color_ramp.elements[0].color = (0,0,0,1)
col_ramp.color_ramp.elements[1].position = (1.0)
col_ramp.color_ramp.elements[1].color = (1, 1, 1, 1)
# Creating Links Between Nodes----------------------------------------------
group.links.new(diffuse_node.outputs["BSDF"], mix_shader_node.inputs[1])
group.links.new(glossy_node.outputs["BSDF"], mix_shader_node.inputs[2])
group.links.new(input_node.outputs["Diffuse Color"], diffuse_node.inputs[0])
group.links.new(input_node.outputs["Glossy Color"], glossy_node.inputs[0])
group.links.new(input_node.outputs["Glossyness"], glossy_node.inputs[1])
group.links.new(output_node.inputs["Diffuse Color"], diffuse_node.outputs[0])
group.links.new(output_node.inputs["Glossy Color"], glossy_node.outputs[0])
group.links.new(output_node.inputs["Mix Output"], mix_shader_node.outputs[0])
group.links.new(col_ramp.outputs["Color"], mix_shader_node.inputs[0])
# Putting Node Group to the node editor
tree = bpy.context.object.active_material.node_tree
group_node = tree.nodes.new("ShaderNodeGroup")
group_node.node_tree = group
group_node.location = (-40, 300)
group_node.use_custom_color = True
group_node.color = (1, 0.341, 0.034)
group_node.width = 250
shader_node_output_material_node = tree.nodes["Material Output"]
links = tree.links
links.new(group_node.outputs[0], shader_node_output_material_node.inputs[0])
#Material ends here------------------------------
class Col_ramp_Property(PropertyGroup):
ramp_pos : FloatProperty(
name = "Position",
description = "A Float Property",
default = "0.750",
min = "0.010",
max = "1.00"
)
class TEST_MATERIAL_PT_layout_panel(Panel):
bl_label = "Test Material Node"
bl_category = "Test Material"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
def draw(self, context):
layout = self.layout
active_object = context.view_layer.objects.active
if not active_object:
print("Select an Object")
return
active_material = active_object.material
if not active_material:
print("Add a material to the selected object")
return
node_tree = active_material.node_tree
if not node_tree:
print("Check 'Use Nodes' in the active material")
return
color_ramp = node_tree.nodes.get("col_ramp")
if not color_ramp_node:
print("Add a color ramp node to the active material")
return
position_control = color_ramp.color_ramp.elements[0]
layout.operator("test_material.add_material", icon='IMPORT')
row = layout.row()
row.prop(position_control, "ramp_pos")
classes = (TEST_MATERIAL_OT_add_material, Col_ramp_Property, TEST_MATERIAL_PT_layout_panel)
def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.Scene.ramp_pos = PointerProperty(type=Col_ramp_Property)
def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
del bpy.types.Scene.ramp_pos
if __name__ == "__main__":
register()
node.name = "***"
when creating it, its name will default to "ColorRamp" or "ColorRamp.00*" if there is already one in the material. So your call should readposition_control = bpy.data.materials["TestMat"].node_tree.nodes["ColorRamp"].color_ramp.elements[0].position
. $\endgroup$col_ramp.name = "col_ramp"
after your initialize it, otherwise you can't access it by this name $\endgroup$