ASKSAGE: Sage Q&A Forum - Individual question feedhttp://ask.sagemath.org/questions/Q&A Forum for SageenCopyright Sage, 2010. Some rights reserved under creative commons license.Fri, 28 Jun 2013 08:53:40 -0500different color on backside of surfacehttp://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/Hey,
I want to animate a 3D plot. Therefore I generate tachyon rendered implicit plots which I then send to ffmpeg. This works quite well. The only disadvantege, is that it's during the video hard to distinguish which side of the surface one sees. Therefore I want to change the color of the backside or at least increase the shadow.
I already tried some stuff with the tachyon raytracer building a scene. But this does not work for implicit plots. The solution given [here](http://ask.sagemath.org/question/20/the-tachyon-object-used-for-rendering-plots) seems not to be very usefull in this context.
Is there perhaps a simply trick, which does the job?
Wed, 26 Jun 2013 10:38:03 -0500http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/Answer by niles for <p>Hey,</p>
<p>I want to animate a 3D plot. Therefore I generate tachyon rendered implicit plots which I then send to ffmpeg. This works quite well. The only disadvantege, is that it's during the video hard to distinguish which side of the surface one sees. Therefore I want to change the color of the backside or at least increase the shadow.</p>
<p>I already tried some stuff with the tachyon raytracer building a scene. But this does not work for implicit plots. The solution given <a href="http://ask.sagemath.org/question/20/the-tachyon-object-used-for-rendering-plots">here</a> seems not to be very usefull in this context. </p>
<p>Is there perhaps a simply trick, which does the job?</p>
http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?answer=15154#post-id-15154Maybe you could use idea (2) for a Kummer surface like this (using [Mathworld's equation for Kummer surface](http://mathworld.wolfram.com/KummerSurface.html)):
sage: var('mu2,x,y,z') # mu2 for mu^2
(mu2, x, y, z)
sage: la(mu2) = (3*mu2 - 1)/(3 - mu2)
sage: pqrs(w,x,y,z) = (w - z - sqrt(2)*x)*(w - z + sqrt(2)*x)*(w + z + sqrt(2)*y)*(w + z - sqrt(2)*y)
sage: Kmu(mu2,w,x,y,z) = (x^2 + y^2 + z^2 - mu2*w^2)^2 - la(mu2)*pqrs(w,x,y,z)
sage: def kummer(mu2,a,c=0,**kwds):
f(x,y,z) = Kmu(mu2,1,x,y,z) - c
P = implicit_plot3d(f,(x,-1*a,a),(y,-1*a,a),(z,-1*a,a),frame=False,**kwds)
return P
....:
sage: Inn = kummer(2,1.5,c=-.2,plot_points=150)
sage: Out = kummer(2,1.5,c=0,plot_points=150,color='red')
sage: (Inn+Out).show(viewer='tachyon')
<img src="/upfiles/1372427970499417.png" width="300"></img>Fri, 28 Jun 2013 04:04:17 -0500http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?answer=15154#post-id-15154Comment by Thorsten for <p>Maybe you could use idea (2) for a Kummer surface like this (using <a href="http://mathworld.wolfram.com/KummerSurface.html">Mathworld's equation for Kummer surface</a>):</p>
<pre><code>sage: var('mu2,x,y,z') # mu2 for mu^2
(mu2, x, y, z)
sage: la(mu2) = (3*mu2 - 1)/(3 - mu2)
sage: pqrs(w,x,y,z) = (w - z - sqrt(2)*x)*(w - z + sqrt(2)*x)*(w + z + sqrt(2)*y)*(w + z - sqrt(2)*y)
sage: Kmu(mu2,w,x,y,z) = (x^2 + y^2 + z^2 - mu2*w^2)^2 - la(mu2)*pqrs(w,x,y,z)
sage: def kummer(mu2,a,c=0,**kwds):
f(x,y,z) = Kmu(mu2,1,x,y,z) - c
P = implicit_plot3d(f,(x,-1*a,a),(y,-1*a,a),(z,-1*a,a),frame=False,**kwds)
return P
....:
sage: Inn = kummer(2,1.5,c=-.2,plot_points=150)
sage: Out = kummer(2,1.5,c=0,plot_points=150,color='red')
sage: (Inn+Out).show(viewer='tachyon')
</code></pre>
<p><img src="/upfiles/1372427970499417.png" width="300"/></p>
http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?comment=17432#post-id-17432This is in fact much easier and faster. Seeing this solution I'm a bit ashamed, that it's so simple. But thank you very much for pointing this out. Fri, 28 Jun 2013 07:45:45 -0500http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?comment=17432#post-id-17432Comment by niles for <p>Maybe you could use idea (2) for a Kummer surface like this (using <a href="http://mathworld.wolfram.com/KummerSurface.html">Mathworld's equation for Kummer surface</a>):</p>
<pre><code>sage: var('mu2,x,y,z') # mu2 for mu^2
(mu2, x, y, z)
sage: la(mu2) = (3*mu2 - 1)/(3 - mu2)
sage: pqrs(w,x,y,z) = (w - z - sqrt(2)*x)*(w - z + sqrt(2)*x)*(w + z + sqrt(2)*y)*(w + z - sqrt(2)*y)
sage: Kmu(mu2,w,x,y,z) = (x^2 + y^2 + z^2 - mu2*w^2)^2 - la(mu2)*pqrs(w,x,y,z)
sage: def kummer(mu2,a,c=0,**kwds):
f(x,y,z) = Kmu(mu2,1,x,y,z) - c
P = implicit_plot3d(f,(x,-1*a,a),(y,-1*a,a),(z,-1*a,a),frame=False,**kwds)
return P
....:
sage: Inn = kummer(2,1.5,c=-.2,plot_points=150)
sage: Out = kummer(2,1.5,c=0,plot_points=150,color='red')
sage: (Inn+Out).show(viewer='tachyon')
</code></pre>
<p><img src="/upfiles/1372427970499417.png" width="300"/></p>
http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?comment=17431#post-id-17431Sure -- I had a great time thinking about this :) Also, your solution will work for *any* type of plot, not just implicit plots, as long as there is some way to get an orientation.Fri, 28 Jun 2013 08:53:40 -0500http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?comment=17431#post-id-17431Answer by niles for <p>Hey,</p>
<p>I want to animate a 3D plot. Therefore I generate tachyon rendered implicit plots which I then send to ffmpeg. This works quite well. The only disadvantege, is that it's during the video hard to distinguish which side of the surface one sees. Therefore I want to change the color of the backside or at least increase the shadow.</p>
<p>I already tried some stuff with the tachyon raytracer building a scene. But this does not work for implicit plots. The solution given <a href="http://ask.sagemath.org/question/20/the-tachyon-object-used-for-rendering-plots">here</a> seems not to be very usefull in this context. </p>
<p>Is there perhaps a simply trick, which does the job?</p>
http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?answer=15147#post-id-15147Hi!
I've used Tachyon some, but I don't know a way to give different colors to two sides of a surface. I suspect this functionality doesn't exist because at the most fundamental level the surfaces Tachyon makes are just 2-dimensional. Tachyon's [Triangle][1] object, in particular, is a 2-dimensional triangle. You could think of them as being just 1 pixel thick, and then your question would be how you can color two "sides" of a pixel with different colors.
But I think being able to color 2 sides of an orientable surface differently would be a *great* feature! I can think of a few ways to do this:
1. Shading: This isn't really a solution but it is certainly the easiest way to (sort of) differentiate between different parts of the surface. The "diffuse" attribute is probably the useful one for this; if you're not familiar with what ambient, diffuse, and specular mean, take a look at [Phong shading][2].
1. Two surfaces: This is another relatively easy way to simulate a non-zero thickness: just draw two copies of the same surface very close to eachother. Whether or not this is feasible depends a lot on the surface you are interested in and how its parametrized. Also this might double the rendering time!
1. Hack the Tachyon string: The answer you linked to shows how to get the Tachyon string for an object. You could write a program to search for triangles in that string and, for each triangle, add a *second* triangle pushed just a little in the (positive) normal direction, with a new color. Knowing which direction is "positive" might be tricky, and doing so consistently is equivalent to actually constructing an orientation on your surface. Again the feasibility of this approach depends a lot on the particular surface you're interested in.
1. Make a ThickTriangle class, and modify the Sage source: This is definitely the most daunting and far-reaching approach, but depending on your background might be doable. Find where in the plotting process Sage is making Tachyon triangles, and add a new type of triangle which makes *two* triangles with different textures, separated by a given parameter. There are already two triangles (standard and "smooth"), and I see that the [SmoothTriangle][3]s also require a normal direction. In fact, if Sage is producing SmoothTriangles from your parametric plot, then the tricky issue of choosing a "positive" normal direction may already be done for you!
[1]:http://www.sagemath.org/doc/reference/plot3d/sage/plot/plot3d/tachyon.html#sage.plot.plot3d.tachyon.TachyonTriangle
[2]:http://en.wikipedia.org/wiki/Phong_shading
[3]:http://www.sagemath.org/doc/reference/plot3d/sage/plot/plot3d/tachyon.html#sage.plot.plot3d.tachyon.TachyonSmoothTriangleThu, 27 Jun 2013 03:52:40 -0500http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?answer=15147#post-id-15147Comment by niles for <p>Hi!</p>
<p>I've used Tachyon some, but I don't know a way to give different colors to two sides of a surface. I suspect this functionality doesn't exist because at the most fundamental level the surfaces Tachyon makes are just 2-dimensional. Tachyon's <a href="http://www.sagemath.org/doc/reference/plot3d/sage/plot/plot3d/tachyon.html#sage.plot.plot3d.tachyon.TachyonTriangle">Triangle</a> object, in particular, is a 2-dimensional triangle. You could think of them as being just 1 pixel thick, and then your question would be how you can color two "sides" of a pixel with different colors.</p>
<p>But I think being able to color 2 sides of an orientable surface differently would be a <em>great</em> feature! I can think of a few ways to do this:</p>
<ol>
<li><p>Shading: This isn't really a solution but it is certainly the easiest way to (sort of) differentiate between different parts of the surface. The "diffuse" attribute is probably the useful one for this; if you're not familiar with what ambient, diffuse, and specular mean, take a look at <a href="http://en.wikipedia.org/wiki/Phong_shading">Phong shading</a>.</p></li>
<li><p>Two surfaces: This is another relatively easy way to simulate a non-zero thickness: just draw two copies of the same surface very close to eachother. Whether or not this is feasible depends a lot on the surface you are interested in and how its parametrized. Also this might double the rendering time!</p></li>
<li><p>Hack the Tachyon string: The answer you linked to shows how to get the Tachyon string for an object. You could write a program to search for triangles in that string and, for each triangle, add a <em>second</em> triangle pushed just a little in the (positive) normal direction, with a new color. Knowing which direction is "positive" might be tricky, and doing so consistently is equivalent to actually constructing an orientation on your surface. Again the feasibility of this approach depends a lot on the particular surface you're interested in.</p></li>
<li><p>Make a ThickTriangle class, and modify the Sage source: This is definitely the most daunting and far-reaching approach, but depending on your background might be doable. Find where in the plotting process Sage is making Tachyon triangles, and add a new type of triangle which makes <em>two</em> triangles with different textures, separated by a given parameter. There are already two triangles (standard and "smooth"), and I see that the <a href="http://www.sagemath.org/doc/reference/plot3d/sage/plot/plot3d/tachyon.html#sage.plot.plot3d.tachyon.TachyonSmoothTriangle">SmoothTriangle</a>s also require a normal direction. In fact, if Sage is producing SmoothTriangles from your parametric plot, then the tricky issue of choosing a "positive" normal direction may already be done for you!</p></li>
</ol>
http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?comment=17437#post-id-17437Great! Of course an implicit_plot always has an orientation coming from the gradient -- I overlooked that detail of your original question : OFri, 28 Jun 2013 03:51:37 -0500http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?comment=17437#post-id-17437Comment by Thorsten for <p>Hi!</p>
<p>I've used Tachyon some, but I don't know a way to give different colors to two sides of a surface. I suspect this functionality doesn't exist because at the most fundamental level the surfaces Tachyon makes are just 2-dimensional. Tachyon's <a href="http://www.sagemath.org/doc/reference/plot3d/sage/plot/plot3d/tachyon.html#sage.plot.plot3d.tachyon.TachyonTriangle">Triangle</a> object, in particular, is a 2-dimensional triangle. You could think of them as being just 1 pixel thick, and then your question would be how you can color two "sides" of a pixel with different colors.</p>
<p>But I think being able to color 2 sides of an orientable surface differently would be a <em>great</em> feature! I can think of a few ways to do this:</p>
<ol>
<li><p>Shading: This isn't really a solution but it is certainly the easiest way to (sort of) differentiate between different parts of the surface. The "diffuse" attribute is probably the useful one for this; if you're not familiar with what ambient, diffuse, and specular mean, take a look at <a href="http://en.wikipedia.org/wiki/Phong_shading">Phong shading</a>.</p></li>
<li><p>Two surfaces: This is another relatively easy way to simulate a non-zero thickness: just draw two copies of the same surface very close to eachother. Whether or not this is feasible depends a lot on the surface you are interested in and how its parametrized. Also this might double the rendering time!</p></li>
<li><p>Hack the Tachyon string: The answer you linked to shows how to get the Tachyon string for an object. You could write a program to search for triangles in that string and, for each triangle, add a <em>second</em> triangle pushed just a little in the (positive) normal direction, with a new color. Knowing which direction is "positive" might be tricky, and doing so consistently is equivalent to actually constructing an orientation on your surface. Again the feasibility of this approach depends a lot on the particular surface you're interested in.</p></li>
<li><p>Make a ThickTriangle class, and modify the Sage source: This is definitely the most daunting and far-reaching approach, but depending on your background might be doable. Find where in the plotting process Sage is making Tachyon triangles, and add a new type of triangle which makes <em>two</em> triangles with different textures, separated by a given parameter. There are already two triangles (standard and "smooth"), and I see that the <a href="http://www.sagemath.org/doc/reference/plot3d/sage/plot/plot3d/tachyon.html#sage.plot.plot3d.tachyon.TachyonSmoothTriangle">SmoothTriangle</a>s also require a normal direction. In fact, if Sage is producing SmoothTriangles from your parametric plot, then the tricky issue of choosing a "positive" normal direction may already be done for you!</p></li>
</ol>
http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?comment=17439#post-id-17439Thank you very much for your ideas. As my surface is a algebraic variety (Kummer surface) the second idea is a bit difficult. So I tried the third one. I hoped that the normal is determined by the order of the vertices in the triangle, but this seems rather random. In my case I could calculate the normals via the gradient. Unfortunately the rendering is now very slow. I hope I can increase the speed a bit by cleaning up my code. Thu, 27 Jun 2013 12:40:15 -0500http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?comment=17439#post-id-17439Answer by Thorsten for <p>Hey,</p>
<p>I want to animate a 3D plot. Therefore I generate tachyon rendered implicit plots which I then send to ffmpeg. This works quite well. The only disadvantege, is that it's during the video hard to distinguish which side of the surface one sees. Therefore I want to change the color of the backside or at least increase the shadow.</p>
<p>I already tried some stuff with the tachyon raytracer building a scene. But this does not work for implicit plots. The solution given <a href="http://ask.sagemath.org/question/20/the-tachyon-object-used-for-rendering-plots">here</a> seems not to be very usefull in this context. </p>
<p>Is there perhaps a simply trick, which does the job?</p>
http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?answer=15153#post-id-15153If someone deals with a similar problem it might help seeing my (messy) code for this:
def plottosided(f,color):
P = implicit_plot3d(f(x,y,z),(x,-1.5,1.5),(y,-1.5,1.5),(z,-1.5,1.5),plot_points=20,frame=False,viewer='tachyon')
opts = P._process_viewing_options({})
T = P._prepare_for_tachyon(opts['frame'],opts['axes'], opts['frame_aspect_ratio'],opts['aspect_ratio'],opts['zoom'])
R=newtriangle(f,T.tachyon(),0.001)
R=R.replace('resolution 400 400','resolution 500 500')
print('Converting complete')
tachyon_rt(R)
def tovector(A):
B=[]
for a in A:
if a!='':
B += [float(a)]
return vector(B)
def tostring(v):
s=''
for i in v:
s+= str(i)+' '
return s
def newtriangle(f,S,C): #f defining implicit function, S the tachyon string, C the second rgb color
Colorstring = str(color[0])+' '+str(color[1])+' '+str(color[2])
Triangles = S.split('TRI')
Pre = Triangles[0]
App = Triangles[len(Triangles)-1]
Triangles=Triangles[1:len(Triangles)-1]
newtexture=' Texdef texture89\n Ambient 0.230769230769 Diffuse 0.769230769231 Specular 0.0 Opacity 1\n Color '+Colorstring+'\n TexFunc 0\n\n'
Ret=Pre + newtexture
count = 1
max = len(Triangles)
step= floor(max/10)+1
for Triangle in Triangles:
if (count%step==0):
print (count/step).str() + '0%'
Triangle2 = normalshifted(f,Triangle,-0.001)
Ret += 'TRI'+Triangle + 'TRI' + Triangle2
count += 1
Ret += 'TRI' +App
return Ret
def normalshifted(f,T,shift): #f defining function, T TriangleString
V0=tovector(T[T.find('V0')+2:T.find('V1')].split(' '))
V1=tovector(T[T.find('V1')+2:T.find('V2')].split(' '))
V2=tovector(T[T.find('V2')+2:T.find('\n')].split(' '))
Suf=T[T.find('\n'):]
#normal = ((V2-V0).cross_product(V1-V0)).normalize()
SP=1/3*(V0+V1+V2)
normal=vector(f.gradient()(SP[0],SP[1],SP[2])).n()
V0=shift*normal+V0
V1=shift*normal+V1
V2=shift*normal+V2
String = ' V0 ' +tostring(V0)+'V1 '+tostring(V1)+'V2 '+tostring(V2)+'\ntexture89\n'
return String
And a Test with a simple sphere:
f(x,y,z)=x^2+y^2+z^2-3
color=(0.9, 0.2, 1.0)
plottosided(f,color)Thu, 27 Jun 2013 22:13:55 -0500http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?answer=15153#post-id-15153Comment by niles for <p>If someone deals with a similar problem it might help seeing my (messy) code for this:</p>
<pre><code>def plottosided(f,color):
P = implicit_plot3d(f(x,y,z),(x,-1.5,1.5),(y,-1.5,1.5),(z,-1.5,1.5),plot_points=20,frame=False,viewer='tachyon')
opts = P._process_viewing_options({})
T = P._prepare_for_tachyon(opts['frame'],opts['axes'], opts['frame_aspect_ratio'],opts['aspect_ratio'],opts['zoom'])
R=newtriangle(f,T.tachyon(),0.001)
R=R.replace('resolution 400 400','resolution 500 500')
print('Converting complete')
tachyon_rt(R)
def tovector(A):
B=[]
for a in A:
if a!='':
B += [float(a)]
return vector(B)
def tostring(v):
s=''
for i in v:
s+= str(i)+' '
return s
def newtriangle(f,S,C): #f defining implicit function, S the tachyon string, C the second rgb color
Colorstring = str(color[0])+' '+str(color[1])+' '+str(color[2])
Triangles = S.split('TRI')
Pre = Triangles[0]
App = Triangles[len(Triangles)-1]
Triangles=Triangles[1:len(Triangles)-1]
newtexture=' Texdef texture89\n Ambient 0.230769230769 Diffuse 0.769230769231 Specular 0.0 Opacity 1\n Color '+Colorstring+'\n TexFunc 0\n\n'
Ret=Pre + newtexture
count = 1
max = len(Triangles)
step= floor(max/10)+1
for Triangle in Triangles:
if (count%step==0):
print (count/step).str() + '0%'
Triangle2 = normalshifted(f,Triangle,-0.001)
Ret += 'TRI'+Triangle + 'TRI' + Triangle2
count += 1
Ret += 'TRI' +App
return Ret
def normalshifted(f,T,shift): #f defining function, T TriangleString
V0=tovector(T[T.find('V0')+2:T.find('V1')].split(' '))
V1=tovector(T[T.find('V1')+2:T.find('V2')].split(' '))
V2=tovector(T[T.find('V2')+2:T.find('\n')].split(' '))
Suf=T[T.find('\n'):]
#normal = ((V2-V0).cross_product(V1-V0)).normalize()
SP=1/3*(V0+V1+V2)
normal=vector(f.gradient()(SP[0],SP[1],SP[2])).n()
V0=shift*normal+V0
V1=shift*normal+V1
V2=shift*normal+V2
String = ' V0 ' +tostring(V0)+'V1 '+tostring(V1)+'V2 '+tostring(V2)+'\ntexture89\n'
return String
</code></pre>
<p>And a Test with a simple sphere:</p>
<pre><code>f(x,y,z)=x^2+y^2+z^2-3
color=(0.9, 0.2, 1.0)
plottosided(f,color)
</code></pre>
http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?comment=17436#post-id-17436Wow -- I'm actually surprised idea (3) was so straightforward :) Making something like this generally available for Tachyon plots would be a great contribution to Sage!! But I'm not sure it's necessary for implicit plots; couldn't you just plot f == 0 and f == epsilon to give two nearby surfaces? I'll post a second answer showing what I mean.Fri, 28 Jun 2013 03:54:39 -0500http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?comment=17436#post-id-17436Answer by niles for <p>Hey,</p>
<p>I want to animate a 3D plot. Therefore I generate tachyon rendered implicit plots which I then send to ffmpeg. This works quite well. The only disadvantege, is that it's during the video hard to distinguish which side of the surface one sees. Therefore I want to change the color of the backside or at least increase the shadow.</p>
<p>I already tried some stuff with the tachyon raytracer building a scene. But this does not work for implicit plots. The solution given <a href="http://ask.sagemath.org/question/20/the-tachyon-object-used-for-rendering-plots">here</a> seems not to be very usefull in this context. </p>
<p>Is there perhaps a simply trick, which does the job?</p>
http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?answer=15148#post-id-15148Also, since I'm **really** interested in making animations with Sage, I've been working on a framework for doing this. It's a collection of Sage classes for working with large sequences of frames and rendering them in parallel. I designed it based on my own workflow, so I don't know if it will make sense or be useful for you, but I hope so! I just put the first draft of this on GitHub yesterday, so I'd love to hear what you think :) The link is
https://github.com/nilesjohnson/sage_animateThu, 27 Jun 2013 03:59:57 -0500http://ask.sagemath.org/question/10290/different-color-on-backside-of-surface/?answer=15148#post-id-15148