{"id":1106,"date":"2018-08-04T11:41:32","date_gmt":"2018-08-04T09:41:32","guid":{"rendered":"https:\/\/zoltane.com\/pages\/?page_id=1106"},"modified":"2018-08-23T17:53:19","modified_gmt":"2018-08-23T15:53:19","slug":"aisim","status":"publish","type":"page","link":"https:\/\/zoltane.com\/pages\/unreal\/aisim\/","title":{"rendered":"aiSim"},"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]<strong>aiSim<\/strong> is a simulator for self-driving cars. The ability to recreate real-world situations and create unique scenarios ensures the safe development of autonomous vehicle technology. Virtual testing guarantees that the final product can adapt to different environments. Scenarios based on situations which are common overall but rarely experienced by single drivers allow engineers to evaluate new solutions before real-world road tests. To support artificial intelligence research and training aiSim can also generate machine learning datasets.<\/p>\n<div id=\"s3gt_translate_tooltip_mini\" class=\"s3gt_translate_tooltip_mini_box\" style=\"background: initial !important; border: initial !important; border-radius: initial !important; border-spacing: initial !important; border-collapse: initial !important; direction: ltr !important; flex-direction: initial !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; min-width: initial !important; max-width: initial !important; min-height: initial !important; max-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; table-layout: initial !important; text-align: initial !important; text-shadow: initial !important; width: initial !important; word-break: initial !important; word-spacing: initial !important; overflow-wrap: initial !important; box-sizing: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific,sans-serif,Tahoma,Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 29px; top: 35px; opacity: 0.55;\">\n<div id=\"s3gt_translate_tooltip_mini_logo\" class=\"s3gt_translate_tooltip_mini\" title=\"Translate selected text\"><\/div>\n<div id=\"s3gt_translate_tooltip_mini_sound\" class=\"s3gt_translate_tooltip_mini\" title=\"Play\"><\/div>\n<div id=\"s3gt_translate_tooltip_mini_copy\" class=\"s3gt_translate_tooltip_mini\" title=\"Copy text to Clipboard\"><\/div>\n<\/div>\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_single_image image=\u201d1107\u2033 img_size=\u201dfull\u201d alignment=\u201dcenter\u201d qode_css_animation=\u201d\u201d el_class=\u201dimage_frame\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]I was hired as an Unreal expert when the work started on aiSim and for the first few months I was training the team to use <strong>Unreal Engine 4<\/strong>. They learned the ropes quickly so I transitioned into a more traditional technical artist role.<\/p>\n<div id=\"s3gt_translate_tooltip_mini\" class=\"s3gt_translate_tooltip_mini_box\" style=\"background: initial !important; border: initial !important; border-radius: initial !important; border-spacing: initial !important; border-collapse: initial !important; direction: ltr !important; flex-direction: initial !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; min-width: initial !important; max-width: initial !important; min-height: initial !important; max-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; table-layout: initial !important; text-align: initial !important; text-shadow: initial !important; width: initial !important; word-break: initial !important; word-spacing: initial !important; overflow-wrap: initial !important; box-sizing: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific,sans-serif,Tahoma,Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 990px; top: 36px; opacity: 0.55;\">\n<div id=\"s3gt_translate_tooltip_mini_logo\" class=\"s3gt_translate_tooltip_mini\" title=\"Translate selected text\"><\/div>\n<div id=\"s3gt_translate_tooltip_mini_sound\" class=\"s3gt_translate_tooltip_mini\" title=\"Play\"><\/div>\n<div id=\"s3gt_translate_tooltip_mini_copy\" class=\"s3gt_translate_tooltip_mini\" title=\"Copy text to Clipboard\"><\/div>\n<\/div>\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_column_text]Our initial art asset workflow was designed for production speed in order to provide the AI research teams with as much data as possible, as soon as possible. That meant that most assets didn\u2019t have a unique texture set but used several material definitions from a library we built. Those materials mostly came from Substance and were applied onto the meshes in Unreal. The result was 1-5 drawcalls per mesh but that worked on the limited scope of the early levels, which covered a only a few city blocks.<\/p>\n<p>\u00a0<\/p>\n<p>As the aiSim got extended with multi camera capabilities rendering performance became an issue so LOD generation and per instance max draw distance setting became a necessity. We also had to create much larger areas which slow down content creation even further. The biggest time sink on the modeling side was the manual reproduction of roads while level designers spent inordinate amounts of time setting all the metadata expected by the AI trainer team.[\/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=\u201d1\/4\u2033][vc_single_image image=\u201d1120\u2033 img_size=\u201dfull\u201d qode_css_animation=\u201d\u201d el_class=\u201dimage_frame\u201d][\/vc_column][vc_column width=\u201d3\/4\u2033][vc_column_text]When aiSim got to a \u201cfeature complete for now\u201d state then we, the tech artist duo, set out to solve the biggest issues with our content creation pipeline: creative people doing donkey work. We want to automate every repetitive task from UVing to import\/export file juggling so we picked <strong>Houdini<\/strong> as the backbone for the new workflow.<\/p>\n<p>\u00a0<\/p>\n<p>There are 2 main parts of our Houdini toolset:<\/p>\n<p style=\"padding-left: 30px;\">\u2013 <a href=\"http:\/\/www.opendrive.org\/\">OpenDrive<\/a> compatible scene components which allow the creation of the abstract representation of road networks and related objects.<\/p>\n<p>\u00a0<\/p>\n<p style=\"padding-left: 30px;\">\u2013 A set of mesh generators which take those abstract descriptions of the different elements and produce polygons for them.<\/p>\n<div id=\"s3gt_translate_tooltip_mini\" class=\"s3gt_translate_tooltip_mini_box\" style=\"background: initial !important; border: initial !important; border-radius: initial !important; border-spacing: initial !important; border-collapse: initial !important; direction: ltr !important; flex-direction: initial !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; min-width: initial !important; max-width: initial !important; min-height: initial !important; max-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; table-layout: initial !important; text-align: initial !important; text-shadow: initial !important; width: initial !important; word-break: initial !important; word-spacing: initial !important; overflow-wrap: initial !important; box-sizing: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific,sans-serif,Tahoma,Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 93px; top: 75px; opacity: 0.25;\">\n<div id=\"s3gt_translate_tooltip_mini_logo\" class=\"s3gt_translate_tooltip_mini\" title=\"Translate selected text\"><\/div>\n<div id=\"s3gt_translate_tooltip_mini_sound\" class=\"s3gt_translate_tooltip_mini\" title=\"Play\"><\/div>\n<div id=\"s3gt_translate_tooltip_mini_copy\" class=\"s3gt_translate_tooltip_mini\" title=\"Copy text to Clipboard\"><\/div>\n<\/div>\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=\u201dEditor tools\u201d text_in_box=\u201dyes\u201d text_position=\u201dcenter\u201d box_border_style=\u201dsolid\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]To aid debugging performance issues I made an tool for building and visualizing a <strong>heat map<\/strong> of different rendering stats.<\/p>\n<p>\u00a0<\/p>\n<p>First the level is traversed by an editor mode blueprint: it finds the important areas and places measurement points there. The result is written to a file and used in a special game mode. That game mode places the camera at each measurement point and saves Game, draw and GPU timings for each of 8 directions. The stats are saved and read back by visualization editor blueprint which creates indicator meshes on the level:<\/p>\n<div id=\"s3gt_translate_tooltip_mini\" class=\"s3gt_translate_tooltip_mini_box\" style=\"background: initial !important; border: initial !important; border-radius: initial !important; border-spacing: initial !important; border-collapse: initial !important; direction: ltr !important; flex-direction: initial !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; min-width: initial !important; max-width: initial !important; min-height: initial !important; max-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; table-layout: initial !important; text-align: initial !important; text-shadow: initial !important; width: initial !important; word-break: initial !important; word-spacing: initial !important; overflow-wrap: initial !important; box-sizing: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific,sans-serif,Tahoma,Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 990px; top: 36px; opacity: 0.55;\">\n<div id=\"s3gt_translate_tooltip_mini_logo\" class=\"s3gt_translate_tooltip_mini\" title=\"Translate selected text\"><\/div>\n<div id=\"s3gt_translate_tooltip_mini_sound\" class=\"s3gt_translate_tooltip_mini\" title=\"Play\"><\/div>\n<div id=\"s3gt_translate_tooltip_mini_copy\" class=\"s3gt_translate_tooltip_mini\" title=\"Copy text to Clipboard\"><\/div>\n<\/div>\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 el_class=\u201dimage_frame\u201d]<style> .gvpfpmain1128 .fp-controls { background-color:#878477 !important;}\n\t\t\t   .gvpfpmain1128 .fp-timeline { background-color: #EBEBE2 !important;}\n\t\t\t   .gvpfpmain1128 .fp-progress { background-color: #404040 !important;}\n\t\t\t   .gvpfpmain1128 .fp-buffer { background-color: #BAB9AC !important;} \n\t\t\t   .gvpfpmain1128 .fp-time { font-size:11px !important; }.overlay2 { display: inline-block; }<\/style><\/p>\n<div class=\"gvpfpmain1128\" style=\"text-align:center;\"><div style=\"max-width:px; margin-right:0px;display:inline-block;width:100%; \"> <div style=\"max-width:px; \" class=\"flowplayer flowplayer1128 minimalist no-time no-volume no-mute \" data-key=\"$940018184765530\" data-analytics=\"UA-4183565-3\" data-ratio=\"0.5625\" data-embed=\"false\" data-fullscreen=\"false\"><video preload><source type=\"video\/mp4\" src=\"\/\/zoltane.com\/pages\/wp-content\/uploads\/PerfVis.mp4\"><\/source><\/video><\/div>\n<\/div><\/div>\n<script> jQuery(document).ready(function($){ $(\".flowplayer1128\").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 indicator cells have different modes:\n<ul>\n<li>Chosen stat in the direction of the viewport camera<\/li>\n<li>Worst stat in the direction of the viewport camera<\/li>\n<li>Worst direction for chosen stat<\/li>\n<li>Worst stat of worst direction<\/li>\n<\/ul>\n<p>The colors correspond to a freely adjustable min-max time range.<\/p>\n<p>The cells are instanced static meshes sharing the same material so thousands can be displayed without problems. I used the instance\u2019s scale to push extra data, the stats into the material. Those values are used to change text, color and arrow direction while the instance\u2019s scale is compensated in the vertex shader.[\/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]Another editor side visualizer I made is for displaying metadata associated with splines:[\/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> .gvpfpmain1125 .fp-controls { background-color:#878477 !important;}\n\t\t\t   .gvpfpmain1125 .fp-timeline { background-color: #EBEBE2 !important;}\n\t\t\t   .gvpfpmain1125 .fp-progress { background-color: #404040 !important;}\n\t\t\t   .gvpfpmain1125 .fp-buffer { background-color: #BAB9AC !important;} \n\t\t\t   .gvpfpmain1125 .fp-time { font-size:11px !important; }.overlay2 { display: inline-block; }<\/style><\/p>\n<div class=\"gvpfpmain1125\" style=\"text-align:center;\"><div style=\"max-width:px; margin-right:0px;display:inline-block;width:100%; \"> <div style=\"max-width:px; \" class=\"flowplayer flowplayer1125 minimalist no-time no-volume no-mute \" data-key=\"$940018184765530\" data-analytics=\"UA-4183565-3\" data-ratio=\"0.5625\" data-embed=\"false\" data-fullscreen=\"false\"><video preload><source type=\"video\/mp4\" src=\"\/\/zoltane.com\/pages\/wp-content\/uploads\/SplineVis.mp4\"><\/source><\/video><\/div>\n<\/div><\/div>\n<script> jQuery(document).ready(function($){ $(\".flowplayer1125\").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]Strings, ID numbers, spline directions and inter-spline relations are shown. The meshes and UMG widgets are managed by an editor ticker blueprint which factors in viewport camera location, orientation, nearest splines and their properties.[\/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]We also have an editor tool blueprint for locating collision problems. When fired it traces for colliders in a circle, increasing the radius every frame:[\/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> .gvpfpmain1129 .fp-controls { background-color:#878477 !important;}\n\t\t\t   .gvpfpmain1129 .fp-timeline { background-color: #EBEBE2 !important;}\n\t\t\t   .gvpfpmain1129 .fp-progress { background-color: #404040 !important;}\n\t\t\t   .gvpfpmain1129 .fp-buffer { background-color: #BAB9AC !important;} \n\t\t\t   .gvpfpmain1129 .fp-time { font-size:11px !important; }.overlay2 { display: inline-block; }<\/style>\n<div class=\"gvpfpmain1129\" style=\"text-align:center;\"><div style=\"max-width:px; margin-right:0px;display:inline-block;width:100%; \"> <div style=\"max-width:px; \" class=\"flowplayer flowplayer1129 minimalist no-time no-volume no-mute \" data-key=\"$940018184765530\" data-analytics=\"UA-4183565-3\" data-ratio=\"0.5625\" data-embed=\"false\" data-fullscreen=\"false\"><video preload><source type=\"video\/mp4\" src=\"\/\/zoltane.com\/pages\/wp-content\/uploads\/CollisionTester.mp4\"><\/source><\/video><\/div>\n<\/div><\/div>\n<script> jQuery(document).ready(function($){ $(\".flowplayer1129\").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_text_separator title=\u201dMaterials\u201d text_in_box=\u201dyes\u201d text_position=\u201dcenter\u201d box_border_style=\u201dsolid\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]The most complex material in the simulator by far is for the road. Beyond mixing textures which capture the road surface at different scales it also reacts to changing weather. Our environment manager system controls time of day, time of year, location on earth, temperature, wind and so on.[\/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> .gvpfpmain1127 .fp-controls { background-color:#878477 !important;}\n\t\t\t   .gvpfpmain1127 .fp-timeline { background-color: #EBEBE2 !important;}\n\t\t\t   .gvpfpmain1127 .fp-progress { background-color: #404040 !important;}\n\t\t\t   .gvpfpmain1127 .fp-buffer { background-color: #BAB9AC !important;} \n\t\t\t   .gvpfpmain1127 .fp-time { font-size:11px !important; }.overlay2 { display: inline-block; }<\/style>\n<div class=\"gvpfpmain1127\" style=\"text-align:center;\"><div style=\"max-width:px; margin-right:0px;display:inline-block;width:100%; \"> <div style=\"max-width:px; \" class=\"flowplayer flowplayer1127 minimalist no-time no-volume no-mute \" data-key=\"$940018184765530\" data-analytics=\"UA-4183565-3\" data-ratio=\"0.5625\" data-embed=\"false\" data-fullscreen=\"false\"><video preload><source type=\"video\/mp4\" src=\"\/\/zoltane.com\/pages\/wp-content\/uploads\/WeatherManager.mp4\"><\/source><\/video><\/div>\n<\/div><\/div>\n<script> jQuery(document).ready(function($){ $(\".flowplayer1127\").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 modified the Speed Tree materials so it handles the color change and loss of foliage. The wheel tracks are either placed as a special, tiling noise or can be based on recordings of actual vehicles driving on the road.[\/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]To add random potholes, oil spills, dirt and other details to the road I created a texture bomber:[\/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> .gvpfpmain1126 .fp-controls { background-color:#878477 !important;}\n\t\t\t   .gvpfpmain1126 .fp-timeline { background-color: #EBEBE2 !important;}\n\t\t\t   .gvpfpmain1126 .fp-progress { background-color: #404040 !important;}\n\t\t\t   .gvpfpmain1126 .fp-buffer { background-color: #BAB9AC !important;} \n\t\t\t   .gvpfpmain1126 .fp-time { font-size:11px !important; }.overlay2 { display: inline-block; }<\/style>\n<div class=\"gvpfpmain1126\" style=\"text-align:center;\"><div style=\"max-width:px; margin-right:0px;display:inline-block;width:100%; \"> <div style=\"max-width:px; \" class=\"flowplayer flowplayer1126 minimalist no-time no-volume no-mute \" data-key=\"$940018184765530\" data-analytics=\"UA-4183565-3\" data-ratio=\"0.5625\" data-embed=\"false\" data-fullscreen=\"false\"><video preload><source type=\"video\/mp4\" src=\"\/\/zoltane.com\/pages\/wp-content\/uploads\/TextureBombing.mp4\"><\/source><\/video><\/div>\n<\/div><\/div>\n<script> jQuery(document).ready(function($){ $(\".flowplayer1126\").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]Cell size, rotation, random seed and density can be adjusted. The cell contents are picked from a texture atlas. Parallax and normal mapping works properly even if a cell\u2019s content is rotated.[\/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=\u201d1110\u2033 img_size=\u201dfull\u201d alignment=\u201dcenter\u201d qode_css_animation=\u201d\u201d el_class=\u201dimage_frame\u201d][\/vc_column][\/vc_row]\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]aiSim is a simulator for self-driving cars. The ability to recreate real-world situations and create unique scenarios ensures the safe development of autonomous vehicle technology. Virtual testing guarantees that the final product can adapt to different environments&#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-1106","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/zoltane.com\/pages\/wp-json\/wp\/v2\/pages\/1106","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=1106"}],"version-history":[{"count":14,"href":"https:\/\/zoltane.com\/pages\/wp-json\/wp\/v2\/pages\/1106\/revisions"}],"predecessor-version":[{"id":1134,"href":"https:\/\/zoltane.com\/pages\/wp-json\/wp\/v2\/pages\/1106\/revisions\/1134"}],"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=1106"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}