@Mr Whippy I guess ultimately the best way to see if a particular method works is to just test it and find out Results speak for themselves etc. etc. lol
I agree.
I suppose I can use the importer/editor as it'll no doubt use the same renderer as the game engine itself. I can at least do visual checks?
So far I've not had much luck getting a car working in AC, just following the tutorial and renaming that open wheeler car name made AC error haha
@Stereo, authoring normals is a pita in Max too. That's likely why many in the industry avoid custom normals unless they have big teams who can have nice tools written to manage them easily.
Assuming AC does indeed use them, this is the script I use for Max, found somewhere on polycount wiki/threads.
Given your knowledge with blender and python, perhaps this could be used as inspiration for a blender tool?
Basically it 'smooths' any given selection of faces the usual way, but saves those smoothed normals. An example workflow is posted below.
Original author's code here:
Code:
macroScript GetVertNormalsFromFaces
category:"Normal Tools"
buttonText:"Get Vert Normals from Faces"
tooltip:"Get Vert Normals from Faces"
(
function getVertNormalsFromFaces =
(
if (getCommandPanelTaskMode() != #modify) do
setCommandPanelTaskMode #modify
if (Filters.Is_EditPoly()) do
(
local theNode = selection[1]
local theEditObj = modPanel.getCurrentObject()
local theEditNorm = undefined
local iModIndex = theNode.modifiers.count
if ((classOf theEditObj) == Editable_Poly) then
(
theEditNorm = theNode.modifiers[theNode.modifiers.count]
local baFaceSelection = polyOp.getFaceSelection theEditObj
)
if (not baFaceSelection.isEmpty) do
(
if ((classOf theEditNorm) == UndefinedClass) then
(
theEditNorm = Edit_Normals()
addModifier theNode theEditNorm
)
else if ((classOf theEditNorm) != Edit_Normals) then
(
theEditNorm = Edit_Normals()
addModifier theNode theEditNorm before:iModIndex
)
if (theEditNorm != undefined) do
(
local baVertsFromFaceSelection = polyOp.getVertsUsingFace theEditObj baFaceSelection
local ap3FaceNormals = for iFace = 1 to (polyOp.getNumFaces theEditObj) collect
( if (baFaceSelection[iFace]) then ( polyOp.getFaceNormal theEditObj iFace ) else ( 0.0 ) )
modPanel.setCurrentObject theEditNorm
local abaFaceVertNormals = #()
for iFace = 1 to (polyOp.getNumFaces theEditObj) do
(
local baFaceVertNormals = #{}
if (baFaceSelection[iFace]) do
theEditNorm.convertFaceSelection #{iFace} baFaceVertNormals node:theNode
append abaFaceVertNormals baFaceVertNormals
)
local baAllVertNormals = #{}
theEditNorm.convertFaceSelection baFaceSelection baAllVertNormals node:theNode
for iVert in baVertsFromFaceSelection do
(
local baVertNormals = #{}
theEditNorm.convertVertexSelection #{iVert} baVertNormals node:theNode
baVertNormals *= baAllVertNormals
local baProxiFaces = (polyOp.getFacesUsingVert theEditObj iVert) * baFaceSelection
if (baVertNormals.numberSet == 1) then
(
local p3AvgFaceNormal = Point3 0.0 0.0 0.0
for iFace in baProxiFaces do
p3AvgFaceNormal += ap3FaceNormals[iFace]
p3AvgFaceNormal /= baProxiFaces.numberSet
local iNormal = (baVertNormals as Array)[1]
theEditNorm.setNormal iNormal p3AvgFaceNormal node:theNode
)
else
(
for iNormal in baVertNormals do
(
local p3AvgFaceNormal = Point3 0.0 0.0 0.0
for iFace in baProxiFaces do
if (abaFaceVertNormals[iFace][iNormal]) do
p3AvgFaceNormal += ap3FaceNormals[iFace]
p3AvgFaceNormal = normalize p3AvgFaceNormal
theEditNorm.setNormal iNormal p3AvgFaceNormal node:theNode
)
)
)
theEditNorm.makeExplicit selection:baAllVertNormals node:theNode
maxOps.collapseNodeTo theNode theNode.modifiers.count true
modPanel.setCurrentObject theNode.baseObject
subObjectLevel = 4
)
)
)
)
on execute do
(
undo "Get Vert Normals From Faces" on
(
getVertNormalsFromFaces()
)
)
)
Starting:
Selected top faces:
Smoothed top faces normals:
Selected perpendicular faces:
Smoothed perpendicular faces:
Deleted perpendicular faces:
So basically you do a chamfer for a 45deg edge. Select the main panel faces, process them, select the perp faces, process them... this leaves the 45deg faces with normals that wrap from front main panel facing to perp facing at the back.
Then you trim those back faces.
Now if AC doesn't support this then fine.
But if it does then this is a really nice way to reduce polys, increase ease of tweaking (keeping those support loops normals smooth is near impossible by hand!), easier UV mapping and probably better looking AO into panel gaps, and once you understand the workflow it's imo easier to work with and use vs support loop methodology!
I've been using this approach in Racer and it looks nice.