Загрузка данных
# ASUS ROG Astral GeForce RTX 5090 — procedural Blender model
# Run in Blender: Scripting > New > paste this file > Run Script.
# Detailed procedural model based on ASUS/ROG published specs and reference photos.
# Includes procedural micro-bump/roughness, layered armour, fasteners, dense fins and PCB components.
# Units are millimetres (1 Blender unit = 1 mm). Not a manufacturing/CAD model.
import bpy
import math
from mathutils import Vector
# ---------- Scene ----------
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)
for datablocks in (bpy.data.materials,):
for block in list(datablocks):
if block.users == 0:
datablocks.remove(block)
scene = bpy.context.scene
scene.unit_settings.system = 'NONE'
# ---------- Materials ----------
def mat(name, color, metallic=0.0, roughness=0.4, emission=None):
m = bpy.data.materials.new(name)
m.diffuse_color = (*color, 1)
m.use_nodes = True
nt = m.node_tree
nt.nodes.clear()
out = nt.nodes.new('ShaderNodeOutputMaterial')
bsdf = nt.nodes.new('ShaderNodeBsdfPrincipled')
bsdf.inputs['Base Color'].default_value = (*color, 1)
bsdf.inputs['Metallic'].default_value = metallic
bsdf.inputs['Roughness'].default_value = roughness
if emission:
if 'Emission Color' in bsdf.inputs:
bsdf.inputs['Emission Color'].default_value = (*emission, 1)
bsdf.inputs['Emission Strength'].default_value = 0.7
elif 'Emission' in bsdf.inputs:
bsdf.inputs['Emission'].default_value = (*emission, 1)
# Procedural surface finish: fine machining grain + subtle bump.
# Every material gets a stable node tree; no node-name lookups are used.
texcoord = nt.nodes.new('ShaderNodeTexCoord')
noise = nt.nodes.new('ShaderNodeTexNoise')
noise.inputs['Scale'].default_value = 185.0 if metallic > 0.3 else 95.0
noise.inputs['Detail'].default_value = 2.0
noise.inputs['Roughness'].default_value = 0.72
bump = nt.nodes.new('ShaderNodeBump')
bump.inputs['Strength'].default_value = 0.12 if metallic > 0.3 else 0.075
bump.inputs['Distance'].default_value = 0.08
ramp = nt.nodes.new('ShaderNodeValToRGB')
ramp.color_ramp.elements[0].position = 0.18
ramp.color_ramp.elements[1].position = 0.82
# Keep the bump subtle; this is microfinish, not a lumpy surface.
nt.links.new(texcoord.outputs['Generated'], noise.inputs['Vector'])
nt.links.new(noise.outputs['Fac'], bump.inputs['Height'])
nt.links.new(bump.outputs['Normal'], bsdf.inputs['Normal'])
# Slight roughness variation makes black anodized metal and plastic read better.
nt.links.new(noise.outputs['Fac'], ramp.inputs['Fac'])
nt.links.new(ramp.outputs['Color'], bsdf.inputs['Roughness'])
nt.links.new(bsdf.outputs['BSDF'], out.inputs['Surface'])
return m
black = mat('Graphite | die-cast shroud', (0.035, 0.038, 0.043), 0.45, 0.29)
black2 = mat('Backplate black', (0.018, 0.020, 0.024), 0.35, 0.32)
plastic = mat('Fan blades', (0.012, 0.014, 0.019), 0.15, 0.3)
metal = mat('Brushed aluminium', (0.42, 0.44, 0.47), 0.8, 0.25)
silver = mat('Fan ring silver', (0.62, 0.64, 0.67), 0.82, 0.22)
gold = mat('PCIe contacts', (0.72, 0.48, 0.12), 0.75, 0.24)
pcbmat = mat('PCB', (0.025, 0.055, 0.045), 0.15, 0.45)
portmat = mat('Port interiors', (0.005, 0.006, 0.008), 0.25, 0.28)
rgb = mat('Subtle ROG RGB', (0.10, 0.015, 0.42), 0.25, 0.24, (0.12, 0.01, 0.65))
white = mat('Lettering', (0.75, 0.77, 0.8), 0.2, 0.35)
rubber = mat('Fan hub rubberized polymer', (0.025, 0.027, 0.032), 0.05, 0.62)
copper = mat('Heatpipe copper', (0.48, 0.19, 0.075), 0.82, 0.25)
solder = mat('PCB solder and component metal', (0.34, 0.36, 0.39), 0.82, 0.26)
# ---------- Helpers ----------
def cube(name, loc, scale, material, bevel=0):
bpy.ops.mesh.primitive_cube_add(size=1, location=loc)
o = bpy.context.object
o.name = name
o.dimensions = scale
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
if material: o.data.materials.append(material)
if bevel:
mod = o.modifiers.new('Machined softened edges', 'BEVEL')
mod.width = bevel
mod.segments = 3
o.modifiers.new('Weighted corner normals', 'WEIGHTED_NORMAL')
return o
def cyl(name, loc, radius, depth, material, axis='Z', vertices=64, bevel=0):
bpy.ops.mesh.primitive_cylinder_add(vertices=vertices, radius=radius, depth=depth, location=loc)
o = bpy.context.object
o.name = name
if axis == 'X': o.rotation_euler[1] = math.pi/2
elif axis == 'Y': o.rotation_euler[0] = math.pi/2
if material: o.data.materials.append(material)
if bevel:
mod=o.modifiers.new('Edge glint', 'BEVEL'); mod.width=bevel; mod.segments=2
o.modifiers.new('Weighted normals','WEIGHTED_NORMAL')
return o
def text_obj(body, name, loc, size, material, rotation=(0,0,0), extrude=0.15):
curve = bpy.data.curves.new(name, 'FONT')
curve.body = body
curve.size = size
curve.extrude = extrude
curve.bevel_depth = 0.025
curve.bevel_resolution = 1
ob = bpy.data.objects.new(name, curve)
bpy.context.collection.objects.link(ob)
ob.location = loc
ob.rotation_euler = rotation
ob.data.materials.append(material)
return ob
def blade_mesh(name, cx, cy, z, angle, radius=31, material=plastic, reverse=False):
# Broad swept, tapered fan blade silhouette, built as a shallow extruded mesh.
# The curved sweep is approximated with a four-point profile.
pts = [(7.0, -3.5), (radius*0.53, -10.0), (radius*0.94, -4.0), (radius*0.72, 7.0), (radius*0.38, 10.0), (13.0, 5.0)]
if reverse:
pts = [(x, -y) for x,y in pts]
ca, sa = math.cos(angle), math.sin(angle)
verts=[]
for zz in (-0.9,0.9):
for x,y in pts:
verts.append((cx+x*ca-y*sa, cy+x*sa+y*ca, z+zz))
n=len(pts)
faces=[tuple(range(n)), tuple(range(n,2*n))]
for i in range(n):
j=(i+1)%n
faces.append((i,j,j+n,i+n))
mesh=bpy.data.meshes.new(name+' mesh'); mesh.from_pydata(verts,[],faces); mesh.materials.append(material); mesh.update()
ob=bpy.data.objects.new(name,mesh); bpy.context.collection.objects.link(ob)
bevel=ob.modifiers.new('Soft blade edges','BEVEL'); bevel.width=0.6; bevel.segments=2
ob.modifiers.new('Blade normals','WEIGHTED_NORMAL')
return ob
def make_fan(cx, cy, face_z, label, reverse=False):
sign = 1 if face_z > 0 else -1
# shroud surround and silver trim ring
cyl(label+' outer fan ring', (cx,cy,face_z), 43.5, 2.2, black, 'Z', 96, 0.5)
cyl(label+' silver accent ring', (cx,cy,face_z+sign*1.35), 41.0, 1.0, silver, 'Z', 96, 0.25)
cyl(label+' inner ring', (cx,cy,face_z+sign*1.95), 37.8, 1.2, black, 'Z', 96, 0.25)
blade_z = face_z + sign*2.1
for i in range(7):
blade_mesh(label+' axial-tech blade %02d'%i, cx,cy,blade_z,2*math.pi*i/7+0.18, 31.5, plastic, reverse)
cyl(label+' central hub', (cx,cy,face_z+sign*4.0), 14.0, 4.0, black, 'Z', 64, 1.0)
cyl(label+' hub badge', (cx,cy,face_z+sign*6.15), 10.8, 0.8, silver, 'Z', 64, 0.3)
cyl(label+' hub centre', (cx,cy,face_z+sign*6.65), 9.5, 0.8, black2, 'Z', 64, 0.25)
torus(label+' hub fine rim', (cx,cy,face_z+sign*7.12), 8.5, 0.32, silver)
for k in range(7):
a=2*math.pi*k/7
# Small blade-root fastener details on the fan frame
screw(label+' frame micro screw %02d'%k, cx+35.5*math.cos(a), cy+35.5*math.sin(a),
face_z+sign*2.55, radius=0.72, material=metal)
# A small ROG-style badge mark; avoids relying on external logo files.
text_obj('ROG', label+' hub lettering', (cx-6.6,cy-2.8,face_z+sign*7.12), 4.6, white,
rotation=(0,0,0), extrude=0.05)
# ---------- Fine detail helpers ----------
def torus(name, loc, major, minor, material, rotation=(0,0,0), major_segments=64, minor_segments=10):
bpy.ops.mesh.primitive_torus_add(major_segments=major_segments, minor_segments=minor_segments,
location=loc, major_radius=major, minor_radius=minor)
o=bpy.context.object; o.name=name; o.rotation_euler=rotation
if material: o.data.materials.append(material)
for poly in o.data.polygons: poly.use_smooth=True
return o
def screw(name, x, y, z, radius=1.6, material=silver, axis='Z'):
cyl(name+' head', (x,y,z), radius, 0.8, material, axis, 24, 0.18)
# Phillips slot represented by two fine dark cuts.
if axis == 'Z':
cube(name+' slot A', (x,y,z+0.43), (radius*1.25,0.28,0.12), black2, 0.04)
cube(name+' slot B', (x,y,z+0.44), (0.28,radius*1.25,0.12), black2, 0.04)
else:
cube(name+' slot', (x+0.43,y,z), (0.12,radius*1.25,0.28), black2, 0.04)
def vent_slot(name, loc, size, material=portmat, bevel=0.7):
return cube(name, loc, size, material, bevel)
# ---------- Card body: ASUS published overall dimensions 357.6 x 149.3 x 76 mm ----------
L, W, T = 357.6, 149.3, 76.0
# Main die-cast cooler and central PCB
cube('Main cooler chassis', (0,0,0), (L-7,W-7,T-8), black, 7.0)
cube('PCB core', (0,0,-8), (L-14,W-14,5), pcbmat, 1.2)
# Large front face plate under the three visible fans
cube('Front fan shroud', (0,0,T/2-1.2), (L-9,W-8,5.5), black, 6.0)
# Backplate face
cube('Full metal backplate', (0,0,-T/2+1.2), (L-8,W-8,4.5), black2, 5.0)
cube('Backplate inset panel', (12,0,-T/2-1.3), (L-50,W-28,1.1), black, 3.0)
# Three front fans, matching the provided product views
fan_x = [-111.0, 0.0, 111.0]
for i,x in enumerate(fan_x,1):
make_fan(x, 0, T/2+2.2, 'Front fan %d'%i, False)
# Rear fourth fan on the backplate (Astral's four-fan cooling design)
make_fan(-126.0, 0, -T/2-2.2, 'Rear backplate fan', True)
# Radiator fins visible around the long side edges
for i in range(70):
x = -166 + i*4.8
cube('Cooling fin %02d'%i, (x, W/2-2.5, 0), (1.15, 4.5, 48), metal, 0.25)
cube('Cooling fin underside %02d'%i, (x, -W/2+2.5, 0), (1.15, 4.5, 48), metal, 0.25)
# Side rail and brand stripe on one long side
cube('Side rail branding strip', (0,W/2+0.2,8), (L-18,2.0,12), black2, 1.5)
text_obj('GEFORCE RTX', 'GeForce RTX side lettering', (42,W/2+1.45,4.2), 8.0, white,
rotation=(math.pi/2,0,0), extrude=0.04)
text_obj('REPUBLIC OF GAMERS', 'ROG side lettering', (-142,W/2+1.45,4.2), 4.2, silver,
rotation=(math.pi/2,0,0), extrude=0.04)
# Backplate detailing: geometric panel seams, screws, and restrained logo text
for x in [-145,-90,-35,25,85,140]:
cube('Backplate etched seam', (x,0,-T/2-2.05), (0.8,82,0.35), black, 0.12)
text_obj('REPUBLIC OF GAMERS', 'Backplate ROG lettering', (42,47,-T/2-2.5), 7.0, white,
rotation=(0,0,0), extrude=0.04)
# Four mounting screws on backplate
for x in [-155,155]:
for y in [-57,57]:
cyl('Backplate screw', (x,y,-T/2-2.2), 2.7, 0.8, silver, 'Z', 24, 0.15)
cube('Screw slot', (x,y,-T/2-2.72), (2.8,0.45,0.18), black2, 0.05)
# PCIe edge connector along lower edge, with individual gold fingers
cube('PCIe connector substrate', (-10,-W/2+1.0,-T/2-5.2), (116,10,3.5), black2, 0.5)
for i in range(48):
x=-65+i*2.25
cube('PCIe gold contact %02d'%i, (x,-W/2+0.1,-T/2-7.05), (1.35,7.0,0.55), gold, 0.12)
# Rear I/O bracket at the left end, with 3 DisplayPort + 2 HDMI apertures.
# Port face points toward -X; all five ports are shown along the bracket height.
cube('I O bracket', (-L/2-2.3,0,0), (4.5,W-20,T-5), metal, 1.2)
# Ventilation slots across bracket
for y in [-48,-36,-24,-12,0,12,24,36,48]:
cube('I O bracket vent', (-L/2-4.7,y,12), (0.7,5.5,25), portmat, 0.7)
# Five port cutout-like dark face plates in a row
port_y = [-43,-22,0,22,43]
for i,y in enumerate(port_y):
is_hdmi = i in (1,4)
w = 13.5 if is_hdmi else 15.0
h = 5.5 if is_hdmi else 4.0
cube(('HDMI' if is_hdmi else 'DisplayPort')+' socket rim', (-L/2-5.0,y,-18), (1.2,w+2.5,h+2.5), black2, 0.8)
cube(('HDMI' if is_hdmi else 'DisplayPort')+' socket opening', (-L/2-5.75,y,-18), (0.6,w,h), portmat, 0.6)
# Small port labels
text_obj('HDMI DP DP DP HDMI', 'I O labels', (-L/2-6.0,-50,-31), 3.0, white,
rotation=(math.pi/2,0,-math.pi/2), extrude=0.025)
# 16-pin power connector on upper edge, offset toward one end
cube('16 pin power socket surround', (115,W/2-7,8), (25,11,15), black2, 2.0)
cube('16 pin power socket cavity', (115,W/2-1.2,8), (18,1.0,9), portmat, 0.6)
for row in range(2):
for col in range(6):
cube('Power pin %d %d'%(row,col), (108+col*2.8,W/2-0.55,5.7+row*3.2), (1.2,0.35,1.2), gold, 0.15)
# Subtle RGB accents along the upper shroud edge
for x in [-105,0,105]:
cube('RGB accent diffuser', (x,W/2-10,T/2+2.0), (43,2.2,1.1), rgb, 0.45)
# ---------- Added high-detail product geometry ----------
# Beveled geometric armour panels on the fan shroud
for idx, x in enumerate([-160,-54,54,160]):
cube('Armour panel inset %d'%idx, (x,-W/2+13,T/2+1.7), (42,15,1.25), black2, 2.0)
cube('Armour panel highlight %d'%idx, (x,-W/2+13,T/2+2.38), (30,0.65,0.25), metal, 0.12)
# More convincing radiator fin stack visible through the open side
for i in range(100):
x=-169+i*3.4
cube('Dense radiator fin %03d'%i, (x,W/2-7,0), (0.72,9.0,50), metal, 0.12)
cube('Dense radiator fin lower %03d'%i, (x,-W/2+7,0), (0.72,9.0,50), metal, 0.12)
# Long side ventilation openings and structural ribs
for i in range(23):
x=-148+i*13.2
vent_slot('Side exhaust vent %02d'%i, (x,W/2+1.35,-17), (7.5,0.65,12), portmat, 1.1)
cube('Side frame rib %02d'%i, (x+5.3,W/2+1.4,-17), (1.1,0.8,14), black, 0.3)
# Heat pipes / vapor-chamber edge hints running along the cooler core
for yy in [-31,-21,-11,0,11,21,31]:
cyl('Heatpipe edge detail', (0,yy,-1), 1.35, L-42, copper, 'X', 20, 0.15)
# Backplate design: additional recessed geometric accents and corner protection
for idx, x in enumerate([-125,-65,0,65,125]):
cube('Backplate angular groove %d'%idx, (x,-42,-T/2-2.25), (42,1.0,0.32), black2, 0.25)
cube('Backplate angular groove return %d'%idx, (x+18,-30,-T/2-2.25), (1.0,24,0.32), black2, 0.25)
for x in [-165,165]:
cube('Backplate corner guard', (x,0,-T/2-2.1), (11,92,1.2), black, 2.0)
for y in [-38,38]:
screw('Backplate corner screw', x,y,-T/2-3.0, radius=2.1)
# A more detailed PCIe bracket flange and screws
for yy in [-61,-48,48,61]:
screw('I O bracket screw', -L/2-5.2, yy, 25, radius=2.0, axis='X')
screw('I O bracket lower screw', -L/2-5.2, yy, -25, radius=1.7, axis='X')
# Gold connector fingers and PCB surface components
for i in range(22):
x=-155+i*14.5
cube('PCB power stage component %02d'%i, (x,-W/2+13,-11), (8.0,7.0,3.2), black2, 0.45)
cube('Power stage metal cap %02d'%i, (x,-W/2+13,-9.1), (5.4,4.2,0.45), solder, 0.25)
for i in range(16):
x=-130+i*17
cube('PCB capacitor %02d'%i, (x,-W/2+23,-12), (4.2,4.2,4.8), metal, 0.65)
cyl('Capacitor top %02d'%i, (x,-W/2+23,-9.4), 1.45, 0.35, silver, 'Z', 20, 0.08)
# Power connector detail: outer lip, latch, and individual contacts
cube('16-pin socket metallic lip', (115,W/2-0.6,8), (22,1.1,12), metal, 1.0)
cube('16-pin latch', (115,W/2-0.2,15.5), (7,1.3,2.2), black, 0.45)
for row in range(2):
for col in range(6):
cube('16-pin contact glint %d %d'%(row,col),
(108+col*2.8,W/2-0.31,5.7+row*3.2), (0.75,0.18,0.65), gold, 0.08)
# Small identification plate and etched technical markings on the backplate
cube('Serial plate', (118,18,-T/2-2.6), (35,17,0.7), metal, 0.7)
cube('Serial plate black inset', (118,18,-T/2-3.05), (32,14,0.35), black2, 0.4)
text_obj('ROG ASTRAL', 'Serial plate title', (105,14,-T/2-3.3), 3.2, white, extrude=0.025)
text_obj('RTX 5090', 'Serial plate model', (108,20,-T/2-3.3), 2.6, silver, extrude=0.025)
# Fan frame accent ticks around the outer silver rings
for cx in fan_x:
for i in range(24):
a=2*math.pi*i/24
x=cx+40.0*math.cos(a); y=40.0*math.sin(a)
tick=cube('Fan ring index mark', (x,y,T/2+4.1), (1.2,0.55,0.35), black2, 0.08)
tick.rotation_euler[2]=a
# Tiny rubber isolation pads and screw heads around shroud edges
for x in [-165,-112,-56,0,56,112,165]:
for y in [-62,62]:
cyl('Shroud isolation pad', (x,y,T/2+1.9), 1.6, 0.8, rubber, 'Z', 24, 0.15)
screw('Shroud fastener', x,y,T/2+2.5, radius=1.0, material=metal)
# Side branding line and small warning label
cube('Side accent line', (0,W/2+1.3,18), (L-32,0.9,0.9), silver, 0.25)
cube('Side warning label', (-115,W/2+1.55,-24), (36,0.6,7), black2, 0.3)
text_obj('CAUTION / HIGH POWER', 'Side warning text', (-131,W/2+2.0,-26), 2.1, white,
rotation=(math.pi/2,0,0), extrude=0.02)
# ---------- Presentation setup ----------
# Ground plane and camera are included for an immediately viewable render.
groundmat = mat('Studio floor', (0.025,0.028,0.034), 0.05, 0.5)
cube('Studio floor', (0,0,-105), (900,650,3), groundmat, 0)
def point_at(obj, target):
obj.rotation_euler = (Vector(target)-obj.location).to_track_quat('-Z','Y').to_euler()
bpy.ops.object.camera_add(location=(475,-470,390))
camera=bpy.context.object
camera.name='Product hero camera'
point_at(camera,(0,0,0))
camera.data.type='ORTHO'
camera.data.ortho_scale=570
scene.camera=camera
def area_light(name, loc, energy, size, target=(0,0,0)):
bpy.ops.object.light_add(type='AREA', location=loc)
l=bpy.context.object; l.name=name; l.data.energy=energy; l.data.shape='DISK'; l.data.size=size
point_at(l,target)
area_light('Key softbox',(100,-260,360),2400,260)
area_light('Fill softbox',(-260,-80,180),1600,220)
area_light('Rim softbox',(40,260,260),2600,240)
scene.render.engine='CYCLES'
scene.cycles.samples=64
scene.render.resolution_x=1800
scene.render.resolution_y=1250
scene.render.resolution_percentage=100
scene.render.image_settings.file_format='PNG'
scene.render.film_transparent=False
scene.world.color=(0.025,0.025,0.025)
# Set useful viewport angle and select the whole card chassis.
bpy.ops.object.select_all(action='DESELECT')
body=bpy.data.objects.get('Main cooler chassis')
if body:
body.select_set(True)
bpy.context.view_layer.objects.active=body
for area in bpy.context.screen.areas:
if area.type=='VIEW_3D':
area.spaces.active.region_3d.view_distance=520
area.spaces.active.region_3d.view_location=(0,0,0)
print('ROG Astral RTX 5090 model created. Dimensions approx. 357.6 x 149.3 x 76 mm.')