LDraw.org Discussion Forums

Full Version: OpengGL color / material properties
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi all,

I'm playing around with making the difference between plastic and e.g. rubber parts visible in LDCad.

I've found some nice OpenGL material references but was wondering if there is some kind of 'standard' floating around. Especially for determining the diffuse, ambient and specular components based upon the single rgb supplied in LDConfig.ldr

Up to now I'm using the rgb for both diffuse and ambient, and have a static specular of 1,1,1 and shininess of 128 (which is more appropriate for chrome I'm realizing now).

I'm doing this with the standard lighting model (not shaders) for now (LDCad runs on OpenGL as low as 1.1), so I only can play with the base four components for now.
Hi Roland,

I'm not sure what kind of standard you're looking for. The LDConfig file appears to specify the material primarily through enumerations, which I think is good - standardizing the lighting model for LDraw would IMO be really problematic. (Either the lighting model would be extremely complex and every non-shader-based renderer would have to ignore the spec, or the lighting standard would be something that could be implemented in fixed function and we'd miss out on a lot of really good effects.)

In terms of actual rendering, when I did my first materials experiment I found that having a fresnel term to limit the specular hilites really helped to differentiate plastic and metal. In the experiment I used cube maps for both reflections and specularity; the fresnel term makes the plastic more reflective "on edge" than when viewed "straight on" - which makes the material not just look like a dull mirror.

(The code I used came straight from GPU gems chapter 19 - Schlick's fresnel approximation is what everyone uses.)


Ben Supnik Wrote:I'm not sure what kind of standard you're looking for.

Well the part authors have gone trough some trouble to define the RGB's of colors (which I consider the diffuse ones), so I was thinking maybe they have (secret) tables of the specular, ambient and shininess ones too.

I too discovered playing with specular (and shininess) is pretty much enough to create visual distinctions. I was a bit put off guard by 'scientific' tables like this one:

OpenGL material table

But it seems using the ldr RGB as both ambient and diffuse in combinations with static (shades of white) specular and shininess values per material finish type is good enough for most ldraw colors.

Thanks for the more advanced pointers Ben, I might go that route for the HQ option, but first I want an basic one. So I'm going to continue playing / tweaking the specular and shininess values for a while. If any of the part / color maintainers have ideas on those please let me know.
For what it's worth, LDView uses the following:
| Specular         | Shininess
Standard    | .5, .5, .5       | 64
Transparent | .75, .75, .75    | 128
Rubber      | .075, .075, .075 | 15

It uses RGB for ambient and diffuse. Its standard lighting uses .2, .2, .2 for the ambient term, and its diffuse lighting uses .7, .7, .7. I also enable GL_SEPARATE_SPECULAR_COLOR in order to have correct specular on textured sections.

I did spend some time fiddling with the numbers looking for values that looked good, but I'll freely admit that it's highly likely that better numbers exist.
Thanks Travis,

I've been playing around and I'm using the following at the moment (shininess 0..1):

specular=0.5 0.5 0.5

specular=1 1 1

specular=0.3 0.3 0.3

specular=0.1 0.1 0.1

specular=0.4 0.4 0.4

specular=0.8 0.8 0.8

Although I'm not very happy with the metal and chrome ones, the difference with plain plastic is almost invisible unless you rotate it continuously so the spec properties become more apparent.
Ok, I've managed to get chrome more 'chromy'.

[Image: chromeTest.png]

but I'm still not completely happy, it's like you need to watch the picture for awhile in order to 'learn' the contrast, so the longer you look the more metal/chrome it starts to look.

But on the other hand I think this is the best you can do without using texture maps and or custom shaders, or does anybody have has a different insight?

Also it seems the current LDConfig doesn't use the 'matte metal' property for any color, I would have expected it to be used for at least magnets or something.
I think it's about as good as you can do. In LDView, I cheated when ldconfig.ldr parsing is turned off, and use a light blue specular for chrome, which doesn't provide an accurate look, but at least provides a distinct look.

For what it's worth, Lego magnets aren't metal; they're ceramic.
I think you've gotten as much as you can out of the fixed function pipeline without environment texture maps - to even get that level of shininess is good!

(You can technically do some limited cube mapping or sphere mapping with fixed function, although by that point you might just want to invest in some shaders. :-)

Magnet is defined as metal in the current LDConfig.ldr which is too shiny imho.

That's why I expected it to be matte metal (duller look), which I discovered isn't used anywhere at the moment.
I'm basically using overexposure Smile

In a future version I want to introduce HQ rendering which will be using env mapping and maybe things like bump mapping to simulate imperfect (rubber) surfaces etc.

I might even give shader based ray tracing a try for fun.
Hi Roland,

I've been thinking about some kind of bump mapping, e.g. for the rough surface on the angled side of slope bricks. I see two possible problems:

1. I don't think the slope bricks actually notate their angled side as smooth and the flat sides as rough. (Is there a tag or meta data I don't know about here?)

2. Most of the time the 'grain' of the bump mapping will be much smaller than screen pixels, so to look good the bump mapping scheme and specular lighting equation have to minify. LEAN mapping (http://www.csee.umbc.edu/~olano/papers/lean/) is a good candidate here - it copes with mipmapping nicely and for a few 'reference' materials, the extra VRAM costs are quite affordable.

From what I can tell from the bricks I have in my office, there is some subtle variation in the normal directions of 'smooth' sides of bricks, and possibly the edges of the bricks are beveled. Does anyone know of a write-up on the micro-level details of lego bricks? (I know lego is famous for their mold precision, so I have to think that someone is paying attention to such details.) These would matter to a high-quality render because they 'bend' reflections and (in the case of edges) sometimes catch bright lights.

Ben Supnik Wrote:1. I don't think the slope bricks actually notate their angled side as smooth and the flat sides as rough. (Is there a tag or meta data I don't know about here?)

2. Most of the time the 'grain' of the bump mapping will be much smaller than screen pixels, so to look good the bump mapping scheme and specular lighting equation have to minify. LEAN mapping (http://www.csee.umbc.edu/~olano/papers/lean/) is a good candidate here - it copes with mipmapping nicely and for a few 'reference' materials, the extra VRAM costs are quite affordable.

There are no meta's for individual surfaces unless they use a different color code, only indication might be the part author comments.

But I was planning to use bump mapping only for the rough material classes used in ldconfig, and only at very close distances (zoom factors).
Ben Supnik Wrote:1. I don't think the slope bricks actually notate their angled side as smooth and the flat sides as rough. (Is there a tag or meta data I don't know about here?)

No, there isn't. I'm pretty sure the idea has been mentioned once or twice.

Fun fact: Lego slopes have had three very different bump patterns over the years: extremely coarse, fine grain, and practically non-existent. Bricklink doesn't distinguish them, but they look horrible if you mix them up.
slope surfaces rendering comparison:

and here the differences in texture can be seen in beautiful action:
Hi Steffen,

The sloped brick renders with the rough surface look great!

To get that, the regular LDraw bricks have been substituted with custom definitions with more info for POV-Ray, right?

The renders use LGEO, and since LGEO bricks are custom POV code (completely ignoring the original LDraw geometry), they can include whatever surface texture they desire on whatever surface.

The implementation details for LGEO are that "slope" bricks are tagged as such in the lookup table that maps from LDraw to LGEO. Any bricks that include textured sloped geometry are split into two separate POV objects, one that contains the sloped geometry, and a second one that contains all the other geometry. Both objects are then referenced from the parent object with the same transformation matrix, but with different textures. (In POV, "texture" includes color, image-based or computational texture graphics, image-based or computational bump maps, and probably other things.)

If you look at the POV output from LDView or L3P when LGEO is enabled, you will see these two entries for sloped bricks. (For example, LDView's m6459 sample model has two references to lg_32083, and two to lg_32083_slope, because it uses LDraw part 32083 twice.) To enable LGEO output in LDView's POV export, check the "Use XML mapping file" option in the "Native POV Geometry" group of its POV export settings. Leave the "Path to XML mapping file" field blank to use LDView's default LGEO mapping file.
this brings me to the question/suggestion if we should add more colors to our LDConfig.ldr,
allowing to use different ones for normal plastic and the slope's more rough material.......

Just some thinking:

Extending our syntax by introducine new line types (like "6" for example) would require
to modify all parsers of all tools. So this probably is not the way to go.

However, our ldconfig.ldr still has plenty of room for new colors, and we already have "rubber", "metal", "lacquered" there,
I really would love to see "rough slope surface" in addition there as well.

We currently use the special syntax
for specifying a custom RGB color.

We could use the
prefix for the rough slopes surface.
I would like to use corresponding color numbers here, thus, if "15" is white, then "white rough surface" would be
(remember that 0x switches into hex mode).
Analogously, if
0x02RRGGBB is some color, then
0x03RRGGBB would be the same color, but with a "rough" surface texture for slopes.

darn, introducing the 0x03 prefix would as well require to modify all the parsers.... Sad

however, could we _still_ add this stuff to the color table in ldconfig.ldr, then?
analogously to "rubber"?
New colors won't help with sloped bricks. When the user places a sloped brick in the model, they can only specify one color. The rough slope geometry has to be specified inside the brick using color 16, or it won't track the user's color choice for the brick. If we want to allow renderers to show the slope as being rough, the geometry in question has to be tagged in some other way. As far as I can tell, this could only be accomplished with a new meta-command.

I have nothing against creating a new meta-command for this. And even if I don't support it in LDView's 3D view, I would probably support it in its POV export code.
Just to make this more complicated, there are bricks that contain both printing and roughness, right? (I'm thinking of the slope brick 33 3x2 parts that have the classic space logo, for example.)

So ideally we want a meta command that let us specify a surface roughness or grit to the "contained" geometry (within the meta command) but such roughness is orthogonal both to part color (set for the whole part) and texturing (because it would be sane to allow the author to build the classic space logo using the new texture extensions.
Indeed. In fact, I think the scoping rules from !TEXMAP would apply equally well to any new command that specifies surface roughness. I could even see creating a !BUMPMAP meta-command that behaves just like !TEXMAP, except applying a bump-map, but with the addition of allowing for succinct specification of a procedural bump map for slopes, instead of always requiring an image file. An appropriate image file could be used for stud logos, and procedural guidelines for rough slopes. For example, the POV code used for bumpy slopes coming out of LDView is normal { bumps 0.3 scale 25*0.2 }.

Note: I've never actually done bump-mapping, so I'm not sure an actual image file is used, since those would typically only give 8 bits of precision to each of the X, Y, and Z components of the surface normals. However, I do know that something very like an image file is used, where each "pixel" specifies a surface normal modifier, instead of a color.
Hi Travis,

I agree, re: the scoping rules. For the actual file, I think we might want to have meta-tokens (e.g. like "rubber" and "chrome") and let the visualization app implement a series of known effects, rather than having a specific image technology.

- The number of "bumpy textures" in our brickset is, at least I think, relatively small.
- The rendering technology to be implemented might be rather variable.

For example, a fixed-function renderer could intentionally hack the specularity params to do gritty reflections and at least the overall specularity would be correct. But if provided with an actual bump map, if the renderer can't use it directly, it has no way to know what was intended. I think providing actual bump map images externally is most useful when

(1) the bump map must match the location of a texture map exactly (e.g. this is the extrusion of the painted thing you see) and/or
(2) when the bump map's UV-coordinate application is custom to the model, rather than just a repeating pattern.

The actual bump maps are typically 8-bits per channel; in X-Plane we hit the case where some very smooth, very shallow bump maps showed banding of specular hilites due to the precision limit. We solved this by in some cases adding a scaler factor so that the 8-bits of precision could be used for the full range of bump-perturbations or for high precision very subtle effects. While a number of normal mapping schemes are possible, tangent space bump mapping is often popular because the normal map can be used just like the texture it matches.

Some apps stash the original height map from which the normal map was derived into another texture channel; this lets the app extrude geometry or apply parallax effects to the normal map. (http://en.wikipedia.org/wiki/Parallax_mapping)

In case it wasn't clear, my intention was for the bump map to be specified procedurally most of the time. My POV example showed one way to do that, but your suggestion of meta tokens (like, say "slope", "smooth_slope", etc) is probably a better choice. The only place I can think of off-hand for an actual bump map "image" is the LEGO logo on studs. There could be others, though. One problem I can see is that I'm definitely not qualified to specify details about the image format, and I'm not sure anyone else on the LSC is either.
Hi Travis,

Right! The motivation for the enumerated "well-known" surfaces is exactly illustrated by procedural bump maps - some programs might want to use procedural bump maps and program the grit pattern in-shader or pass a shader function to POV-Ray; other programs might simply want to create a bump map texture with a pre-generated pattern and use it.

The lego logo on stud tops would be well-handled via an explicit bump-map texture; I would recommend tangent-space normal maps, e.g.


Put the red and green (X and Y in tangent-space) vectors into the red and green channels of an RGB png; leave the blue channel defined as reserved for future expansion. The shader can reconstruct the blue channel from the red and green using the pythagorean theorem.

(Saving channels can be useful later for displacement information, etc. Or the program can use a 2-channel texture and save VRAM. There are also dedicated compressed texture formats for normal maps that compress two channels instead of 3 or 4.)