Howto:Dynamic Liveries via Canvas: Difference between revisions

Jump to navigation Jump to search
m
cat
m (cat)
(28 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{Canvas Navigation}}


== Objective ==
== Objective ==
Demonstrate how to modify/animate liveries using Nasal/Canvas.
Demonstrate how to modify/animate liveries using Nasal/Canvas.


{{FGCquote
  |The code is already in place for the "dirtying" effect - it's a fairly simple linear introduction of the dirt texture, becoming less transparent the more the aircraft flies without being washed. Being washed also includes rain - continued exposure to precipitation will "wash away" dirt by making the dirt layer more transparent according to the heaviness of the weather. It's been tried on the APU smudge, and whilst the values will need to be tweaked, it already works pretty much to my expectations and satisfaction.
  |{{cite web |url=http://forum.flightgear.org/viewtopic.php?p=218792#p218792
    |title=<nowiki>Re: Two Images to a Texture</nowiki>
    |author=<nowiki>Algernon</nowiki>
    |date=<nowiki>Wed Sep 17</nowiki>
  }}
}}
{{FGCquote
  |But in the long-term, I would prefer turning this into a Nasal class that can manage multiple Canvases per aircraft, so that we can also re-implement the existing livery system accordingly, so that it stops interfering with canvas. Which would also mean that people can reuse the same class for placing bullet holes or doing other fancy things (e.g. [[Immatriculation]])
  |{{cite web |url=http://forum.flightgear.org/viewtopic.php?p=218789#p218789
    |title=<nowiki>Re: Two Images to a Texture</nowiki>
    |author=<nowiki>Hooray</nowiki>
    |date=<nowiki>Wed Sep 17</nowiki>
  }}
}}


== Proof of Concept ==
== Proof of Concept: Exhaust dirt ==
''by [[User:Algernon|Algernon]] ([[User talk:Algernon|talk]]) 17:09, 17 September 2014 (UTC) ''
''by [[User:Algernon|Algernon]] ([[User talk:Algernon|talk]]) 17:09, 17 September 2014 (UTC) ''


Line 10: Line 28:
The intention is to use Canvas to allow multiple textures per livery, in this case those textures being the original livery paintwork and another, alpha-transparent texture consisting of dirt streaks specifically added to the livery paintwork to match with vents, seams and other sources of grimy build-ups. The intention is to allow dynamic management of the transparency of the dirt layer according to time and exposure to various elements, maintaining compatibility with the standard livery switching method and working similarly whether Rembrandt is enabled or not.  
The intention is to use Canvas to allow multiple textures per livery, in this case those textures being the original livery paintwork and another, alpha-transparent texture consisting of dirt streaks specifically added to the livery paintwork to match with vents, seams and other sources of grimy build-ups. The intention is to allow dynamic management of the transparency of the dirt layer according to time and exposure to various elements, maintaining compatibility with the standard livery switching method and working similarly whether Rembrandt is enabled or not.  


<gallery mode=packed>
<gallery mode="packed">
Two-layers.jpg|The two textures concerned, the ASG paintwork and the separate alpha transparency with dirt streaks
Two-layers.jpg|The two textures concerned, the ASG paintwork and the separate alpha transparency with dirt streaks
Dynamic-Textures-First-Try.jpg|A first (failed) attempt to put a canvas onto a model object in place of its texture.
Dynamic-Textures-First-Try.jpg|A first (failed) attempt to put a canvas onto a model object in place of its texture.
Ef2000dyn1.jpg|The EF2000 showing a dynamically-changed texture on the fuselage - at the moment, the resolution appears to be wrong and the UV coordinates seem to be being ignored.
Ef2000dyn1.jpg|The EF2000 showing a dynamically-changed texture on the fuselage - at the moment, the resolution appears to be wrong and the UV coordinates seem to be being ignored.
 
File:Ef2000dyn2.jpg|Changing the dialog window size to be the same size as the texture fixed the issue - note that the fuselage sections are free of dirt (except the APU exhaust smudge, which is a special case) where as the wings and tail have integral dirt in the texture.
File:Ef2000dyn3.jpg|A full-screen illustration using the updated Canvas code to make the canvas independent of the window, but with the window still displaying the canvas. Here, only the base "clean" paintwork texture is added to the fuselage element.
File:Ef2000dyn4.jpg|After creating a canvas with the base "clean" paintwork texture, another child is added containing the dirt layer transparency. The effect is seen both in the dialog window and on the airframe.
</gallery>
</gallery>


Line 27: Line 47:


=== Canvas Code ===
=== Canvas Code ===
From the code snippets above and [[Howto:Using_raster_images_and_nested_canvases]], I've put together my first attempt at some Canvas code. It appears that the canvas is the right size, and both .jpg and .png textures are loaded. But the placement line did not seem to make any difference to the texture on the named model object ("Fuselage"). When the native XML/Nasal livery object was commented out, the image was successfully displayed on the fuselage, but incorrectly sized and apparently without UV mapping (see image below).
From the code snippets above and [[Howto:Using raster images and nested canvases]], I've put together my first attempt at some Canvas code. It appears that the canvas is the right size, and both .jpg and .png textures are loaded. But the placement line did not seem to make any difference to the texture on the named model object ("Fuselage"). When the native XML/Nasal livery object was commented out, the image was successfully displayed on the fuselage, but incorrectly sized and apparently without UV mapping (see image below).


<syntaxhighlight lang="nasal">
<syntaxhighlight lang="nasal">
# Create a Canvas dialog window to hold the canvas and show that it's working
# Create a standalone Canvas (not attached to any GUI dialog/aircraft etc)
var window = canvas.Window.new([512,512],"dialog");
var myCanvas = canvas.new({
  "name": "Livery Test",  # The name is optional but allow for easier identification
  "size": [2048, 2048], # Size of the underlying texture (should be a power of 2, required) [Resolution]
  "view": [2048, 2048],  # Virtual resolution (Defines the coordinate system of the canvas [Dimensions]
                        # which will be stretched the size of the texture, required)
  "mipmapping": 1      # Enable mipmapping (optional)
});


# Create a Canvas in the window and create a containing group called root
# create our top-level/root group that contains all other Canvas elements
var myCanvas = window.createCanvas();
var root = myCanvas.createGroup();
var root = myCanvas.createGroup();


# Add a placement by replacing the textured face "Fuselage" in the 3D model
# Add a placement by replacing the textured face "Fuselage" in the 3D model
# This replaces the texture on the aircraft and attaches the Canvas texture
myCanvas.addPlacement({"node": "Fuselage"});
myCanvas.addPlacement({"node": "Fuselage"});
 
# Put a raster image into the canvas
# hash with all images added
root.createChild("image")
var layers = {};
     .setFile("Aircraft/EF2000/Models/EF2000.png")
# texture path
     .setSize(2048,2048);
var path="Aircraft/EF2000/Models/";
foreach(var image; ['EF2000.png','EF2000-dirt.png']) {
if(contains(layers, image)) print("Warning: replacing texture (added twice): ", image);
# Put a raster image into the canvas and save the image in a hash: layers['EF2000.png].hide();
layers[image] = root.createChild("image")
     .setFile( path~image )
    .setSize(2048,2048)
}
 
# object-oriented settimer() replacement
# see: http://wiki.flightgear.org/List_of_Nasal_extension_functions#maketimer.28.29_.282.11.2B.29
var timer_hide = maketimer(3.0, func() {
  layers['EF2000-dirt.png'].hide();
});
 
var timer_show = maketimer(5.0, func() {
  layers['EF2000-dirt.png'].show();
});
 
# start those two timers to hide/show the dirt texture with 2 second delays
timer_hide.start();
timer_show.start();
 
# Create a Canvas dialog window to hold the canvas and show that it's working
# the Canvas is now standalone, i.e. continues to live once the dialog is closed!
var window = canvas.Window.new([512,512],"dialog");
window.setCanvas(myCanvas);
</syntaxhighlight>
 
Here's another slightly-restructured version (untested), to better encapsulate the concept of a "managed texture" so that the code can be reused for other aircraft/purposes, e.g. for placing bullet holes etc:
<syntaxhighlight lang="nasal">
var ManagedTexture = {
 
# this create a new TextureManager object
new: func(name, size, path) {
# create a temporary object that inherits from TextureManager
var m = {parents:[ManagedTexture]};
 
# Create a standalone Canvas (not attached to any GUI dialog/aircraft etc)
m.canvas = canvas.new({
"name": name, # The name is optional but allow for easier identification
"size": [size[0], size[1]], # Size of the underlying texture (should be a power of 2, required) [Resolution]
"view": [size[0], size[1]], # Virtual resolution (Defines the coordinate system of the canvas [Dimensions]
                        # which will be stretched the size of the texture, required)
"mipmapping": 1      # Enable mipmapping (optional)
});
 
# create our top-level/root group that contains all other Canvas elements
m.root = m.canvas.createGroup();
 
# hash with all layers/images added
m.layers = {};
m.basepath = path;
 
# return the new object to the caller
return m;
},
 
replaceTexture: func(name) {
# Add a placement by replacing the textured face specified (name) in the 3D model
# This replaces the texture on the aircraft and attaches the Canvas texture
m.canvas.addPlacement({"node": name});
},
 
addDynamicLayer: func(filename, callback=nil) {
if(contains(layers, image)) print("Warning: replacing texture (added twice): ", image);
# Put a raster image into the canvas and save the image in a hash: layers['EF2000.png].hide();
m.layers[image] = root.createChild("image")
    .setFile( m.basepath~image )
     .setSize(2048,2048)
return m.layers[image];
},
}; # of ManagedTexture
 
 
# now, create a new managed texture, specifying the path to use for texture lookups
var ExhaustDirt = ManagedTexture.new( name:"ExhaustDirt",
size:[2048,2048],
path:'Aircraft/EF2000/Models/' );
 
ExhaustDirt.replaceTexture('Fuselage');
 
# Create a Canvas dialog window to hold the canvas and show that it's working
# the Canvas is now standalone, i.e. continues to live once the dialog is closed!
var window = canvas.Window.new([512,512],"dialog");
window.setCanvas(ExhaustDirt.canvas);
 
foreach(var layer; [ {file:'EF2000.png'},
{file:'EF2000-dirt.png'} ]) {
ExhaustDirt.addDynamicLayer(layer.file);
}
 
 
var timer_hide = maketimer(3.0, func() {
  ExhaustDirt.layers['EF2000-dirt.png'].hide();
});
 
var timer_show = maketimer(5.0, func() {
  ExhaustDirt.layers['EF2000-dirt.png'].show();
});
 
# start those two timers to hide/show the dirt texture with 2 second delays
timer_hide.start();
timer_show.start();
 
</syntaxhighlight>
</syntaxhighlight>


Line 195: Line 325:
   }}
   }}
}}
}}
[[Category:Canvas]]
[[Category:Aircraft enhancement]]

Navigation menu