Skip to content

Commit 821e5f4

Browse files
committed
Merge branch 'develop'
2 parents 5f3dd75 + 6157901 commit 821e5f4

File tree

16 files changed

+191
-76
lines changed

16 files changed

+191
-76
lines changed

RadeonProRenderSDK

Submodule RadeonProRenderSDK updated 41 files

src/bindings/pyrpr/src/pyrprapi.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,8 @@ def get_rif_sdk(base=Path()):
663663
'RPR_SHAPE_SET_LIGHTMAP_CHART_INDEX_FUNC_NAME',
664664
'RPR_MESH_UPDATE_FUNC_NAME',
665665
'RPR_SHAPE_SET_TRANSFORM_BATCH_FUNC_NAME',
666-
'rprDirectionalLightSetRasterShadowSplits']
666+
'rprDirectionalLightSetRasterShadowSplits',
667+
'RPR_CONTEXT_CREATE_MESH_EDITABLE_FUNC_NAME',]
667668
)
668669

669670
export(

src/rprblender/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
bl_info = {
2121
"name": "Radeon ProRender",
2222
"author": "AMD",
23-
"version": (3, 0, 2),
23+
"version": (3, 0, 8),
2424
"blender": (2, 80, 0),
2525
"location": "Info header, render engine menu",
2626
"description": "Radeon ProRender rendering plugin for Blender 2.8x",

src/rprblender/engine/export_engine.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
world,
2626
camera
2727
)
28-
from .context import RPRContext
28+
from .context import RPRContext, RPRContext2
2929
from .engine import Engine
3030
import pyrpr
3131

@@ -48,7 +48,9 @@ def sync(self, context):
4848
self.rpr_context.blender_data['depsgraph'] = depsgraph
4949
scene = depsgraph.scene
5050

51-
scene.rpr.init_rpr_context(self.rpr_context)
51+
use_contour = scene.rpr.is_contour_used
52+
53+
scene.rpr.init_rpr_context(self.rpr_context, use_contour_integrator=use_contour)
5254

5355
self.rpr_context.scene.set_name(scene.name)
5456
self.rpr_context.width = int(scene.render.resolution_x * scene.render.resolution_percentage / 100)
@@ -102,3 +104,11 @@ def export_to_rpr(self, filepath: str, flags):
102104
"""
103105
log('export_to_rpr')
104106
pyrpr_load_store.export(filepath, self.rpr_context.context, self.rpr_context.scene, flags)
107+
108+
109+
class ExportEngine2(ExportEngine):
110+
TYPE = 'EXPORT'
111+
112+
def __init__(self):
113+
self.rpr_context = RPRContext2()
114+
self.rpr_context.engine_type = self.TYPE

src/rprblender/engine/render_engine.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ def __init__(self, rpr_engine):
6262
self.camera_data: camera.CameraData = None
6363
self.tile_order = None
6464

65+
self.use_contour = False
66+
6567
self.world_backplate = None
6668

6769
self.render_stamp_text = ""
@@ -145,7 +147,7 @@ def _render(self):
145147
break
146148

147149
render_iteration += 1
148-
if render_iteration > 1 and self.render_update_samples < MAX_RENDER_ITERATIONS:
150+
if render_iteration > 1 and self.render_update_samples < MAX_RENDER_ITERATIONS and not self.use_contour:
149151
# progressively increase update samples up to 32
150152
self.render_update_samples *= 2
151153

@@ -248,7 +250,7 @@ def _render_tiles(self):
248250
break
249251

250252
render_iteration += 1
251-
if render_iteration > 1 and self.render_update_samples < MAX_RENDER_ITERATIONS:
253+
if render_iteration > 1 and self.render_update_samples < MAX_RENDER_ITERATIONS and not self.use_contour:
252254
# progressively increase update samples up to 32
253255
self.render_update_samples *= 2
254256

@@ -318,7 +320,7 @@ def render(self):
318320
log('Finish render')
319321

320322
def _init_rpr_context(self, scene):
321-
scene.rpr.init_rpr_context(self.rpr_context, use_contour_integrator=scene.rpr.is_contour_used)
323+
scene.rpr.init_rpr_context(self.rpr_context, use_contour_integrator=self.use_contour)
322324

323325
self.rpr_context.scene.set_name(scene.name)
324326

@@ -339,6 +341,7 @@ def sync(self, depsgraph):
339341

340342
self.notify_status(0, "Start syncing")
341343

344+
self.use_contour = scene.rpr.is_contour_used
342345
self._init_rpr_context(scene)
343346

344347
border = ((0, 0), (1, 1)) if not scene.render.use_border else \
@@ -353,8 +356,7 @@ def sync(self, depsgraph):
353356

354357
self.rpr_context.resize(self.width, self.height)
355358

356-
use_contour = scene.rpr.is_contour_used
357-
if use_contour:
359+
if self.use_contour:
358360
scene.rpr.export_contour_mode(self.rpr_context)
359361

360362
self.rpr_context.blender_data['depsgraph'] = depsgraph
@@ -368,7 +370,7 @@ def sync(self, depsgraph):
368370
indirect_only = obj.original.indirect_only_get(view_layer=view_layer)
369371
object.sync(self.rpr_context, obj,
370372
indirect_only=indirect_only, material_override=material_override,
371-
frame_current=scene.frame_current, use_contour=use_contour)
373+
frame_current=scene.frame_current, use_contour=self.use_contour)
372374

373375
if self.rpr_engine.test_break():
374376
log.warn("Syncing stopped by user termination")
@@ -388,7 +390,7 @@ def sync(self, depsgraph):
388390
indirect_only = inst.parent.original.indirect_only_get(view_layer=view_layer)
389391
instance.sync(self.rpr_context, inst,
390392
indirect_only=indirect_only, material_override=material_override,
391-
frame_current=scene.frame_current, use_contour=use_contour)
393+
frame_current=scene.frame_current, use_contour=self.use_contour)
392394

393395
if self.rpr_engine.test_break():
394396
log.warn("Syncing stopped by user termination")
@@ -480,8 +482,11 @@ def sync(self, depsgraph):
480482

481483
self.render_samples, self.render_time = (scene.rpr.limits.max_samples, scene.rpr.limits.seconds)
482484

483-
if scene.rpr.render_quality == 'FULL2' and not scene.rpr.use_contour_render:
484-
self.render_update_samples = scene.rpr.limits.update_samples_rpr2
485+
if scene.rpr.render_quality == 'FULL2':
486+
if self.use_contour:
487+
self.render_update_samples = 1
488+
else:
489+
self.render_update_samples = scene.rpr.limits.update_samples_rpr2
485490
else:
486491
self.render_update_samples = scene.rpr.limits.update_samples
487492

src/rprblender/export/instance.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import numpy as np
1616
import bpy
1717

18-
from . import object, light
18+
from . import object, light, mesh
1919
from rprblender.utils import logging
2020
log = logging.Log(tag='export.instance')
2121

@@ -56,7 +56,7 @@ def sync(rpr_context, instance: bpy.types.DepsgraphObjectInstance, **kwargs):
5656

5757
# exporting visibility from parent object
5858
indirect_only = kwargs.get("indirect_only", False)
59-
instance.parent.rpr.export_visibility(rpr_shape, indirect_only)
59+
mesh.export_visibility(instance.parent, rpr_shape, indirect_only)
6060

6161
rpr_context.scene.attach(rpr_shape)
6262

src/rprblender/export/light.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def get_radiant_power(light: bpy.types.Light, area=0.0):
4545
if light.type in ('POINT', 'SPOT'):
4646
units = rpr.intensity_units_point
4747
if units == 'DEFAULT':
48-
return default_intensity / (4*math.pi) # dividing by 4*pi to be more convenient with cycles point light
48+
return color * math.sqrt(light.energy) # to match cycles
4949

5050
# converting to lumen
5151
if units == 'LUMEN':
@@ -60,7 +60,7 @@ def get_radiant_power(light: bpy.types.Light, area=0.0):
6060
elif light.type == 'SUN':
6161
units = rpr.intensity_units_dir
6262
if units == 'DEFAULT':
63-
return default_intensity * 0.01 # multiplying by 0.01 to be more convenient with point light
63+
return default_intensity
6464

6565
# converting to luminance
6666
if units == 'LUMINANCE':
@@ -134,7 +134,7 @@ def sync(rpr_context: RPRContext, obj: bpy.types.Object, instance_key=None):
134134

135135
elif light.type in ('SUN', 'HEMI'): # just in case old scenes will have outdated Hemi
136136
rpr_light = rpr_context.create_light(light_key, 'directional')
137-
rpr_light.set_shadow_softness_angle(light.rpr.shadow_softness_angle)
137+
rpr_light.set_shadow_softness_angle(light.angle / 2.0) # to match cycles
138138

139139
elif light.type == 'SPOT':
140140
rpr_light = rpr_context.create_light(light_key, 'disk')

src/rprblender/export/mesh.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,23 @@ def assign_override_material(rpr_context, rpr_shape, obj, material_override) ->
257257
return bool(rpr_material or rpr_displacement)
258258

259259

260+
def export_visibility(obj, rpr_shape, indirect_only):
261+
""" Exports visibility settings """
262+
cycles_visibility = obj.cycles_visibility
263+
264+
camera_visibility = cycles_visibility.camera and not indirect_only
265+
266+
rpr_shape.set_visibility_primary_only(camera_visibility)
267+
rpr_shape.set_visibility_ex("visible.reflection", cycles_visibility.glossy)
268+
rpr_shape.set_visibility_ex("visible.reflection.glossy", cycles_visibility.glossy)
269+
rpr_shape.set_visibility_ex("visible.refraction", cycles_visibility.transmission)
270+
rpr_shape.set_visibility_ex("visible.refraction.glossy", cycles_visibility.transmission)
271+
rpr_shape.set_visibility_ex("visible.diffuse", cycles_visibility.diffuse)
272+
rpr_shape.set_shadow(cycles_visibility.shadow)
273+
274+
obj.rpr.set_catchers(rpr_shape)
275+
276+
260277
def sync_visibility(rpr_context, obj: bpy.types.Object, rpr_shape: pyrpr.Shape, indirect_only: bool = False, use_contour: bool = False):
261278
from rprblender.engine.viewport_engine import ViewportEngine
262279

@@ -267,7 +284,7 @@ def sync_visibility(rpr_context, obj: bpy.types.Object, rpr_shape: pyrpr.Shape,
267284
if not rpr_shape.is_visible:
268285
return
269286

270-
obj.rpr.export_visibility(rpr_shape, indirect_only)
287+
export_visibility(obj, rpr_shape, indirect_only)
271288
obj.rpr.export_subdivision(rpr_shape)
272289

273290
if use_contour:

src/rprblender/nodes/blender_nodes.py

Lines changed: 84 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -410,20 +410,28 @@ class ShaderNodeBsdfVelvet(RuleNodeParser):
410410
# inputs: Color, Sigma
411411

412412
nodes = {
413+
"ONE_MINUS_SIGMA": {
414+
"type": "-",
415+
"params": {
416+
pyrpr.MATERIAL_INPUT_COLOR0: 1.0,
417+
pyrpr.MATERIAL_INPUT_COLOR1: "inputs.Sigma",
418+
}
419+
},
420+
413421
"BSDF": {
414422
"type": pyrpr.MATERIAL_NODE_UBERV2,
415423
"params": {
416424
pyrpr.MATERIAL_INPUT_UBER_DIFFUSE_COLOR: "inputs.Color",
417-
pyrpr.MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT: "inputs.Sigma",
425+
pyrpr.MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT: "nodes.ONE_MINUS_SIGMA",
418426
pyrpr.MATERIAL_INPUT_UBER_DIFFUSE_NORMAL: "normal:inputs.Normal",
427+
pyrpr.MATERIAL_INPUT_UBER_DIFFUSE_ROUGHNESS: 1.0,
419428
pyrpr.MATERIAL_INPUT_UBER_REFLECTION_WEIGHT: 0.0,
420-
pyrpr.MATERIAL_INPUT_UBER_SHEEN_WEIGHT: 1.0,
421-
pyrpr.MATERIAL_INPUT_UBER_SHEEN_TINT: "inputs.Sigma",
429+
pyrpr.MATERIAL_INPUT_UBER_SHEEN_WEIGHT: "inputs.Sigma",
430+
pyrpr.MATERIAL_INPUT_UBER_SHEEN_TINT: 1.0,
422431
pyrpr.MATERIAL_INPUT_UBER_SHEEN: "inputs.Color"
423432
}
424433
}
425434
}
426-
# TODO: Has to be fixed, probably diffuse is not needed here
427435

428436

429437
class ShaderNodeEmission(RuleNodeParser):
@@ -861,28 +869,37 @@ def export(self):
861869
base_color = self.get_input_value('Color')
862870

863871
rotation_angle = self.get_input_value('Offset')
864-
roughness_u = self.get_input_value('RoughnessU')
865-
roughness_v = self.get_input_value('RoughnessV')
872+
roughness_u = self.get_input_value('RoughnessU').clamp(0.001, 1.0)
873+
roughness_v = self.get_input_value('RoughnessV').clamp(0.001, 1.0)
866874

867875
# TODO: use Tangent input
868876

869877
# Treat reflection as WARD shader
870878
if component == 'Reflection':
871-
rpr_node = self.create_node(pyrpr.MATERIAL_NODE_WARD)
872-
rpr_node.set_input(pyrpr.MATERIAL_INPUT_ROUGHNESS_X, roughness_u)
873-
rpr_node.set_input(pyrpr.MATERIAL_INPUT_ROUGHNESS_Y, roughness_v)
874-
rpr_node.set_input(pyrpr.MATERIAL_INPUT_ROTATION, rotation_angle)
875-
rpr_node.set_input(pyrpr.MATERIAL_INPUT_COLOR, base_color)
879+
rpr_node = self._create_ward_node(base_color, roughness_u, roughness_v, rotation_angle)
880+
else:
881+
roughness = (roughness_u + roughness_v) * 0.5
882+
rpr_node = self._create_transmission_node(base_color, roughness)
883+
884+
return rpr_node
885+
886+
def export_rpr2(self):
887+
component = self.node.component
888+
base_color = self.get_input_value('Color')
889+
890+
rotation_angle = self.get_input_value('Offset')
891+
roughness_u = self.get_input_value('RoughnessU').clamp(0.001, 1.0)
892+
roughness_v = self.get_input_value('RoughnessV').clamp(0.001, 1.0)
893+
894+
# Treat reflection as and Uber shader with anisotropic reflection
895+
if component == 'Reflection':
896+
rotation_angle = 0.5 - rotation_angle % math.pi # fit angle to the range [-0.5..+0.5]
876897

898+
rpr_node = self._create_aniso_reflection_node(base_color, roughness_u, roughness_v,
899+
rotation_angle)
877900
else:
878-
rpr_node = self.create_node(pyrpr.MATERIAL_NODE_UBERV2, {
879-
pyrpr.MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT: 0.0,
880-
pyrpr.MATERIAL_INPUT_UBER_DIFFUSE_COLOR: base_color,
881-
pyrpr.MATERIAL_INPUT_UBER_DIFFUSE_ROUGHNESS: 1.0,
882-
pyrpr.MATERIAL_INPUT_UBER_REFLECTION_WEIGHT: 0.0,
883-
pyrpr.MATERIAL_INPUT_UBER_BACKSCATTER_WEIGHT: 1.0,
884-
pyrpr.MATERIAL_INPUT_UBER_BACKSCATTER_COLOR: base_color,
885-
})
901+
roughness = (roughness_u + roughness_v) * 0.5
902+
rpr_node = self._create_transmission_node(base_color, roughness)
886903

887904
return rpr_node
888905

@@ -894,7 +911,7 @@ def export_hybrid(self):
894911

895912
rpr_node = self.create_node(pyrpr.MATERIAL_NODE_UBERV2)
896913
rpr_node.set_input(pyrpr.MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT, 0.0)
897-
914+
898915
if component == 'Reflection':
899916
rpr_node.set_input(pyrpr.MATERIAL_INPUT_UBER_REFLECTION_WEIGHT, 1.0)
900917
rpr_node.set_input(pyrpr.MATERIAL_INPUT_UBER_REFLECTION_COLOR, color)
@@ -904,6 +921,53 @@ def export_hybrid(self):
904921

905922
return rpr_node
906923

924+
def _create_ward_node(self, base_color, roughness_u, roughness_v, rotation_angle):
925+
rpr_node = self.create_node(pyrpr.MATERIAL_NODE_WARD)
926+
rpr_node.set_input(pyrpr.MATERIAL_INPUT_ROUGHNESS_X, roughness_u)
927+
rpr_node.set_input(pyrpr.MATERIAL_INPUT_ROUGHNESS_Y, roughness_v)
928+
rpr_node.set_input(pyrpr.MATERIAL_INPUT_ROTATION, rotation_angle)
929+
rpr_node.set_input(pyrpr.MATERIAL_INPUT_COLOR, base_color)
930+
return rpr_node
931+
932+
def _create_aniso_reflection_node(self, base_color, roughness_u, roughness_v, rotation_angle):
933+
rotation_angle = 0.5 - rotation_angle % math.pi # fit angle to the range [-0.5..+0.5]
934+
935+
rough_max = roughness_v.max(roughness_u)
936+
rough_min = roughness_v.min(roughness_u)
937+
938+
anisotropy = 0
939+
if not roughness_u.data == roughness_v.data:
940+
anisotropy = (rough_max - rough_min).clamp(0.001, 1.0) # limit anisotropy amount
941+
942+
# a rough approximation of reflection roughness
943+
rough_med = (roughness_u + roughness_v) * 0.5
944+
rough_aniso = (rough_min + rough_med) * 0.5
945+
946+
rpr_node = self.create_node(pyrpr.MATERIAL_NODE_UBERV2)
947+
rpr_node.set_input(pyrpr.MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT, 0.0)
948+
949+
rpr_node.set_input(pyrpr.MATERIAL_INPUT_UBER_REFLECTION_WEIGHT, 1.0)
950+
rpr_node.set_input(pyrpr.MATERIAL_INPUT_UBER_REFLECTION_COLOR, base_color)
951+
rpr_node.set_input(pyrpr.MATERIAL_INPUT_UBER_REFLECTION_ROUGHNESS, rough_aniso)
952+
rpr_node.set_input(pyrpr.MATERIAL_INPUT_UBER_REFLECTION_ANISOTROPY, anisotropy)
953+
rpr_node.set_input(pyrpr.MATERIAL_INPUT_UBER_REFLECTION_ANISOTROPY_ROTATION, rotation_angle)
954+
rpr_node.set_input(pyrpr.MATERIAL_INPUT_UBER_REFLECTION_MODE,
955+
pyrpr.UBER_MATERIAL_IOR_MODE_METALNESS)
956+
rpr_node.set_input(pyrpr.MATERIAL_INPUT_UBER_REFLECTION_METALNESS, 1.0)
957+
958+
return rpr_node
959+
960+
def _create_transmission_node(self, base_color, roughness):
961+
rpr_node = self.create_node(pyrpr.MATERIAL_NODE_UBERV2, {
962+
pyrpr.MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT: 0.0,
963+
pyrpr.MATERIAL_INPUT_UBER_DIFFUSE_COLOR: base_color,
964+
pyrpr.MATERIAL_INPUT_UBER_DIFFUSE_ROUGHNESS: roughness,
965+
pyrpr.MATERIAL_INPUT_UBER_REFLECTION_WEIGHT: 0.0,
966+
pyrpr.MATERIAL_INPUT_UBER_BACKSCATTER_WEIGHT: 1.0,
967+
pyrpr.MATERIAL_INPUT_UBER_BACKSCATTER_COLOR: base_color,
968+
})
969+
return rpr_node
970+
907971

908972
class ShaderNodeNewGeometry(RuleNodeParser):
909973
# outputs: Position, Normal, Tangent, True Normal, Incoming, Parametric, Backfacing, Pointiness

src/rprblender/nodes/node_parser.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import bpy
1818
import pyrpr
1919

20-
from rprblender.engine.context import RPRContext
20+
from rprblender.engine.context import RPRContext, RPRContext2
2121
from rprblender.engine.context_hybrid import RPRContext as RPRContextHybrid
2222
from .node_item import NodeItem
2323

@@ -292,6 +292,8 @@ def final_export(self):
292292
node_item = self.export_muted()
293293
elif isinstance(self.rpr_context, RPRContextHybrid):
294294
node_item = self.export_hybrid()
295+
elif isinstance(self.rpr_context, RPRContext2):
296+
node_item = self.export_rpr2()
295297
else:
296298
node_item = self.export()
297299
rpr_node = node_item.data if node_item else None
@@ -310,6 +312,9 @@ def export(self) -> [NodeItem, None]:
310312
def export_hybrid(self) -> [NodeItem, None]:
311313
return self.export()
312314

315+
def export_rpr2(self) -> [NodeItem, None]:
316+
return self.export()
317+
313318
def export_muted(self) -> [NodeItem, None]:
314319
rpr_node = super().export_muted()
315320
return self.node_item(rpr_node) if rpr_node is not None else None

0 commit comments

Comments
 (0)