1933
6
09-11-2013 08:25 AM
New Contributor
Hello,

I am wondering if there is a way to procedurally adapt roof images in the same way the façade wizard works. I have a solar array and a green roof image that I am trying to tile based on the random building size and shape. So if the building is larger, it adds another tile of the image to the initial one so that the scale of the image stays constant and realistic.

Any suggestions appreciated, thanks!
Tags (2)
1 Solution

Accepted Solutions
Frequent Contributor
Hi,

The Facade Wizard creates CGA code which is 'hardcoded' to work automatically only on vertical ( world orientation yUp, direction of gravity ) shapes properly by default.

Note that the Facade Wizard produces rules which should only be assigned to exactly rectangular shapes.

If you look at any rule created that way, you'll note a thing:
> any split done is in scope.sx or scope.sy

If you watch this video closely :
you'll learn that after a comp(f), the scope is automatically aligned 'zUp'. Means after an initial first extrusion of a footprint, after this Mass'es comp(f){side.. }, you'll get Facade shapes with a zUp scope, scope.sz being 0 since the polygon is flat. Thus also logically follows that any split must be done in x and y direction.

Now in your case, where you do e.g. a comp(f) to get the sloped or flat roof shape, theoretically all splits produced are already ok and usable, since those splits are always done RELATIVE to the scope, no matter what the orientation in the world is.

So in theory, you should get this working very fast. I did never try this yet, but it's worth a try.

Let me know ..

m.
6 Replies
Frequent Contributor
Hi,

The Facade Wizard creates CGA code which is 'hardcoded' to work automatically only on vertical ( world orientation yUp, direction of gravity ) shapes properly by default.

Note that the Facade Wizard produces rules which should only be assigned to exactly rectangular shapes.

If you look at any rule created that way, you'll note a thing:
> any split done is in scope.sx or scope.sy

If you watch this video closely :
you'll learn that after a comp(f), the scope is automatically aligned 'zUp'. Means after an initial first extrusion of a footprint, after this Mass'es comp(f){side.. }, you'll get Facade shapes with a zUp scope, scope.sz being 0 since the polygon is flat. Thus also logically follows that any split must be done in x and y direction.

Now in your case, where you do e.g. a comp(f) to get the sloped or flat roof shape, theoretically all splits produced are already ok and usable, since those splits are always done RELATIVE to the scope, no matter what the orientation in the world is.

So in theory, you should get this working very fast. I did never try this yet, but it's worth a try.

Let me know ..

m.
New Contributor
Thanks, Matt,

I did watch the video and it worked at one point when the roof was a flat object but when I added the Lot--> extrude, it gave a white box without the image.

Here is the code that I modified from the gen_Facade_.cga file, I think I have conflicting alignScope commands...

attr LOD = 2
# LOD 0 generates the original texture
# LOD 1 generates flat splits
# LOD 2 generates splits with depth as defined in Facade Wizard

#! SIZE 30.0 17.423582

const n = 3

Lot --> extrude(10)
comp(f) {top : alignScopeToGeometry(yUp, 0, world.lowest)Roof.

Roof -->
case LOD <= 0:
texture("/CityEngine_ForestLawn/images/plastic_panels.jpg")
setupProjection(0, scope.xy, '1.0000, '1.0000)
projectUV(0)
else:
texture("/CityEngine_ForestLawn/images/plastic_panels.jpg")
split(y, noAdjust) { ~5.84: Roof__1(0) | ~4.67: Roof__1(1) | ~6.91: Roof__1(2) }

RoofTrigger(i) -->
case LOD <= 0:
texture("/CityEngine_ForestLawn/images/plastic_panels.jpg")
setupProjection(0, scope.xy, '1.0000, '1.0000)
projectUV(0)
else:
texture("/CityEngine_ForestLawn/images/plastic_panels.jpg")
Roof__1(i)

Roof__1(i) -->
case i == 0: Roof__1_1
case i == 1: Roof__1_2
case i == 2: Roof__1_3
else: Roof__1_1

Roof__1_1 -->
split(x, noAdjust) { ~13.21: Roof__1_1_1 | 2.29: Roof__1_1_2 | 14.50: Roof__1_1_3 }

Roof__1_1_1 -->
setupProjection(0, scope.xy, '2.2707, '2.9822)
projectUV(0)

Roof__1_1_2 -->
setupProjection(0, scope.xy, '13.1258, '2.9822, '-5.7806, '0.0000)
projectUV(0)

Roof__1_1_3 -->
setupProjection(0, scope.xy, '2.0686, '2.9822, '-1.0686, '0.0000)
projectUV(0)

Roof__1_2 -->
setupProjection(0, scope.xy, '1.0000, '3.7302, '0.0000, '-1.2508)
projectUV(0)

Roof__1_3 -->
split(x, noAdjust) { ~3.91: Roof__1_3_1 | 17.68: Roof__1_3_2 | ~8.40: Roof__1_3_3 }

Roof__1_3_1 -->
setupProjection(0, scope.xy, '7.6630, '2.5215, '0.0000, '-1.5214)
projectUV(0)

Roof__1_3_2 -->
setupProjection(0, scope.xy, '1.6968, '2.5215, '-0.2214, '-1.5214)
projectUV(0)

Roof__1_3_3 -->
setupProjection(0, scope.xy, '3.5695, '2.5215, '-2.5695, '-1.5214)
projectUV(0)

Is this the right approach? Thank you, it would be very cool to get this working 🙂
New Contributor
It actually didn't need any scope rotation, so it works perfectly just by changing the façade id to roof 🙂

Thanks for the pointers.
New Contributor
Hi again,

I am now trying to tile the roof textures so that they don't stretch out of proportion. I've tried the tileUV and the scaleUV but neither seems to have an effect. Could you explain in a bit more detail how this should work? The texture will be applied randomly on different sizes of buildings so it needs to adapt.

Thank you!
Carmen
New Contributor
Here is the piece of code I am using...

Roof -->
10% : texture("/CityEngine_ForestLawn/images/Greenroof2.jpg")
alignScopeToGeometry(zUp, 0, world.lowest)
setupProjection(0, scope.xy, '1.0000, '1.0000)
scaleUV(0, 20, .5)
projectUV(0)
Frequent Contributor
Hi,

usually setupProjection() and projectUV() go right after each other, because projectUV() 'bakes' the UVs into the geometry based on the last projection. Scaling existing UVs in between will show no effect.

once UVs are projected, you can rotate , translate, tile them, ..

tileUV() takes metric values, so e.g. '~2' means tile the texture approximately each 2 meters.

Ok so far ?

m.