For bugs and new features, use the issue tracker located at GitHub.
Also try the chat room!
ElementSortingHelper.cs help
Rogad wrote at 2014-02-23 02:08:
After a long search I eventually found that I need to order my rendering.
Objo, I found this ElementSortingHelper.cs file and it's similar to other scripts I have seen.
I was wondering if this was a stab at ordering the rendering so that transparent textures get rendered in the right order.
Could you give me an example of how to use it please if that is what it does ?
I see this in the code :
public static void AlphaSort(Point3D cameraPosition, Model3DCollection models, Transform3D worldTransform)
I am stuck on what to use for 'worldTransform'. My Helix Viewport is called 'myView' and I can get as far as :
Visual3DCollection mymodels = (Visual3DCollection)myView.Children;
ElementSortingHelper.AlphaSort(myView.Camera.Position, mymodels, ???)
But what should go in the '???' Thanks for taking a look :)
Rogad wrote at 2014-02-23 14:58:
<Grid HorizontalAlignment="Left" Height="517" Margin="241,10,0,0" VerticalAlignment="Top" Width="559">
<HelixToolkit:HelixViewport3D x:Name="myView" ZoomExtentsWhenLoaded="True" Margin="10" Grid.RowSpan="2">
<HelixToolkit:HelixViewport3D.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF4987D3" Offset="0.993"/>
<GradientStop Color="White" Offset="0.007"/>
</LinearGradientBrush>
</HelixToolkit:HelixViewport3D.Background>
<!-- Remember to add light to the scene -->
<HelixToolkit:SunLight/>
<ModelVisual3D x:Name="scene"/>
<!-- You can also add elements here in the xaml -->
<HelixToolkit:GridLinesVisual3D Width="8" Length="8" MinorDistance="1" MajorDistance="1" Thickness="0.01"/>
</HelixToolkit:HelixViewport3D>
</Grid>
objo wrote at 2014-02-23 21:39:
Visual3D
containing the models. Note that the second argument should be a
Model3DCollection
. In your case, I think you can use
Transform3D.Identity
for the transform.Rogad wrote at 2014-02-23 22:16:
Hmm how would I do the Model3DCollection then ?
Rogad wrote at 2014-02-24 00:30:
private void Button_Click_4(object sender, RoutedEventArgs e)
{
Model3DCollection mymodels = new Model3DCollection();
mymodels.Add(current);
ElementSortingHelper.AlphaSort(myView.Camera.Position, mymodels, Transform3D.Identity);
}
It does nothing, but I am not entirely sure if my usage is correct.2 Questions: mesh export and adding controls
ChevyCP wrote at 2011-11-22 18:52:
Hi,
First off, awesome code! Very well done! Using the "subdivision demo", I played with the options and found a cube I like. I recreated it in a new project with just the options neccessary. My question is what is the best way to export that mesh. I'm thinking of using it as a windows resource so I can view VS design mode as well as in blend.
My next question is what is the best way to put controls on that cube. Basically I have an app that has different menus, but instead of boring pop-ups I want to have a cube spin around to the appropriate side. I have this working using viewport2dvisual3d panels as in the example here:
http://archive.msdn.microsoft.com/wpf3dcubewindow
The difference is instead of a cube with sharp corners, I want one with round corners. So my thinking is I use your tools to create the 3d cube I'm after and wrap my controls around it. Any info would be much appreciated!
Thanks.,
Viewport2DVisual3D
objo wrote at 2011-11-23 06:45:
hi ChevyCP, note that the subdivided cube is not containing texture coordinates. It could, but that has to be added into the subdivision algorithm. Sorry I have not used the Viewport2DVisual3D panels, so cannot give you any input there.
Use the XamlExporter if you want to use the subdivided cube in Blend!
ChevyCP wrote at 2011-11-29 16:32:
Thanks. I'm giving that a try, but get the following error: "Cannot serialize a generic type 'System.Collections.Generic.List`1[System.Int32[]]'." Here is my code where "Cube" is the name of my MeshVisual3D:
XamlExporter exporter = new XamlExporter("C:\\directory\\myExport.xaml"); exporter.CreateResourceDictionary = true; exporter.Export(Cube); exporter.Close();
objo wrote at 2011-12-03 12:04:
I think you can only use built-in Windows.Media.Media3D Visual3D when using the XamlExporter.
Otherwise you need to register the custom types with the XamlWriter - I have not checked this.
DisableUpdates() & EnableUpdates() in MeshElement3D
phichaikid wrote at 2011-11-07 11:34:
Hallo,
I am developing a visualizer of multi-body system simulation. There are components, which bump into each other during the simulation. I can compute the bumping pressure and visualize it with ArrowVisual3D. In an animation, there can be 100 - 1000 of ArrowVisual3D to update during each frame (time point). I plug the update of ArrowVisual3D in CompositionTarget.Rendering. I have to update .Point1, .Point2 (direction of pressure), .HeadLength, .Diameter (for better visualization).
Till change set 70988, there is DisableUpdates() & EnableUpdates() in MeshElement3D, which I use in the update process of ArrowVisual3D, because I have to update 4 properties but do not want the program to update ArrowVisual3D 4 times. After the change set 70988, there aren't DisableUpdates() & EnableUpdates() anymore. Is there any ways to achieve the same effect i.e. ArrowVisual3D is updated only 1 time in each frame, even though, I want to update 4 properties. Or should I copy this DisableUpdates() & EnableUpdates() to the newer release?
I did some searchs in google but did not find anything useful from .net framework. Or do you perhaps implement other method in Helix 3D Toolkit, which yields the same effect?
Thanks in advanced,
Chatdanai.
objo wrote at 2011-11-07 12:43:
hi Chatdanai, I made two changes that could help. Get the latest source and try
myArrow.BeginEdit();
// do your changes
myArrow.EndEdit();
or
myArrow.Diameter = 0;
// change the points and head length
myArrow.Diameter = arrowDiameter;
phichaikid wrote at 2011-11-07 13:23:
Hallo objo,
Thank you very much for the super fast response.
I have tried both approaches. The 2nd one works perfectly. But the 1st one updates the ArrowVisual3D only if I change another property after call to EndEdit(). Is it intentionally? I think you mean I should change properties within calls to BeginEdit() & EndEdit().
Anyway, it is working for me now. Thanks a lot.
Best regards,
Chatdanai.
objo wrote at 2011-11-07 13:40:
I checked in a correction. The first solution should hopefully also work now. Please verify!
phichaikid wrote at 2011-11-07 14:44:
Hallo objo,
verified. Both works perfectly now.
Thanks again,
Chatdanai.
HelixView3D cannot catch MouseWheel event
Flanfl wrote at 2011-06-17 17:14:
Hi,
I'm doing a project where I have to do a panorama application and I'm using the great sample that you provided. However, I need to handle mouse event and I've issue with the MouseWheel event which is never fired. I tried it in my code and in your sample as follow:
<ht:HelixView3D x:Name="view1" ShowViewCube="False" ShowCameraTarget="False" CameraMode="FixedPosition" RotationSensitivity="0.1"
ShowCoordinateSystem="True" ShowFieldOfView="True" ShowFrameRate="True" MouseWheel="view1_MouseWheel">
The code behind is:
private void view1_MouseWheel(object sender, MouseWheelEventArgs e) { int i = 0; }
If I put a break point on the line int i = 0, nothing hapen when I scroll. I've tried another mouse event: MouseMove and it is working fin. MouseWheel is also working fine with other components. I'm guessing that you are handling the MouseEvent (or else it would not be possible to zoom) but I cannot find where. I would like to overload it to continue to use your functionalities and to add mine on it.
Do you have any idea of where I should look at?
Thanks!
objo wrote at 2011-06-19 12:31:
hi Flanfl, you find the mouse wheel handling in the CameraController code. It is setting Handled to true as you noticed.
Do you want to disable mouse wheel zooming? That could be a feature to add!
I suggest adding a MouseWheelAction { None, Zoom } or a EnableMouseWheelZooming property.
Will this work for you?
Flanfl wrote at 2011-06-21 12:38:
Hi,
Thanks for the answer, I saw the CameraController class but when I created a HelixView3D object, the property CameraController is always null (I tried in the panorama test sample as well) and it is a read only property.
I think I do not understand something but I don't know what.
I do not want to disable the zooming function I just want to know how much a user zoom in/out so I can know how "close" he is from the picture, they might be already a property that can tell me that but I didn't find it ^^
So what I'am doing wrong?
Thanks!
objo wrote at 2011-06-22 10:28:
The CameraController of the HelixView3D is set when the template is applied. HelixView3D is not supporting custom camera controllers (I try to keep it simple), so you are right - it is only gettable.
Did you try calculating the distance from the Camera.LookDirection.Length or Camera.FieldOfView (for 'FixedPosition' camera controller)?
Flanfl wrote at 2011-06-22 16:02:
Hi Objo,
I already tried LookDirection.Length but it was not really useful, but I didn't thought about FieldOfView! That's what I needed :)
Thanks a lot!
Camera Default Settings
przem321 wrote at 2012-01-15 07:03:
Hi,
one more issue: it would be nice to provide a way to set up own defaults for the camera which can be then called by the ResetCamera function. Of course, one can write an own Reset function just by setting the camera Props. So far so good, nice, but since the CameraResetGesture always calls the CameraHelper.ResetCamera(...) and these values are hard coded, there is no way to use the gesture for an own default camera. Or am I wrong and there is a way to do that?
ddklo wrote at 2012-01-15 12:07:
I'm not that familiar with the Gestures, but currently we are solving this by removing all input bindings from the CameraController class and adding our own in code (for some reason mouse wheel scrolling is still active). You can find the default ones in the Generic.xaml resource dictionary. Not sure if there is a better way, but it appears to be working.
przem321 wrote at 2012-01-15 22:39:
Well, removing all bindings and adding own functions is a solution... which causes a lot of overhead to a in general very well defined camera. I wish one could replace particular bindings, such like that:
view.CameraController.CommandBindings.RemoveAt(5); view.CameraController.CommandBindings.Add(new CommandBinding(CameraController.ResetCameraCommand, (s, ea) => { view.Camera.Position = new Point3D(4, 2, 16); view.Camera.LookDirection = new Vector3D(-4, -2, -16); view.Camera.UpDirection = new Vector3D(0, 1, 0); } ));
This only works well if one replaces the binding for CameraController.ResetCameraCommand, but in order to do so one has to know that it is at index #5 in the list. Well, this is not the nicest solution I guess... Is there any way to do it better?
objo wrote at 2012-01-16 05:55:
Should find a solution where it is not necessary to change the command bindings.
Idea: could we add a "DefaultCamera" property in the CameraController and HelixViewport3D. The Reset command could then copy the properties of the "DefaultCamera" to the current camera (or clone the default camera and assign it to the current camera).
do you see other solutions?
przem321 wrote at 2012-01-16 07:43:
Yes, a DefaultCamera property was the first thing I was thinking about too. This is a reasonable solution.
On the other hand, replacing bindings might be also a useful solutions for those who really know what they are doing and wish to customize their camera controller. But I am not enough into the commanding to say how to do that properly. I will first need to read all this stuff here: http://msdn.microsoft.com/en-us/library/ms752308.aspx which I have no time for at the moment.
objo wrote at 2012-01-16 08:39:
the current implementation makes it easy to change the gestures, but more work to change the command bindings.
Let us know if you can find a better architecture/pattern to use here!
objo wrote at 2012-01-19 11:01:
added a "DefaultCamera" property in the HelixViewport3D. If this is defined, it will be used for the initial camera position and to reset the camera.
CompositionTarget.Rendering memory leak
ddklo wrote at 2012-01-12 18:56:
Hi.
I notice that this event is subscribed to in multiple places in the Helix 3D Toolkit creating a memory leak if it is not unsubscribed. In some of the places there is a method or property to unsubscribed from this event which is nice, but it can be hard to know when these objects should be disposed. In our app we leak HelixViewport3D's because there is no way to unsubscribed from this event which is attached in the constructor for the fps. Perhaps weak event subscription as discussed in this blog post: http://blog.catenalogic.com/post/2011/11/23/A-weak-event-listener-for-WPF-Silverlight-and-Windows-Phone-7.aspx could be used to allow for garbage collection. Or an public Unsubscribe/Dispose method on the HelixViewport3D.
Regards
Dagfinn
objo wrote at 2012-01-12 21:09:
thanks for the link, that's an interesting implementation!
Another approach: Can overriding OnVisualParentChanged be used to unsubcribe the Rendering events? Like I did in the ScreenSpaceVisual3D class, it seems to work there. Subscribe if the parent is not null, and unsubscribe if the parent is null.
ddklo wrote at 2012-01-13 00:03:
I think the OnVisualParentChanged method only works when the parent becomes "null" which might not always be the case unless it is explicit set to be null be implementing some dispose logic. We have some scenarios where we generate at lot of screenshots of the HelixViewport3D (hv) off screen where the hv is assigned a temporary RootVisual and in another circumstances the hv is contained within a another control so even though the container control parent might become "null" I don't think the hv parent will be null.
Since knowing exactly when to unsubscribe from the CompositionTarget.Rendering can be hard I think the weak event solution looks good. Also it might make sense to only subscribe to the event if needed (ShowTriangleCountInfo or ShowFrameRate is enabled) since it is fired a lot.
ddklo wrote at 2012-01-15 00:10:
Hi.
I profiled the source code with the ANTS MemoryProfiler by having a window open another window containing the HelixVewport3D and other visuals. By subscribing to the CompositionTarget.Rendering event a strong reference is created from the object subscribing to System.Windows.Media.MediaContext which prevents the object from being garbage collected. Even worse if the scene contains one of the visuals subscribing to this event the entire scene and viewport is kept in memory. Closing the window did not trigger the OnVisualParentChanged event so it was never removed for the visuals where this method is overrided.
By copying over the WeakEventListner for the blog post and replacing all the events subscriptions to CompositionTarget.Rendering with
var weakEvent = WeakEventListener.SubscribeToWeakEvent(this, null, "Rendering", CompositionTargetRendering);
all the memory leaks went away. And it did not seem to have any impact on the performance for the samples.
Currently this is quite a big issue for us, especially the event on the HelixViewport3D where there is no way to unsubscribe.
Do you think it makes sense changing the event subscription? If so can you provide a timeframe? We can work around it by compiling the source code ourself, but it would be nice to still get updates through nuget.
Regards Dagfinn
objo wrote at 2012-01-15 12:35:
hi Dagfinn, I am looking into this now! Thanks for good change suggestions!
I prefer to explicitly unsubscribe the events, but if there is not a reliable way to do this, I'll go for the weak event listener.
Can subscribing/unsubscribing to the Rendering event be done in the Loaded/Unloaded events? This seems to work in my test cases.
Using WeakEventListener I see the HelixViewport3Ds are freed, but it is leaking instances of WeakEventListener. Do you know what I am doing wrong? I used:
WeakEventListener<HelixViewport3D,CompositionTarget,EventArgs>.SubscribeToWeakEvent(this, null, "Rendering", this.CompositionTargetRendering);
ddklo wrote at 2012-01-15 13:07:
I agree that explictly unsubscribing usually is the prefered approch. But I think its quiet common to use weak events when designing WPF controls (see the Weak Event Pattern - http://msdn.microsoft.com/en-us/library/aa970850.aspx). I'm not sure why the framework designeres didn't make the CompositionTarget.Rendering a weak event (probably some performance reason I think thats why the signature is using EventArgs instead of RenderingEventArgs).
I think what you are seeing is the expected behaviour it can take a little while before the WeakEventListener is GC. Try waiting a while and then calling:
GC.Collect(); GC.WaitForPendingFinalizers();
The unloaded worked for my simple example for the HelixViewport3D, but then you have to be careful and reconnected when its loaded again. But since the Unloaded event is only for framework elements it can't be used for the Visual3D's. Not sure what would be the best approch overall, but I think since managing lifetime can be hard the weak event options is the safest. Otherwise it can be hard to know when the HelixToolkit could cause memory leaks without looking at the source code.
objo wrote at 2012-01-16 05:47:
Thanks! I was using dotTrace Memory, and it didn't do the garbage collection before taking the snapshot.
I have the Catel solution working, but I would like to see if it can be done with a standard WeakEventManager. I posted a question on stack overflow why a static event does not seem to work. Do you know?
http://stackoverflow.com/questions/8876112/using-weakeventmanager-with-a-static-event
ddklo wrote at 2012-01-16 11:08:
No, I'm not sure . Remember trying it myself without luck. It will be interesting to see if anyone knows.
There is an interesting article discribing different approches on codeproject:
http://www.codeproject.com/KB/cs/WeakEvents.aspx
I think the Catel solution is an improvment on Solution 4: Reusable Wrapper.
objo wrote at 2012-01-18 12:14:
Found the error (should set sender=null when calling DeliverEvent), will submit the solution using WeakEventManager soon.
Grunwald's article is great. I will also keep the Catel solution in mind!
ddklo wrote at 2012-01-19 10:21:
Hi.
I profiled some more and can't see any memory leaks now. Thank you for your efforts. I also think its worth removing the destructors/finalizers since they are not needed or only include them in the debug build because they are expensive for the gc and causes the objects to live longer.
objo wrote at 2012-01-19 11:07:
good, I'll remove the finalizers (in the latest changeset they are wrapped in #if DEBUGs) and Debug.WriteLine completely if the problem is solved! Using the HelixViewport3D in TabControls seems to hold the instances a little longer than other containers, but from what I can see, these HelixViewport3D instances are also freed later...
Unexpected skin behaviour
saphua wrote at 2011-02-24 18:55:
Hello,
Disclaimer: First time user of Helix and complete 3D nubcake.
I am trying to load and display 3d models from a game called League of Legends. The models are stored as .skn files and the materials as .dds files. I found two tools that help me conver these to a .obj and a .jpg file.
After converting I can add them to a Expression Bled project and drop the .obj file in my workspace. I can then alter the create DiffuseMaterial to use a ImageBrush and get this result:
http://stuff.saphua.com/Temp/Helix/blend.jpg
Now I am trying to do the same using Helix using this simple method which loads and parses the .obj file and changes the Diffusematerial to use an ImageBrush with the .jpg file:
private Model3D LoadFile(string objPath, string jpgPath) { BitmapImage bmp = new BitmapImage(); bmp.BeginInit(); bmp.UriSource = new Uri(jpgPath, UriKind.Relative); bmp.EndInit(); Model3DGroup group = ModelImporter.Load(objPath); GeometryModel3D model = group.Children[0] as GeometryModel3D; MaterialGroup materialGroup = model.Material as MaterialGroup; DiffuseMaterial material = materialGroup.Children[0] as DiffuseMaterial; material.Brush = new ImageBrush(bmp); return group; }
However, this produces this result (face-sword?):
http://stuff.saphua.com/Temp/Helix/helix.jpg
What do I need to do to fix this?
Here are my source files (copyright League of Legends blah blah!)
http://stuff.saphua.com/Temp/Helix/model.jpg
http://stuff.saphua.com/Temp/Helix/model.obj
Thanks!
saphua wrote at 2011-02-25 09:52:
Ok, I am one step further:
Apperantly when I flip the image vertically it works perfectly.
Now I need to figure out how to do this in Helix.
Edit: Applying a ScaleTransform to the Brush doesn't seem to change a thing.
Edit: Oh wait, it does work! Woohoo!
objo wrote at 2011-02-25 11:23:
there might be a bug in the obj importer - not sure if I tested it with texture coordinates - try to change the ObjReader.AddTexCoord method to
private void AddTexCoord(string values) { double[] fields = Split(values); TexCoords.Add(new Point(fields[0], 1-fields[1])); }
saphua wrote at 2011-03-01 12:06:
Yes that fixed it, although I'm not sure if my textures are upside down or if the code was 'upside down'.
objo wrote at 2011-03-02 19:50:
If it was correct in Blend I guess this was wrong in Helix toolkit. I will check with other obj files with texture coordinates.
Loading a texture onto a model.
Rogad wrote at 2013-12-05 17:04:
Eventually I will be moving vertices around, so I need to know how to load the textures dynamically.
I can understand this code taken from the SimpleDemo :
// Create some materials
var greenMaterial = MaterialHelper.CreateMaterial(Colors.Green);
var redMaterial = MaterialHelper.CreateMaterial(Colors.Red);
var blueMaterial = MaterialHelper.CreateMaterial(Colors.Blue);
var insideMaterial = MaterialHelper.CreateMaterial(Colors.Yellow);
// Add 3 models to the group (using the same mesh, that's why we had to freeze it)
modelGroup.Children.Add(new GeometryModel3D { Geometry = mesh, Material = greenMaterial, BackMaterial = insideMaterial });
modelGroup.Children.Add(new GeometryModel3D { Geometry = mesh, Transform = new TranslateTransform3D(-2, 0, 0), Material = redMaterial, BackMaterial = insideMaterial });
modelGroup.Children.Add(new GeometryModel3D { Geometry = mesh, Transform = new TranslateTransform3D(2, 0, 0), Material = blueMaterial, BackMaterial = insideMaterial });
How do I do this same thing but with an image, for example I am trying to load a .PNG image....Many thanks !
Rogad wrote at 2013-12-05 18:20:
I load a .OBJ model that has 7 children, the first child 0 is the mesh of the hair.
I'm loading my 'start' model like this :
ObjReader CurrentHelixObjReader = new ObjReader();
start = CurrentHelixObjReader.Read("C:/Users/Roger/Desktop/head/base_med_.obj");
So I load the OBJ fine but when I try to grab the material of the original model child 0 (ie the hair) like this :Material matty = (MaterialGroup)((GeometryModel3D)start.Children[0]).Material;
It gives me an error :An unhandled exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll
Additional information: 'The invocation of the constructor on type 'HelixTrial.MainWindow' that matches the specified binding constraints threw an exception.' Line number '4' and line position '9'.
I can remove the line and get the model to load, but I need to get hold of the start up material for the hair so that I can apply it later when I alter the mesh via morph targets and rebuild it.So I would be trying to apply 'matty' like so (partial code) when I rebuild the model :
final.Children.Add(new GeometryModel3D { Geometry = mes, Material = matty });
That last line is part of a loop that rebuilds the Model3DGroup for display in the viewport.I hope I made sense ! Anyone care to tell me what I am doing wrong ? Here's a picture if it helps visualise... it's just a starting point, I haven;t looked at transparency for the hair at all yet.
Rogad wrote at 2013-12-05 21:04:
To load a material image you can simple do this :
Material myMaterial = MaterialHelper.CreateImageMaterial("path/to/image/image.jpg", 1);
The '1' is opacity. And in my particular problem of getting an existing model's texture you can do this :
Instead of my using :
Material matty = (MaterialGroup)((GeometryModel3D)start.Children[0]).Material;
I did this :Material anotherMaterial = ((GeometryModel3D)start.Children[0]).Material;
Now I have grabbed the hair texture from the original model and can use it later to reapply it when needed.
I do still have an icky problem with the hair and it's transparency. The original model used TGA images. I am not sure exactly how these compare to PNG, but I used an online converter and converted it to PNG. The texture loads but it's not rendering quite right.
As can be seen it doesn't appear to be rendering the transparent areas as see-through.
Any ideas on fixing that please ?
Performance of camera rotation with big STL file
gmgunderground wrote at 2014-05-07 18:44:
Best regards
Importing DAZ3D model, textures messed up.
Rogad wrote at 2013-12-10 17:43:
So I am trying to load a Daz3D figure. Only problem is the textures are all messed up. Most of the textures don't show up at all. The face is about the only one that loads up correctly, despite one eye texture going AWOL too. Confused :/
I looked at the UV maps in UVMapper and they seem okay, so I don't think it's an export problem in DazStudio.
I'm exporting from DazStudio in .OBJ file format.
Do you think there could be a problem with your .OBJ importer ?
I can send you the model I guess, I won't post a link here as it's probably copyright, even though it's a freebie and freely obtainable.
Thanks for looking :)
Rogad wrote at 2013-12-13 11:25:
objo wrote at 2013-12-16 18:45:
Can you export a small model that can be used for debugging? I would prefer a model that can be posted here and included in the unit tests!
Rogad wrote at 2013-12-16 21:19:
Yes I imported the model into Blender and the textures all load correctly. The only thing that was not quite right was the eyelashes, but I think that is some transparency thing that I have yet to figure out.
I don't have any other models from Daz3D I just have a few morphs which are commercial so I cannot pass on. It's free to download DazStudio though if you want to have a look. It should come with a basic figure and texture.
David_NET wrote at 2013-12-18 23:32:
Rogad wrote at 2013-12-21 17:36:
Objo, would you like me to email you the model so you can experiment ?
objo wrote at 2014-01-07 22:38:
David: It should be possible, and it would be interesting to see a WPF demo using Assimp.NET!
Rogad wrote at 2014-01-09 01:42:
objo wrote at 2014-01-24 21:32:
Rogad wrote at 2014-01-25 20:23:
I just realised the eyebrows are not transparent, but it's using a JPG file for that, so no wonder. I will try to locate a PNG and see if that works.
Great work objo !
Customer support service by UserEcho