# 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 seems not to be very usefull in this context.

Is there perhaps a simply trick, which does the job?

edit retag close merge delete

Sort by » oldest newest most voted

Maybe you could use idea (2) for a Kummer surface like this (using Mathworld's equation for Kummer surface):

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')


more

This 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.

( 2013-06-28 07:45:45 -0500 )edit

Sure -- 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.

( 2013-06-28 08:53:40 -0500 )edit

Hi!

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 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. 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!

3. 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.

4. 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 SmoothTriangles 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!

more

1

Thank 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.

( 2013-06-27 12:40:15 -0500 )edit

Great! Of course an implicit_plot always has an orientation coming from the gradient -- I overlooked that detail of your original question : O

( 2013-06-28 03:51:37 -0500 )edit

If 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)
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)

more

Wow -- 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.

( 2013-06-28 03:54:39 -0500 )edit

Also, 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_...

more