Sometimes the object of the exercise is not to create a 3D model, but what kind of surface material one can apply to it. In 3D Graphics games, the choice by now is usually more vast than with Bryce 5.5 . Yet, even the GUI-built surface materials of Bryce have become very sophisticated over time. One of my interests is 3D or 'VR Game' Design with Open-Source alternatives. Such software allows procedures to be written which run directly on the graphics card, called vertex shaders and pixel haders.

I applied this material to the model of a player game entity, but more practically it could be used for animals in future games, as well as for terrain which is supposed to be grassy, but in the different colour. Therefore it's important to me that ths effect can be adjusted without having to be reprogrammed.

You may download my .fx file to use in your own applications. However it would be up to you to adapt the file. It has been backwards-designed for DirectX 8.1 , and therefore imports numerous variables from my 3D Game Studio script which you need to supply. Most importantly, you would need to specify a texture map, called "mtlSkin1" in the .fx file, which provides scratchy lines and an important alpha channel, as a basis for producing a fur effect. The size of this file needs to be a power of two pixels in each direction, such as 512x512 or 256x256 pixels.
My .fx file has 2 fallback techniques for weaker graphics cards, but the main technique makes 14 passes over the model to achieve this effect.




Now, since "OpenGL 2", which corresponded to DirectX 9, OpenGL 3.2, like DirectX 10, allows "Geometry Shaders" to be written in addition to Vertex Shaders. Geometry Shaders invariably require that a vertex shader precede them, which allows the vertex shader to place the input vertices into whatever coordinate system most suited for the 'GS'. Even though I've never written a working Geometry Shader, I have written some pseudo-code to incorporate ideas for a "Tessellator", which should implement an approximation of general-purpose NURBS, as well as of Bezier-splines, even though true Beziers would require slightly different parameters. I won't get in to what little I really know about NURBS, because in order really to unerstand them, I'd need to have actually studied them at University or College, which I haven't done.

One really dumb problem with Geometry Shaders though, that hoses my idea for now, is the apparent fact that they do not input triangles as such, nor quads, but one choice out of {1, 2, 3, 4, 6} vertices, as input type 'points', 'lines', 'lines_adjacency', 'triangles', or 'triangles_adjacency'. That's it! And so my working assumption goes unfulfilled for now, that the input topology can really be set up.

Added Note on August 18, 2013:

I feel that I've gotten a fresh idea about how to do 'Splines of sorts', from within either a 'GS', or from within a 'DirectX 11' / 'OpenGL 4' Tessellator's Domain Function. This idea has made all my earlier psuedo-code obsolete. The idea becomes, that a tessellated surface should use a set of cubic polynomials, between the 3 points of each triangle. Cubic polynomials have as special capability, that they can not only satisfy the position of a pair of endpoints, but also the derivative - i.e. the velocity - at each endpoint. Further, there exists a standard matrix to compute the coefficients of these polynomials. This matrix exists as a 4x4 , which is a Mathematical inverse of one other matrix, which would be more intuitive. Such an inverse matrix can be computed once when the program is written, and then coded into that program or shader as a kind of constant. Then, the 2 point positions and 2 velocities at the ends of one interval can be multiplied by this matrix as one vector, yielding the coefficients. And, the GPU is already good at multiplying a 4-element vector by a 4x4 matrix.

One question which would need to be answered for a tessellator, is where it's to take the velocities from (separately for X, Y and Z). And the best answer I could think of, is that it could relate velocity to the available normal vecor. I.e., the base segment of a triangle could itself be read in as a vector, and cross-multiplied by the stored vertex normal of each end. Then, the resulting vector could be "re-crossed" with the normal vectors, yielding the tangential velocity vectors.

An added touch that seems plausible, would be that the velocity vector could then be multiplied by a single 'velocity multiplier' , a scalar that could be gleaned from each vertex, let's say as one component of the vertex color, without changing the direction of the velocity vector. But it already seems fitting, that the velocity will decrease as the vertex normals stand at a greater angle. This should make higher-angle vertices 'more pointy', even after acting as control points for a continuous spline. [:*]

When classical bicubic interpolation is done, it preserves the cross-derivatives, as mixed terms. But I don't imagine that my tessellator would be able to do the same. Instead, I'd also first pick a base edge let's say between Points P1 and P2 of the triangle, and do a 1-dimensional cubic interpolation according to the parameter (u) ranging from 0.0 to 1.0 . This should ideally result in a list of 3 polynomials for the 3 vector components {X, Y, and Z}. Then, I'd try to regenerate the Normal vector at (u = 0.5) from the interpolated velocity, in order to perform another 1-D interpolation. But for a Tessellator Control Function it would be necessary to generate only 1 set of coefficents. In that case, another 1-D cubic interpolation could be made between P1 and P3, this time creating the function of (v).

One important fact to note about a Dx11 / GL4 domain function, is that it computes a vector (b), as a function of (u), (v) and (w). This deters me from writing any pseudo-code for the moment. If such a domain function is assumed (and not a 'Geometry Shader'), it must generate only one set of 3rd-order coefficients, for the entire patch. Note: All the coefficients used below, are vectors!

Link To External, nVidia PDF Reference Document

But then the next question which we might find ourselves asking, since the equation along the first edge is of the form

w = 1 - u - v
b = a1 w3 + 3 a2 w2u + 3 a3 w u2 + a4 u3 (In my own notation)

'Is, What is the derivative of 3 w u2 , when u = 1 and w = 0?'
The derivative of this term when u = 0 and w = 1 equals zero (that of u2). And the answer is -3.

And so the vector (a3) as above should be set to (a4) - (1/3) Velocity(P2) ,
while (a2) as above should be set to (a1) + (1/3) Velocity(P1) .

[Note: This system can also be used to implement basic splines on the CPU, in 2 dimensions. Just think of (a1) and (a4) as 'the control points', which unlike those of NURBS are touched by the curve, while (a2) and (a3) would be 'the handles', which are never 'met' or 'satisfied' by the intended curve.]

What the Dx11 / GL 4 Tessellator also requires us to do on the GPU, is to instantiate an analogous equation for the normal vector, which in this case is a quadratic, mixed-term equation, because it only satisfies 3 points, and not 2 points and 2 derivatives:
w = 1 - u - v
N = N200w2 + 2 N110uw + N020u2

for one edge, where v = 0.0. As before, N200 and N020 define the end-points. The ( 2 N110 ) term allows the Tessellator Control Function to define the midpoint as well.

What I have computed, is that the derivative
(db / du), at u = 0.5 , v = 0.0 , w = 0.5
equals (3 / 4)(-a1 -a2 +a3 +a4) .
[And, 1/8 + 3/8 + 3/8 + 1/8 = 8/8.]

Here is the Proof of the Derivative in PDF Format.

This makes the computation of the intended normal vector at the midpoint fortunately simple. The velocity vector (a3 + a4 - a1 - a2) can simply be computed as-is, ignoring its magnitude, and can then be cross-multiplied with ( N200 + N020 ) . Next, the result can be 're-crosssed' with the velocity vector, and normalized, to give us Nmidpoint. Finally, N110 can be computed as
N110 = ( 1/2 ) ( 4 Nmidpoint - N200 - N020 ) , or, as
N110 = 2 Nmidpoint - ( ( N200 + N020 ) / 2 ) .

Then, when we have all 3 single-terms and all 3 mixed terms computed for the patch, we can also plug in w = u = v = ( 1 / 3 ) in order to compute the derived normal vector smack in the middle of the triangle, not forgetting to normalize of course. [Or, we can just use the sum of all the 2nd-order coefficients, since Here their terms all equal 1/9.]

[And Here,
1/27 + 1/27 + 1/27 = 3/27, ...
3/27 + 3/27 = 6/27, ...
3/27 + 3/27 = 6/27, ...
3/27 + 3/27 = 6/27, ...
... + 6/27 = 27/27.]

Modification to the concept made on August 23, 2013:

As for the other position term applied by the domain shader, "6 b111 wuv", I now believe the best coefficient to put is just ( ( P1 + P2 + P3 ) / 3) .

This recent idea embraces the spline as a parametric function.

*] While I'm dreaming in technicolor, I could also add the idea to the concept of a per-vertex velocity multiplier, that this multiplier will take on a special meaning if the (alpha) color component was 'greater than 0.9' or some similar trigger value. By default, the multiplier could equal ( 2.0 * the color component ) , but the main problem I'd see with this comes up, when a slightly curved surface is finely subdivided in the usual fashion, into a medium- or high-poly mesh. What would happen is that any texture image {U,V}-mapped from this mesh, would seem to pucker around all the vertices, because all the velocity vectors slow down by default. And, it would be difficult for artists to determine by how much to accelerate these velocities again, using exact vertex values, depending on the small angles of all the vertex normals.

The enhanced algorithm might read, 'If the multiplier for a given vertex has this trigger value, normalize the velocity vector, and scalar-multiply it by the length of the current edge.' The effect which I was trying to avoid from the outset, was that curves would bulge outward at high angles. But using such a vertex parameter, it would be possible to keep tangent velocities ~uniform~ again.


Dirk Mittler

Phone: (514)685-8343
e-mail: mdirk@sympatico.ca