Sketch render script
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hi all,
Not sure this is of interest for anyone, considering that usually VRED is intended to make things look photo real. But I have been in need of a one stop solution to doing some renders/videos that have a technical drawing aesthetic, that can be easily mapped over or below photo real renders with appropriately visible details.
To do so I have made a quite poor but somewhat functional script.
It essentially recreates the style of the non-realistic renderer, but you can ray-trace the result. It requires opencv-python and numpy to be installed.
I convert NURBS to mesh (and rename them as otherwise bad things happen), then use the UV editor to make a snapshot, then modify the image to black lines, thicken them, and then UV map the result. I also make material switches so that the effect can be switched using another script... but this makes a mess of the material editor, as it makes a material, and switch per part...!
I don't think it's very efficient, and the results can be a bit hit and miss (some parts seem to require multiple dilate iterations... see the cab and hydraulics).
But I think the result kind of cool, and roughly works for what I want it to... It just takes an age to do more complex models, with the UV editor throwing some errors, and VRED becoming unresponsive for a while (It took roughly 4 minutes for the digger).
No idea if its useful to anyone, but if so... great. If anyone has any ideas for an approach that could do this more efficiently, I'd be interested.
Cheers.
import numpy as np
import cv2 as cv
def sketcherize(node_group):
root_node = vrNodeService.findNode(node_group)
geo_nodes = [child for child in root_node.getChildrenRecursive() if child.isType(vrdGeometryNode)]
nodes = [geo_node for geo_node in geo_nodes if geo_node.isShell()]
for node in nodes:
if not node.isMesh():
vrScenegraphService.convertToMesh([node])
map_size = 2056
resolution = 1024
padding = 10 #pixels
padding /= map_size #UV 0.0-1
save_path = 'YOUR PATH GOES HERE :)'
layout_settings = vrdUVLayoutSettings()
layout_settings.setIslandPadding(padding)
layout_settings.setTilePadding(padding)
layout_settings.setResolution(resolution)
unfold_settings = vrdUVUnfoldSettings()
unfold_settings.setMapSize(map_size)
vrUVService.unfold(nodes, unfold_settings, layout_settings, vrUVTypes.UVSet.MaterialUVSet)
sketch_material_group_list = []
sketch_material_group = vrMaterialService.createMaterialGroup()
sketch_material_group.setName('sketch_material_group')
for node in nodes:
node.setName(f'{node.getName()}_{node.getObjectId()}')
uv_path=f'{save_path}{node.getName()}.png'
vrUVService.saveUVSnapshot(
[node],
uv_path,
2056,2056,
vrUVTypes.UVSet.MaterialUVSet,
vrUVTypes.ShowBorders)
# read image into openCV
image = cv.imread(uv_path)
# convert img to grayscale
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
# make anything not white into black
mask = gray.copy()
mask[mask!=0] = 255
# do this...
kernel = np.ones((5,5),np.uint8)
# grow the mask (1 times but can be reduced/increased depending on the requirements).
dilate = cv.dilate(mask, kernel, iterations=1)
# invert to black on white
inverted = cv.bitwise_not(dilate)
# overwrite the original
cv.imwrite(uv_path, inverted)
old_mat = node.getMaterial()
new_mat = vrMaterialService.createMaterial(
f'{node.getName()}_sketchUV',
vrMaterialTypes.MaterialType.Plastic,
sketch_material_group)
sketch_texture = vrImageService.loadImage(uv_path)
dif_texture = new_mat.getDiffuseTexture()
dif_color = QVector3D(1.,1.,1.)
new_mat.setDiffuseColor(dif_color)
dif_texture.setImage(sketch_texture)
dif_texture.setUseTexture(True)
dif_texture.setUseAlpha(False)
dif_texture.setMappingType(vrTextureTypes.MappingType.UVMapping)
mat_switch = vrMaterialService.createSwitchMaterial([new_mat,old_mat],sketch_material_group)
mat_switch.setName(f'{node.getName()}_sketchUV_material_switch')
node.applyMaterial(mat_switch)