{"id":1481,"date":"2020-01-20T10:37:27","date_gmt":"2020-01-20T09:37:27","guid":{"rendered":"https:\/\/zoltane.com\/pages\/?page_id=1481"},"modified":"2020-01-20T10:54:46","modified_gmt":"2020-01-20T09:54:46","slug":"chainbot","status":"publish","type":"page","link":"https:\/\/zoltane.com\/pages\/unreal\/chainbot\/","title":{"rendered":"Chainbot"},"content":{"rendered":"<section class=\"wpb-content-wrapper\"><p>[vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_column_text]I dusted off a prototype I threw together years ago, the <strong>Chainbot<\/strong>. It was composed entirely of gray boxes so I gave it some polish with proper art assets. Designing the robot allowed me to finally learn Modo\u2019s live boolean toolset <a href=\"https:\/\/learn.foundry.com\/modo\/content\/help\/pages\/meshfusion\/mf_introduction.html\">Mesh Fusion<\/a>. It was also a great opportunity to develop my <a href=\"https:\/\/zoltane.com\/pages\/houdini\/mesh-processor\/\">Mesh Processor<\/a> further and implement the features I didn\u2019t have time for previously. Here is the result:[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column el_class=\u201dimage_frame\u201d]<style> .gvpfpmain1487 .fp-controls { background-color:#878477 !important;}\n\t\t\t   .gvpfpmain1487 .fp-timeline { background-color: #EBEBE2 !important;}\n\t\t\t   .gvpfpmain1487 .fp-progress { background-color: #404040 !important;}\n\t\t\t   .gvpfpmain1487 .fp-buffer { background-color: #BAB9AC !important;} \n\t\t\t   .gvpfpmain1487 .fp-time { font-size:11px !important; }.overlay2 { display: inline-block; }<\/style><\/p>\n<div class=\"gvpfpmain1487\" style=\"text-align:center;\"><div style=\"max-width:960px; margin-right:0px;display:inline-block;width:100%; \"> <div style=\"max-width:960px; \" class=\"flowplayer flowplayer1487 minimalist no-time no-volume no-mute \" data-key=\"$940018184765530\" data-analytics=\"UA-4183565-3\" data-ratio=\"0.625\" data-embed=\"false\" data-fullscreen=\"false\"><video preload><source type=\"video\/mp4\" src=\"\/\/zoltane.com\/pages\/wp-content\/uploads\/Chainbot.mp4\"><\/source><\/video><\/div>\n<\/div><\/div>\n<script> jQuery(document).ready(function($){ $(\".flowplayer1487\").each (function() { var gvpcheckprogress = 0; var gvpbeforeseekval = 0; var gvpseekval = 0; $(this).bind(\"ready\", function(event, api) {  }).bind(\"pause\", function(event, api) { myType =  \".\"+api.video.type;  if(api.video.time < api.video.duration && api.video.time > 0) { ga(\"send\", \"event\", \"Video Paused\", \"FlowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType, \"\")); } }).bind(\"finish\", function(event, api) {  myType2 =  \".\"+api.video.type; ga(\"send\", \"event\", \"Video Finished\", \"FLowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType2, \"\"));  }).bind(\"beforeseek\", function(event, api) {  gvpbeforeseekval = api.video.time; }).bind(\"seek\", function(event, api) {  gvpseekval = api.video.time; myType5 =  \".\"+api.video.type; var seekthiny = Math.round(Math.round(gvpbeforeseekval)+\"000\"+Math.round(gvpseekval)); ga(\"send\", \"event\", \"Video Seeked\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType5, \"\"), seekthiny, seekthiny);  }).bind(\"resume\", function(event, api) { if(api.video.time > 0 ) { myType4 =  \".\"+api.video.type;  ga(\"send\", \"event\", \"Video Resumed\", \"FLowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType4, \"\"));  } }).bind(\"progress\", function(event, api) { if(api.video.time > 0) { if(gvpcheckprogress == 0) { myType3 =  \".\"+api.video.type; ga(\"send\", \"event\", \"Video Total Time\", \"FLowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType3, \"\"), Math.round(api.video.duration)); gvpcheckprogress = 1; } } }); }); });<\/script>[\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_column_text]\n<p>[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_text_separator title=\u201dThe code\u201d text_in_box=\u201dno\u201d text_position=\u201dcenter\u201d line_border_style=\u201dsolid\u201d line_dots=\u201dno\u201d][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_column_text]As usual I used Unreal\u2019s Blueprints to set up the \u201cgame mechanics\u201d. The main components (chain driver box, suspensions, etc) are positioned manually while the chain itself is generated procedurally so the number of links can be changed in-game.[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column el_class=\u201dimage_frame\u201d]<style> .gvpfpmain1489 .fp-controls { background-color:#878477 !important;}\n\t\t\t   .gvpfpmain1489 .fp-timeline { background-color: #EBEBE2 !important;}\n\t\t\t   .gvpfpmain1489 .fp-progress { background-color: #404040 !important;}\n\t\t\t   .gvpfpmain1489 .fp-buffer { background-color: #BAB9AC !important;} \n\t\t\t   .gvpfpmain1489 .fp-time { font-size:11px !important; }.overlay2 { display: inline-block; }<\/style><\/p>\n<div class=\"gvpfpmain1489\" style=\"text-align:center;\"><div style=\"max-width:960px; margin-right:0px;display:inline-block;width:100%; \"> <div style=\"max-width:960px; \" class=\"flowplayer flowplayer1489 minimalist no-time no-volume no-mute \" data-key=\"$940018184765530\" data-analytics=\"UA-4183565-3\" data-ratio=\"0.625\" data-embed=\"false\" data-fullscreen=\"false\"><video preload><source type=\"video\/mp4\" src=\"\/\/zoltane.com\/pages\/wp-content\/uploads\/LinkCount.mp4\"><\/source><\/video><\/div>\n<\/div><\/div>\n<script> jQuery(document).ready(function($){ $(\".flowplayer1489\").each (function() { var gvpcheckprogress = 0; var gvpbeforeseekval = 0; var gvpseekval = 0; $(this).bind(\"ready\", function(event, api) {  }).bind(\"pause\", function(event, api) { myType =  \".\"+api.video.type;  if(api.video.time < api.video.duration && api.video.time > 0) { ga(\"send\", \"event\", \"Video Paused\", \"FlowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType, \"\")); } }).bind(\"finish\", function(event, api) {  myType2 =  \".\"+api.video.type; ga(\"send\", \"event\", \"Video Finished\", \"FLowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType2, \"\"));  }).bind(\"beforeseek\", function(event, api) {  gvpbeforeseekval = api.video.time; }).bind(\"seek\", function(event, api) {  gvpseekval = api.video.time; myType5 =  \".\"+api.video.type; var seekthiny = Math.round(Math.round(gvpbeforeseekval)+\"000\"+Math.round(gvpseekval)); ga(\"send\", \"event\", \"Video Seeked\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType5, \"\"), seekthiny, seekthiny);  }).bind(\"resume\", function(event, api) { if(api.video.time > 0 ) { myType4 =  \".\"+api.video.type;  ga(\"send\", \"event\", \"Video Resumed\", \"FLowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType4, \"\"));  } }).bind(\"progress\", function(event, api) { if(api.video.time > 0) { if(gvpcheckprogress == 0) { myType3 =  \".\"+api.video.type; ga(\"send\", \"event\", \"Video Total Time\", \"FLowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType3, \"\"), Math.round(api.video.duration)); gvpcheckprogress = 1; } } }); }); });<\/script>[\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_column_text]The chain links are physics driven static mesh components in the bot actor but they are moving independently from the root component. To create the illusion that the parts are a single system and the chain carry the main body I reposition the root every frame based on the locations of the links closest to the top center of the ring.\n<p>\u00a0<\/p>\n<p>The main body keeps tracing downward from a few locations to measure the average distance from the ground and rotate the suspension arms when necessary for more clearance.[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column width=\u201d2\/5\u2033][vc_single_image image=\u201d1493\u2033 img_size=\u201dmedium\u201d onclick=\u201dlink_image\u201d qode_css_animation=\u201d\u201d el_class=\u201dimage_frame\u201d][\/vc_column][vc_column width=\u201d3\/5\u2033][vc_column_text]The bot is looking around randomly by rotating the eye piece. When moving backward the whole head rotates by a certain amount. These very simple mechanics add a surprising amount of \u201clife\u201d to the creature.[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_column_text]The walking is achieved by brute force IK where each branch of the broken chain is constrained to an invisible target. When a target is repositioned (by holding the left or right buttons and moving the mouse) then another target is activated: it pulls the still planted leg so the overall posture remains in balance. (At least visually, the physics simulation is 2D and helper constrains keeps things stable no matter what.)[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column el_class=\u201dimage_frame\u201d]<style> .gvpfpmain1491 .fp-controls { background-color:#878477 !important;}\n\t\t\t   .gvpfpmain1491 .fp-timeline { background-color: #EBEBE2 !important;}\n\t\t\t   .gvpfpmain1491 .fp-progress { background-color: #404040 !important;}\n\t\t\t   .gvpfpmain1491 .fp-buffer { background-color: #BAB9AC !important;} \n\t\t\t   .gvpfpmain1491 .fp-time { font-size:11px !important; }.overlay2 { display: inline-block; }<\/style><\/p>\n<div class=\"gvpfpmain1491\" style=\"text-align:center;\"><div style=\"max-width:960px; margin-right:0px;display:inline-block;width:100%; \"> <div style=\"max-width:960px; \" class=\"flowplayer flowplayer1491 minimalist no-time no-volume no-mute \" data-key=\"$940018184765530\" data-analytics=\"UA-4183565-3\" data-ratio=\"0.625\" data-embed=\"false\" data-fullscreen=\"false\"><video preload><source type=\"video\/mp4\" src=\"\/\/zoltane.com\/pages\/wp-content\/uploads\/WalkMode.mp4\"><\/source><\/video><\/div>\n<\/div><\/div>\n<script> jQuery(document).ready(function($){ $(\".flowplayer1491\").each (function() { var gvpcheckprogress = 0; var gvpbeforeseekval = 0; var gvpseekval = 0; $(this).bind(\"ready\", function(event, api) {  }).bind(\"pause\", function(event, api) { myType =  \".\"+api.video.type;  if(api.video.time < api.video.duration && api.video.time > 0) { ga(\"send\", \"event\", \"Video Paused\", \"FlowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType, \"\")); } }).bind(\"finish\", function(event, api) {  myType2 =  \".\"+api.video.type; ga(\"send\", \"event\", \"Video Finished\", \"FLowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType2, \"\"));  }).bind(\"beforeseek\", function(event, api) {  gvpbeforeseekval = api.video.time; }).bind(\"seek\", function(event, api) {  gvpseekval = api.video.time; myType5 =  \".\"+api.video.type; var seekthiny = Math.round(Math.round(gvpbeforeseekval)+\"000\"+Math.round(gvpseekval)); ga(\"send\", \"event\", \"Video Seeked\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType5, \"\"), seekthiny, seekthiny);  }).bind(\"resume\", function(event, api) { if(api.video.time > 0 ) { myType4 =  \".\"+api.video.type;  ga(\"send\", \"event\", \"Video Resumed\", \"FLowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType4, \"\"));  } }).bind(\"progress\", function(event, api) { if(api.video.time > 0) { if(gvpcheckprogress == 0) { myType3 =  \".\"+api.video.type; ga(\"send\", \"event\", \"Video Total Time\", \"FLowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType3, \"\"), Math.round(api.video.duration)); gvpcheckprogress = 1; } } }); }); });<\/script>[\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_column_text]\n<p>[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_text_separator title=\u201dThe robot model\u201d text_in_box=\u201dno\u201d text_position=\u201dcenter\u201d line_border_style=\u201dsolid\u201d line_dots=\u201dno\u201d][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_column_text]Every part of the robot was modeled in Modo using its live boolean tech: the final surface consists of simple subdivision surfaces (spheres, boxes, cylinders, etc) and union, subtraction, intersection operations between them. The whole thing remains \u201clive\u201d so mesh transforms and topology can be modified at interactive speeds, making experimentation and tweaking easy.[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column el_class=\u201dimage_frame\u201d]<style> .gvpfpmain1490 .fp-controls { background-color:#878477 !important;}\n\t\t\t   .gvpfpmain1490 .fp-timeline { background-color: #EBEBE2 !important;}\n\t\t\t   .gvpfpmain1490 .fp-progress { background-color: #404040 !important;}\n\t\t\t   .gvpfpmain1490 .fp-buffer { background-color: #BAB9AC !important;} \n\t\t\t   .gvpfpmain1490 .fp-time { font-size:11px !important; }.overlay2 { display: inline-block; }<\/style><\/p>\n<div class=\"gvpfpmain1490\" style=\"text-align:center;\"><div style=\"max-width:960px; margin-right:0px;display:inline-block;width:100%; \"> <div style=\"max-width:960px; \" class=\"flowplayer flowplayer1490 minimalist no-time no-volume no-mute \" data-key=\"$940018184765530\" data-analytics=\"UA-4183565-3\" data-ratio=\"0.625\" data-embed=\"false\" data-fullscreen=\"false\"><video preload><source type=\"video\/mp4\" src=\"\/\/zoltane.com\/pages\/wp-content\/uploads\/MeshFusion.mp4\"><\/source><\/video><\/div>\n<\/div><\/div>\n<script> jQuery(document).ready(function($){ $(\".flowplayer1490\").each (function() { var gvpcheckprogress = 0; var gvpbeforeseekval = 0; var gvpseekval = 0; $(this).bind(\"ready\", function(event, api) {  }).bind(\"pause\", function(event, api) { myType =  \".\"+api.video.type;  if(api.video.time < api.video.duration && api.video.time > 0) { ga(\"send\", \"event\", \"Video Paused\", \"FlowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType, \"\")); } }).bind(\"finish\", function(event, api) {  myType2 =  \".\"+api.video.type; ga(\"send\", \"event\", \"Video Finished\", \"FLowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType2, \"\"));  }).bind(\"beforeseek\", function(event, api) {  gvpbeforeseekval = api.video.time; }).bind(\"seek\", function(event, api) {  gvpseekval = api.video.time; myType5 =  \".\"+api.video.type; var seekthiny = Math.round(Math.round(gvpbeforeseekval)+\"000\"+Math.round(gvpseekval)); ga(\"send\", \"event\", \"Video Seeked\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType5, \"\"), seekthiny, seekthiny);  }).bind(\"resume\", function(event, api) { if(api.video.time > 0 ) { myType4 =  \".\"+api.video.type;  ga(\"send\", \"event\", \"Video Resumed\", \"FLowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType4, \"\"));  } }).bind(\"progress\", function(event, api) { if(api.video.time > 0) { if(gvpcheckprogress == 0) { myType3 =  \".\"+api.video.type; ga(\"send\", \"event\", \"Video Total Time\", \"FLowPlayer\", api.video.src.split(\"\/\").slice(-1)[0].replace(myType3, \"\"), Math.round(api.video.duration)); gvpcheckprogress = 1; } } }); }); });<\/script>[\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_column_text]I assembled the machine parts in Modo to iterate on dimensions, structure and fine tune the overall look before transferring the mesh to Unreal. When a part was done the frozen mesh was exported and fed into my <a href=\"https:\/\/zoltane.com\/pages\/houdini\/mesh-processor\/\">mesh processor tool<\/a> in Houdini.[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column width=\u201d2\/5\u2033][vc_single_image image=\u201d1492\u2033 img_size=\u201dmedium\u201d onclick=\u201dlink_image\u201d qode_css_animation=\u201d\u201d el_class=\u201dimage_frame\u201d][\/vc_column][vc_column width=\u201d3\/5\u2033][vc_column_text]A most pieces can only be seen from a single side so I set up the importance based tool so the bulk of the detail (polycount and texture resolution) is facing the camera. The unseen areas are super simple but not deleted so the shadows are not truncated and distance field generation doesn\u2019t suffer.[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_column_text]The texturing was done in Substance Painter using materials and alphas from both <a href=\"https:\/\/source.substance3d.com\/\">Substance Source<\/a> and <a href=\"https:\/\/gumroad.com\/discover?query=hard%20surface%20alphas\">Gumroad<\/a>. First I finished the head and saved the layer stack as a smart material which was then applied and fine tuned for every other machine part.[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_column_text]\n<p>[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_text_separator title=\u201dThe environment\u201d text_in_box=\u201dno\u201d text_position=\u201dcenter\u201d line_border_style=\u201dsolid\u201d line_dots=\u201dno\u201d][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column width=\u201d2\/5\u2033][vc_single_image image=\u201d1494\u2033 img_size=\u201dmedium\u201d onclick=\u201dlink_image\u201d qode_css_animation=\u201d\u201d el_class=\u201dimage_frame\u201d][\/vc_column][vc_column width=\u201d3\/5\u2033][vc_column_text]The environment pieces were modeled after the graybox level I originally built for the prototype. Each mesh is unique and was sculpted using Modo\u2019s multiresolution (image-less) tools.[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column width=\u201d2\/5\u2033][vc_single_image image=\u201d1473\u2033 img_size=\u201dmedium\u201d onclick=\u201dlink_image\u201d qode_css_animation=\u201d\u201d el_class=\u201dimage_frame\u201d][\/vc_column][vc_column width=\u201d3\/5\u2033][vc_column_text]The SDS meshes had unwrapped UVs where I wanted to control the flow of the textures. (For example the rock layers on the side of the rock formations or the wood grain on the plank ramp.) This data was maintained throughout the next step (processing the high poly mesh in Houdini) and got baked into a texture.<\/p>\n<p>\u00a0<\/p>\n<p>Since the camera path is very constrained it was fairly easy to set up the simplification so the polygons and texels are spent where they matter the most.[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column width=\u201d2\/5\u2033][vc_single_image image=\u201d1472\u2033 img_size=\u201dmedium\u201d onclick=\u201dlink_image\u201d qode_css_animation=\u201d\u201d el_class=\u201dimage_frame\u201d][\/vc_column][vc_column width=\u201d3\/5\u2033][vc_column_text]The baked UV data was used in Substance Painter to control the projection of underlying materials. (For more on how it works <a href=\"https:\/\/zoltane.com\/pages\/houdini\/mesh-processor\/\">click here<\/a>.)<\/p>\n<p>\u00a0<\/p>\n<p>As per usual I used <a href=\"https:\/\/artomatix.com\/artengine\/\">ArtEngine<\/a> to <a href=\"https:\/\/zoltane.com\/pages\/artengine\/texture-scope-change\/\">generate a bigger scope<\/a> for almost all of the Substance materials.[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column width=\u201d2\/5\u2033][vc_single_image image=\u201d1495\u2033 img_size=\u201dmedium\u201d onclick=\u201dlink_image\u201d qode_css_animation=\u201d\u201d el_class=\u201dimage_frame\u201d][\/vc_column][vc_column width=\u201d3\/5\u2033][vc_column_text]The plants are mostly from the excellent <a href=\"https:\/\/quixel.com\/megascans\/library\/latest\">Megascans library<\/a> and they only received some color correction in Unreal. I created meshes for a few of their textures where I wanted to customize the look.<\/p>\n<p>\u00a0<\/p>\n<p>I placed the bigger plants by hand as static meshed while painted the rest as foliage.[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column width=\u201d2\/5\u2033][vc_single_image image=\u201d1496\u2033 img_size=\u201dmedium\u201d onclick=\u201dlink_image\u201d qode_css_animation=\u201d\u201d el_class=\u201dimage_frame\u201d][\/vc_column][vc_column width=\u201d3\/5\u2033][vc_column_text]The wooden pieces, barrel and coffin went through the same Modo \u2013 Houdini \u2013 Substance Painter pipeline like the rest of the environment but I bought the zombie from CGTraders.[\/vc_column_text][\/vc_column][\/vc_row][vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_single_image image=\u201d1498\u2033 img_size=\u201dlarge\u201d alignment=\u201dcenter\u201d onclick=\u201dlink_image\u201d qode_css_animation=\u201d\u201d el_class=\u201dimage_frame\u201d][\/vc_column][\/vc_row]<\/p>\n<\/section>","protected":false},"excerpt":{"rendered":"<p>[vc_row row_type=\u201drow\u201d use_row_as_full_screen_section=\u201dno\u201d type=\u201dfull_width\u201d oblique_section=\u201dno\u201d text_align=\u201dleft\u201d padding_bottom=\u201d32\u2033 css_animation=\u201d\u201d box_shadow_on_row=\u201dno\u201d][vc_column][vc_column_text]I dusted off a prototype I threw together years ago, the Chainbot. It was composed entirely of gray boxes so I gave it some polish with proper art assets. Designing the robot allowed me to finally learn&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":53,"menu_order":1,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-1481","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/zoltane.com\/pages\/wp-json\/wp\/v2\/pages\/1481","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zoltane.com\/pages\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/zoltane.com\/pages\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/zoltane.com\/pages\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zoltane.com\/pages\/wp-json\/wp\/v2\/comments?post=1481"}],"version-history":[{"count":9,"href":"https:\/\/zoltane.com\/pages\/wp-json\/wp\/v2\/pages\/1481\/revisions"}],"predecessor-version":[{"id":1502,"href":"https:\/\/zoltane.com\/pages\/wp-json\/wp\/v2\/pages\/1481\/revisions\/1502"}],"up":[{"embeddable":true,"href":"https:\/\/zoltane.com\/pages\/wp-json\/wp\/v2\/pages\/53"}],"wp:attachment":[{"href":"https:\/\/zoltane.com\/pages\/wp-json\/wp\/v2\/media?parent=1481"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}