There appear to be two options to access materials in maxscript, through the compact Material Editor and the Slate material editor. The problems is that a scrip that attempts to access/modify materials via the compact editor (currentMaterialLibrary , sceneMaterials, meditMaterials) fail if max is set to use the Slate editor and vice versa.
Is there a way to access the materials directly in maxscript, irrespective of which editor is used?
Once I have the material, I would like to:
Purge unassigned materials from the scene so that missing textures on unused materials don't throw error's on scene open/network rendering.
Check certain material properties (i.e. Glossy subdivision) so purchased models with "unnecessarily high values" don't ruin render times.
If you want to find all existing materials (in the scene or not), the following snippet will do that for you
for aMtlType in material.classes do
(
for aMtl in (getClassInstances aMtlType processAllAnimatables:true) do
(
print aMtl
-- Does this material exist in the scene or not?
if (findItem sceneMaterials aMtl) == 0 do (print "This material does not exist in the scene")
)
)
I'm not quite sure how to purge it from the scene. You could get dependents (refs.dependents aMtl) then replace any references to this material to a new default material. That should work, although I haven't tried it (or even tried to run it). So... test it well and use with care :-).
defMtl = ...
for d in refs.dependents aMtl do (
refIdx = 0
for i = 1 to refs.getNumRefs d do ( if (refs.getreference d i) == aMtl ) do ( refIdx = i )
refs.replaceReference aMtl refIdx defMtl
)
For your second question - checking properties - you can check if it has the apropriate property and set the value as necessary
if (hasProperty aMtl "diffuse") do ( aMtl.diffuse = 0 )
You are not very specific on what you are trying to do, but what you can do is to loop through all materials in the scene, then go from there and pick out what material you want do do anything with. By doing it this way it does not care what setting your material editor is using.
for mat in scenematerials do
(
print ("material name: " + mat.name)
)
Related
Wondering if I could get some help with this:
function setupRound()
local gameModes = {'mode 1','mode 2','mode 3'} -- Game modes
local maps = {'map1','map2','map3'}
--local newMap = maps[math.random(1,#maps)]
local mapData = {maps[math.random(#maps)],gameModes[math.random(#gameModes)]}
local mapData = mapData
return mapData
end
a = setupRound()
print(a[1],a[2]) --Fix from Egor
What the problem is:
`
When trying to get the info from setupRound() I get table: 0x18b7b20
How I am trying to get mapData:
a = setupRound()
print(a)
Edit:
Output Issues
With the current script I will always the the following output: map3 mode 2.
What is the cause of this?
Efficiency; is this the best way to do it?
While this really isn't a question, I just wanted to know if this method that I am using is truly the most efficient way of doing this.
First of all
this line does nothing useful and can be removed (it does something, just not something you'd want)
local mapData = mapData
Output Issues
The problem is math.random. Write a script that's just print(math.random(1,100)) and run it 100 times. It will print the same number each time. This is because Lua, by default, does not set its random seed on startup. The easiest way is to call math.randomseed(os.time()) at the beginning of your program.
Efficiency; is this the best way to do it?
Depends. For what you seem to want, yes, it's definitely efficient enough. If anything, I'd change it to the following to avoid magic numbers which will make it harder to understand the code in the future.
--- etc.
local mapData = {
map = maps[math.random(#maps)],
mode = gameModes[math.random(#gameModes)]
}
-- etc.
print(a.map, a.mode)
And remember:
Premature optimization is the root of all evil.
— Donald Knuth
You did very good by creating a separate function for generating your modes and maps. This separates code and is modular and neat.
Now, you have your game modes in a table modes = {} (=which is basically a list of strings).
And you have your maps in another table maps = {}.
Each of the table items has a key, that, when omitted, becomes a number counted upwards. In your case, there are 3 items in modes and 3 items in maps, so keys would be 1, 2, 3. The key is used to grab a certain item in that table (=list). E.g. maps[2] would grab the second item in the maps table, whose value is map 2. Same applies to the modes table. Hence your output you asked about.
To get a random game mode, you just call math.random(#mode). math.random can accept up to two parameters. With these you define your range, to pick the random number from. You can also pass a single parameter, then Lua assumes to you want to start at 1. So math.random(3) becomes actually math.random(1, 3). #mode in this case stand for "count all game modes in that table and give me that count" which is 3.
To return your chosen map and game mode from that function we could use another table, just to hold both values. This time however the table would have different keys to access the values inside it; namely "map" and "mode".
Complete example would be:
local function setupRound()
local modes = {"mode 1", "mode 2", "mode 3"} -- different game modes
local maps = {"map 1", "map 2", "map 3"} -- different maps
return {map = maps[math.random(#maps)], mode = modes[math.random(#modes)]}
end
for i = 1, 10 do
local freshRound = setupRound()
print(freshRound.map, freshRound.mode)
end
I'm trying to understand how to use knitr_out, file_out and vis_drake_graph properly in drake.
I have two questions.
Q1: Usage of knitr_out and file_out to create markdown reports
While a code like this works correctly for one of my smaller projects:
make_hyp_data_aggregated_report <- function() {
render(
input = knitr_in("rmd/hyptest-is-data-being-aggregated.Rmd"),
output_file = file_out("~/projectname/reports/01-hyp-test.html"),
quiet = TRUE
)
}
plan <- drake_plan(
...
...
hyp_data_aggregated_report = make_hyp_data_aggregated_report()
...
...
)
Exactly similar code in my large project (with ~10+ reports) doesn't work exactly right. i.e., while the reports get built, the knitr_in objects don't get displayed as the blue squares in the graph using drake::vis_drake_graph() in my large project.
Both projects use the drake::loadd(....) within the markdown to get the objects from cache.
Is there some code in vis_drake_graph that removes these squares once the graph gets busy?
Q2: file_out objects in vis_drake_graph
Is there a way to display the file_out objects themselves as circles/squares in vis_drake_graph?
Q3: packages showing up in vis_drake_graph
Is there a way to avoid vis_drake_graph from printing the packages explicitly? (Basically anything with the ::)
Q1
Every literal file path needs its own knitr_in() or file_out(). If you have one function with one knitr_in(), even if you use the function multiple times, that still only counts as one file path. I recommend writing these keywords at the plan level, e.g.
plan <- drake_plan(
r1 = render(knitr_in("report1.Rmd"), output_file = file_out("report1.html")),
r2 = render(knitr_in("report2.Rmd"), output_file = file_out("report2.html")),
r3 = render(knitr_in("report3.Rmd"), output_file = file_out("report3.html"))
)
Q2
They should appear unless you set show_output_files = FALSE in vis_drake_graph().
Q3
No, but if it's any consolation, I do regret the decision to track namespaced functions and objects at all in drake. drake's approach is fundamentally suboptimal for tracking packages, and I plan to get rid of it if there ever comes time for a round of breaking changes. Otherwise, there is no way to get rid of it except vis_drake_graph(targets_only = TRUE), which also gets rid of all the imports in the graph.
Could someone help me change this script into a "mesh" dropper?
wait(2)
workspace:WaitForChild("PartStorage")
while true do
wait(1.5) -- How long in between drops
local part = Instance.new("Part",workspace.PartStorage)
part.BrickColor=script.Parent.Parent.Parent.DropColor.Value
part.Material=script.Parent.Parent.Parent.MaterialValue.Value
local cash = Instance.new("IntValue",part)
cash.Name = "Cash"
cash.Value = 5 -- How much the drops are worth
part.CFrame = script.Parent.Drop.CFrame - Vector3.new(0,1.4,0)
part.FormFactor = "Custom"
part.Size=Vector3.new(1.2, 1.2, 1.2) -- Size of the drops
part.TopSurface = "Smooth"
part.BottomSurface = "Smooth"
game.Debris:AddItem(part,20) -- How long until the drops expire
end
First and foremost, there's a website specifically for Roblox questions: scriptinghelpers.org. I suggest you use it in the future.
Now that that is out of the way...
It's not very hard to add a mesh to any part. You just have to know what kind of mesh you want, what you want its properties to be, and if applicable, the texture you'll use.
Since meshes are an instance, I'd suggest creating a new mesh instance as a child of your part, and giving it the properties you want. This can be accomplished rather easily with the code below.
local mesh = Instance.new("SpecialMesh", part) -- Create the mesh as a child of 'part'
mesh.MeshType = Enum.MeshType.Sphere -- Sets the mesh's MeshType. If you'd like a mesh type other than a sphere, use the corrosponding MeshType Enum, http://wiki.roblox.com/index.php?title=API:Enum/MeshType
mesh.Scale = Vector3.new(1.2,1.2,1.2) -- this will set scale to 1.2 on all axis
mesh.MeshID = nil -- If you're using a FileMesh, replace nil with the mesh ID, otherwise, you can just remove this line
There are also other properties, such as Offset, TextureID, and VertexColor, which you can read more about on the official wiki page for the SpecialMesh instance.
I've been working with the built-in Resize function in Roblox Studio and have been using it to expand the Top Surface of multiple Parts in order to form a wall-like structure.
The only problem that has arisen when using this method is that the surface of the wall created is not even: Some Parts are higher than others.
I later discovered that this problem is due to the fact that the built-in Resize function only takes integers as it's second parameter (or "expand-by" value). Ideally I need the Parts to have the ability expand by any Real Number.
Are there any alternatives to the built-in Resize function that allow one to resize a Surface by any Real Number?
Yes, this is possible, but it actually requires a custom function to do so. With some fairly basic math we can write a simple function to accomplish such a task:
local Resize
do
local directions = {
[Enum.NormalId.Top] = {Scale=Vector3.new(0,1,0),Position=Vector3.new(0,1,0)},
[Enum.NormalId.Bottom] = {Scale=Vector3.new(0,1,0),Position=Vector3.new(0,-1,0)},
[Enum.NormalId.Right] = {Scale=Vector3.new(1,0,0),Position=Vector3.new(1,0,0)},
[Enum.NormalId.Left] = {Scale=Vector3.new(1,0,0),Position=Vector3.new(-1,0,0)},
[Enum.NormalId.Front] = {Scale=Vector3.new(0,0,1),Position=Vector3.new(0,0,1)},
[Enum.NormalId.Back] = {Scale=Vector3.new(0,0,1),Position=Vector3.new(0,0,-1)},
}
function Resize(p, d, n, c)
local prop = c and 'Position' or 'CFrame'
p.Size = p.Size + directions[d].Scale*n
p[prop] = p[prop] + directions[d].Position*(n/2)
return p.Size, p[prop]
end
end
Resize(workspace.Part, Enum.NormalId.Bottom, 10, false) --Resize workspace.Part downards by 10 studs, ignoring collisions
If you're interested more on how and why this code works the way it does, here's a link to a pastebin that's loaded with comments, which I felt would be rather ugly for the answer here: http://pastebin.com/LYKDWZnt
Hi Guys : I wanted to create a power point presentation using a raw text file, so that i can rapidly edit the file and see the results, gauranteed with uniform formatting. Basically, I'm talking about separating the data content from the presentation.
How can I do this ? Im thinking that maybe Latex could be a choice. I've also seen that there are API's for Powerpoint and open office presentations.
Powerpoint exposes it's API via COM - which makes it possible to do (almost) anything that you can do in the GUI in any programming language that supports COM. The difficulty is that the API changes between releases. One way to scope out the API is to use the macro recording facility to manually do one slide, and then translate that to your target language.
I've got some old (not tested recently) python code for Powerpoint 2003 that should give you an idea of what the code might look like depending on your layout needs.
from win32com.client import Dispatch
ppLayoutTitle = 1
ppLayoutText = 2
def writePresentation( fname, data ):
pptApp = Dispatch('Powerpoint.Application')
pres = pptApp.ActivePresentation
aw = pptApp.ActiveWindow
slides = pres.Slides
for item in data:
t1 = item[0]
t2 = item[1]
stype = item[2]
assert(stype in [ppLayoutTitle,ppLayoutText])
s = slides.Add( slides.Count, stype )
aw.View.GotoSlide(s.SlideIndex)
s.Shapes.Item(1).Select()
aw.Selection.ShapeRange.TextFrame.TextRange.Select()
aw.Selection.ShapeRange.TextFrame.TextRange.Characters(Start=1, Length=0).Select
tr = aw.Selection.TextRange
tr.Text = t1
s.Shapes.Item(2).Select()
aw.Selection.ShapeRange.TextFrame.TextRange.Select()
if stype == ppLayoutText:
aw.Selection.ShapeRange.TextFrame.TextRange.ParagraphFormat.Bullet.Visible = 0
aw.Selection.ShapeRange.TextFrame.TextRange.Characters(Start=1, Length=0).Select
tr = aw.Selection.TextRange
tr.Text = t2
slides.Range(slides.Count).Delete()
pres.SaveAs(fname)
Edit:
Openoffice (that can export to powerpoint) also ships with it's scripting API that could be used to solve similar problems.
If all you need is slides with titles and bulleted text, it's quite simple. Create a txt file that looks like this (use the TAB key in place of below):
Slide 1 Title
<tab>Bullet Level One Text
<tab><tab>Bullet Level Two Text
<tab>Back to Bullet Leven One again
Slide 2 Title
Slide 3 Title
<tab>More Bulleted text
<tab><tab>Tufte hates us by now
<tab><tab>But we don't care, do we?
Slide 4 Title
And so on. Save the file, start PowerPoint, choose the file open command, choose Outline or files of all types in the file open dialog box and select your TXT file. Done.