Open stdmn opened 4 years ago
Hi, thanks for the report. This is a known limitation. The basic idea of OutlineEffect is rendering a little bigger same model with black color.
Currently "a little bigger" is implemented by moving vertices towards the direction of normal. Then for example corners of a box can't render outline correctly.
One solution in my mind is using a little bigger scale parameter instead of moving vertices to the direction of normal. I'd like to try when I have a time.
One solution in my mind is using a little bigger scale parameter instead of moving vertices to the direction of normal. I'd like to try when I have a time.
Unfortunately I think this will only have worse results and is significantly dependent on the origin of the model. Here's a quick and dirty image mockup of what might happen if if you used the scale technique but the origin was quite a bit below the model:
As @takahirox mentioned the corners aren't meeting because every vertex is moved along its normal so any vertices that don't have the same normal will diverge. Here are some other solutions that come to mind:
Create a copy of the geometry to outline, merge all the vertices and generate new vertex normals for each vertex. This way all the normals for shared vertex positions will be the same and therefore wont diverge. However the outline thickness at any given face will depend on the angle of a face relative to its neighbors. This could probably be alleviated with an extra generated outline scale vertex attribute or something similar.
Use the outline postprocessing effect. This will have the side effect of only outlining the silhouette of the model and not internal edges, like the outlines around windows in your example.
Another option is to write a new post processing effect that uses something like sobel edge detection using the depth or normal buffer (or both!) to extract edges. Here's a write up on that technique.
@takahirox Understood--looking at the model that makes a lot of sense. How does your algorithm differ from the OutlinePass function? I don't have any problems with the vertices when I use this although it looks like it only recognizes the outline of the entire object, ignoring meshes that are in front of other meshes (see below).
We may want to remove OutlineEffect
... it's a bit of a hack and people struggle to get good results.
What do you think @takahirox?
At least ToonMaterial
should have an outline effect:
https://threejs.org/examples/webgl_materials_variations_toon
Otherwise an important visual aspect of this material would be missing.
IMO, OutlineEffect
works well when used in conjunction with MeshToonMaterial
.
Edge detection is good -- much better than with Sobel, for example.
We may want to remove OutlineEffect... it's a bit of a hack and people struggle to get good results. What do you think @takahirox?
MMD needs OutlineEffect
. It seems to use rendering "little bigger" same model technique rather than post-processing edge detection. The latter one doesn't render outline expectedly for some MMD models.
So I want to keep OutlineEffect
. If it's struggled to get good result for non-MMD model, I'd like to suggest renaming to indicate it's primary designed for MMD like MMDOutlineEffect
.
(Plus, I have a plan to simplify and clean up OutlineEffect
in my mind but lack of time...)
Hi, thanks for the report. This is a known limitation. The basic idea of OutlineEffect is rendering a little bigger same model with black color.
What about rendering a little smaller instead? Or perhaps the ability to switch between inset and outset lines?
Thanks for the comment @gkjohnson. Yeah, whether the scale approach works very depends on the origin of a model. And also it doesn't work for vertex at (0,0,0). We may need another solution.
I found that Unity outline shader has the same problem. It seems this problem is common (and the technique used in OutlineEffect
is also common).
The problem is common so that there may be a common solution. I'll investigate more.
@takahirox
The problem is common so that there may be a common solution. I'll investigate more.
Maybe a good first step would just be documenting the limitations of the effect as is. This technique will work with smooth normals, though -- you'd just have to clone the geometry and generate smooth vertex normals. In modern engines you could generate those in a geometry shader, but we don't have access that that. Maybe the are other approaches to address it, though?
This is maybe just tangentially related but the GDC talk on achieving Guilty Gear Xrds anime art style is really fascinating and they touch if only briefly on outlines. They use the normal extrusion technique and use separate vertex attributes to modulate the outline thickness, as well. The discussion on lines starts at 23:00 but the whole talk is great:
https://www.youtube.com/watch?v=yhGjCzxJV3E
@WestLangley
IMO, OutlineEffect works well when used in conjunction with MeshToonMaterial. Edge detection is good -- much better than with Sobel, for example.
What are you comparing this to out of curiosity? I haven't done any work or comparisons on this myself but I noticed that the three.js sobel edge detection example is operating on the color buffer as input as opposed to a depth or normal buffer so it's not necessarily indicative of what a toon outline could look like. Borderlands -- probably one the games best known for it's for it's toon-like style -- uses sobel edge detection for outlines. The technique is outlined (heh) here along with some other cool stuff:
@gkjohnson Very interesting... Yes, I was specifically referring to the lack of "inside edges" as described in the video. The Borderlands rendering looks much better.
Maybe a good first step would just be documenting the limitations of the effect as is
I agree with it. I investigated the existing solutions but they are pre-processing approaches, like pre-calculating or baking smooth normal for hard edge beforehand. We may do them in OutlineEffect
or script but I'm not sure if we should make it further complex. Interesting to do with geometry shader but yeah it isn't in WebGL. So documenting the limitation and alternative options sounds reasonable.
As I wrote above the technique used in OutlineEffect
seems one of the common techniques to render outline. OutlineEffect
and post-processing approach would have different pros and cons each. So I think having both in Three.js isn't bad. Even if user faces a problem with OutlineEffect
, they can know why and alternatives in the new documentation. So I hope we keep having OutlineEffect
.
- Create a copy of the geometry to outline, merge all the vertices and generate new vertex normals for each vertex. This way all the normals for shared vertex positions will be the same and therefore wont diverge. However the outline thickness at any given face will depend on the angle of a face relative to its neighbors. This could probably be alleviated with an extra generated outline scale vertex attribute or something similar.
If post-processing is too heavy a solution or there are other reasons not to use it, using the above works well enough in my experience:
While the underlying mesh has split normals in several cases and would usually result in the "cube" effect discussed elsewhere in this thread, merging -> averaging -> pushing along vertex normal is a good way to do things. Of course this results in twice the geometry (actually a little less than exactly 2x since there are no vertex splits), there's that to consider. And I seem to remember having to convert to/from BufferGeo in order to merge vertices and recalculate normals.
Hi there, My app would benefit greatly if the outline effect could be improved. Unfortunately, I personally do not have the skills to do it...however since it would benefit me a lot, is there any formal method of donating to ThreeJs in order to prioritise things?
What are you lacking, though?
I'm not sure this is the place to discuss my shortcomings as a software developer, or my lack of time to improve such skills. This seems like quite a common request, and as mentioned would help me out. ThreeJs must have some overheads, I was simply seeing if there's a formal way of putting a bounty on issues.
@sdraper69 There is not. I suggest you post more specifics about your needs on the three.js forum. There you can get feedback as to the feasibility of your request, and perhaps offers to help you.
There was a thread over on the three.js forum by Prisoner849 who had the idea to generalize the LDraw outline effect for any geometry. It has it's own quirks but it's another potential approach for outlining objects and seemed relevant here:
https://discourse.threejs.org/t/ldraw-like-edges/17100/18
Here's an example I put together showing the effect on a model:
@gkjohnson That looks great! Do you think it could replace the current OutlineEffect
?
Do you think it could replace the current
OutlineEffect
?
I see them as different effects with different trade offs. The MMD example wouldn't get the same outline feel, for example, with varying line weights. This one has a very consistent thickness throughout the whole model and requires geometry processing (arguably is the geometry is processed for Outline Effect we could fix the discontinuities at corners).
@gkjohnson Do you mind if posting the screenshots of MMD and Toon material examples with your new outline effect?
I have been thinking of rewriting the current outline effect as material for simplicity and more user friendly API. The new outline effect looks nice so far and resolves the hard edge problem. So how about replacing with the new outline effect, and I create new (MMD)OutlineMaterial
(as ShaderMaterial
?) in example directory? Even if it sounds good, I'm glad if we can keep current outline effect as MMDOutlineEffect
for keeping better MMD support until I create new outline material.
(If having (exposing) three type outline (outline pass, outline effect, and outline material) is confusing to users, I may hide new outline material in MMDLoader.)
It'll be a bit before I can work on / contribute anything related to this. The OutlineEffect in place now fits better with the look of a classic "toon effect" in my opinion so I'm hesitant to get "replace" with this one but I agree it could be improved. The code and demo for the image I posted are available here and here if you want to poke a bit more.
Description of the problem
I've been working to implement an OutlineEffect for a Collada file and have been having problems with the lines not meeting at the corners. I modified the Toon example that you created with cubes instead of spheres and am having the same problem so it doesn't seem to be my implementation: https://jsfiddle.net/4170Lv2z/1/
And here's a screenshot of my model:
Is there a quick fix for this?
Three.js version
Browser
OS
Hardware Requirements (graphics card, VR Device, ...)