Tonight we posted the code for Stereoscopic mode in the Second Life viewer to the SL developer’s list, here: https://jira.secondlife.com/browse/VWR-2972
Also, below is the code for the Second Life scripts that handle our motion capture interface for Becoming Dragon. This script simply reads an XML file over http, extracts the coordinates out and moves the object that contains this script to those coordinates. Then, one only needs to attach the object to your avatar and click on the object to start the motion capture. I left in my comments and debg code. In the next few days we’ll make our code for reading the live Vicon motion capture data out and translating them into XML.
Really, this would be most useful if you use a few objects to represent your avatar and make your avatar invisible. With such a system, by getting the base coordinates right for each body part, you could have full body motion capture. We simply did not have the time to get multiple objects working and mappe into a dragon body, so we only used one coordinate to do position tracking within the room at CRCA, mapping into the room in Second Life.
Since the vicon code is separate, these scripts could easily be used with a Wii, if you use a program like aka.wiimote or Darwiin remote to get the four points of mocap data from the wiibar and translate them to xml. Then these scripts could read that xml over http and viola! wii Second Life motion capture.
Here’s the code:
integer in_world = 0;
key http_request_id;
float timer_secs = 1;
integer moving = 0;
integer moves = 0;
integer max_moves = 60;
//begin xml reading code
list markers;
parseElement(string line)
{
if(line == “<markers>”)
{
//llOwnerSay(“markers line found, starting new markers list”);
markers = [];
return;
}
// determine type of element
string element = llGetSubString(line, 0, llSubStringIndex(line, ” “) – 1);
element = llToLower(element);
// parse known elements
parseMarkerElement(llGetSubString(line, llStringLength(element) + 1, -1));
}
parseMarkerElement(string line) {
//llOwnerSay(“parsing line: “+line);
if(line == “</markers>”) return;
// parse attribute name/value pairs
list parts = llParseString2List(line, ["=\'", "\' ", "\'", ">", "<\/", "\'"], []);
integer n = llGetListLength(parts);
integer i;
// set default values
string position_x = “”;
string position_y = “”;
string position_z = “”;
string visibility = “”;
string marker_name = “”;
// loop through name/value pairs
for(i = 0; i < n; i += 2)
{
// read name/value pair
string name = llList2String(parts, i);
name =
name = llToLower(name);
string value = llList2String(parts, i + 1);
//find content of marker node, slightly hackish
if(value == “marker”) {
value = name;
name = “name”;
}
// assign known values
if(name == “position_x”) position_x = value;
if(name == “position_y”) position_y = value;
if(name == “position_z”) position_z = value;
if(name == “visibility”) visibility = value;
if(name == “name”) marker_name = value;
}
// add new item
if(visibility == “true”)
{
markers += [marker_name];
markers += [position_x];
markers += [position_y];
markers += [position_z];
}
}
//end xml reading code
default {
state_entry() {
if(in_world == 0)
{
llOwnerSay(“Hi, I’m the new movement object xml!”);
in_world = 1;
}
llSetStatus(STATUS_PHYSICS, TRUE);
}
http_response(key request_id, integer status, list metadata, string body) {
//if ( moves < max_moves ) {
list coords;
//llOwnerSay(“http response received…”);
if (request_id == http_request_id) {
//llSetText(body, <0,0,1>, 1);
//llOwnerSay(body);
// parse out xml elements
//list lines = llParseString2List(body, ["/>","<", ">", "\n"], []);
list lines = llParseString2List(body, ["\n"], []);
// loop through elements
integer n = llGetListLength(lines);
integer i;
for(i = 0; i < n; i++)
parseElement(llList2String(lines, i));
//llOwnerSay(“markers: “+(string)markers);
//move by offsets in html body
//= llGetPos();
vector position;
vector offset;
list thiscoord;
if(llGetListLength(markers) > 2) {
//llOwnerSay(“using marker “+llList2String(markers, 0) );
//change these numbers, after the +’s to your origin in your sim
offset.x = (llList2Float(markers, 1)/1000) + 183;
offset.y = (llList2Float(markers, 2)/1000) + 16;
offset.z = (llList2Float(markers, 3)/1000) + 33;
if(offset.x > 0 && offset.y > 0 && offset.z > 0)
{
//llSetPos(offset);
llMoveToTarget(offset, 0.1);
//llOwnerSay(“+++ Moving to “+(string)offset.x+” , “+
// (string)offset.y+” , “+
// (string)offset.z);
llSetText((string)offset.x+”,”+(string)offset.y+”,”+(string)offset.z, <0,0,1>, 1);
}
//moves++;
} //end if coords
} //end if (request_id == http_request_id)
// } else { //end if moves < 5
// llSetTimerEvent(0);
// llOwnerSay(“Newmove : “+(string)moves+” moves! Stopping movement.”);
// moving = 0;
// moves = 0;
//}
}
timer() {
//llOwnerSay((string)timer_secs + ” second timer elapsed, sending http request…”);
http_request_id = llHTTPRequest(“http://yourserver.com/coords.php”, [], “”);
}
touch_start(integer total_number) {
if(moving == 0) {
llSetTimerEvent(timer_secs);
llOwnerSay(“Touched! Timer starting. sending http request…”);
http_request_id = llHTTPRequest(“http://yourserver.com/coords.php”, [], “”);
moving = 1;
} else {
llSetTimerEvent(0);
llOwnerSay(“Touched! Stopping movement.”);
moving = 0;
moves = 0;
}
}
}
And here’s a sample xml data file…
<?xml version='1.0' encoding='ISO-8859-1'?>
<markers>
<marker position_x='316.474' position_y='213.859' position_z='42.4289'visibility='true'>Default:Marker1</marker>
<marker position_x='540.871' position_y='125.609' position_z='44.586'visibility='true'>Default:Marker2</marker>
<marker position_x='602.447' position_y='263.058' position_z='47.1262'visibility='true'>Default:Marker3</marker>
<marker position_x='634.26' position_y='337.013' position_z='48.9091'visibility='true'>Default:Marker4</marker>
<marker position_x='0' position_y='0' position_z='0'visibility='false'>wand:Marker1</marker>
<marker position_x='0' position_y='0' position_z='0'visibility='false'>wand:Marker2</marker>
<marker position_x='0' position_y='0' position_z='0'visibility='false'>wand:Marker3</marker>
</markers>