Jump to content

another small development


Recommended Posts

well we're progressing see enclosed - but i'm having some troubles with the tiled roof

 

are there any textures out there to show terracotta tiling?

 

i've gone through mrmaterials - but it looks like i might need to 3D model the tiled roof from scratch - this client really wants a tiled roof look. :(

Link to comment
Share on other sites

I reckon I would model an individual tile, get it textured properly (new tiles tend to be shiny and have that "I just re-financed my house to get a new roof!" look), and then put it on a roof slope.

 

Dump this into your scripts folder under:

c:\program files\autodesk\3ds max 2009\scripts

 

I have a floating toolbar of the few scripts that I use on a regular basis.

 

Then select the roof as the place to paint on, then pick the tile you've modelled and textured, then 'paint' it on.

 

 

 

I got this script from http://www.3d-palace.com and use it to put rivets on 'mechs and such.

 

 

 

You can also align a user grid to the angle of the roof and then array it. Once you get one side, select/group them and rotate/copy it to the other sloped surface.

 

 

 

Hope this makes sense.

 

 

-- Object Painter by Jon Weimer, 2007
-- A Revised version of Autodesk Placement Tool script


offsetY = 20

globalZero = Point3 0 0 0

globalFirstHit = TRUE

globalDistNode = #(undefined,undefined,undefined)
globalDistNodeMirror = #(undefined,undefined,undefined)

globalHairCopy = #(undefined,undefined,undefined)
globalHairCopyMirror = #(undefined,undefined,undefined)

globalLastNode = #(undefined,undefined,undefined)
globalLastNodeMirror = #(undefined,undefined,undefined)
globalLastPos = #(undefined,undefined,undefined)
globalLastNormal = #(undefined,undefined,undefined)
globalLastPosMirror = #(undefined,undefined,undefined)
globalLastNormalMirror = #(undefined,undefined,undefined)
globalLastStr = 1
globalLastRadius = 1

globalUseDist = #(FALSE,FALSE,FALSE)

globalHairPos = #(globalZero,globalZero,globalZero )
globalHairNormal = #(globalZero,globalZero,globalZero)

globalHairPosMirror = #(globalZero,globalZero,globalZero )
globalHairNormalMirror = #(globalZero,globalZero,globalZero)
globalAlignNormal = 3
globalAlignStroke = 1

globalScaleOption = 1
globalScaleNormal = TRUE
globalScaleStroke = TRUE
globalScaleStrength = TRUE
globalScaleX = 1.0
globalScaleY = 1.0
globalScaleZ = 1.0

globalSourceNode = #()

globalInstance = FALSE

matrix3 fn GetMatrix hairPos mousePos normal str radius =
(
tm = matrix3 1
strNormal = 1
normalBase = 1
strengthBase = 1
strokeBase = 1
strStroke = 1
strStrength = 1

xvec = Point3 1 0 0
yvec = Point3 0 1 0
zvec = Point3 0 0 1
mouseVec = Point3 1 0 0

zvec = normalize normal

mouseVec = mousePos - hairPos

mouseVec = normalize mouseVec

xvec = cross mouseVec zvec
xvec = Normalize xvec

yvec = cross zvec xvec
yvec = normalize yvec

if (globalScaleOption == 1) then
(
)
else if (globalScaleOption == 2) then
(
str = globalScaleX
if (globalScaleY > str) then str = globalScaleY
if (globalScaleZ > str) then str = globalScaleZ
str = Length(mousePos - hairPos)/str
xvec = xvec * str
yvec = yvec * str
zvec = zvec * str
)
else if (globalScaleOption == 3) then
(
if (globalScaleNormal) then
(
strNormal = str*thePainterInterface.normalScale
if (globalAlignNormal == 1) then
normalBase = globalScaleX
else if (globalAlignNormal == 2) then
normalBase = globalScaleY
else if (globalAlignNormal == 3) then
normalBase = globalScaleZ

strNormal = strNormal/normalBase
zvec = zvec * strNormal
)

if (globalScaleStroke) then
(
strStroke = Length(mousePos - hairPos)
if (globalAlignStroke == 1) then
strokeBase = globalScaleX
else if (globalAlignStroke == 2) then
strokeBase = globalScaleY
else if (globalAlignStroke == 3) then
strokeBase = globalScaleZ

strStroke = strStroke/strokeBase
yvec = yvec * strStroke
)

if (globalScaleStrength) then
(
strStrength = radius
if (globalAlignStroke == 1)then
(
if (globalAlignNormal == 2)then
strengthBase = globalScaleZ
else if (globalAlignNormal == 3)then
strengthBase = globalScaleY
)
else if (globalAlignStroke == 2)then
(
if (globalAlignNormal == 1)then
strengthBase = globalScaleZ
else if (globalAlignNormal == 3)then
strengthBase = globalScaleX
)
if (globalAlignStroke == 3)then
(
if (globalAlignNormal == 1)then
strengthBase = globalScaleY
else if (globalAlignNormal == 2)then
strengthBase = globalScaleX
)
strStrength = strStrength/strengthBase
xvec = xvec * strStrength
)


)

if (globalAlignNormal == 1) then
(
tm.row3 = xvec
if (globalAlignStroke == 2) then
(
tm.row1 = yvec
tm.row2 = zvec
)
else
(
tm.row1 = zvec
tm.row2 = yvec
)

)
else if (globalAlignNormal == 2) then
(
tm.row3 = yvec
if (globalAlignStroke == 1) then
(
tm.row1 = xvec
tm.row2 = zvec
)
else
(
tm.row1 = zvec
tm.row2 = xvec
)
)
else
(
tm.row3 = zvec
if (globalAlignStroke == 1) then
(
tm.row1 = yvec
tm.row2 = xvec
)
else
(
tm.row1 = xvec
tm.row2 = yvec
)
)

tm.row4 = hairPos


return tm
)

fn StartStroke =
(
globalFirstHit = TRUE
thePainterInterface.undoStart()
)

fn PlaceStroke =
(

localHit = Point3 0 0 0
localNormal = Point3 0 0 0
worldHit = Point3 0 0 0
worldNormal = Point3 0 0 0
str = 0.0f
radius = 0.0f
if (globalFirstHit == TRUE) then
(
globalFirstHit = FALSE
undo on
(
for i = 1 to 3 do
(
if (globalUseDist[i]) then
(
if (globalInstance) then globalHairCopy[i] = instance globalDistNode[i]
else globalHairCopy[i] = copy globalDistNode[i]

thePainterInterface.getHitPointData &localHit &localNormal &worldHit &worldNormal &radius &str 0

globalHairPos[i] = worldHit
globalHairNormal[i] = worldNormal

if (thePainterInterface.mirrorEnable == TRUE) then
(
if (globalInstance) then globalHairCopyMirror[i] = instance globalDistNode[i]
else globalHairCopyMirror[i] = copy globalDistNode[i]
thePainterInterface.getMirrorHitPointData &localHit &localNormal &worldHit &worldNormal 0
globalHairPosMirror[i] = worldHit
globalHairNormalMirror[i] = worldNormal
)
)

)
)

)

--retrieves the last hit point
thePainterInterface.getHitPointData &localHit &localNormal &worldHit &worldNormal &radius &str 0

--This gets whether the stroke point actually hit the mesh
--Since the user can paint off the mesh
--Right now we ignore this and create a cylinder regardless if they are painting on the mesh or not
hit = thePainterInterface.getIsHit -1

thePainterInterface.offMeshHitPos = globalHairPos[1]

for i = 1 to 3 do
(
if (globalUseDist[i]) then
(

globalScaleX = abs (globalDistNode[i].max[1] - globalDistNode[i].pos[1])
globalScaleY = abs (globalDistNode[i].max[2] - globalDistNode[i].pos[2])
globalScaleZ = abs (globalDistNode[i].max[3] - globalDistNode[i].pos[3])

minScaleX = abs (globalDistNode[i].min[1] - globalDistNode[i].pos[1])
minScaleY = abs (globalDistNode[i].min[2] - globalDistNode[i].pos[2])
minScaleZ = abs (globalDistNode[i].min[3] - globalDistNode[i].pos[3])

if (minScaleX > globalScaleX) then globalScaleX = minScaleX
if (minScaleY > globalScaleY) then globalScaleY = minScaleY
if (minScaleZ > globalScaleZ) then globalScaleZ = minScaleZ

tm = matrix3 1

globalHairCopy[i].transform = GetMatrix globalHairPos[i] worldHit globalHairNormal[i] str radius

--checks if the mirror is on, if so make sure to get that point and proces it also
if (thePainterInterface.mirrorEnable == TRUE) then
(
-- Put mirror stuff here
thePainterInterface.getMirrorHitPointData &localHit &localNormal &worldHit &worldNormal 0
globalHairCopyMirror[i].transform = GetMatrix globalHairPosMirror[i] worldHit globalHairNormalMirror[i] str radius

)
)
)



)

fn PaintStroke =
(


localHit = Point3 0 0 0
localNormal = Point3 0 0 0
worldHit = Point3 0 0 0
mirrorWorldHit = Point3 0 0 0
worldNormal = Point3 0 0 0
str = 0.0f
radius = 0.0f

for i = 1 to 3 do
(
if (globalUseDist[i]) then
(
if (globalInstance) then globalHairCopy[i] = instance globalDistNode[i]
else globalHairCopy[i] = copy globalDistNode[i]

thePainterInterface.getHitPointData &localHit &localNormal &worldHit &worldNormal &radius &str 0

globalHairPos[i] = worldHit
globalHairNormal[i] = worldNormal

if (thePainterInterface.mirrorEnable == TRUE) then
(
if (globalInstance) then globalHairCopyMirror[i] = instance globalDistNode[i]
else globalHairCopyMirror[i] = copy globalDistNode[i]
thePainterInterface.getMirrorHitPointData &localHit &localNormal &worldHit &worldNormal 0
globalHairPosMirror[i] = worldHit
globalHairNormalMirror[i] = worldNormal
)
)
)

--retrieves the last hit point
thePainterInterface.getHitPointData &localHit &localNormal &worldHit &worldNormal &radius &str 0

--This gets whether the stroke point actually hit the mesh
--Since the user can paint off the mesh
--Right now we ignore this and create a cylinder regardless if they are painting on the mesh or not
hit = thePainterInterface.getIsHit -1

thePainterInterface.offMeshHitPos = globalHairPos[1]

for i = 1 to 3 do
(
if (globalUseDist[i]) then
(

globalScaleX = abs (globalDistNode[i].max[1] - globalDistNode[i].pos[1])
globalScaleY = abs (globalDistNode[i].max[2] - globalDistNode[i].pos[2])
globalScaleZ = abs (globalDistNode[i].max[3] - globalDistNode[i].pos[3])

minScaleX = abs (globalDistNode[i].min[1] - globalDistNode[i].pos[1])
minScaleY = abs (globalDistNode[i].min[2] - globalDistNode[i].pos[2])
minScaleZ = abs (globalDistNode[i].min[3] - globalDistNode[i].pos[3])

if (minScaleX > globalScaleX) then globalScaleX = minScaleX
if (minScaleY > globalScaleY) then globalScaleY = minScaleY
if (minScaleZ > globalScaleZ) then globalScaleZ = minScaleZ

tm = matrix3 1

projVec = Point3 0 0 1
if (thePainterInterface.getHitCount() > 1) then projVec = worldHit + (worldHit - globalLastPos[i])
else projVec = worldHit

globalHairCopy[i].transform = GetMatrix globalHairPos[i] projVec globalHairNormal[i] str radius


--checks if the mirror is on, if so make sure to get that point and proces it also
if (thePainterInterface.mirrorEnable == TRUE) then
(
-- Put mirror stuff here
thePainterInterface.getMirrorHitPointData &localHit &localNormal &mirrorWorldHit &worldNormal 0

if (thePainterInterface.getHitCount() > 1) then projVec = mirrorWorldHit + (mirrorWorldHit - globalLastPosMirror[i])
else projVec = mirrorWorldHit

globalHairCopyMirror[i].transform = GetMatrix globalHairPosMirror[i] projVec globalHairNormalMirror[i] str radius

)
)
)



if (thePainterInterface.getHitCount() > 1) then
(
for i = 1 to 3 do
(
if (globalUseDist[i]) then
(
globalLastNode[i].transform = GetMatrix globalLastPos[i] worldHit globalLastNormal[i] globalLastStr globalLastRadius


if (thePainterInterface.mirrorEnable == TRUE) then
(
globalLastNodeMirror[i].transform = GetMatrix globalLastPosMirror[i] mirrorWorldHit globalLastNormalMirror[i] globalLastStr globalLastRadius

)
)
)

)

for i = 1 to 3 do
(
if (globalUseDist[i]) then
(
globalLastNode[i] = globalHairCopy[i]
globalLastNodeMirror[i] = globalHairCopyMirror[i]
globalLastPos[i] = globalHairPos[i]
globalLastNormal[i] = globalHairNormal[i]
globalLastPosMirror[i] = globalHairPosMirror[i]
globalLastNormalMirror[i] = globalHairNormalMirror[i]
globalLastStr = str
globalLastRadius = radius
)
)


)

fn CancelStroke =
(
thePainterInterface.undoCancel()
)

fn EndStroke =
(
thePainterInterface.undoAccept()
)

fn systemEnd =
(
PaintHairRollout.PaintButton.checked = off
PaintHairRollout.PlaceButton.checked = off
)





rollout PaintHairRollout "Object Placement Tool Setup" width:600 height:600
(
   label instruction01 "1. Select the object you want to place other objects onto and then" pos:[11,16] width:500 height:15
   label instruction02 "click here -->" pos:[25,46] width:200 height:15

   Button SourceButton "Set Destination Object" pos:[110,40] width:150 height:24
   -- label SourceObject "Destination Object:" pos:[11,160] width:120 height:15

   label instruction03 "2. Click a Pick Object button and then select an item in the viewport to" pos:[11,80] width:420 height:15
   label instruction04 "place or paint onto the Destination Object:" pos:[25,105] width:400 height:15


   pickButton Dist1Button "Pick Object 1" pos:[186,141] width:120 height:24
   pickButton Dist2Button "Pick Object 2" pos:[186,170] width:120 height:24
   pickButton Dist3Button "Pick Object 3" pos:[186,201] width:120 height:24
   checkbox UseDist1 "Position/Paint With" pos:[30,145] width:176 height:15
   checkbox UseDist2 "Position/Paint With" pos:[30,174] width:176 height:15
   checkbox UseDist3 "Position/Paint With" pos:[30,204] width:176 height:15

   label instruction05 "3. Do you want to place objects or paint with them?" pos:[11,240] width:420 height:15

   checkButton PlaceButton "Place" pos:[30,265] width:104 height:24
   checkButton PaintButton "Paint" pos:[150,265] width:104 height:24
   checkbox UseInstance "Instance Copies" pos:[270,270] width:120 height:15

   label instruction06 "--------------- Advanced User Options ---------------" pos:[80,320] width:420 height:300

   label instruction07 "4. Change tool settings -->" pos:[11,350] width:320 height:24
   button Options "Tool Options" pos:[180,345] width:120 height:24

   label instruction08 "5. Change Object Alignment:" pos:[11,380] width:325 height:24
   label Align2 " Axis To Normal " pos:[25,390+offsetY] width:192 height:15
   dropDownList AlignNormal "" pos:[130,385+offsetY] width:37 height:21 items:#("X", "Y", "Z") selection:3
   label Align4 " Axis To Stroke " pos:[180,390+offsetY] width:92 height:15
   dropDownList AlignStroke "" pos:[280,385+offsetY] width:37 height:21 items:#("X", "Y", "Z") selection:1

   label Align5 "6. Scale Objects " pos:[11,435+offsetY] width:106 height:15
   dropDownList ScaleOptions "" pos:[120,430+offsetY] width:100 height:21 items:#("None", "Uniform Scale", "Custom Scale") selection:1

   checkbox chkScaleNormal "Scale Based On Normal" pos:[28,472+offsetY] width:170 height:22 checked:true
   checkbox chkScaleStroke "Scale Based On Stroke" pos:[28,492+offsetY] width:170 height:22 checked:true
   checkbox chkScaleStrength "Scale Based On Strength" pos:[28,512+offsetY] width:190 height:22 checked:true




on SourceButton pressed do
(
globalSourceNode = $
)

on Dist1Button picked obj do
(
globalDistNode[1] = obj
Dist1Button.text = obj.name
UseDist1.checked = TRUE
globalUseDist[1] = TRUE
)
on Dist2Button picked obj do
(
globalDistNode[2] = obj
Dist2Button.text = obj.name
UseDist2.checked = TRUE
globalUseDist[2] = TRUE
)
on Dist3Button picked obj do
(
globalDistNode[3] = obj
Dist3Button.text = obj.name
UseDist3.checked = TRUE
globalUseDist[3] = TRUE
)
on UseDist1 changed state do
globalUseDist[1] = state
on UseDist2 changed state do
globalUseDist[2] = state
on UseDist3 changed state do
globalUseDist[3] = state

on UseInstance changed state do
globalInstance = state

on PlaceButton changed state do
(
if (PaintButton.checked) then
(
PaintButton.checked = FALSE
thePainterInterface.EndPaintSession()
)


if thePainterInterface.InPaintMode() then
(
PlaceButton.checked = FALSE
thePainterInterface.EndPaintSession()
)
else
(
PaintButton.checked = FALSE
PlaceButton.checked = TRUE

thePainterInterface.initializeNodes 0 globalSourceNode

thePainterInterface.pointGatherEnable = FALSE
thePainterInterface.buildNormals = TRUE
thePainterInterface.offMeshHitType = 2
thePainterInterface.drawTrace = FALSE

thePainterInterface.ScriptFunctions startStroke placeStroke endStroke cancelStroke systemEnd

thePainterInterface.startPaintSession()


)
)


on PaintButton changed state do
(
if (PlaceButton.checked) then
(
PlaceButton.checked = FALSE
thePainterInterface.EndPaintSession()
)

if thePainterInterface.InPaintMode() then
(
PaintButton.checked = FALSE
thePainterInterface.EndPaintSession()
)
else
(
PaintButton.checked = TRUE

thePainterInterface.initializeNodes 0 globalSourceNode

thePainterInterface.pointGatherEnable = FALSE
thePainterInterface.buildNormals = TRUE
thePainterInterface.offMeshHitType = 2
thePainterInterface.drawTrace = FALSE

thePainterInterface.ScriptFunctions startStroke paintStroke endStroke cancelStroke systemEnd

thePainterInterface.startPaintSession()


)
)

On Options pressed do
(
thePainterInterface.paintOptions()
)

on AlignNormal selected sel do
(
globalAlignNormal = sel
)
on AlignStroke selected sel do
(
globalAlignStroke = sel
)

on ScaleOptions selected sel do
(
globalScaleOption = sel
)

on chkScaleNormal changed state do
globalScaleNormal = state

on chkScaleStrength changed state do
globalScaleStrength = state

on chkScaleStroke changed state do
globalScaleStroke = state

on PaintHairRollout oktoclose do
(
thePainterInterface.endPaintSession()
)
)


-- create the rollout window and add the rollout
if FloaterExampleFloater != undefined do
(
closerolloutfloater FloaterExampleFloater
)
Floater = newRolloutFloater "Object Placement/Paint Tool" 450 600
addRollout PaintHairRollout Floater 

Link to comment
Share on other sites

Found some links for you also on modelling tiles:

http://www.cg-blog.com/index.php/2007/04/02/how-to-model-tiled-roof.htm

http://www.robeccaproductions.com/Spanish_Tile_toot.htm

http://www.turbosquid.com/FullPreview/Index.cfm/ID/151967

(a roof tile model for $22)

The guy selling the roof tile says there are tutorials on his 2 websites and lists them, but they don't work any more.

Link to comment
Share on other sites

Hi Stan,

 

Looking better and better each render. I'd say the best way to get a correct tile (the method I use) is to try and get the specs for the actual tile which is going to be used. The architect should definitely know exactly which tile and from which company will be used. You can usually find the measurements on the manufacturers site and go from there. If not, call them up and get them to send you a product pack with specs for their products. Most aussie companies are rather obliging. I have gotten free colour swatches and product range packs from dulux, solver and James Hardie. Very handy as my clients use James Hardie and Bluescope stuff for 95% of the materials for each project.

 

I'll have to have a go of that script Joel some time. Tiles are the worst part of any job for me. Thanks for posting.

Link to comment
Share on other sites

James - it's a great little script. You can paint grass, hair, rivets, any sort of detail that you need.

 

===

 

First roof tile I've ever made.

 

I drew an arc spline then edited it to get the desired profile.

I then extruded it and applied a slight amount of taper.

I had my first row of tiles.

I then dragged a copy behind it and made it 'pop a wheelie' of 2.5 degrees.

I allowed an overlap of about 1.5 inches (trivia: you can enter another unit of measurement (like, Inches or ") even if you are in metric. Max does it and then displays the distance in metric)

I then copied the 2nd row however many times I needed to cover my roof.

I had a column.

I then copied the entire column to the side however many times I needed to cover my roof.

 

Since I never collapsed my stack, I can easily go in and edit the basic shape of the initial spline that formed the first tile. And as long as I don't exceed the overall length by too much, I should be able to change the basic shape of the entire roof in seconds.

 

I've attached my max file if anyone is interested.

 

 

spanish-tile-01a.jpg

 

spanish-tile-01b.jpg

 

spanish-tile-01a.jpg

 

spanish-tile-01b.jpg

Link to comment
Share on other sites

Hey guys,

 

here is the render with the tiles enclosed. Thankfully CSR had the 3D CAD model on their website and so it was a matter of bringing this in to the MAX model.

 

my model though has now ballooned from 89MB to 447MB!!! so i wonder how long final 4000x3000 px render will take.

 

thanks again for all your help with this one :cool:

Link to comment
Share on other sites

my model though has now ballooned from 89MB to 447MB!!! so i wonder how long final 4000x3000 px render will take.

 

Depends on how you adjust the roofing reflections - I'd recommend using the "Highlight Only" if you want the glazing to look clean and new.

 

The Merc needs to be polished too, it looks a little dull for a modern black car. You should be able to see the house reflected down the passenger side. It wouldn't hurt to add some gloss to the tyres too, makes them look like they've just had a wipe with ArmourAll.

 

If you are going to have a reflective driveway, give it some more blur and turn Fresnel on, IoR at about 1.35.

 

Head over to http://www.cgtextures.com and get some good asphalt and concrete textures for your road and footpath - they are in the foreground so the textures need to be good quality.

 

It's looking good and progressing well. Keep it up, Stan.

Edited by shaneis
Link to comment
Share on other sites

Looking much better Stan:cool:. I'm not sure if this is in your control or not, but i think the 'postage stamp' shape needs to go. Maybe try a more 'landscape' view. I realize you can't change it too much because the two houses side by side almost form a square, but i think taking a little off the top and bottom would make a big difference. Your getting some good advice from the other guys so that's all i have to pick. Good to see you moving forward with it.

Link to comment
Share on other sites

Yes it is worth modelling, unless it's a small part of the final picture and it looks much better than a bump map. If you use the approximation features in your renderer, you have control over the level of detail/ tessellation.

 

The following link is an interior I did with exposed beams and roof sheeting. Unfortunately I don't have an exterior example.

 

http://www.cgarchitect.com/vb/attachment.php?attachmentid=27936&d=1216641031

 

Sorry Stan, back to your thread.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...