новая структура проекта
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
import traceback
|
||||
|
||||
from bgl import *
|
||||
|
||||
|
||||
def glCheckError(title):
|
||||
err = glGetError()
|
||||
if err == GL_NO_ERROR:
|
||||
return
|
||||
|
||||
derrs = {
|
||||
GL_INVALID_ENUM: 'invalid enum',
|
||||
GL_INVALID_VALUE: 'invalid value',
|
||||
GL_INVALID_OPERATION: 'invalid operation',
|
||||
GL_OUT_OF_MEMORY: 'out of memory',
|
||||
GL_INVALID_FRAMEBUFFER_OPERATION: 'invalid framebuffer operation',
|
||||
}
|
||||
if err in derrs:
|
||||
print('ERROR (%s): %s' % (title, derrs[err]))
|
||||
else:
|
||||
print('ERROR (%s): code %d' % (title, err))
|
||||
traceback.print_stack()
|
||||
|
||||
|
||||
def check_framebuffer_status(target):
|
||||
status = glCheckFramebufferStatus(target)
|
||||
|
||||
if status == GL_FRAMEBUFFER_COMPLETE:
|
||||
return True
|
||||
elif status == GL_FRAMEBUFFER_UNDEFINED:
|
||||
print("framebuffer not complete: GL_FRAMEBUFFER_UNDEFINED - returned if the specified framebuffer is the default read or draw framebuffer, but the default framebuffer does not exist.")
|
||||
elif status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT - returned if any of the framebuffer attachment points are framebuffer incomplete.")
|
||||
elif status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT - returned if the framebuffer does not have at least one image attached to it.")
|
||||
elif status == GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER - returned if the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for any color attachment point named by GL_DRAW_BUFFERi.")
|
||||
elif status == GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER - returned if GL_READ_BUFFER is not GL_NONE and the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for the color attachment point named by GL_READ_BUFFER.")
|
||||
elif status == GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
print("framebuffer not complete: GL_FRAMEBUFFER_UNSUPPORTED - returned if the combination of internal formats of the attached images violates an implementation-dependent set of restrictions.")
|
||||
elif status == GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
||||
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE - returned if the value of GL_RENDERBUFFER_SAMPLES is not the same for all attached renderbuffers; if the value of GL_TEXTURE_SAMPLES is the not same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, the value of GL_RENDERBUFFER_SAMPLES does not match the value of GL_TEXTURE_SAMPLES. also returned if the value of GL_TEXTURE_FIXED_SAMPLE_LOCATIONS i s not the same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, the value of GL_TEXTURE_FIXED_SAMPLE_LOCATIONS is not GL_TRUE for all attached textures.")
|
||||
elif status == GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
|
||||
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS - returned if any framebuffer attachment is layered, and any populated attachment is not layered, or if all populated color attachments are not from textures of the same target.")
|
||||
else:
|
||||
print("framebuffer not complete: status 0x%x (unknown)" % (status,))
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def create_image(width, height, target=GL_RGBA):
|
||||
"""create an empty image, dimensions pow2"""
|
||||
if target == GL_RGBA:
|
||||
target, internal_format, dimension = GL_RGBA, GL_RGB, 3
|
||||
else:
|
||||
target, internal_format, dimension = GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, 1
|
||||
|
||||
null_buffer = Buffer(GL_BYTE, [(width + 1) * (height + 1) * dimension])
|
||||
|
||||
id_buf = Buffer(GL_INT, 1)
|
||||
glGenTextures(1, id_buf)
|
||||
|
||||
tex_id = id_buf.to_list()[0]
|
||||
glBindTexture(GL_TEXTURE_2D, tex_id)
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, target, width, height, 0, internal_format, GL_UNSIGNED_BYTE, null_buffer)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
|
||||
|
||||
if target == GL_DEPTH_COMPONENT32:
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE)
|
||||
|
||||
glCopyTexImage2D(GL_TEXTURE_2D, 0, target, 0, 0, width, height, 0)
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0)
|
||||
|
||||
del null_buffer
|
||||
|
||||
return tex_id
|
||||
|
||||
|
||||
def delete_image(tex_id):
|
||||
"""clear created image"""
|
||||
id_buf = Buffer(GL_INT, 1)
|
||||
id_buf.to_list()[0] = tex_id
|
||||
|
||||
if glIsTexture(tex_id):
|
||||
glDeleteTextures(1, id_buf)
|
||||
|
||||
|
||||
def create_framebuffer(width, height, target=GL_RGBA):
|
||||
"""create an empty framebuffer"""
|
||||
id_buf = Buffer(GL_INT, 1)
|
||||
|
||||
glGenFramebuffers(1, id_buf)
|
||||
fbo_id = id_buf.to_list()[0]
|
||||
|
||||
if fbo_id == 0:
|
||||
print("Framebuffer error on creation")
|
||||
return -1
|
||||
|
||||
tex_id = create_image(width, height)
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id)
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_id, 0)
|
||||
|
||||
glGenRenderbuffers(1, id_buf)
|
||||
depth_id = id_buf.to_list()[0]
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depth_id)
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, width, height)
|
||||
|
||||
# attach the depth buffer
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_id)
|
||||
|
||||
#glDrawBuffers(fbo_id, GL_COLOR_ATTACHMENT0)
|
||||
|
||||
if not check_framebuffer_status(GL_DRAW_FRAMEBUFFER):
|
||||
delete_framebuffer(fbo_id)
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0)
|
||||
return -1
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0)
|
||||
return fbo_id
|
||||
|
||||
def delete_framebuffer(fbo_id):
|
||||
"""clear created framebuffer"""
|
||||
id_buf = Buffer(GL_INT, 1)
|
||||
id_buf.to_list()[0] = fbo_id
|
||||
|
||||
if glIsFramebuffer(fbo_id):
|
||||
glDeleteFramebuffers(1, id_buf)
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
import bpy
|
||||
import gpu
|
||||
|
||||
import mathutils
|
||||
|
||||
from typing import Union
|
||||
from bgl import *
|
||||
|
||||
from .drawing_elements import ElementTypes
|
||||
from .utils import render_debug
|
||||
from .bgl_ext import glCheckError
|
||||
|
||||
|
||||
class DrawingBatch:
|
||||
"""Abstract base class defining an interface of a drawing batch (drawing element)."""
|
||||
|
||||
c_batch: Union['CM2DrawingBatch', 'CWMODrawingBatch']
|
||||
|
||||
# control
|
||||
mesh_type: int = ElementTypes.M2Mesh
|
||||
shader: gpu.types.GPUShader
|
||||
bl_batch_vert_shader_id: int
|
||||
bl_batch_frag_shader_id: int
|
||||
|
||||
# uniform data
|
||||
draw_material: Union['M2DrawingMaterial', 'WMODrawingMaterial', None]
|
||||
|
||||
# texture slots
|
||||
|
||||
gl_texture_slots = (
|
||||
GL_TEXTURE0,
|
||||
GL_TEXTURE1,
|
||||
GL_TEXTURE2,
|
||||
GL_TEXTURE3
|
||||
)
|
||||
|
||||
def __init__(self
|
||||
, c_batch: Union['CM2DrawingBatch', 'CWMODrawingBatch']
|
||||
, draw_obj: Union['M2DrawingObject', 'WMODrawingObject']
|
||||
, context: bpy.types.Context):
|
||||
|
||||
self.c_batch = c_batch
|
||||
self.context = context
|
||||
self.draw_obj = draw_obj
|
||||
|
||||
self.tag_free = False
|
||||
|
||||
self.mat_id = self.c_batch.get_mat_id()
|
||||
|
||||
try:
|
||||
self.draw_material = self.draw_obj.draw_mgr.draw_materials.get(
|
||||
self.draw_obj.bl_obj.data.materials[self.mat_id].name)
|
||||
|
||||
except IndexError:
|
||||
self.draw_material = None
|
||||
|
||||
self.create_vao()
|
||||
|
||||
self.draw_obj.draw_mgr.draw_elements.add_batch(self)
|
||||
|
||||
render_debug('Instantiated drawing batch for object \"{}\"'.format(draw_obj.bl_obj.name))
|
||||
|
||||
@property
|
||||
def is_transparent(self) -> bool:
|
||||
return False
|
||||
|
||||
@property
|
||||
def priority_plane(self) -> int:
|
||||
return 0
|
||||
|
||||
@property
|
||||
def layer(self) -> int:
|
||||
return 0
|
||||
|
||||
@property
|
||||
def is_skybox(self) -> bool:
|
||||
return False
|
||||
|
||||
@property
|
||||
def bb_center(self) -> mathutils.Vector:
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def sort_radius(self) -> float:
|
||||
return self.c_batch.sort_radius
|
||||
|
||||
@property
|
||||
def sort_distance(self):
|
||||
|
||||
perspective_mat = self.draw_obj.draw_mgr.region_3d.perspective_matrix
|
||||
bb_center = self.draw_obj.bl_obj.matrix_world @ self.bb_center
|
||||
|
||||
value = (perspective_mat.to_translation() - bb_center).length
|
||||
|
||||
if self.draw_material.is_inverted or self.draw_material.is_transformed:
|
||||
result_point = bb_center * (1.0 / value) if value > 0.00000023841858 else bb_center
|
||||
|
||||
sort_dist = perspective_mat.to_translation().length * self.sort_radius
|
||||
|
||||
result_point *= sort_dist
|
||||
|
||||
value = (bb_center - result_point).length \
|
||||
if self.draw_material.is_inverted else (bb_center + result_point).length
|
||||
|
||||
return value
|
||||
|
||||
def create_vao(self):
|
||||
self.shader = self.determine_valid_shader()
|
||||
self.c_batch.set_program(self.shader.program)
|
||||
self.c_batch.create_vao()
|
||||
glCheckError('Create VAO')
|
||||
|
||||
def ensure_context(self):
|
||||
mat_test = self.draw_material.bl_material
|
||||
|
||||
if not mat_test:
|
||||
self.tag_free = True
|
||||
|
||||
return self.tag_free
|
||||
|
||||
def _set_active_textures(self):
|
||||
|
||||
for i, gl_slot in enumerate(self.gl_texture_slots):
|
||||
bind_code = self.draw_material.get_bindcode(i)
|
||||
|
||||
if bind_code:
|
||||
glActiveTexture(gl_slot)
|
||||
glBindTexture(GL_TEXTURE_2D, bind_code)
|
||||
|
||||
def determine_valid_shader(self) -> gpu.types.GPUShader:
|
||||
raise NotImplementedError()
|
||||
|
||||
def draw(self):
|
||||
|
||||
render_debug('Drawing batch for object \"{}\"'.format(self.draw_obj.bl_obj.name))
|
||||
|
||||
bl_obj = self.draw_obj.bl_obj
|
||||
|
||||
if not bl_obj.visible_get():
|
||||
return
|
||||
|
||||
if self.tag_free:
|
||||
return
|
||||
|
||||
if self.draw_material:
|
||||
self.draw_batch()
|
||||
else:
|
||||
self.draw_fallback()
|
||||
|
||||
def draw_fallback(self):
|
||||
|
||||
glCheckError('drawfallback pre')
|
||||
|
||||
self.shader = self.determine_valid_shader()
|
||||
self.shader.bind()
|
||||
self.c_batch.set_program(self.shader.program)
|
||||
|
||||
self.shader.uniform_float('uViewProjectionMatrix', self.draw_obj.draw_mgr.region_3d.perspective_matrix)
|
||||
|
||||
self.shader.uniform_float('uPlacementMatrix', self.draw_obj.bl_obj.matrix_world)
|
||||
self.shader.uniform_float('uSunDirAndFogStart', self.draw_obj.draw_mgr.sun_dir_and_fog_start)
|
||||
self.shader.uniform_float('uSunColorAndFogEnd', self.draw_obj.draw_mgr.sun_color_and_fog_end)
|
||||
self.shader.uniform_float('uAmbientLight', self.draw_obj.draw_mgr.ambient_light)
|
||||
self.shader.uniform_float('uFogColorAndAlphaTest', (*self.draw_obj.draw_mgr.fog_color, 1.0 / 255.0))
|
||||
self.shader.uniform_int('UnFogged_IsAffectedByLight_LightCount', (False, True, 0))
|
||||
|
||||
glEnable(GL_DEPTH_TEST)
|
||||
|
||||
self.c_batch.draw()
|
||||
|
||||
glDisable(GL_DEPTH_TEST)
|
||||
|
||||
gpu.shader.unbind()
|
||||
|
||||
glCheckError('draw fallback post')
|
||||
|
||||
def draw_batch(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def free(self):
|
||||
|
||||
if self.tag_free:
|
||||
return
|
||||
|
||||
self.tag_free = True
|
||||
self.draw_obj.draw_mgr.draw_elements.remove_batch(self)
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
import traceback
|
||||
|
||||
from enum import IntEnum
|
||||
from copy import copy
|
||||
from typing import List
|
||||
from functools import cmp_to_key, partial
|
||||
|
||||
|
||||
class ElementTypes(IntEnum):
|
||||
GeneralMesh = 0
|
||||
AdtMesh = 1
|
||||
WmoMesh = 2
|
||||
OccludingQuery = 3
|
||||
M2Mesh = 4
|
||||
ParticleMesh = 5
|
||||
|
||||
|
||||
class DrawingElements:
|
||||
|
||||
def __init__(self):
|
||||
self.batches: List['M2DrawingBatch'] = []
|
||||
|
||||
def add_batch(self, batch):
|
||||
self.batches.append(batch)
|
||||
|
||||
def remove_batch(self, batch):
|
||||
self.batches.remove(batch)
|
||||
|
||||
def draw(self):
|
||||
batches = copy(self.batches)
|
||||
|
||||
try:
|
||||
sorted_indices = sorted(list(range(len(self.batches))), key=cmp_to_key(partial(self.sort_elements, self)))
|
||||
except IndexError:
|
||||
print('Skipping frame! Iterator invalidated!')
|
||||
self.draw()
|
||||
#traceback.print_exc()
|
||||
return
|
||||
|
||||
#print("Began drawing")
|
||||
for batch_index in sorted_indices:
|
||||
batch = batches[batch_index]
|
||||
|
||||
if batch.tag_free:
|
||||
continue
|
||||
|
||||
try:
|
||||
batch.draw()
|
||||
#print(batch.draw_obj.bl_obj_name, batch.sort_distance)
|
||||
except:
|
||||
batch.free()
|
||||
print('Debug: Freeing batch from DrawingElements!')
|
||||
traceback.print_exc()
|
||||
self.draw()
|
||||
|
||||
@staticmethod
|
||||
def sort_elements(self, a, b):
|
||||
|
||||
batch_a = self.batches[a]
|
||||
batch_b = self.batches[b]
|
||||
|
||||
#print("Comparing:", batch_a.draw_obj.bl_obj_name, batch_b.draw_obj.bl_obj_name)
|
||||
|
||||
if not batch_a.draw_material:
|
||||
return -1
|
||||
|
||||
if not batch_b.draw_material:
|
||||
return 1
|
||||
|
||||
if batch_a.is_transparent > batch_b.is_transparent:
|
||||
return 1
|
||||
|
||||
if batch_a.is_transparent < batch_b.is_transparent:
|
||||
return -1
|
||||
|
||||
if batch_a.mesh_type > batch_b.mesh_type:
|
||||
return 1
|
||||
|
||||
if batch_a.mesh_type < batch_b.mesh_type:
|
||||
return -1
|
||||
|
||||
if batch_a.is_skybox > batch_b.is_skybox:
|
||||
return -1
|
||||
|
||||
if batch_a.is_skybox < batch_b.is_skybox:
|
||||
return 1
|
||||
|
||||
if batch_a.mesh_type == ElementTypes.M2Mesh and batch_a.is_transparent and batch_b.is_transparent:
|
||||
if batch_a.priority_plane != batch_b.priority_plane:
|
||||
return -1 if batch_b.priority_plane > batch_a.priority_plane else 1
|
||||
|
||||
if batch_a.sort_distance > batch_b.sort_distance:
|
||||
return -1
|
||||
|
||||
if batch_a.sort_distance < batch_b.sort_distance:
|
||||
return 1
|
||||
|
||||
if batch_b.layer != batch_a.layer:
|
||||
return -1 if batch_b.layer < batch_a.layer else 1
|
||||
|
||||
if batch_a.mesh_type == ElementTypes.ParticleMesh and batch_b.mesh_type == ElementTypes.ParticleMesh:
|
||||
if batch_a.priority_plane != batch_b.priority_plane:
|
||||
return -1 if batch_b.priority_plane > batch_a.priority_plane else 1
|
||||
|
||||
if batch_a.sort_distance > batch_b.sort_distance:
|
||||
return -1
|
||||
if batch_a.sort_distance < batch_b.sort_distance:
|
||||
return 1
|
||||
|
||||
if batch_a.draw_material.blend_mode.index != batch_b.draw_material.blend_mode.index:
|
||||
return -1 if batch_a.draw_material.blend_mode.index < batch_b.draw_material.blend_mode.index else 1
|
||||
|
||||
'''
|
||||
min_tex_count = min(batch_a.texture_count, batch_b.texture_count)
|
||||
for i in range(min_tex_count):
|
||||
if batch_a.m_texture[i] != batch_b.m_texture[i]:
|
||||
return batch_a.m_texture[i] < batch_b.m_texture[i]
|
||||
|
||||
if batch_a.texture_count != batch_b.texture_count:
|
||||
return batch_a.texture_count < batch_b.texture_count
|
||||
|
||||
'''
|
||||
|
||||
"""
|
||||
if batch_a.m_start != batch_b.m_start:
|
||||
return batch_a.m_start < batch_b.m_start
|
||||
|
||||
if batch_a.m_end != batch_b.m_end:
|
||||
return batch_a.m_end < batch_b.m_end
|
||||
|
||||
"""
|
||||
|
||||
return 1 if a > b else -1
|
||||
|
||||
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
import bpy
|
||||
import gpu
|
||||
import traceback
|
||||
|
||||
from typing import List, Tuple, Dict, Union
|
||||
from mathutils import Vector
|
||||
|
||||
from .m2.shaders import M2ShaderPermutations
|
||||
from .m2.drawing_object import M2DrawingObject
|
||||
from .m2.drawing_material import M2DrawingMaterial
|
||||
from .drawing_elements import DrawingElements
|
||||
from .utils import render_debug
|
||||
from .bgl_ext import glCheckError
|
||||
|
||||
from profilehooks import profile
|
||||
|
||||
from bgl import *
|
||||
|
||||
|
||||
class DrawingManager:
|
||||
|
||||
sun_dir_and_fog_start: Tuple[float, float, float, float]
|
||||
sun_color_and_fog_end: Tuple[float, float, float, float]
|
||||
ambient_light: Tuple[float, float, float]
|
||||
fog_color: Tuple[float, float, float]
|
||||
|
||||
def __init__(self, context):
|
||||
glCheckError("draw mgr init pre")
|
||||
self.context: bpy.types.Context = context
|
||||
self.shaders = M2ShaderPermutations()
|
||||
self.m2_objects: Dict[str, M2DrawingObject] = {}
|
||||
self.draw_materials: Dict[str, M2DrawingMaterial] = {}
|
||||
self.draw_elements = DrawingElements()
|
||||
self.update_handlers = {'MESH': self._m2_handle_mesh_update}
|
||||
self.is_dirty = True
|
||||
|
||||
self.editable_context = context.scene.wow_scene.type
|
||||
|
||||
# get active viewport
|
||||
self.region_3d: bpy.types.SpaceView3D = bpy.context.space_data.region_3d
|
||||
self.region: bpy.types.Region = self._get_active_region()
|
||||
|
||||
'''
|
||||
# depth pass
|
||||
self.depth_tex_id_buf = Buffer(GL_INT, 1)
|
||||
glGenTextures(1, self.depth_tex_id_buf)
|
||||
self.depth_tex_bindcode = self.depth_tex_id_buf.to_list()[0]
|
||||
self.depth_buf = Buffer(GL_FLOAT, self.region.width * self.region.height)
|
||||
|
||||
'''
|
||||
|
||||
# uniform data
|
||||
self._update_global_uniforms()
|
||||
|
||||
glCheckError("draw mgr init post")
|
||||
render_debug('Instantiated drawing manager.')
|
||||
|
||||
def _update_global_uniforms(self):
|
||||
sun_dir = Vector(self.context.scene.wow_render_settings.sun_direction)
|
||||
sun_dir.negate()
|
||||
self.sun_dir_and_fog_start = (*sun_dir[:3], self.context.scene.wow_render_settings.fog_start)
|
||||
self.sun_color_and_fog_end = (*self.context.scene.wow_render_settings.ext_dir_color[:3],
|
||||
self.context.scene.wow_render_settings.fog_end)
|
||||
self.ambient_light = self.context.scene.wow_render_settings.ext_ambient_color
|
||||
self.fog_color = self.context.scene.wow_render_settings.fog_color
|
||||
|
||||
@profile
|
||||
def update_render_data(self, depsgraph: bpy.types.Depsgraph):
|
||||
|
||||
glCheckError("update render data pre")
|
||||
|
||||
try:
|
||||
|
||||
for update in depsgraph.updates:
|
||||
|
||||
if isinstance(update.id, bpy.types.Scene):
|
||||
self._update_global_uniforms()
|
||||
|
||||
elif isinstance(update.id, bpy.types.Object) and update.is_updated_geometry:
|
||||
|
||||
update_handler = self.update_handlers.get(update.id.type)
|
||||
|
||||
if update_handler:
|
||||
update_handler(depsgraph, update)
|
||||
|
||||
elif isinstance(update.id, bpy.types.Material):
|
||||
|
||||
render_debug('Detected update for material \"{}\"'.format(update.id.name))
|
||||
draw_mat = self.draw_materials.get(update.id.name)
|
||||
|
||||
if draw_mat:
|
||||
draw_mat.update_uniform_data()
|
||||
else:
|
||||
self.draw_materials[update.id.name] = M2DrawingMaterial(update.id.original)
|
||||
# TODO: timer cleanup
|
||||
|
||||
except:
|
||||
render_debug('Exception occured on depsgraph update of render data. Traceback is below.')
|
||||
traceback.print_exc() # DEBUG
|
||||
|
||||
def init_datablocks(self, depsgraph: bpy.types.Depsgraph):
|
||||
|
||||
# init materials
|
||||
for material in bpy.data.materials:
|
||||
self.draw_materials[material.name] = M2DrawingMaterial(material)
|
||||
|
||||
for datablock in depsgraph.ids:
|
||||
if isinstance(datablock, bpy.types.Scene):
|
||||
self._update_global_uniforms()
|
||||
elif isinstance(datablock, bpy.types.Object) and datablock.type == 'MESH':
|
||||
self.m2_objects[datablock.name] = M2DrawingObject(datablock.original.evaluated_get(depsgraph), self, self.context)
|
||||
|
||||
def _m2_handle_mesh_update(self, depsgraph: bpy.types.Depsgraph, update: bpy.types.DepsgraphUpdate):
|
||||
render_debug('Detected update for mesh \"{}\"'.format(update.id.name))
|
||||
|
||||
glCheckError("mesh update pre")
|
||||
|
||||
draw_obj = self.m2_objects.get(update.id.name)
|
||||
|
||||
if draw_obj:
|
||||
draw_obj.update_geometry(update.id.original.evaluated_get(depsgraph))
|
||||
|
||||
else:
|
||||
self.m2_objects[update.id.name] = M2DrawingObject(update.id.original.evaluated_get(depsgraph), self, self.context)
|
||||
|
||||
glCheckError("mesh update post")
|
||||
|
||||
@profile
|
||||
def draw(self):
|
||||
|
||||
self.region_3d = bpy.context.space_data.region_3d
|
||||
self.region = self._get_active_region()
|
||||
|
||||
for draw_obj in self.m2_objects.values():
|
||||
if draw_obj.is_dirty:
|
||||
draw_obj.update_geometry_opengl()
|
||||
|
||||
self.draw_elements.draw()
|
||||
|
||||
#self._render_depth_opengl()
|
||||
#self.render_depth_texture()
|
||||
|
||||
#self._destroy_depthbuffer_texture()
|
||||
|
||||
def _linearize(self, depth):
|
||||
znear = self.region_3d.clip_start
|
||||
zfar = self.region_3d.clip_end
|
||||
|
||||
return (*([(-zfar * znear / (depth * (zfar - znear) - zfar)) / zfar] * 3), 1.0)
|
||||
|
||||
def render_depth_texture(self):
|
||||
""" Render scene depth_tex_bindcode into texture """
|
||||
|
||||
width, height = self.region.width, self.region.height
|
||||
|
||||
image_name = "DepthBuffer"
|
||||
if image_name not in bpy.data.images:
|
||||
image = bpy.data.images.new(image_name, width, height)
|
||||
else:
|
||||
return
|
||||
|
||||
image.scale(width, height)
|
||||
|
||||
image.pixels = [y for x in [self._linearize(v) for v in self.depth_buf] for y in x]
|
||||
|
||||
@staticmethod
|
||||
def _get_active_region() -> bpy.types.Region:
|
||||
|
||||
for region in bpy.context.area.regions:
|
||||
if region.type == 'WINDOW':
|
||||
return region
|
||||
|
||||
def _render_depth_opengl(self):
|
||||
|
||||
width, height = self.region.width, self.region.height
|
||||
|
||||
glActiveTexture(GL_TEXTURE0)
|
||||
glBindTexture(GL_TEXTURE_2D, self.depth_tex_bindcode)
|
||||
|
||||
glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, self.depth_buf)
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height,
|
||||
0, GL_DEPTH_COMPONENT, GL_FLOAT, self.depth_buf)
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
GL_NEAREST)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_NEAREST)
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, self.depth_tex_bindcode)
|
||||
|
||||
return self.depth_tex_bindcode
|
||||
|
||||
def _destroy_depthbuffer_texture(self):
|
||||
glDeleteTextures(1, self.depth_tex_id_buf)
|
||||
|
||||
@staticmethod
|
||||
def _draw_callback(self):
|
||||
self.draw()
|
||||
|
||||
def free(self):
|
||||
for draw_obj in list(self.m2_objects.values()):
|
||||
draw_obj.free()
|
||||
|
||||
render_debug('Freed drawing manager.')
|
||||
@@ -0,0 +1,189 @@
|
||||
import bpy
|
||||
import bgl
|
||||
|
||||
from .drawing_manager import DrawingManager
|
||||
from .utils import render_debug
|
||||
from .bgl_ext import create_framebuffer, glCheckError
|
||||
from ..wbs_kernel.render import OpenGLUtils
|
||||
|
||||
|
||||
class WoWRenderEngine(bpy.types.RenderEngine):
|
||||
# These three members are used by blender to set up the
|
||||
# RenderEngine; define its internal name, visible name and capabilities.
|
||||
bl_idname = "WOW"
|
||||
bl_label = "WoW"
|
||||
bl_use_preview = False
|
||||
bl_use_eevee_viewport = True
|
||||
|
||||
# Init is called whenever a new render engine instance is created. Multiple
|
||||
# instances may exist at the same time, for example for a viewport and final
|
||||
# render.
|
||||
def __init__(self):
|
||||
|
||||
self.glew_init = False
|
||||
self.first_time = True
|
||||
self.draw_manager = DrawingManager(bpy.context)
|
||||
|
||||
render_debug('Instantiated render engine.')
|
||||
|
||||
# When the render engine instance is destroy, this is called. Clean up any
|
||||
# render engine data here, for example stopping running render threads.
|
||||
def __del__(self):
|
||||
render_debug('Freed render engine.')
|
||||
|
||||
# This is the method called by Blender for both final renders (F12) and
|
||||
# small preview for materials, world and lights.
|
||||
def render(self, depsgraph):
|
||||
scene = depsgraph.scene
|
||||
scale = scene.render.resolution_percentage / 100.0
|
||||
self.size_x = int(scene.render.resolution_x * scale)
|
||||
self.size_y = int(scene.render.resolution_y * scale)
|
||||
|
||||
# Fill the render result with a flat color. The framebuffer is
|
||||
# defined as a list of pixels, each pixel itself being a list of
|
||||
# R,G,B,A values.
|
||||
if self.is_preview:
|
||||
color = [0.1, 0.2, 0.1, 1.0]
|
||||
else:
|
||||
color = [0.2, 0.1, 0.1, 1.0]
|
||||
|
||||
pixel_count = self.size_x * self.size_y
|
||||
rect = [color] * pixel_count
|
||||
|
||||
# Here we write the pixel values to the RenderResult
|
||||
result = self.begin_result(0, 0, self.size_x, self.size_y)
|
||||
layer = result.layers[0].passes["Combined"]
|
||||
layer.rect = rect
|
||||
self.end_result(result)
|
||||
|
||||
# For viewport renders, this method gets called once at the start and
|
||||
# whenever the scene or 3D viewport changes. This method is where data
|
||||
# should be read from Blender in the same thread. Typically a render
|
||||
# thread will be started to do the work while keeping Blender responsive.
|
||||
def view_update(self, context, depsgraph):
|
||||
# depsgraph = context.evaluated_depsgraph_get()
|
||||
|
||||
if not self.glew_init:
|
||||
OpenGLUtils.init_glew()
|
||||
self.glew_init = True
|
||||
|
||||
region = context.region
|
||||
view3d = context.space_data
|
||||
scene = depsgraph.scene
|
||||
|
||||
# Get viewport dimensions
|
||||
dimensions = region.width, region.height
|
||||
|
||||
if self.first_time:
|
||||
self.first_time = False
|
||||
self.draw_manager.init_datablocks(depsgraph)
|
||||
else:
|
||||
self.draw_manager.update_render_data(depsgraph)
|
||||
|
||||
'''
|
||||
# Loop over all object instances in the scene.
|
||||
if first_time or depsgraph.id_type_updated('OBJECT'):
|
||||
for instance in depsgraph.object_instances:
|
||||
pass
|
||||
|
||||
'''
|
||||
|
||||
render_debug('Num unfreed materials: {}\n'
|
||||
'Num unfreed drawing objects: {}\n'
|
||||
'Num unfreed batches: {}\n'.format(
|
||||
len(self.draw_manager.draw_materials),
|
||||
len(self.draw_manager.m2_objects),
|
||||
len(self.draw_manager.draw_elements.batches))
|
||||
)
|
||||
|
||||
# For viewport renders, this method is called whenever Blender redraws
|
||||
# the 3D viewport. The renderer is expected to quickly draw the render
|
||||
# with OpenGL, and not perform other expensive work.
|
||||
# Blender will draw overlays for selection and editing on top of the
|
||||
# rendered image automatically.
|
||||
|
||||
def view_draw(self, context, depsgraph):
|
||||
|
||||
# buf = bgl.Buffer(bgl.GL_INT, 1)
|
||||
# bgl.glGetIntegerv(bgl.GL_FRAMEBUFFER_BINDING, buf)
|
||||
# cur_fbo = buf.to_list()[0]
|
||||
# del buf
|
||||
#
|
||||
# region = context.region
|
||||
# view3d = context.space_data
|
||||
# scene = depsgraph.scene
|
||||
#
|
||||
# # Get viewport dimensions
|
||||
# width, height = region.width, region.height
|
||||
#
|
||||
# bgl.glBindFramebuffer(bgl.GL_FRAMEBUFFER, self.fbo_id)
|
||||
|
||||
#bgl.glEnable(bgl.GL_BLEND)
|
||||
#bgl.glBlendFunc(bgl.GL_ONE, bgl.GL_ONE_MINUS_SRC_ALPHA)
|
||||
#self.bind_display_space_shader(context.scene)
|
||||
|
||||
self.draw_manager.draw()
|
||||
|
||||
bgl.glColorMask(False, False, False, True)
|
||||
bgl.glClearColor(0, 0, 0, 1.0)
|
||||
bgl.glClear(bgl.GL_COLOR_BUFFER_BIT)
|
||||
|
||||
#self.unbind_display_space_shader()
|
||||
#bgl.glDisable(bgl.GL_BLEND)
|
||||
|
||||
# glCheckError('post-draw-all')
|
||||
#
|
||||
# bgl.glBindFramebuffer(bgl.GL_DRAW_FRAMEBUFFER, cur_fbo)
|
||||
# bgl.glDrawBuffer(bgl.GL_BACK)
|
||||
#
|
||||
# bgl.glBindFramebuffer(bgl.GL_READ_FRAMEBUFFER, self.fbo_id)
|
||||
# bgl.glReadBuffer(bgl.GL_COLOR_ATTACHMENT0)
|
||||
#
|
||||
# glCheckError('bind fbos')
|
||||
#
|
||||
# bgl.glBlitFramebuffer(
|
||||
# 0, 0, width, height,
|
||||
# 0, 0, width, height,
|
||||
# bgl.GL_COLOR_BUFFER_BIT | bgl.GL_DEPTH_BUFFER_BIT,
|
||||
# bgl.GL_NEAREST)
|
||||
#
|
||||
# glCheckError('blit')
|
||||
#
|
||||
# bgl.glBindFramebuffer(bgl.GL_FRAMEBUFFER, cur_fbo)
|
||||
|
||||
|
||||
# RenderEngines also need to tell UI Panels that they are compatible with.
|
||||
# We recommend to enable all panels marked as BLENDER_RENDER, and then
|
||||
# exclude any panels that are replaced by custom panels registered by the
|
||||
# render engine, or that are not supported.
|
||||
def get_panels():
|
||||
exclude_panels = {
|
||||
}
|
||||
|
||||
panels = []
|
||||
for panel in bpy.types.Panel.__subclasses__():
|
||||
if hasattr(panel, 'COMPAT_ENGINES'): # and 'BLENDER_RENDER' in panel.COMPAT_ENGINES:
|
||||
if panel.__name__ not in exclude_panels:
|
||||
panels.append(panel)
|
||||
|
||||
return panels
|
||||
|
||||
|
||||
""" def register():
|
||||
# Register the RenderEngine
|
||||
bpy.utils.register_class(WoWRenderEngine)
|
||||
|
||||
for panel in get_panels():
|
||||
panel.COMPAT_ENGINES.add('WOW')
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_class(WoWRenderEngine)
|
||||
|
||||
for panel in get_panels():
|
||||
if 'WOW' in panel.COMPAT_ENGINES:
|
||||
panel.COMPAT_ENGINES.remove('WOW')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register() """
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
import bpy
|
||||
import gpu
|
||||
|
||||
import mathutils
|
||||
|
||||
from typing import Union
|
||||
from bgl import *
|
||||
|
||||
from ..drawing_batch import DrawingBatch
|
||||
from ...wbs_kernel.render import CM2DrawingBatch
|
||||
from ...wbs_kernel.render import OpenGLUtils
|
||||
from .shaders import M2ShaderPermutations, EGxBLend
|
||||
from .drawing_material import M2DrawingMaterial
|
||||
from ..drawing_elements import ElementTypes
|
||||
from ..utils import render_debug
|
||||
from ..bgl_ext import glCheckError
|
||||
|
||||
|
||||
class M2DrawingBatch(DrawingBatch):
|
||||
c_batch: CM2DrawingBatch
|
||||
|
||||
# control
|
||||
mesh_type: int = ElementTypes.M2Mesh
|
||||
shader: gpu.types.GPUShader
|
||||
bl_batch_vert_shader_id: int
|
||||
bl_batch_frag_shader_id: int
|
||||
|
||||
gl_texture_slots = (
|
||||
GL_TEXTURE0,
|
||||
GL_TEXTURE1,
|
||||
GL_TEXTURE2,
|
||||
GL_TEXTURE3
|
||||
)
|
||||
|
||||
# uniform data
|
||||
draw_material: Union[M2DrawingMaterial, None]
|
||||
|
||||
def __init__(self
|
||||
, c_batch: 'CM2DrawingBatch'
|
||||
, draw_obj: 'M2DrawingObject'
|
||||
, context: bpy.types.Context):
|
||||
|
||||
self.c_batch = c_batch
|
||||
self.context = context
|
||||
self.draw_obj = draw_obj
|
||||
|
||||
self.tag_free = False
|
||||
|
||||
self.mat_id = self.c_batch.get_mat_id()
|
||||
|
||||
try:
|
||||
self.draw_material = self.draw_obj.draw_mgr.draw_materials.get(
|
||||
self.draw_obj.bl_obj.data.materials[self.mat_id].name)
|
||||
|
||||
except IndexError:
|
||||
self.draw_material = None
|
||||
|
||||
self.create_vao()
|
||||
|
||||
self.draw_obj.draw_mgr.draw_elements.add_batch(self)
|
||||
|
||||
render_debug('Instantiated drawing batch for object \"{}\"'.format(draw_obj.bl_obj.name))
|
||||
|
||||
@property
|
||||
def is_transparent(self) -> bool:
|
||||
return (self.draw_material.blend_mode.index > EGxBLend.AlphaKey.index) \
|
||||
or not self.draw_material.depth_write
|
||||
|
||||
@property
|
||||
def priority_plane(self) -> int:
|
||||
return self.draw_material.bl_material.wow_m2_material.priority_plane
|
||||
|
||||
@property
|
||||
def layer(self) -> int:
|
||||
return self.draw_material.bl_material.wow_m2_material.layer
|
||||
|
||||
@property
|
||||
def is_skybox(self) -> bool:
|
||||
return self.draw_obj.is_skybox
|
||||
|
||||
@property
|
||||
def bb_center(self) -> mathutils.Vector:
|
||||
return mathutils.Vector(self.c_batch.bb_center)
|
||||
|
||||
@property
|
||||
def sort_radius(self) -> float:
|
||||
return self.c_batch.sort_radius
|
||||
|
||||
def determine_valid_shader(self) -> gpu.types.GPUShader:
|
||||
|
||||
shaders = M2ShaderPermutations()
|
||||
|
||||
if self.draw_material:
|
||||
|
||||
self.bl_batch_vert_shader_id = int(self.draw_material.bl_material.wow_m2_material.vertex_shader)
|
||||
self.bl_batch_frag_shader_id = int(self.draw_material.bl_material.wow_m2_material.fragment_shader)
|
||||
|
||||
return shaders.get_shader_by_id(self.bl_batch_vert_shader_id,
|
||||
self.bl_batch_frag_shader_id)
|
||||
else:
|
||||
return shaders.default_shader
|
||||
|
||||
def draw_batch(self):
|
||||
|
||||
glCheckError('draw')
|
||||
|
||||
#render_debug('Drawing batch for object \"{}\"'.format(self.draw_obj.bl_obj.name))
|
||||
|
||||
color_name = self.draw_material.bl_material.wow_m2_material.color
|
||||
transparency_name = self.draw_material.bl_material.wow_m2_material.transparency
|
||||
color = self.context.scene.wow_m2_colors[color_name].color if color_name else (1.0, 1.0, 1.0, 1.0)
|
||||
|
||||
if transparency_name:
|
||||
transparency_rec = self.context.scene.wow_m2_transparency.get(transparency_name)
|
||||
transparency = transparency_rec.value if transparency_rec else 1.0
|
||||
else:
|
||||
transparency = 1.0
|
||||
|
||||
combined_color = (*color[:3], color[3] * transparency)
|
||||
|
||||
u_alpha_test = 128.0 / 255.0 * combined_color[3] \
|
||||
if self.draw_material.blend_mode.index == EGxBLend.AlphaKey.index else 1.0 / 255.0 # Maybe move this to shader logic?
|
||||
|
||||
self._set_active_textures()
|
||||
|
||||
self.shader = self.determine_valid_shader()
|
||||
self.shader.bind()
|
||||
glCheckError('Pre-link program')
|
||||
self.c_batch.set_program(self.shader.program)
|
||||
glCheckError('Post-link program')
|
||||
|
||||
# draw
|
||||
if self.draw_material.depth_culling:
|
||||
glEnable(GL_DEPTH_TEST)
|
||||
|
||||
glDepthMask(GL_TRUE if self.draw_material.depth_write else GL_FALSE)
|
||||
|
||||
if self.draw_material.backface_culling:
|
||||
glEnable(GL_CULL_FACE)
|
||||
|
||||
if self.draw_material.blend_mode.blending_enabled:
|
||||
glEnable(GL_BLEND)
|
||||
|
||||
if self.is_skybox:
|
||||
glDepthRange(0.998, 1.0)
|
||||
|
||||
glBlendFunc(self.draw_material.blend_mode.src_color, self.draw_material.blend_mode.dest_color)
|
||||
# OpenGLUtils.glBlendFuncSeparate(self.draw_material.blend_mode.src_color,
|
||||
# self.draw_material.blend_mode.dest_color,
|
||||
# self.draw_material.blend_mode.src_alpha,
|
||||
# self.draw_material.blend_mode.dest_alpha)
|
||||
|
||||
self.shader.uniform_float('uViewProjectionMatrix', self.draw_obj.draw_mgr.region_3d.perspective_matrix)
|
||||
|
||||
self.shader.uniform_float('uPlacementMatrix', self.draw_obj.bl_obj.matrix_world)
|
||||
self.shader.uniform_float('uSunDirAndFogStart', self.draw_obj.draw_mgr.sun_dir_and_fog_start)
|
||||
self.shader.uniform_float('uSunColorAndFogEnd', self.draw_obj.draw_mgr.sun_color_and_fog_end)
|
||||
self.shader.uniform_float('uAmbientLight', self.draw_obj.draw_mgr.ambient_light)
|
||||
self.shader.uniform_float('uFogColorAndAlphaTest', (*self.draw_obj.draw_mgr.fog_color, u_alpha_test))
|
||||
self.shader.uniform_int('UnFogged_IsAffectedByLight_LightCount', (self.draw_material.is_unfogged,
|
||||
not self.draw_material.is_unlit, 0))
|
||||
|
||||
try:
|
||||
self.shader.uniform_int('uTexture', 0)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
self.shader.uniform_int('uTexture2', 1)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
self.shader.uniform_int('uTexture3', 2)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
self.shader.uniform_int('uTexture4', 3)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
self.shader.uniform_float('color_Transparency', combined_color)
|
||||
|
||||
self.c_batch.draw()
|
||||
|
||||
if self.is_skybox:
|
||||
glDepthRange(0, 0.996)
|
||||
|
||||
if self.draw_material.blend_mode.blending_enabled:
|
||||
glDisable(GL_BLEND)
|
||||
|
||||
if self.draw_material.backface_culling:
|
||||
glDisable(GL_CULL_FACE)
|
||||
|
||||
glDepthMask(GL_FALSE if self.draw_material.depth_write else GL_TRUE)
|
||||
|
||||
if self.draw_material.depth_culling:
|
||||
glDisable(GL_DEPTH_TEST)
|
||||
|
||||
gpu.shader.unbind()
|
||||
|
||||
glCheckError('draw end')
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
import bpy
|
||||
|
||||
from .shaders import EGxBlendRecord, M2BlendingModeToEGxBlend
|
||||
|
||||
|
||||
class M2DrawingMaterial:
|
||||
__slots__ = (
|
||||
'draw_mgr',
|
||||
'bl_material_name',
|
||||
'blend_mode',
|
||||
'depth_write',
|
||||
'depth_culling',
|
||||
'backface_culling',
|
||||
'is_unlit',
|
||||
'is_unfogged',
|
||||
'is_inverted',
|
||||
'is_transformed',
|
||||
)
|
||||
|
||||
blend_mode: EGxBlendRecord
|
||||
depth_write: bool
|
||||
depth_culling: bool
|
||||
backface_culling: bool
|
||||
is_unlit: bool
|
||||
is_unfogged: bool
|
||||
is_inverted: bool
|
||||
is_transformed: bool
|
||||
|
||||
def __init__(self, material: bpy.types.Material):
|
||||
self.bl_material_name = material.name
|
||||
|
||||
self.update_uniform_data()
|
||||
|
||||
@property
|
||||
def bl_material(self):
|
||||
try:
|
||||
return bpy.data.materials[self.bl_material_name]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def get_texture(self, tex_index: int):
|
||||
mat = self.bl_material
|
||||
|
||||
if mat:
|
||||
return getattr(mat.wow_m2_material, 'texture_{}'.format(tex_index + 1))
|
||||
|
||||
@property
|
||||
def texture_count(self):
|
||||
mat = self.bl_material
|
||||
counter = 0
|
||||
|
||||
if mat:
|
||||
for i in range(4):
|
||||
tex = getattr(mat.wow_m2_material, 'texture_{}'.format(i + 1))
|
||||
if tex:
|
||||
counter += 1
|
||||
|
||||
return counter
|
||||
|
||||
def update_uniform_data(self):
|
||||
|
||||
bl_material = self.bl_material
|
||||
|
||||
if not bl_material:
|
||||
return
|
||||
|
||||
self.blend_mode = M2BlendingModeToEGxBlend[int(self.bl_material.wow_m2_material.blending_mode)]
|
||||
self.depth_write = '16' not in bl_material.wow_m2_material.render_flags
|
||||
self.depth_culling = '8' not in bl_material.wow_m2_material.render_flags
|
||||
self.backface_culling = '4' not in bl_material.wow_m2_material.render_flags
|
||||
self.is_unlit = '1' in bl_material.wow_m2_material.render_flags
|
||||
self.is_unfogged = '2' in bl_material.wow_m2_material.render_flags
|
||||
|
||||
self.is_inverted = '1' in bl_material.wow_m2_material.flags
|
||||
self.is_transformed = '2' in bl_material.wow_m2_material.flags
|
||||
|
||||
def get_bindcode(self, tex_index: int) -> int:
|
||||
|
||||
texture = self.get_texture(tex_index)
|
||||
|
||||
if texture:
|
||||
if not texture.bindcode:
|
||||
texture.gl_load()
|
||||
|
||||
return texture.bindcode
|
||||
|
||||
return 0
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
import traceback
|
||||
import bpy
|
||||
import numpy as np
|
||||
|
||||
from mathutils import Matrix
|
||||
from typing import List
|
||||
|
||||
from .drawing_batch import M2DrawingBatch
|
||||
from ..utils import render_debug
|
||||
from ...wbs_kernel.render import CM2DrawingMesh, CM2DrawingBatch
|
||||
from ..bgl_ext import glCheckError
|
||||
|
||||
|
||||
class M2DrawingObject:
|
||||
|
||||
batches: List[CM2DrawingBatch]
|
||||
|
||||
def __init__(self
|
||||
, bl_obj: bpy.types.Object
|
||||
, drawing_mgr: 'M2DrawingManager'
|
||||
, context: bpy.types.Context
|
||||
, is_skybox: bool = False):
|
||||
|
||||
self.context = context
|
||||
self.draw_mgr = drawing_mgr
|
||||
self.bl_obj_name = bl_obj.name
|
||||
self.is_skybox = is_skybox
|
||||
self.is_dirty = True
|
||||
self.is_batching_valid = False
|
||||
|
||||
self.mesh_ptr = bl_obj.data.as_pointer()
|
||||
self.c_mesh = CM2DrawingMesh(self.mesh_ptr)
|
||||
self.batches = []
|
||||
bl_obj.data.calc_loop_triangles()
|
||||
render_debug('Initialized drawing object \"{}\"'.format(self.bl_obj_name))
|
||||
|
||||
self.update_geometry()
|
||||
|
||||
def update_geometry(self, bl_obj: bpy.types.Object = None):
|
||||
if bl_obj:
|
||||
self.c_mesh.update_mesh_pointer(bl_obj.data.as_pointer())
|
||||
bl_obj.data.calc_loop_triangles()
|
||||
|
||||
self.is_batching_valid = self.c_mesh.update_geometry(not(self.context.screen.is_animation_playing or self.bl_obj.mode != 'OBJECT'))
|
||||
|
||||
self.is_dirty = True
|
||||
|
||||
def update_geometry_opengl(self, bl_obj: bpy.types.Object = None):
|
||||
|
||||
self.c_mesh.update_buffers()
|
||||
|
||||
if not self.is_batching_valid:
|
||||
|
||||
for batch in self.batches:
|
||||
batch.free()
|
||||
|
||||
self.batches = \
|
||||
[M2DrawingBatch(c_batch, self, self.context) for c_batch in self.c_mesh.get_drawing_batches()]
|
||||
|
||||
self.is_dirty = False
|
||||
|
||||
@property
|
||||
def bl_obj(self):
|
||||
|
||||
try:
|
||||
return bpy.data.objects[self.bl_obj_name]
|
||||
except KeyError:
|
||||
self.free()
|
||||
|
||||
def free(self):
|
||||
|
||||
for batch in self.batches:
|
||||
batch.free()
|
||||
|
||||
del self.draw_mgr.m2_objects[self.bl_obj_name]
|
||||
|
||||
render_debug('Freed drawing object \"{}\"'.format(self.bl_obj_name))
|
||||
|
||||
'''
|
||||
def update_bone_matrices(self):
|
||||
rig = self.bl_rig
|
||||
for i, pbone in enumerate(rig.pose.bones):
|
||||
self.bone_matrices[i] = [j[i] for i in range(4) for j in pbone.matrix_channel]
|
||||
|
||||
def create_batches_from_armature(self, rig: bpy.types.Object):
|
||||
|
||||
for obj in filter(lambda x: x.type == 'MESH', rig.children):
|
||||
|
||||
# Limit bone influences to 4. TODO: rework to be non-destructive!
|
||||
"""
|
||||
if obj.vertex_groups:
|
||||
active_obj = bpy.context.view_layer.objects.active
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
bpy.ops.object.vertex_group_limit_total()
|
||||
bpy.context.view_layer.objects.active = active_obj
|
||||
|
||||
"""
|
||||
|
||||
self.create_batch_from_object(obj)
|
||||
|
||||
def create_batch_from_object(self, obj: bpy.types.Object):
|
||||
self.batches[obj.name] = M2DrawingBatch(obj, self, self.context)
|
||||
|
||||
'''
|
||||
|
||||
|
||||
|
||||
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
import os
|
||||
import gpu
|
||||
|
||||
from enum import IntEnum
|
||||
from ctypes import c_uint, c_uint8
|
||||
from collections import namedtuple
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from ...utils.misc import singleton, Sequence
|
||||
from ..shaders import ShaderPermutationsManager
|
||||
from bgl import *
|
||||
|
||||
|
||||
class M2PixelShader(IntEnum):
|
||||
# Wotlk deprecated shaders
|
||||
'''
|
||||
Combiners_Decal = -1
|
||||
Combiners_Add = -2
|
||||
Combiners_Mod2x = -3
|
||||
Combiners_Fade = -4,
|
||||
Combiners_Opaque_Add = -5
|
||||
Combiners_Opaque_AddNA = -6
|
||||
Combiners_Add_Mod = -7
|
||||
Combiners_Mod2x_Mod2x = -8
|
||||
'''
|
||||
|
||||
# Legion modern shaders
|
||||
Combiners_Opaque = 0
|
||||
Combiners_Mod = 1
|
||||
Combiners_Opaque_Mod = 2
|
||||
Combiners_Opaque_Mod2x = 3
|
||||
Combiners_Opaque_Mod2xNA = 4
|
||||
Combiners_Opaque_Opaque = 5
|
||||
Combiners_Mod_Mod = 6
|
||||
Combiners_Mod_Mod2x = 7
|
||||
Combiners_Mod_Add = 8
|
||||
Combiners_Mod_Mod2xNA = 9
|
||||
Combiners_Mod_AddNA = 10
|
||||
Combiners_Mod_Opaque = 11
|
||||
Combiners_Opaque_Mod2xNA_Alpha = 12
|
||||
Combiners_Opaque_AddAlpha = 13
|
||||
Combiners_Opaque_AddAlpha_Alpha = 14
|
||||
Combiners_Opaque_Mod2xNA_Alpha_Add = 15
|
||||
Combiners_Mod_AddAlpha = 16
|
||||
Combiners_Mod_AddAlpha_Alpha = 17
|
||||
Combiners_Opaque_Alpha_Alpha = 18
|
||||
Combiners_Opaque_Mod2xNA_Alpha_3s = 19
|
||||
Combiners_Opaque_AddAlpha_Wgt = 20
|
||||
Combiners_Mod_Add_Alpha = 21
|
||||
Combiners_Opaque_ModNA_Alpha = 22
|
||||
Combiners_Mod_AddAlpha_Wgt = 23
|
||||
Combiners_Opaque_Mod_Add_Wgt = 24
|
||||
Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha = 25
|
||||
Combiners_Mod_Dual_Crossfade = 26
|
||||
Combiners_Opaque_Mod2xNA_Alpha_Alpha = 27
|
||||
Combiners_Mod_Masked_Dual_Crossfade = 28
|
||||
Combiners_Opaque_Alpha = 29
|
||||
Guild = 30
|
||||
Guild_NoBorder = 31
|
||||
Guild_Opaque = 32
|
||||
Combiners_Mod_Depth = 33
|
||||
Illum = 34
|
||||
Combiners_Mod_Mod_Mod_Const = 35
|
||||
|
||||
|
||||
class M2VertexShader(IntEnum):
|
||||
Diffuse_T1 = 0
|
||||
Diffuse_Env = 1
|
||||
Diffuse_T1_T2 = 2
|
||||
Diffuse_T1_Env = 3
|
||||
Diffuse_Env_T1 = 4
|
||||
Diffuse_Env_Env = 5
|
||||
Diffuse_T1_Env_T1 = 6
|
||||
Diffuse_T1_T1 = 7
|
||||
Diffuse_T1_T1_T1 = 8
|
||||
Diffuse_EdgeFade_T1 = 9
|
||||
Diffuse_T2 = 10
|
||||
Diffuse_T1_Env_T2 = 11
|
||||
Diffuse_EdgeFade_T1_T2 = 12
|
||||
Diffuse_EdgeFade_Env = 13
|
||||
Diffuse_T1_T2_T1 = 14
|
||||
Diffuse_T1_T2_T3 = 15
|
||||
Color_T1_T2_T3 = 16
|
||||
BW_Diffuse_T1 = 17
|
||||
BW_Diffuse_T1_T2 = 18
|
||||
|
||||
|
||||
EGxBlendRecord = namedtuple('EGxBlendRecord',
|
||||
['blending_enabled', 'src_color', 'dest_color', 'src_alpha', 'dest_alpha', 'index'])
|
||||
|
||||
|
||||
class EGxBLend(metaclass=Sequence):
|
||||
Opaque = EGxBlendRecord(False, GL_ONE, GL_ZERO, GL_ONE, GL_ZERO, 0)
|
||||
AlphaKey = EGxBlendRecord(False, GL_ONE, GL_ZERO, GL_ONE, GL_ZERO, 1)
|
||||
Alpha = EGxBlendRecord(True, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, 2)
|
||||
Add = EGxBlendRecord(True, GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE, 3)
|
||||
Mod = EGxBlendRecord(True, GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO, 4)
|
||||
Mod2x = EGxBlendRecord(True, GL_DST_COLOR, GL_SRC_COLOR, GL_DST_ALPHA, GL_SRC_ALPHA, 5)
|
||||
ModAdd = EGxBlendRecord(True, GL_DST_COLOR, GL_ONE, GL_DST_ALPHA, GL_ONE, 6)
|
||||
InvSrcAlphaAdd = EGxBlendRecord(True, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, 7)
|
||||
InvSrcAlphaOpaque = EGxBlendRecord(True, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, 8)
|
||||
SrcAlphaOpaque = EGxBlendRecord(True, GL_SRC_ALPHA, GL_ZERO, GL_SRC_ALPHA, GL_ZERO, 9)
|
||||
NoAlphaAdd = EGxBlendRecord(True, GL_ONE, GL_ONE, GL_ZERO, GL_ONE, 10)
|
||||
ConstantAlpha = EGxBlendRecord(True, GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA, GL_CONSTANT_ALPHA,
|
||||
GL_ONE_MINUS_CONSTANT_ALPHA, 11)
|
||||
Screen = EGxBlendRecord(True, GL_ONE_MINUS_DST_COLOR, GL_ONE, GL_ONE, GL_ZERO, 12)
|
||||
BlendAdd = EGxBlendRecord(True, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, 13)
|
||||
|
||||
|
||||
class M2BlendingModeToEGxBlend(metaclass=Sequence):
|
||||
|
||||
Blend_Opaque = EGxBLend.Opaque
|
||||
Blend_AlphaKey = EGxBLend.AlphaKey
|
||||
Blend_Alpha = EGxBLend.Alpha
|
||||
Blend_NoAlphaAdd = EGxBLend.NoAlphaAdd
|
||||
Blend_Add = EGxBLend.Add
|
||||
Blend_Mod = EGxBLend.Mod
|
||||
Blend_Mod2x = EGxBLend.Mod2x
|
||||
Blend_BlendAdd = EGxBLend.BlendAdd
|
||||
|
||||
|
||||
M2ShaderTableRecord = namedtuple('M2ShaderTableRecord', ['pixel_shader', 'vertex_shader'])
|
||||
|
||||
|
||||
class M2ShaderTable(metaclass=Sequence):
|
||||
Combiners_Opaque_Mod2xNA_Alpha_Diffuse_T1_Env = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_Mod2xNA_Alpha, M2VertexShader.Diffuse_T1_Env)
|
||||
|
||||
Combiners_Opaque_AddAlpha_Diffuse_T1_Env = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_AddAlpha, M2VertexShader.Diffuse_T1_Env)
|
||||
|
||||
Combiners_Opaque_AddAlpha_Alpha_Diffuse_T1_Env = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_AddAlpha_Alpha, M2VertexShader.Diffuse_T1_Env)
|
||||
|
||||
Combiners_Opaque_Mod2xNA_Alpha_Add_Diffuse_T1_Env_T1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_Mod2xNA_Alpha_Add, M2VertexShader.Diffuse_T1_Env_T1)
|
||||
|
||||
Combiners_Mod_AddAlpha_Diffuse_T1_Env = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_AddAlpha, M2VertexShader.Diffuse_T1_Env)
|
||||
|
||||
Combiners_Opaque_AddAlpha_Diffuse_T1_T1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_AddAlpha, M2VertexShader.Diffuse_T1_T1)
|
||||
|
||||
Combiners_Mod_AddAlpha_Diffuse_T1_T1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_AddAlpha, M2VertexShader.Diffuse_T1_T1)
|
||||
|
||||
Combiners_Mod_AddAlpha_Alpha_Diffuse_T1_Env = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_AddAlpha_Alpha, M2VertexShader.Diffuse_T1_Env)
|
||||
|
||||
Combiners_Opaque_Alpha_Alpha_Diffuse_T1_Env = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_Alpha_Alpha, M2VertexShader.Diffuse_T1_Env)
|
||||
|
||||
Combiners_Opaque_Mod2xNA_Alpha_3s_Diffuse_T1_Env_T1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_Mod2xNA_Alpha_3s, M2VertexShader.Diffuse_T1_Env_T1)
|
||||
|
||||
Combiners_Opaque_AddAlpha_Wgt_Diffuse_T1_T1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_AddAlpha_Wgt, M2VertexShader.Diffuse_T1_T1)
|
||||
|
||||
Combiners_Mod_Add_Alpha_Diffuse_T1_Env = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_Add_Alpha, M2VertexShader.Diffuse_T1_Env)
|
||||
|
||||
Combiners_Opaque_ModNA_Alpha_Diffuse_T1_Env = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_ModNA_Alpha, M2VertexShader.Diffuse_T1_Env)
|
||||
|
||||
Combiners_Mod_AddAlpha_Wgt_Diffuse_T1_Env = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_AddAlpha_Wgt, M2VertexShader.Diffuse_T1_Env)
|
||||
|
||||
Combiners_Mod_AddAlpha_Wgt_Diffuse_T1_T1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_AddAlpha_Wgt, M2VertexShader.Diffuse_T1_T1)
|
||||
|
||||
Combiners_Opaque_AddAlpha_Wgt_Diffuse_T1_T2 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_AddAlpha_Wgt, M2VertexShader.Diffuse_T1_T2)
|
||||
|
||||
Combiners_Opaque_Mod_Add_Wgt_Diffuse_T1_Env = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_Mod_Add_Wgt, M2VertexShader.Diffuse_T1_Env)
|
||||
|
||||
Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha, M2VertexShader.Diffuse_T1_Env_T1)
|
||||
|
||||
Combiners_Mod_Dual_Crossfade_Diffuse_T1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_Dual_Crossfade, M2VertexShader.Diffuse_T1)
|
||||
|
||||
Combiners_Mod_Depth_Diffuse_EdgeFade_T1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_Depth, M2VertexShader.Diffuse_EdgeFade_T1)
|
||||
|
||||
Combiners_Opaque_Mod2xNA_Alpha_Alpha_Diffuse_T1_Env_T2 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_Mod2xNA_Alpha_Alpha, M2VertexShader.Diffuse_T1_Env_T2)
|
||||
|
||||
Combiners_Mod_Mod_Diffuse_EdgeFade_T1_T2 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_Mod, M2VertexShader.Diffuse_EdgeFade_T1_T2)
|
||||
|
||||
Combiners_Mod_Masked_Dual_Crossfade_Diffuse_T1_T2 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_Masked_Dual_Crossfade, M2VertexShader.Diffuse_T1_T2)
|
||||
|
||||
Combiners_Opaque_Alpha_Diffuse_T1_T1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_Alpha, M2VertexShader.Diffuse_T1_T1)
|
||||
|
||||
Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha2 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha, M2VertexShader.Diffuse_T1_Env_T2)
|
||||
|
||||
Combiners_Mod_Depth_Diffuse_EdgeFade_Env = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_Depth, M2VertexShader.Diffuse_EdgeFade_Env)
|
||||
|
||||
Guild_Diffuse_T1_T2_T1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Guild, M2VertexShader.Diffuse_T1_T2_T1)
|
||||
|
||||
Guild_NoBorder_Diffuse_T1_T2 = M2ShaderTableRecord(
|
||||
M2PixelShader.Guild_NoBorder, M2VertexShader.Diffuse_T1_T2)
|
||||
|
||||
Guild_Opaque_Diffuse_T1_T2_T1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Guild_Opaque, M2VertexShader.Diffuse_T1_T2_T1)
|
||||
|
||||
Illum_Diffuse_T1_T1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Illum, M2VertexShader.Diffuse_T1_T1)
|
||||
|
||||
Combiners_Mod_Mod_Mod_Const_Diffuse_T1_T2_T3 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_Mod_Mod_Const, M2VertexShader.Diffuse_T1_T2_T3)
|
||||
|
||||
Combiners_Mod_Mod_Mod_Const_Color_T1_T2_T3 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_Mod_Mod_Const, M2VertexShader.Color_T1_T2_T3)
|
||||
|
||||
Combiners_Opaque_Diffuse_T1 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Opaque, M2VertexShader.Diffuse_T1)
|
||||
|
||||
Combiners_Mod_Mod2x_Diffuse_EdgeFade_T1_T2 = M2ShaderTableRecord(
|
||||
M2PixelShader.Combiners_Mod_Mod2x, M2VertexShader.Diffuse_EdgeFade_T1_T2)
|
||||
|
||||
|
||||
@singleton
|
||||
class M2ShaderPermutations(ShaderPermutationsManager):
|
||||
|
||||
shader_source_path = 'm2_shader'
|
||||
|
||||
@staticmethod
|
||||
def get_vertex_shader_id(texture_count: int, shader_id: int) -> int:
|
||||
|
||||
if shader_id < 0: # all shaders with negative shader id
|
||||
vertex_shader_id = shader_id & 0x7FFF
|
||||
|
||||
if c_uint(vertex_shader_id).value >= 0x22:
|
||||
raise ValueError("Wrong shader ID for vertex shader")
|
||||
|
||||
result = c_uint(M2ShaderTable[vertex_shader_id].vertex_shader).value
|
||||
|
||||
# reverse: vertex_shader_id | 0x80000000 for int32) (do with ctypes)
|
||||
|
||||
elif texture_count == 1: # 0, 1, 10
|
||||
if (shader_id & 0x80) != 0:
|
||||
result = 1
|
||||
else:
|
||||
result = 10
|
||||
if not (shader_id & 0x4000):
|
||||
result = 0
|
||||
|
||||
elif (shader_id & 0x80) != 0: # 4, 5
|
||||
result = ((shader_id & 8) >> 3) | 4
|
||||
|
||||
else: # 3, 7, 8
|
||||
result = 3
|
||||
if not (shader_id & 8):
|
||||
result = 5 * c_uint((shader_id & 0x4000) == 0).value + 2
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def get_pixel_shader_id(texture_count: int, shader_id: int):
|
||||
|
||||
array1 = [
|
||||
M2PixelShader.Combiners_Mod_Mod2x,
|
||||
M2PixelShader.Combiners_Mod_Mod,
|
||||
M2PixelShader.Combiners_Mod_Mod2xNA,
|
||||
M2PixelShader.Combiners_Mod_AddNA,
|
||||
M2PixelShader.Combiners_Mod_Opaque,
|
||||
M2PixelShader.Combiners_Mod_Mod,
|
||||
M2PixelShader.Combiners_Mod_Mod,
|
||||
M2PixelShader.Combiners_Mod_Add
|
||||
]
|
||||
|
||||
array2 = [
|
||||
M2PixelShader.Combiners_Opaque_Mod2x,
|
||||
M2PixelShader.Combiners_Opaque_Mod,
|
||||
M2PixelShader.Combiners_Opaque_Mod2xNA,
|
||||
M2PixelShader.Combiners_Opaque_AddAlpha_Alpha,
|
||||
M2PixelShader.Combiners_Opaque_Opaque,
|
||||
M2PixelShader.Combiners_Opaque_Mod,
|
||||
M2PixelShader.Combiners_Opaque_Mod,
|
||||
M2PixelShader.Combiners_Opaque_AddAlpha_Alpha
|
||||
]
|
||||
|
||||
if shader_id < 0: # all shaders with negative shader id
|
||||
|
||||
pixel_shader_id = shader_id & 0x7FFF
|
||||
if c_uint(pixel_shader_id).value >= 0x22:
|
||||
raise ValueError("Wrong shader ID for pixel shader")
|
||||
|
||||
result = c_uint(M2ShaderTable[pixel_shader_id].pixel_shader).value
|
||||
|
||||
# reverse: pixel_shader_id | 0x80000000 for int32) (do with ctypes)
|
||||
|
||||
elif texture_count == 1: # 0, 1
|
||||
|
||||
result = int((shader_id & 0x70) != 0)
|
||||
else:
|
||||
|
||||
cur_array = array2
|
||||
if shader_id & 0x70:
|
||||
cur_array = array1
|
||||
|
||||
result = cur_array[(c_uint8(shader_id).value ^ 4) & 7].value
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def get_shader_combo_index(vertex_shader_id: int, pixel_shader_id: int):
|
||||
|
||||
for record in M2ShaderTable:
|
||||
if record.value.vertex_shader == vertex_shader_id and record.value.pixel_shader == pixel_shader_id:
|
||||
return record.index
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import os
|
||||
import gpu
|
||||
|
||||
from typing import Tuple, Dict, Any
|
||||
|
||||
from ..utils.misc import singleton, Sequence
|
||||
|
||||
|
||||
class ShaderPermutationsFormat:
|
||||
M2 = 0,
|
||||
WMO = 1,
|
||||
ADT = 2
|
||||
|
||||
|
||||
class ShaderPermutationsManager:
|
||||
|
||||
shader_source_path: str
|
||||
extra_defines: Dict[str, Any]
|
||||
|
||||
def __init__(self):
|
||||
self.shader_permutations: Dict = {}
|
||||
self.shader_source: str
|
||||
self.default_shader: gpu.types.GPUShader
|
||||
|
||||
rel_path = 'shaders\\glsl330\\{}.glsl'.format(self.shader_source_path) if os.name == 'nt'\
|
||||
else 'shaders/glsl330/{}.glsl'.format(self.shader_source_path)
|
||||
|
||||
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), rel_path)) as f:
|
||||
self.shader_source = "".join(f.readlines())
|
||||
|
||||
rel_path = 'shaders\\glsl330\\default.glsl' if os.name == 'nt' else 'shaders/glsl330/default.glsl'
|
||||
|
||||
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), rel_path)) as f:
|
||||
shader_source_fallback = "".join(f.readlines())
|
||||
|
||||
vert_shader_string_perm = "#define COMPILING_VS {}\n" \
|
||||
"{}".format(1, shader_source_fallback)
|
||||
frag_shader_string_perm = "#define COMPILING_FS {}\n" \
|
||||
"{}".format(1, shader_source_fallback)
|
||||
|
||||
self.default_shader = gpu.types.GPUShader(vert_shader_string_perm, frag_shader_string_perm)
|
||||
|
||||
def _compile_shader_permutation(self
|
||||
, vert_shader_id: int
|
||||
, frag_shader_id: int) -> gpu.types.GPUShader:
|
||||
|
||||
vert_shader_string_perm = "#define COMPILING_VS {}\n" \
|
||||
"#define VERTEXSHADER {}\n" \
|
||||
"{}".format(1, vert_shader_id, self.shader_source)
|
||||
frag_shader_string_perm = "#define COMPILING_FS {}\n" \
|
||||
"#define FRAGMENTSHADER {}\n" \
|
||||
"{}".format(1, frag_shader_id, self.shader_source)
|
||||
|
||||
shader = gpu.types.GPUShader(vert_shader_string_perm, frag_shader_string_perm)
|
||||
self.shader_permutations[vert_shader_id, frag_shader_id] = shader
|
||||
|
||||
return shader
|
||||
|
||||
def get_shader_by_id(self
|
||||
, vert_shader_id: int
|
||||
, frag_shader_id: int) -> gpu.types.GPUShader:
|
||||
|
||||
shader = self.shader_permutations.get((vert_shader_id, frag_shader_id))
|
||||
|
||||
if not shader:
|
||||
shader = self._compile_shader_permutation(vert_shader_id, frag_shader_id)
|
||||
|
||||
return shader
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
#ifdef COMPILING_VS
|
||||
|
||||
/* vertex shader code */
|
||||
|
||||
in vec3 aPosition;
|
||||
in vec3 aNormal;
|
||||
|
||||
// Whole model
|
||||
uniform mat4 uViewProjectionMatrix;
|
||||
uniform mat4 uPlacementMatrix;
|
||||
|
||||
//Individual meshes
|
||||
uniform vec4 color_Transparency;
|
||||
|
||||
//Shader output
|
||||
out vec3 vPosition;
|
||||
out vec3 vNormal;
|
||||
|
||||
|
||||
void main() {
|
||||
|
||||
vec4 aPositionVec4 = vec4(aPosition, 1.0f);
|
||||
|
||||
mat3 viewModelMatTransposed = mat3(uViewProjectionMatrix);
|
||||
mat4 cameraMatrix = uViewProjectionMatrix;
|
||||
vec4 cameraPoint = cameraMatrix * (uPlacementMatrix * aPositionVec4);
|
||||
|
||||
vec3 normal = normalize(viewModelMatTransposed * (mat3(uPlacementMatrix) * aNormal));
|
||||
|
||||
vNormal = normal;
|
||||
vPosition = cameraPoint.xyz;
|
||||
|
||||
gl_Position = cameraPoint;
|
||||
|
||||
}
|
||||
|
||||
#endif //COMPILING_VS
|
||||
|
||||
|
||||
#ifdef COMPILING_FS
|
||||
|
||||
struct LocalLight
|
||||
{
|
||||
vec4 color;
|
||||
vec4 position;
|
||||
vec4 attenuation;
|
||||
};
|
||||
|
||||
in vec3 vPosition;
|
||||
in vec3 vNormal;
|
||||
|
||||
|
||||
out vec4 outputColor;
|
||||
|
||||
//Whole model
|
||||
uniform mat4 uViewProjectionMatrix;
|
||||
|
||||
uniform vec4 uSunDirAndFogStart;
|
||||
uniform vec4 uSunColorAndFogEnd;
|
||||
uniform vec4 uAmbientLight;
|
||||
|
||||
|
||||
uniform ivec3 UnFogged_IsAffectedByLight_LightCount;
|
||||
uniform vec4 uFogColorAndAlphaTest;
|
||||
uniform LocalLight pc_lights[4];
|
||||
|
||||
|
||||
vec3 makeDiffTerm(vec3 matDiffuse, vec3 accumLight) {
|
||||
vec3 currColor;
|
||||
float mult = 1.0;
|
||||
vec3 lDiffuse = vec3(0.0, 0.0, 0.0);
|
||||
vec4 viewUp = uViewProjectionMatrix * vec4(0, 0, 1, 0);
|
||||
|
||||
if (UnFogged_IsAffectedByLight_LightCount.y == 1) {
|
||||
vec3 normalizedN = normalize(vNormal);
|
||||
float nDotL = clamp(dot(normalizedN, -(uSunDirAndFogStart.xyz)), 0.0, 1.0);
|
||||
float nDotUp = dot(normalizedN, viewUp.xyz);
|
||||
|
||||
vec4 AmbientLight = uAmbientLight;
|
||||
|
||||
vec3 adjAmbient = (AmbientLight.rgb );
|
||||
vec3 adjHorizAmbient = (AmbientLight.rgb );
|
||||
vec3 adjGroundAmbient = (AmbientLight.rgb );
|
||||
|
||||
if ((nDotUp >= 0.0))
|
||||
{
|
||||
currColor = mix(adjHorizAmbient, adjAmbient, vec3(nDotUp));
|
||||
}
|
||||
else
|
||||
{
|
||||
currColor= mix(adjHorizAmbient, adjGroundAmbient, vec3(-(nDotUp)));
|
||||
}
|
||||
|
||||
vec3 skyColor = (currColor * 1.10000002);
|
||||
vec3 groundColor = (currColor* 0.699999988);
|
||||
|
||||
|
||||
lDiffuse = (uSunColorAndFogEnd.xyz * nDotL);
|
||||
currColor = mix(groundColor, skyColor, vec3((0.5 + (0.5 * nDotL))));
|
||||
|
||||
} else {
|
||||
currColor = vec3 (1.0, 1.0, 1.0) ;
|
||||
accumLight = vec3(0,0,0);
|
||||
mult = 1.0;
|
||||
}
|
||||
|
||||
|
||||
vec3 gammaDiffTerm = matDiffuse * (currColor + lDiffuse);
|
||||
vec3 linearDiffTerm = (matDiffuse * matDiffuse) * accumLight;
|
||||
|
||||
return sqrt(gammaDiffTerm*gammaDiffTerm + linearDiffTerm) ;
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
|
||||
vec4 finalColor = vec4(0);
|
||||
vec4 meshResColor = vec4(0.5, 0.5, 0.5, 1.0);
|
||||
vec4 vDiffuseColor = meshResColor;
|
||||
|
||||
vec3 accumLight;
|
||||
if ((UnFogged_IsAffectedByLight_LightCount.y == 1)) {
|
||||
vec3 vPos3 = vPosition.xyz;
|
||||
vec3 vNormal3 = normalize(vNormal.xyz);
|
||||
vec3 lightColor = vec3(0.0);
|
||||
int count = int(pc_lights[0].attenuation.w);
|
||||
int index = 0;
|
||||
for (;;)
|
||||
{
|
||||
if ( index >= UnFogged_IsAffectedByLight_LightCount.z) break;
|
||||
LocalLight lightRecord = pc_lights[index];
|
||||
vec3 vectorToLight = ((lightRecord.position).xyz - vPos3);
|
||||
float distanceToLightSqr = dot(vectorToLight, vectorToLight);
|
||||
float distanceToLightInv = inversesqrt(distanceToLightSqr);
|
||||
float distanceToLight = (distanceToLightSqr * distanceToLightInv);
|
||||
float diffuseTerm1 = max((dot(vectorToLight, vNormal3) * distanceToLightInv), 0.0);
|
||||
vec4 attenuationRec = lightRecord.attenuation;
|
||||
|
||||
float attenuation = (1.0 - clamp((distanceToLight - attenuationRec.x) * (1.0 / (attenuationRec.z - attenuationRec.x)), 0.0, 1.0));
|
||||
|
||||
vec3 attenuatedColor = attenuation * lightRecord.color.xyz * attenuationRec.y;
|
||||
lightColor = (lightColor + vec3(attenuatedColor * attenuatedColor * diffuseTerm1 ));
|
||||
index++;
|
||||
}
|
||||
meshResColor.rgb = clamp(lightColor , 0.0, 1.0);
|
||||
accumLight = meshResColor.rgb;
|
||||
//finalColor.rgb = finalColor.rgb * lightColor;
|
||||
}
|
||||
|
||||
float opacity;
|
||||
float finalOpacity = 0.0;
|
||||
vec3 matDiffuse;
|
||||
vec3 specular = vec3(0.0, 0.0, 0.0);
|
||||
vec3 visParams = vec3(1.0, 1.0, 1.0);
|
||||
vec4 genericParams[3];
|
||||
genericParams[0] = vec4( 1.0, 1.0, 1.0, 1.0 );
|
||||
genericParams[1] = vec4( 1.0, 1.0, 1.0, 1.0 );
|
||||
genericParams[2] = vec4( 1.0, 1.0, 1.0, 1.0 );
|
||||
|
||||
//Combiners_Opaque
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000;
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
|
||||
finalColor = vec4(makeDiffTerm(matDiffuse, accumLight) + specular, finalOpacity);
|
||||
|
||||
int uUnFogged = UnFogged_IsAffectedByLight_LightCount.x;
|
||||
float uFogEnd = uSunColorAndFogEnd.w;
|
||||
if (uUnFogged == 0) {
|
||||
|
||||
vec3 fogColor = uFogColorAndAlphaTest.xyz;
|
||||
|
||||
float fog_rate = 1.5;
|
||||
float fog_bias = 0.01;
|
||||
|
||||
//vec4 fogHeightPlane = pc_fog.heightPlane;
|
||||
//float heightRate = pc_fog.color_and_heightRate.w;
|
||||
|
||||
float distanceToCamera = length(vPosition.xyz);
|
||||
float z_depth = (distanceToCamera - fog_bias);
|
||||
float expFog = 1.0 / (exp((max(0.0, (z_depth - uSunDirAndFogStart.w)) * fog_rate)));
|
||||
//float height = (dot(fogHeightPlane.xyz, vPosition.xyz) + fogHeightPlane.w);
|
||||
//float heightFog = clamp((height * heightRate), 0, 1);
|
||||
float heightFog = 1.0;
|
||||
expFog = (expFog + heightFog);
|
||||
float endFadeFog = clamp(((uFogEnd - distanceToCamera) / (0.699999988 * uFogEnd)), 0.0, 1.0);
|
||||
float fog_out = min(expFog, endFadeFog);
|
||||
finalColor.rgba = vec4(mix(fogColor.rgb, finalColor.rgb, vec3(fog_out)), finalColor.a);
|
||||
}
|
||||
|
||||
//outputColor = blender_srgb_to_framebuffer_space(finalColor);
|
||||
finalColor.a = clamp(finalColor.a, 0.0, 1.0);
|
||||
outputColor = vec4(finalColor.rgb, finalColor.a);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif //COMPILING_FS
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
[remap]
|
||||
|
||||
importer="glsl"
|
||||
type="RDShaderFile"
|
||||
uid="uid://dm7a4pi3f0j31"
|
||||
path="res://.godot/imported/default.glsl-3ffe109a58103ff0ad40364a19be71ef.res"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://reference/blender-wow-studio-3.4-1.1.0_Experimental/io_scene_wmo/render/shaders/glsl330/default.glsl"
|
||||
dest_files=["res://.godot/imported/default.glsl-3ffe109a58103ff0ad40364a19be71ef.res"]
|
||||
|
||||
[params]
|
||||
|
||||
+574
@@ -0,0 +1,574 @@
|
||||
// Library code
|
||||
|
||||
vec2 posToTexCoord(vec3 cameraPoint, vec3 normal){
|
||||
// vec3 normPos = -normalize(cameraPoint.xyz);
|
||||
// vec3 normPos = cameraPoint.xyz;
|
||||
// vec3 reflection = reflect(normPos, normal);
|
||||
// return (normalize(vec3(reflection.r, reflection.g, reflection.b + 1.0)).rg * 0.5) + vec2(0.5);
|
||||
|
||||
vec3 normPos_495 = normalize(cameraPoint.xyz);
|
||||
vec3 temp_500 = (normPos_495 - (normal * (2.0 * dot(normPos_495, normal))));
|
||||
vec3 temp_657 = vec3(temp_500.x, temp_500.y, (temp_500.z + 1.0));
|
||||
|
||||
return ((normalize(temp_657).xy * 0.5) + vec2(0.5));
|
||||
}
|
||||
|
||||
float edgeScan(vec3 position, vec3 normal){
|
||||
float dotProductClamped = clamp(dot(-normalize(position),normal), 0.000000, 1.000000);
|
||||
return clamp(2.700000 * dotProductClamped * dotProductClamped - 0.400000, 0.000000, 1.000000);
|
||||
}
|
||||
|
||||
mat3 blizzTranspose(mat4 value) {
|
||||
return mat3(
|
||||
value[0].xyz,
|
||||
value[1].xyz,
|
||||
value[2].xyz
|
||||
);
|
||||
}
|
||||
|
||||
// Shader code
|
||||
#ifdef COMPILING_VS
|
||||
|
||||
precision highp float;
|
||||
|
||||
/* vertex shader code */
|
||||
in vec3 aPosition;
|
||||
in vec3 aNormal;
|
||||
in vec2 aTexCoord;
|
||||
in vec2 aTexCoord2;
|
||||
|
||||
|
||||
// Whole model
|
||||
uniform mat4 uViewProjectionMatrix;
|
||||
uniform mat4 uPlacementMatrix;
|
||||
|
||||
//Individual meshes
|
||||
uniform vec4 color_Transparency;
|
||||
|
||||
//Shader output
|
||||
out vec3 vPosition;
|
||||
out vec3 vNormal;
|
||||
out vec2 vTexCoord;
|
||||
out vec2 vTexCoord2;
|
||||
out vec2 vTexCoord3;
|
||||
out vec4 vDiffuseColor;
|
||||
|
||||
|
||||
void main() {
|
||||
|
||||
vec4 aPositionVec4 = vec4(aPosition, 1.0f);
|
||||
|
||||
vec4 lDiffuseColor = color_Transparency;
|
||||
vec4 combinedColor = clamp(lDiffuseColor /*+ vc_matEmissive*/, 0.000000, 1.000000);
|
||||
vec4 combinedColorHalved = combinedColor * 0.5;
|
||||
|
||||
mat3 viewModelMatTransposed = mat3(uViewProjectionMatrix);
|
||||
mat4 cameraMatrix = uViewProjectionMatrix;
|
||||
vec4 cameraPoint = cameraMatrix * (uPlacementMatrix * aPositionVec4);
|
||||
|
||||
// Handle normals
|
||||
vec3 normal = normalize(viewModelMatTransposed * (mat3(uPlacementMatrix) * aNormal));
|
||||
|
||||
vec2 envCoord = posToTexCoord(cameraPoint.xyz, normal);
|
||||
float edgeScanVal = edgeScan(cameraPoint.xyz, normal);
|
||||
|
||||
// Handle colors and texture coordinates
|
||||
vTexCoord2 = vec2(0.0);
|
||||
vTexCoord3 = vec2(0.0);
|
||||
|
||||
//Diffuse_T1
|
||||
#if VERTEXSHADER == 0
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
|
||||
vTexCoord = aTexCoord;
|
||||
#endif
|
||||
//Diffuse_Env
|
||||
#if VERTEXSHADER == 1
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
|
||||
vTexCoord = envCoord;
|
||||
#endif
|
||||
//Diffuse_T1_T2
|
||||
#if VERTEXSHADER == 2
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = aTexCoord2;
|
||||
#endif
|
||||
#if VERTEXSHADER == 3 //Diffuse_T1_Env
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = envCoord;
|
||||
#endif
|
||||
#if VERTEXSHADER == 4 //Diffuse_Env_T1
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
|
||||
vTexCoord = envCoord;
|
||||
vTexCoord2 = aTexCoord;
|
||||
#endif
|
||||
#if VERTEXSHADER == 5 //Diffuse_Env_Env
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
|
||||
vTexCoord = envCoord;
|
||||
vTexCoord2 = envCoord;
|
||||
#endif
|
||||
#if VERTEXSHADER == 6 //Diffuse_T1_Env_T1
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = envCoord;
|
||||
vTexCoord3 = aTexCoord;
|
||||
#endif
|
||||
#if VERTEXSHADER == 7 //Diffuse_T1_T1
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = aTexCoord;
|
||||
#endif
|
||||
#if VERTEXSHADER == 8 //Diffuse_T1_T1_T1
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = aTexCoord;
|
||||
vTexCoord3 = aTexCoord;
|
||||
#endif
|
||||
#if VERTEXSHADER == 9 //Diffuse_EdgeFade_T1+
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a * edgeScanVal);
|
||||
vTexCoord = aTexCoord;
|
||||
#endif
|
||||
#if VERTEXSHADER == 10 //Diffuse_T2
|
||||
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
|
||||
vTexCoord = aTexCoord2;
|
||||
#endif
|
||||
#if VERTEXSHADER == 11 //Diffuse_T1_Env_T2
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = envCoord;
|
||||
vTexCoord3 = aTexCoord2;
|
||||
#endif
|
||||
#if VERTEXSHADER == 12 //Diffuse_EdgeFade_T1_T2
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a * edgeScanVal);
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = aTexCoord2;
|
||||
#endif
|
||||
#if VERTEXSHADER == 13 //Diffuse_EdgeFade_Env
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a * edgeScanVal);
|
||||
vTexCoord = envCoord;
|
||||
#endif
|
||||
#if VERTEXSHADER == 14 //Diffuse_T1_T2_T1
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = aTexCoord2;
|
||||
vTexCoord3 = aTexCoord;
|
||||
#endif
|
||||
#if VERTEXSHADER == 15 //Diffuse_T1_T2_T3
|
||||
vDiffuseColor = vec4(combinedColorHalved.r, combinedColorHalved.g, combinedColorHalved.b, combinedColor.a);
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = aTexCoord2;
|
||||
vTexCoord3 = vTexCoord3;
|
||||
#endif
|
||||
#if VERTEXSHADER == 16 //Color_T1_T2_T3
|
||||
vec4 in_col0 = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
vDiffuseColor = vec4((in_col0.rgb * 0.500000).r, (in_col0.rgb * 0.500000).g, (in_col0.rgb * 0.500000).b, in_col0.a);
|
||||
vTexCoord = aTexCoord2;
|
||||
vTexCoord2 = vec2(0.000000, 0.000000);
|
||||
vTexCoord3 = vTexCoord3;
|
||||
#endif
|
||||
#if VERTEXSHADER == 17 //BW_Diffuse_T1
|
||||
vDiffuseColor = vec4(combinedColor.rgb * 0.500000, combinedColor.a);
|
||||
vTexCoord = aTexCoord;
|
||||
#endif
|
||||
#if VERTEXSHADER == 18 //BW_Diffuse_T1_T2
|
||||
vDiffuseColor = vec4(combinedColor.rgb * 0.500000, combinedColor.a);
|
||||
vTexCoord = aTexCoord;
|
||||
#endif
|
||||
|
||||
vNormal = normal;
|
||||
vPosition = cameraPoint.xyz;
|
||||
|
||||
gl_Position = cameraPoint;
|
||||
|
||||
}
|
||||
|
||||
#endif //COMPILING_VS
|
||||
|
||||
|
||||
#ifdef COMPILING_FS
|
||||
|
||||
precision highp float;
|
||||
|
||||
struct LocalLight
|
||||
{
|
||||
vec4 color;
|
||||
vec4 position;
|
||||
vec4 attenuation;
|
||||
};
|
||||
|
||||
|
||||
in vec3 vNormal;
|
||||
in vec2 vTexCoord;
|
||||
in vec2 vTexCoord2;
|
||||
in vec2 vTexCoord3;
|
||||
in vec3 vPosition;
|
||||
in vec4 vDiffuseColor;
|
||||
|
||||
uniform sampler2D uTexture;
|
||||
uniform sampler2D uTexture2;
|
||||
uniform sampler2D uTexture3;
|
||||
uniform sampler2D uTexture4;
|
||||
|
||||
|
||||
out vec4 outputColor;
|
||||
|
||||
//Whole model
|
||||
uniform mat4 uViewProjectionMatrix;
|
||||
|
||||
uniform vec4 uSunDirAndFogStart;
|
||||
uniform vec4 uSunColorAndFogEnd;
|
||||
uniform vec4 uAmbientLight;
|
||||
|
||||
|
||||
|
||||
uniform ivec3 UnFogged_IsAffectedByLight_LightCount;
|
||||
uniform vec4 uFogColorAndAlphaTest;
|
||||
uniform LocalLight pc_lights[4];
|
||||
|
||||
|
||||
vec3 makeDiffTerm(vec3 matDiffuse, vec3 accumLight) {
|
||||
vec3 currColor;
|
||||
float mult = 1.0;
|
||||
vec3 lDiffuse = vec3(0.0, 0.0, 0.0);
|
||||
vec4 viewUp = uViewProjectionMatrix * vec4(0, 0, 1, 0);
|
||||
|
||||
if (UnFogged_IsAffectedByLight_LightCount.y == 1) {
|
||||
vec3 normalizedN = normalize(vNormal);
|
||||
float nDotL = clamp(dot(normalizedN, -(uSunDirAndFogStart.xyz)), 0.0, 1.0);
|
||||
float nDotUp = dot(normalizedN, viewUp.xyz);
|
||||
|
||||
vec4 AmbientLight = uAmbientLight;
|
||||
|
||||
vec3 adjAmbient = (AmbientLight.rgb );
|
||||
vec3 adjHorizAmbient = (AmbientLight.rgb );
|
||||
vec3 adjGroundAmbient = (AmbientLight.rgb );
|
||||
|
||||
if ((nDotUp >= 0.0))
|
||||
{
|
||||
currColor = mix(adjHorizAmbient, adjAmbient, vec3(nDotUp));
|
||||
}
|
||||
else
|
||||
{
|
||||
currColor= mix(adjHorizAmbient, adjGroundAmbient, vec3(-(nDotUp)));
|
||||
}
|
||||
|
||||
vec3 skyColor = (currColor * 1.10000002);
|
||||
vec3 groundColor = (currColor* 0.699999988);
|
||||
|
||||
|
||||
lDiffuse = (uSunColorAndFogEnd.xyz * nDotL);
|
||||
currColor = mix(groundColor, skyColor, vec3((0.5 + (0.5 * nDotL))));
|
||||
|
||||
} else {
|
||||
currColor = vec3 (1.0, 1.0, 1.0) ;
|
||||
accumLight = vec3(0,0,0);
|
||||
mult = 1.0;
|
||||
}
|
||||
|
||||
|
||||
vec3 gammaDiffTerm = matDiffuse * (currColor + lDiffuse);
|
||||
vec3 linearDiffTerm = (matDiffuse * matDiffuse) * accumLight;
|
||||
|
||||
return sqrt(gammaDiffTerm*gammaDiffTerm + linearDiffTerm) ;
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
|
||||
/* Animation support */
|
||||
vec2 texCoord = vTexCoord.xy;
|
||||
vec2 texCoord2 = vTexCoord2.xy;
|
||||
vec2 texCoord3 = vTexCoord3.xy;
|
||||
|
||||
vec3 gamma = vec3(0.454);
|
||||
|
||||
/* Get color from texture */
|
||||
vec4 tex = texture(uTexture, texCoord).rgba;
|
||||
//tex = vec4(pow(tex.rgb, gamma), tex.a);
|
||||
|
||||
vec4 tex2 = texture(uTexture2, texCoord2).rgba;
|
||||
//tex2 = vec4(pow(tex2.rgb, gamma), tex2.a);
|
||||
|
||||
vec4 tex3 = texture(uTexture3, texCoord3).rgba;
|
||||
//tex3 = vec4(pow(tex3.rgb, gamma), tex3.a);
|
||||
|
||||
|
||||
vec4 tex2WithTextCoord1 = texture(uTexture2,texCoord);
|
||||
vec4 tex3WithTextCoord1 = texture(uTexture3,texCoord);
|
||||
vec4 tex4WithTextCoord2 = texture(uTexture4,texCoord2);
|
||||
|
||||
vec4 finalColor = vec4(0);
|
||||
vec4 meshResColor = vDiffuseColor;
|
||||
|
||||
vec3 accumLight;
|
||||
if ((UnFogged_IsAffectedByLight_LightCount.y == 1))
|
||||
{
|
||||
vec3 vPos3 = vPosition.xyz;
|
||||
vec3 vNormal3 = normalize(vNormal.xyz);
|
||||
vec3 lightColor = vec3(0.0);
|
||||
int count = int(pc_lights[0].attenuation.w);
|
||||
int index = 0;
|
||||
for (;;)
|
||||
{
|
||||
if ( index >= UnFogged_IsAffectedByLight_LightCount.z) break;
|
||||
LocalLight lightRecord = pc_lights[index];
|
||||
vec3 vectorToLight = ((lightRecord.position).xyz - vPos3);
|
||||
float distanceToLightSqr = dot(vectorToLight, vectorToLight);
|
||||
float distanceToLightInv = inversesqrt(distanceToLightSqr);
|
||||
float distanceToLight = (distanceToLightSqr * distanceToLightInv);
|
||||
float diffuseTerm1 = max((dot(vectorToLight, vNormal3) * distanceToLightInv), 0.0);
|
||||
vec4 attenuationRec = lightRecord.attenuation;
|
||||
|
||||
float attenuation = (1.0 - clamp((distanceToLight - attenuationRec.x) * (1.0 / (attenuationRec.z - attenuationRec.x)), 0.0, 1.0));
|
||||
|
||||
vec3 attenuatedColor = attenuation * lightRecord.color.xyz * attenuationRec.y;
|
||||
lightColor = (lightColor + vec3(attenuatedColor * attenuatedColor * diffuseTerm1 ));
|
||||
index++;
|
||||
}
|
||||
meshResColor.rgb = clamp(lightColor , 0.0, 1.0);
|
||||
accumLight = meshResColor.rgb;
|
||||
//finalColor.rgb = finalColor.rgb * lightColor;
|
||||
}
|
||||
|
||||
float opacity;
|
||||
float finalOpacity = 0.0;
|
||||
vec3 matDiffuse;
|
||||
vec3 specular = vec3(0.0, 0.0, 0.0);
|
||||
vec3 visParams = vec3(1.0, 1.0, 1.0);
|
||||
vec4 genericParams[3];
|
||||
genericParams[0] = vec4( 1.0, 1.0, 1.0, 1.0 );
|
||||
genericParams[1] = vec4( 1.0, 1.0, 1.0, 1.0 );
|
||||
genericParams[2] = vec4( 1.0, 1.0, 1.0, 1.0 );
|
||||
|
||||
#if(FRAGMENTSHADER==0) //Combiners_Opaque
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==1) //Combiners_Mod
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
|
||||
opacity = tex.a * vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==2) //Combiners_Opaque_Mod
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb;
|
||||
opacity = tex2.a * vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==3) //Combiners_Opaque_Mod2x
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb * 2.000000;
|
||||
opacity = tex2.a * 2.000000 * vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==4) //Combiners_Opaque_Mod2xNA
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb * 2.000000;
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==5) //Combiners_Opaque_Opaque
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb;
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==6) //Combiners_Mod_Mod
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb;
|
||||
opacity = tex.a * tex2.a * vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==7) //Combiners_Mod_Mod2x
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb * 2.000000;
|
||||
opacity = tex.a * tex2.a * 2.000000 * vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==8) //Combiners_Mod_Add
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
|
||||
opacity = (tex.a + tex2.a) * vDiffuseColor.a;
|
||||
specular = tex2.rgb;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==9) //Combiners_Mod_Mod2xNA
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb * 2.000000;
|
||||
opacity = tex.a * vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==10) //Combiners_Mod_AddNA
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
|
||||
opacity = tex.a * vDiffuseColor.a;
|
||||
specular = tex2.rgb;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==11) //Combiners_Mod_Opaque
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * tex2.rgb;
|
||||
opacity = tex.a * vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==12) //Combiners_Opaque_Mod2xNA_Alpha
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * tex2.rgb * 2.000000, tex.rgb, vec3(tex.a));
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==13) //Combiners_Opaque_AddAlpha
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
|
||||
specular = tex2.rgb * tex2.a;
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==14) //Combiners_Opaque_AddAlpha_Alpha
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
|
||||
specular = tex2.rgb * tex2.a * (1.000000 - tex.a);
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==15) //Combiners_Opaque_Mod2xNA_Alpha_Add
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * tex2.rgb * 2.000000, tex.rgb, vec3(tex.a));
|
||||
specular = tex3.rgb * tex3.a * genericParams[0].b;
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==16) //Combiners_Mod_AddAlpha
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
|
||||
opacity = tex.a * vDiffuseColor.a;
|
||||
specular = tex2.rgb * tex2.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==17) //Combiners_Mod_AddAlpha_Alpha
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
|
||||
opacity = (tex.a + tex2.a * (0.300000 * tex2.r + 0.590000 * tex2.g + 0.110000 * tex2.b)) * vDiffuseColor.a;
|
||||
specular = tex2.rgb * tex2.a * (1.000000 - tex.a);
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==18) //Combiners_Opaque_Alpha_Alpha
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(mix(tex.rgb, tex2.rgb, vec3(tex2.a)), tex.rgb, vec3(tex.a));
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==19) //Combiners_Opaque_Mod2xNA_Alpha_3s
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * tex2.rgb * 2.000000, tex3.rgb, vec3(tex3.a));
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==20) //Combiners_Opaque_AddAlpha_Wgt
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
|
||||
specular = tex2.rgb * tex2.a * genericParams[0].g;
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==21) //Combiners_Mod_Add_Alpha
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
|
||||
opacity = (tex.a + tex2.a) * vDiffuseColor.a;
|
||||
specular = tex2.rgb * (1.000000 - tex.a);
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==22) //Combiners_Opaque_ModNA_Alpha
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * tex2.rgb, tex.rgb, vec3(tex.a));
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==23) //Combiners_Mod_AddAlpha_Wgt
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
|
||||
opacity = tex.a * vDiffuseColor.a;
|
||||
specular = tex2.rgb * tex2.a * genericParams[0].g;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==24) //Combiners_Opaque_Mod_Add_Wgt
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb, tex2.rgb, vec3(tex2.a));
|
||||
specular = tex.rgb * tex.a * genericParams[0].r;
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==25) //Combiners_Opaque_Mod2xNA_Alpha_UnshAlpha
|
||||
float glowOpacity = clamp((tex3.a * genericParams[0].z), 0.0, 1.0);
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * tex2.rgb * 2.000000, tex.rgb, vec3(tex.a)) * (1.000000 - glowOpacity);
|
||||
specular = tex3.rgb * glowOpacity;
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==26) //Combiners_Mod_Dual_Crossfade
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(mix(tex, tex2WithTextCoord1, vec4(clamp(genericParams[0].g, 0.000000, 1.000000))), tex3WithTextCoord1, vec4(clamp(genericParams[0].b, 0.000000, 1.000000))).rgb;
|
||||
opacity = mix(mix(tex, tex2WithTextCoord1, vec4(clamp(genericParams[0].g, 0.000000, 1.000000))), tex3WithTextCoord1, vec4(clamp(genericParams[0].b, 0.000000, 1.000000))).a * vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==27) //Combiners_Opaque_Mod2xNA_Alpha_Alpha
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(mix(tex.rgb * tex2.rgb * 2.000000, tex3.rgb, vec3(tex3.a)), tex.rgb, vec3(tex.a));
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==28) //Combiners_Mod_Masked_Dual_Crossfade
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(mix(tex, tex2WithTextCoord1, vec4(clamp(genericParams[0].g, 0.000000, 1.000000))), tex3WithTextCoord1, vec4(clamp(genericParams[0].b, 0.000000, 1.000000))).rgb;
|
||||
opacity = mix(mix(tex, tex2WithTextCoord1, vec4(clamp(genericParams[0].g, 0.000000, 1.000000))), tex3WithTextCoord1, vec4(clamp(genericParams[0].b, 0.000000, 1.000000))).a * tex4WithTextCoord2.a * vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==29) //Combiners_Opaque_Alpha
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb, tex2.rgb, vec3(tex2.a));
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==30) //Guild
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * mix(genericParams[0].rgb, tex2.rgb * genericParams[1].rgb, vec3(tex2.a)), tex3.rgb * genericParams[2].rgb, vec3(tex3.a));
|
||||
opacity = tex.a * vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==31) //Guild_NoBorder
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb * mix(genericParams[0].rgb, tex2.rgb * genericParams[1].rgb, vec3(tex2.a));
|
||||
opacity = tex.a * vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==32) //Guild_Opaque
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * mix(tex.rgb * mix(genericParams[0].rgb, tex2.rgb * genericParams[1].rgb, vec3(tex2.a)), tex3.rgb * genericParams[2].rgb, vec3(tex3.a));
|
||||
opacity = vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==33) //Combiners_Mod_Depth
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * tex.rgb;
|
||||
opacity = tex.a * vDiffuseColor.a * visParams.r;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==34) //Illum
|
||||
finalColor = vec4(1.0,1.0,1.0, 1.0);
|
||||
|
||||
//Unusued
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==35) //Combiners_Mod_Mod_Mod_Const
|
||||
matDiffuse = vDiffuseColor.rgb * 2.000000 * (tex * tex2 * tex3 * genericParams[0]).rgb;
|
||||
opacity = (tex * tex2 * tex3 * genericParams[0]).a * vDiffuseColor.a;
|
||||
finalOpacity = opacity * visParams.r;
|
||||
#endif
|
||||
|
||||
finalColor = vec4(makeDiffTerm(matDiffuse, accumLight) + specular, finalOpacity);
|
||||
|
||||
if(finalColor.a < uFogColorAndAlphaTest.w)
|
||||
discard;
|
||||
|
||||
int uUnFogged = UnFogged_IsAffectedByLight_LightCount.x;
|
||||
float uFogEnd = uSunColorAndFogEnd.w;
|
||||
if (uUnFogged == 0) {
|
||||
|
||||
vec3 fogColor = uFogColorAndAlphaTest.xyz;
|
||||
|
||||
float fog_rate = 1.5;
|
||||
float fog_bias = 0.01;
|
||||
|
||||
//vec4 fogHeightPlane = pc_fog.heightPlane;
|
||||
//float heightRate = pc_fog.color_and_heightRate.w;
|
||||
|
||||
float distanceToCamera = length(vPosition.xyz);
|
||||
float z_depth = (distanceToCamera - fog_bias);
|
||||
float expFog = 1.0 / (exp((max(0.0, (z_depth - uSunDirAndFogStart.w)) * fog_rate)));
|
||||
//float height = (dot(fogHeightPlane.xyz, vPosition.xyz) + fogHeightPlane.w);
|
||||
//float heightFog = clamp((height * heightRate), 0, 1);
|
||||
float heightFog = 1.0;
|
||||
expFog = (expFog + heightFog);
|
||||
float endFadeFog = clamp(((uFogEnd - distanceToCamera) / (0.699999988 * uFogEnd)), 0.0, 1.0);
|
||||
float fog_out = min(expFog, endFadeFog);
|
||||
finalColor.rgba = vec4(mix(fogColor.rgb, finalColor.rgb, vec3(fog_out)), finalColor.a);
|
||||
}
|
||||
|
||||
//outputColor = blender_srgb_to_framebuffer_space(finalColor);
|
||||
finalColor.a = clamp(finalColor.a, 0.0, 1.0);
|
||||
outputColor = vec4(finalColor.rgb, finalColor.a);
|
||||
|
||||
}
|
||||
|
||||
#endif //COMPILING_FS
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
[remap]
|
||||
|
||||
importer="glsl"
|
||||
type="RDShaderFile"
|
||||
uid="uid://ilf2tqewt1xj"
|
||||
path="res://.godot/imported/m2_shader.glsl-f5a0cdc7b7a147950d5f7fe94dd0ed5e.res"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://reference/blender-wow-studio-3.4-1.1.0_Experimental/io_scene_wmo/render/shaders/glsl330/m2_shader.glsl"
|
||||
dest_files=["res://.godot/imported/m2_shader.glsl-f5a0cdc7b7a147950d5f7fe94dd0ed5e.res"]
|
||||
|
||||
[params]
|
||||
|
||||
+407
@@ -0,0 +1,407 @@
|
||||
#ifdef COMPILING_VS
|
||||
/* vertex shader code */
|
||||
precision highp float;
|
||||
layout (location = 0) in vec3 aPosition;
|
||||
layout (location = 1) in vec3 aNormal;
|
||||
layout (location = 2) in vec2 aTexCoord;
|
||||
layout (location = 3) in vec2 aTexCoord2;
|
||||
layout (location = 4) in vec2 aTexCoord3;
|
||||
layout (location = 5) in vec4 aColor;
|
||||
layout (location = 6) in vec4 aColor2;
|
||||
|
||||
uniform mat4 uViewProjectionMatrix;
|
||||
uniform mat4 uPlacementMat;
|
||||
uniform vec4 uAmbientBakedTerm; // color to subtract in FixColorVertexAlpha, see CMapObjGroup::FixColorVertexAlpha(CMapObjGroup *mapObjGroup)
|
||||
|
||||
out vec2 vTexCoord;
|
||||
out vec2 vTexCoord2;
|
||||
out vec2 vTexCoord3;
|
||||
out vec4 vColor;
|
||||
out vec4 vColor2;
|
||||
out vec4 vPosition;
|
||||
out vec3 vNormal;
|
||||
|
||||
// trans batch
|
||||
#if(BATCH_TYPE==0)
|
||||
#if(DO_NOT_FIX_ALPHA==1)
|
||||
vec4 FixColorVertexAlpha(vec4 vertexColor)
|
||||
{
|
||||
return vertexColor;
|
||||
}
|
||||
#else
|
||||
vec4 FixColorVertexAlpha(vec4 vertexColor)
|
||||
{
|
||||
vec4 vertexColor = aColor;
|
||||
vertexColor.b -= uAmbientBakedTerm.b;
|
||||
vertexColor.g -= uAmbientBakedTerm.g;
|
||||
vertexColor.r -= uAmbientBakedTerm.r;
|
||||
|
||||
float alpha_factor = mccv.a;
|
||||
|
||||
vertexColor.b = (vertexColor.b - alpha_factor * vertexColor.b) / 2;
|
||||
vertexColor.g = (vertexColor.g - alpha_factor * vertexColor.g) / 2;
|
||||
vertexColor.r = (vertexColor.r - alpha_factor * vertexColor.r) / 2;
|
||||
|
||||
return vertexColor;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// int batch
|
||||
#if(BATCH_TYPE==1 || BATCH_TYPE==2)
|
||||
#if(DO_NOT_FIX_ALPHA==1)
|
||||
vec4 FixColorVertexAlpha(vec4 vertexColor)
|
||||
{
|
||||
vec4 vertexColor = aColor;
|
||||
#if(EXTERIOR==1)
|
||||
vertexColor.a = 255;
|
||||
#else
|
||||
vertexColor.a = 0;
|
||||
#endif
|
||||
|
||||
return vertexColor;
|
||||
}
|
||||
#else
|
||||
vec4 FixColorVertexAlpha(vec4 vertexColor)
|
||||
{
|
||||
vec4 vertexColor = aColor;
|
||||
float new_b = (vertexColor.b * vertexColor.a) / 0.25 + vertexColor.b - uAmbientBakedTerm.b;
|
||||
vertexColor.b = min (1.0, max(new_b / 2, 0));
|
||||
|
||||
float new_g = (vertexColor.g * vertexColor.a) / 0.25 + vertexColor.g - uAmbientBakedTerm.g;
|
||||
vertexColor.g = min (1.0, max(new_g / 2, 0));
|
||||
|
||||
float new_r = (vertexColor.r * vertexColor.a) / 0.25 + vertexColor.r - uAmbientBakedTerm.r;
|
||||
vertexColor.r = min (1.0, max(new_r / 2, 0));
|
||||
|
||||
#if(EXTERIOR==1)
|
||||
vertexColor.a = 255;
|
||||
#else
|
||||
vertexColor.a = 0;
|
||||
#endif
|
||||
|
||||
return vertexColor;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
void main() {
|
||||
vec4 worldPoint = uPlacementMat * vec4(aPosition, 1);
|
||||
|
||||
vec4 cameraPoint = uLookAtMat * worldPoint;
|
||||
|
||||
|
||||
mat4 viewModelMat = uLookAtMat * uPlacementMat;
|
||||
mat3 viewModelMatTransposed = mat3(
|
||||
viewModelMat[0].xyz,
|
||||
viewModelMat[1].xyz,
|
||||
viewModelMat[2].xyz
|
||||
);
|
||||
|
||||
gl_Position = cameraPoint.xyz;
|
||||
|
||||
vertexColor = FixColorVertexAlpha(aColor);
|
||||
|
||||
vPosition = vec4(cameraPoint.xyz, vertexColor.w);
|
||||
vNormal = normalize(viewModelMatTransposed * aNormal);
|
||||
|
||||
vColor.rgba = vec4(vec3(0.5, 0.499989986, 0.5), 1.0);
|
||||
vColor2 = vec4((vertexColor.rgb * 2.0), aColor2.a);
|
||||
|
||||
#if(VERTEXSHADER==-1)
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = aTexCoord2;
|
||||
vTexCoord3 = aTexCoord3;
|
||||
#endif
|
||||
#if(VERTEXSHADER==0) //MapObjDiffuse_T1
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = aTexCoord2; //not used
|
||||
vTexCoord3 = aTexCoord3; //not used
|
||||
#endif
|
||||
#if(VERTEXSHADER==1) //MapObjDiffuse_T1_Refl
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = reflect(normalize(cameraPoint.xyz), vNormal).xy;
|
||||
vTexCoord3 = aTexCoord3; //not used
|
||||
#endif
|
||||
#if(VERTEXSHADER==2) //MapObjDiffuse_T1_Env_T2
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = posToTexCoord(vPosition.xyz, vNormal);;
|
||||
vTexCoord3 = aTexCoord3;
|
||||
#endif
|
||||
#if(VERTEXSHADER==3) //MapObjSpecular_T1
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = aTexCoord2; //not used
|
||||
vTexCoord3 = aTexCoord3; //not used
|
||||
#endif
|
||||
#if(VERTEXSHADER==4) //MapObjDiffuse_Comp
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = aTexCoord2; //not used
|
||||
vTexCoord3 = aTexCoord3; //not used
|
||||
#endif
|
||||
#if(VERTEXSHADER==5) //MapObjDiffuse_Comp_Refl
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = aTexCoord2;
|
||||
vTexCoord3 = reflect(normalize(cameraPoint.xyz), vNormal).xy;
|
||||
#endif
|
||||
#if(VERTEXSHADER==6) //MapObjDiffuse_Comp_Terrain
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = vPosition.xy * -0.239999995;
|
||||
vTexCoord3 = aTexCoord3; //not used
|
||||
#endif
|
||||
#if(VERTEXSHADER==7) //MapObjDiffuse_CompAlpha
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = vPosition.xy * -0.239999995;
|
||||
vTexCoord3 = aTexCoord3; //not used
|
||||
#endif
|
||||
#if(VERTEXSHADER==8) //MapObjParallax
|
||||
vTexCoord = aTexCoord;
|
||||
vTexCoord2 = vPosition.xy * -0.239999995;
|
||||
vTexCoord3 = aTexCoord3; //not used
|
||||
#endif
|
||||
|
||||
//
|
||||
// vs_out.vTexCoord = vTexCoord;
|
||||
// vs_out.vTexCoord2 = vTexCoord2;
|
||||
// vs_out.vTexCoord3 = vTexCoord3;
|
||||
// vs_out.vColor = vColor;
|
||||
// vs_out.vColor2 = vColor2;
|
||||
// vs_out.vPosition = vPosition;
|
||||
// vs_out.vNormal = vNormal;
|
||||
}
|
||||
#endif //COMPILING_VS
|
||||
|
||||
#ifdef COMPILING_FS
|
||||
|
||||
precision highp float;
|
||||
in vec2 vTexCoord;
|
||||
in vec2 vTexCoord2;
|
||||
in vec2 vTexCoord3;
|
||||
in vec4 vColor;
|
||||
in vec4 vColor2;
|
||||
in vec4 vPosition;
|
||||
in vec3 vNormal;
|
||||
|
||||
uniform vec4 uSunDir_FogStart;
|
||||
uniform vec4 uSunColor_uFogEnd;
|
||||
uniform vec4 uAmbientLight;
|
||||
uniform vec4 uAmbientLight2AndIsBatchA;
|
||||
uniform ivec4 UseLitColor_EnableAlpha_PixelShader;
|
||||
uniform vec4 FogColor_AlphaTest;
|
||||
|
||||
uniform sampler2D uTexture;
|
||||
uniform sampler2D uTexture2;
|
||||
uniform sampler2D uTexture3;
|
||||
|
||||
layout (location = 0) out vec4 outputColor;
|
||||
|
||||
vec3 makeDiffTerm(vec3 matDiffuse) {
|
||||
vec3 currColor;
|
||||
vec3 lDiffuse = vec3(0.0, 0.0, 0.0);
|
||||
vec4 viewUp = uViewProjectionMatrix * vec4(0, 0, 1, 0);
|
||||
|
||||
if (UseLitColor_EnableAlpha_PixelShader.x == 1) {
|
||||
//vec3 viewUp = normalize(vec3(0, 0.9, 0.1));
|
||||
vec3 normalizedN = normalize(vNormal);
|
||||
float nDotL = dot(normalizedN, -(uSunDir_FogStart.xyz));
|
||||
float nDotUp = dot(normalizedN, ViewUp.xyz);
|
||||
|
||||
vec3 precomputed = vColor2.rgb;
|
||||
|
||||
vec3 ambientColor = uAmbientLight.rgb;
|
||||
if (uAmbientLight2AndIsBatchA.w > 0.0) {
|
||||
ambientColor = mix(uAmbientLight.rgb, uAmbientLight2AndIsBatchA.rgb, vec3(vPosition.w));
|
||||
}
|
||||
|
||||
vec3 adjAmbient = (ambientColor.rgb + precomputed);
|
||||
vec3 adjHorizAmbient = (ambientColor.rgb + precomputed);
|
||||
vec3 adjGroundAmbient = (ambientColor.rgb + precomputed);
|
||||
|
||||
if ((nDotUp >= 0.0))
|
||||
{
|
||||
currColor = mix(adjHorizAmbient, adjAmbient, vec3(nDotUp));
|
||||
}
|
||||
else
|
||||
{
|
||||
currColor= mix(adjHorizAmbient, adjGroundAmbient, vec3(-(nDotUp)));
|
||||
}
|
||||
|
||||
vec3 skyColor = (currColor * 1.10000002);
|
||||
vec3 groundColor = (currColor* 0.699999988);
|
||||
currColor = mix(groundColor, skyColor, vec3((0.5 + (0.5 * nDotL))));
|
||||
lDiffuse = (uSunColor_uFogEnd.xyz * clamp(nDotL, 0.0, 1.0));
|
||||
} else {
|
||||
currColor = vec3 (1.0, 1.0, 1.0) * uAmbientLight.rgb;
|
||||
}
|
||||
|
||||
vec3 gammaDiffTerm = matDiffuse * (currColor + lDiffuse);
|
||||
vec3 linearDiffTerm = (matDiffuse * matDiffuse) * vec3(0.0);
|
||||
return sqrt(gammaDiffTerm*gammaDiffTerm + linearDiffTerm) ;
|
||||
|
||||
// return matDiffuse * currColor.rgb ;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 tex = texture(uTexture, vTexCoord).rgba ;
|
||||
vec4 tex2 = texture(uTexture2, vTexCoord2).rgba;
|
||||
vec4 tex3 = texture(uTexture3, vTexCoord3).rgba;
|
||||
|
||||
if (UseLitColor_EnableAlpha_PixelShader.y == 1) {
|
||||
if ((tex.a - 0.501960814) < 0.0) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
|
||||
int uPixelShader = UseLitColor_EnableAlpha_PixelShader.z;
|
||||
vec4 finalColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
#if(FRAGMENTSHADER==-1)
|
||||
finalColor = vec4(makeDiffTerm(tex.rgb * vColor.rgb + tex2.rgb*vColor2.bgr), tex.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==0) //MapObjDiffuse
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==1) //MapObjSpecular
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==2) //MapObjMetal
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==3) //MapObjEnv
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
vec3 env = tex2.rgb * tex.a;
|
||||
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse)+env, vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==4) //MapObjOpaque
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==5) //MapObjEnvMetal
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
vec3 env = (tex.rgb * tex.a) * tex2.rgb;
|
||||
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse)+env, vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==6) //MapObjTwoLayerDiffuse
|
||||
vec3 layer1 = tex.rgb;
|
||||
vec3 layer2 = mix(layer1, tex2.rgb, tex2.a);
|
||||
vec3 matDiffuse = (vColor.rgb * 2.0) * mix(layer2, layer1, vColor2.a);
|
||||
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), 1.0);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==7) //MapObjTwoLayerEnvMetal
|
||||
vec4 colorMix = mix(tex2, tex, vColor2.a);
|
||||
vec3 env = (colorMix.rgb * colorMix.a) * tex3.rgb;
|
||||
vec3 matDiffuse = colorMix.rgb * (2.0 * vColor.rgb);
|
||||
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse)+env, vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==8) //MapObjTwoLayerTerrain
|
||||
vec3 layer1 = tex.rgb;
|
||||
vec3 layer2 = tex2.rgb;
|
||||
|
||||
vec3 matDiffuse = ((vColor.rgb * 2.0) * mix(layer2, layer1, vColor2.a));
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==9) //MapObjDiffuseEmissive
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
vec3 env = tex2.rgb * tex2.a * vColor2.a;
|
||||
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse)+env, vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==10) //MapObjMaskedEnvMetal
|
||||
float mixFactor = clamp((tex3.a * vColor2.a), 0.0, 1.0);
|
||||
vec3 matDiffuse =
|
||||
(vColor.rgb * 2.0) *
|
||||
mix(mix(((tex.rgb * tex2.rgb) * 2.0), tex3.rgb, mixFactor), tex.rgb, tex.a);
|
||||
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==11) //MapObjEnvMetalEmissive
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
vec3 env =
|
||||
(
|
||||
((tex.rgb * tex.a) * tex2.rgb) +
|
||||
((tex3.rgb * tex3.a) * vColor2.a)
|
||||
);
|
||||
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse)+env, vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==12) //MapObjTwoLayerDiffuseOpaque
|
||||
vec3 matDiffuse =
|
||||
(vColor.rgb * 2.0) *
|
||||
mix(tex2.rgb, tex.rgb, vColor2.a);
|
||||
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==13) //MapObjTwoLayerDiffuseEmissive
|
||||
vec3 t1diffuse = (tex2.rgb * (1.0 - tex2.a));
|
||||
|
||||
vec3 matDiffuse =
|
||||
((vColor.rgb * 2.0) *
|
||||
mix(t1diffuse, tex.rgb, vColor2.a));
|
||||
|
||||
//TODO: there is env missing here
|
||||
vec3 env = ((tex2.rgb * tex2.a) * (1.0 - vColor2.a));
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse)+env, vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==14) //MapObjAdditiveMaskedEnvMetal
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==15) //MapObjTwoLayerDiffuseMod2x
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==16) //MapObjTwoLayerDiffuseMod2xNA
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==17) //MapObjTwoLayerDiffuseAlpha
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==18) //MapObjLod
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
|
||||
#endif
|
||||
#if(FRAGMENTSHADER==19) //MapObjParallax
|
||||
vec3 matDiffuse = tex.rgb * (2.0 * vColor.rgb);
|
||||
finalColor.rgba = vec4(makeDiffTerm(matDiffuse), vColor.a);
|
||||
#endif
|
||||
|
||||
//finalColor.rgb *= 4.0;
|
||||
|
||||
if(finalColor.a < FogColor_AlphaTest.w)
|
||||
discard;
|
||||
|
||||
vec3 fogColor = FogColor_AlphaTest.xyz;
|
||||
float fog_start = uSunDir_FogStart.w;
|
||||
float fog_end = uSunColor_uFogEnd.w;
|
||||
float fog_rate = 1.5;
|
||||
float fog_bias = 0.01;
|
||||
|
||||
//vec4 fogHeightPlane = pc_fog.heightPlane;
|
||||
//float heightRate = pc_fog.color_and_heightRate.w;
|
||||
|
||||
float distanceToCamera = length(vPosition.xyz);
|
||||
float z_depth = (distanceToCamera - fog_bias);
|
||||
float expFog = 1.0 / (exp((max(0.0, (z_depth - fog_start)) * fog_rate)));
|
||||
//float height = (dot(fogHeightPlane.xyz, vPosition.xyz) + fogHeightPlane.w);
|
||||
//float heightFog = clamp((height * heightRate), 0, 1);
|
||||
float heightFog = 1.0;
|
||||
expFog = (expFog + heightFog);
|
||||
float endFadeFog = clamp(((fog_end - distanceToCamera) / (0.699999988 * fog_end)), 0.0, 1.0);
|
||||
|
||||
finalColor.rgb = mix(fogColor.rgb, finalColor.rgb, vec3(min(expFog, endFadeFog)));
|
||||
|
||||
finalColor.a = 1.0; //do I really need it now?
|
||||
|
||||
outputColor = finalColor;
|
||||
}
|
||||
|
||||
#endif //COMPILING_FS
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
[remap]
|
||||
|
||||
importer="glsl"
|
||||
type="RDShaderFile"
|
||||
uid="uid://6u013f07jwx4"
|
||||
path="res://.godot/imported/wmo_shader.glsl-c651a24623613dfab3d43adcd04efd4d.res"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://reference/blender-wow-studio-3.4-1.1.0_Experimental/io_scene_wmo/render/shaders/glsl330/wmo_shader.glsl"
|
||||
dest_files=["res://.godot/imported/wmo_shader.glsl-c651a24623613dfab3d43adcd04efd4d.res"]
|
||||
|
||||
[params]
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
// M2
|
||||
|
||||
mathfu::vec3 &M2MeshBufferUpdater::getFogColor(EGxBlendEnum blendMode, mathfu::vec3 &originalFogColor) {
|
||||
|
||||
static mathfu::vec3 fog_zero = mathfu::vec3(0,0,0);
|
||||
static mathfu::vec3 fog_half = mathfu::vec3(0.5,0.5,0.5);
|
||||
static mathfu::vec3 fog_one = mathfu::vec3(1.0,1.0,1.0);
|
||||
|
||||
switch (blendMode) {
|
||||
case EGxBlendEnum::GxBlend_Opaque: //Blend_Opaque
|
||||
case EGxBlendEnum::GxBlend_AlphaKey : //Blend_AlphaKey
|
||||
case EGxBlendEnum::GxBlend_Alpha : //Blend_Alpha
|
||||
return originalFogColor;
|
||||
|
||||
case EGxBlendEnum::GxBlend_NoAlphaAdd : //Blend_NoAlphaAdd
|
||||
case EGxBlendEnum::GxBlend_Add : //Blend_Add
|
||||
return fog_zero;
|
||||
|
||||
case EGxBlendEnum::GxBlend_Mod: //Blend_Mod
|
||||
return fog_one;
|
||||
|
||||
case EGxBlendEnum::GxBlend_Mod2x:
|
||||
case EGxBlendEnum::GxBlend_BlendAdd:
|
||||
return fog_half;
|
||||
|
||||
default :
|
||||
debuglog("Unknown blending mode in M2 file")
|
||||
break;
|
||||
}
|
||||
|
||||
return originalFogColor;
|
||||
}
|
||||
|
||||
|
||||
void M2MeshBufferUpdater::fillLights(const M2Object &m2Object, meshWideBlockPS &meshblockPS) {
|
||||
bool BCLoginScreenHack = m2Object.m_api->getConfig()->getBCLightHack();
|
||||
int lightCount = (int) std::min(m2Object.lights.size(), (size_t) 4);
|
||||
for (int j = 0; j < lightCount; j++) {
|
||||
std::string uniformName;
|
||||
mathfu::vec4 attenVec;
|
||||
if (BCLoginScreenHack) {
|
||||
attenVec = mathfu::vec4(m2Object.lights[j].attenuation_start, 1.0, m2Object.lights[j].attenuation_end, m2Object.lights.size());
|
||||
} else {
|
||||
// if ((lights[i].attenuation_end - lights[i].attenuation_start < 0.1)) continue;
|
||||
// attenVec = mathfu::vec4(lights[i].attenuation_start, 1.0, lights[i].attenuation_end, lights.size());
|
||||
attenVec = mathfu::vec4(m2Object.lights[j].attenuation_start, m2Object.lights[j].diffuse_intensity, m2Object.lights[j].attenuation_end, m2Object.lights.size());
|
||||
}
|
||||
|
||||
meshblockPS.pc_lights[j].attenuation = attenVec;//;lights[i].diffuse_color);
|
||||
meshblockPS.pc_lights[j].color = m2Object.lights[j].diffuse_color;
|
||||
|
||||
|
||||
// mathfu::vec4 viewPos = modelView * m2Object.lights[j].position;
|
||||
meshblockPS.pc_lights[j].position = m2Object.lights[j].position;
|
||||
}
|
||||
meshblockPS.LightCount = lightCount;
|
||||
|
||||
}
|
||||
|
||||
// sorting
|
||||
|
||||
void M2Object::sortMaterials(mathfu::mat4 &modelViewMat) {
|
||||
if (!m_loaded) return;
|
||||
|
||||
M2Data * m2File = this->m_m2Geom->getM2Data();
|
||||
M2SkinProfile * skinData = this->m_skinGeom->getSkinData();
|
||||
|
||||
for (int i = 0; i < this->m_meshArray.size(); i++) {
|
||||
//Update info for sorting
|
||||
M2MeshBufferUpdater::updateSortData(this->m_meshArray[i], *this, m_materialArray[i], m2File, skinData, modelViewMat);
|
||||
}
|
||||
}
|
||||
|
||||
void M2MeshBufferUpdater::updateSortData(HGM2Mesh &hmesh, const M2Object &m2Object, M2MaterialInst &materialData,
|
||||
const M2Data * m2File, const M2SkinProfile *m2SkinProfile, mathfu::mat4 &modelViewMat) {
|
||||
|
||||
M2Batch *textMaterial = m2SkinProfile->batches.getElement(materialData.texUnitTexIndex);
|
||||
M2SkinSection *submesh = m2SkinProfile->submeshes.getElement(textMaterial->skinSectionIndex);
|
||||
|
||||
mathfu::vec4 centerBB = mathfu::vec4(mathfu::vec3(submesh->sortCenterPosition), 1.0);
|
||||
|
||||
const mathfu::mat4 &boneMat = m2Object.bonesMatrices[submesh->centerBoneIndex];
|
||||
centerBB = modelViewMat * (boneMat * centerBB);
|
||||
|
||||
float value = centerBB.xyz().Length();
|
||||
|
||||
if (textMaterial->flags & 3) {
|
||||
mathfu::vec4 resultPoint;
|
||||
|
||||
if ( value > 0.00000023841858 ) {
|
||||
resultPoint = centerBB * (1.0f / value);
|
||||
} else {
|
||||
resultPoint = centerBB;
|
||||
}
|
||||
|
||||
mathfu::mat4 mat4 = modelViewMat * boneMat;
|
||||
float dist = mat4.GetColumn(3).xyz().Length();
|
||||
float sortDist = dist * submesh->sortRadius;
|
||||
|
||||
resultPoint *= sortDist;
|
||||
|
||||
if (textMaterial->flags & 1) {
|
||||
value = (centerBB - resultPoint).xyz().Length();
|
||||
} else {
|
||||
value = (centerBB + resultPoint).xyz().Length();
|
||||
}
|
||||
}
|
||||
|
||||
hmesh->setSortDistance(value);
|
||||
|
||||
|
||||
static inline bool sortMeshes(const HGMesh a, const HGMesh b) {
|
||||
auto* pA = a.get();
|
||||
auto* pB = b.get();
|
||||
|
||||
if (pA->getIsTransparent() > pB->getIsTransparent()) {
|
||||
return false;
|
||||
}
|
||||
if (pA->getIsTransparent() < pB->getIsTransparent()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pA->getMeshType() > pB->getMeshType()) {
|
||||
return false;
|
||||
}
|
||||
if (pA->getMeshType() < pB->getMeshType()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pA->m_renderOrder != pB->m_renderOrder ) {
|
||||
if (!pA->getIsTransparent()) {
|
||||
return pA->m_renderOrder < pB->m_renderOrder;
|
||||
} else {
|
||||
return pA->m_renderOrder > pB->m_renderOrder;
|
||||
}
|
||||
}
|
||||
|
||||
if (pA->m_isSkyBox > pB->m_isSkyBox) {
|
||||
return true;
|
||||
}
|
||||
if (pA->m_isSkyBox < pB->m_isSkyBox) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pA->getMeshType() == MeshType::eM2Mesh && pA->getIsTransparent() && pB->getIsTransparent()) {
|
||||
if (pA->m_priorityPlane != pB->m_priorityPlane) {
|
||||
return pB->m_priorityPlane > pA->m_priorityPlane;
|
||||
}
|
||||
|
||||
if (pA->m_sortDistance > pB->m_sortDistance) {
|
||||
return true;
|
||||
}
|
||||
if (pA->m_sortDistance < pB->m_sortDistance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pA->m_m2Object > pB->m_m2Object) {
|
||||
return true;
|
||||
}
|
||||
if (pA->m_m2Object < pB->m_m2Object) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pB->m_layer != pA->m_layer) {
|
||||
return pB->m_layer < pA->m_layer;
|
||||
}
|
||||
}
|
||||
|
||||
if (pA->getMeshType() == MeshType::eParticleMesh && pB->getMeshType() == MeshType::eParticleMesh) {
|
||||
if (pA->m_priorityPlane != pB->m_priorityPlane) {
|
||||
return pB->m_priorityPlane > pA->m_priorityPlane;
|
||||
}
|
||||
|
||||
if (pA->m_sortDistance > pB->m_sortDistance) {
|
||||
return true;
|
||||
}
|
||||
if (pA->m_sortDistance < pB->m_sortDistance) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pA->m_bindings != pB->m_bindings) {
|
||||
return pA->m_bindings > pB->m_bindings;
|
||||
}
|
||||
|
||||
if (pA->getGxBlendMode() != pB->getGxBlendMode()) {
|
||||
return pA->getGxBlendMode() < pB->getGxBlendMode();
|
||||
}
|
||||
|
||||
int minTextureCount = pA->m_textureCount < pB->m_textureCount ? pA->m_textureCount : pB->m_textureCount;
|
||||
for (int i = 0; i < minTextureCount; i++) {
|
||||
if (pA->m_texture[i] != pB->m_texture[i]) {
|
||||
return pA->m_texture[i] < pB->m_texture[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (pA->m_textureCount != pB->m_textureCount) {
|
||||
return pA->m_textureCount < pB->m_textureCount;
|
||||
}
|
||||
|
||||
if (pA->m_start != pB->m_start) {
|
||||
return pA->m_start < pB->m_start;
|
||||
}
|
||||
if (pA->m_end != pB->m_end) {
|
||||
return pA->m_end < pB->m_end;
|
||||
}
|
||||
|
||||
|
||||
return a > b;
|
||||
}
|
||||
|
||||
|
||||
void M2Object::collectMeshes(std::vector<HGMesh> &renderedThisFrame, int renderOrder) {
|
||||
if (!m_loaded) return;
|
||||
|
||||
M2SkinProfile* skinData = this->m_skinGeom->getSkinData();
|
||||
|
||||
int minBatch = m_api->getConfig()->getM2MinBatch();
|
||||
int maxBatch = std::min(m_api->getConfig()->getM2MaxBatch(), (const int &) this->m_meshArray.size());
|
||||
|
||||
for (int i = minBatch; i < maxBatch; i++) {
|
||||
float finalTransparency = M2MeshBufferUpdater::calcFinalTransparency(*this, i, skinData);
|
||||
if ((finalTransparency < 0.0001) ) continue;
|
||||
|
||||
this->m_meshArray[i]->setRenderOrder(renderOrder);
|
||||
renderedThisFrame.push_back(this->m_meshArray[i]);
|
||||
}
|
||||
|
||||
// renderedThisFrame.push_back(occlusionQuery);
|
||||
}
|
||||
|
||||
float M2MeshBufferUpdater::calcFinalTransparency(const M2Object &m2Object, int batchIndex, M2SkinProfile * m2SkinProfile){
|
||||
auto textMaterial = m2SkinProfile->batches[batchIndex];
|
||||
int renderFlagIndex = textMaterial->materialIndex;
|
||||
|
||||
mathfu::vec4 meshColor = M2Object::getCombinedColor(m2SkinProfile, batchIndex, m2Object.subMeshColors);
|
||||
float transparency = M2Object::getTransparency(m2SkinProfile, batchIndex, m2Object.transparencies);
|
||||
float finalTransparency = meshColor.w;
|
||||
if ( textMaterial->textureCount && !(textMaterial->flags & 0x40)) {
|
||||
finalTransparency *= transparency;
|
||||
}
|
||||
|
||||
return finalTransparency;
|
||||
|
||||
}
|
||||
|
||||
enum class MeshType {
|
||||
eGeneralMesh = 0,
|
||||
eAdtMesh = 1,
|
||||
eWmoMesh = 2,
|
||||
eOccludingQuery = 3,
|
||||
eM2Mesh = 4,
|
||||
eParticleMesh = 5,
|
||||
};
|
||||
|
||||
m_isTransparent = m_blendMode > EGxBlendEnum::GxBlend_AlphaKey || !m_depthWrite ;
|
||||
|
||||
|
||||
meshTemplate.blendMode = M2BlendingModeToEGxBlendEnum[material.blending_mode];
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
RENDER_ENGINE_DEBUG = False
|
||||
|
||||
|
||||
def render_debug(message: str):
|
||||
global RENDER_ENGINE_DEBUG
|
||||
|
||||
if RENDER_ENGINE_DEBUG:
|
||||
print('Debug:', message)
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
import bpy
|
||||
import gpu
|
||||
|
||||
import mathutils
|
||||
|
||||
from typing import Union
|
||||
from bgl import *
|
||||
|
||||
from ...wbs_kernel.render import CWMODrawingBatch
|
||||
from ...wbs_kernel.render import OpenGLUtils
|
||||
from .shaders import WMOShaderPermutations, EGxBLend
|
||||
from .drawing_material import WMODrawingMaterial
|
||||
from ..drawing_elements import ElementTypes
|
||||
from ..utils import render_debug
|
||||
from ..bgl_ext import glCheckError
|
||||
|
||||
|
||||
class WMODrawingBatch:
|
||||
c_batch: CWMODrawingBatch
|
||||
|
||||
# control
|
||||
mesh_type: int = ElementTypes.WmoMesh
|
||||
shader: gpu.types.GPUShader
|
||||
bl_batch_vert_shader_id: int
|
||||
bl_batch_frag_shader_id: int
|
||||
|
||||
# uniform data
|
||||
draw_material: Union[CWMODrawingBatch, None]
|
||||
|
||||
def __init__(self
|
||||
, c_batch: 'CWMODrawingBatch'
|
||||
, draw_obj: 'WMODrawingObject'
|
||||
, context: bpy.types.Context):
|
||||
|
||||
self.c_batch = c_batch
|
||||
self.context = context
|
||||
self.draw_obj = draw_obj
|
||||
|
||||
self.tag_free = False
|
||||
|
||||
self.mat_id = self.c_batch.get_mat_id()
|
||||
|
||||
try:
|
||||
self.draw_material = self.draw_obj.draw_mgr.draw_materials.get(
|
||||
self.draw_obj.bl_obj.data.materials[self.mat_id].name)
|
||||
|
||||
except IndexError:
|
||||
self.draw_material = None
|
||||
|
||||
self.create_vao()
|
||||
|
||||
self.draw_obj.draw_mgr.draw_elements.add_batch(self)
|
||||
|
||||
render_debug('Instantiated drawing batch for object \"{}\"'.format(draw_obj.bl_obj.name))
|
||||
|
||||
@property
|
||||
def is_transparent(self) -> bool:
|
||||
return False
|
||||
|
||||
@property
|
||||
def priority_plane(self) -> int:
|
||||
return 0
|
||||
|
||||
@property
|
||||
def layer(self) -> int:
|
||||
return 0
|
||||
|
||||
@property
|
||||
def is_skybox(self) -> bool:
|
||||
return False
|
||||
|
||||
@property
|
||||
def bb_center(self) -> mathutils.Vector:
|
||||
return mathutils.Vector(self.c_batch.bb_center)
|
||||
|
||||
@property
|
||||
def sort_radius(self) -> float:
|
||||
return self.c_batch.sort_radius
|
||||
|
||||
@property
|
||||
def sort_distance(self):
|
||||
|
||||
perspective_mat = self.draw_obj.draw_mgr.region_3d.perspective_matrix
|
||||
bb_center = self.draw_obj.bl_obj.matrix_world @ self.bb_center
|
||||
|
||||
value = (perspective_mat.to_translation() - bb_center).length
|
||||
|
||||
if self.draw_material.is_inverted or self.draw_material.is_transformed:
|
||||
result_point = bb_center * (1.0 / value) if value > 0.00000023841858 else bb_center
|
||||
|
||||
sort_dist = perspective_mat.to_translation().length * self.sort_radius
|
||||
|
||||
result_point *= sort_dist
|
||||
|
||||
value = (bb_center - result_point).length \
|
||||
if self.draw_material.is_inverted else (bb_center + result_point).length
|
||||
|
||||
return value
|
||||
|
||||
def create_vao(self):
|
||||
self.shader = self.determine_valid_shader()
|
||||
self.c_batch.set_program(self.shader.program)
|
||||
self.c_batch.create_vao()
|
||||
glCheckError('Create VAO')
|
||||
|
||||
def ensure_context(self):
|
||||
mat_test = self.draw_material.bl_material
|
||||
|
||||
if not mat_test:
|
||||
self.tag_free = True
|
||||
|
||||
return self.tag_free
|
||||
|
||||
def _set_active_textures(self):
|
||||
|
||||
gl_texture_slots = (
|
||||
GL_TEXTURE0,
|
||||
GL_TEXTURE1,
|
||||
GL_TEXTURE2,
|
||||
GL_TEXTURE3
|
||||
)
|
||||
|
||||
for i, gl_slot in enumerate(gl_texture_slots):
|
||||
bind_code = self.draw_material.get_bindcode(i)
|
||||
|
||||
if bind_code:
|
||||
glActiveTexture(gl_slot)
|
||||
glBindTexture(GL_TEXTURE_2D, bind_code)
|
||||
|
||||
def determine_valid_shader(self) -> gpu.types.GPUShader:
|
||||
|
||||
shaders = WMOShaderPermutations()
|
||||
|
||||
if self.draw_material:
|
||||
|
||||
shader_rec = WMOShaderPermutations.get_shader_combo(int(self.draw_material.bl_material.wow_wmo_material.shader))
|
||||
self.bl_batch_vert_shader_id = shader_rec.vertex_shader
|
||||
self.bl_batch_frag_shader_id = shader_rec.pixel_shader
|
||||
|
||||
return shaders.get_shader_by_id(self.bl_batch_vert_shader_id,
|
||||
self.bl_batch_frag_shader_id)
|
||||
else:
|
||||
return shaders.default_shader
|
||||
|
||||
def draw(self):
|
||||
|
||||
render_debug('Drawing batch for object \"{}\"'.format(self.draw_obj.bl_obj.name))
|
||||
|
||||
bl_obj = self.draw_obj.bl_obj
|
||||
|
||||
if not bl_obj.visible_get():
|
||||
return
|
||||
|
||||
if self.tag_free:
|
||||
return
|
||||
|
||||
if self.draw_material:
|
||||
self.draw_wmo_batch()
|
||||
else:
|
||||
self.draw_fallback()
|
||||
|
||||
def draw_fallback(self):
|
||||
|
||||
glCheckError('drawfallback pre')
|
||||
|
||||
self.shader = self.determine_valid_shader()
|
||||
self.shader.bind()
|
||||
self.c_batch.set_program(self.shader.program)
|
||||
|
||||
self.shader.uniform_float('uViewProjectionMatrix', self.draw_obj.draw_mgr.region_3d.perspective_matrix)
|
||||
|
||||
self.shader.uniform_float('uPlacementMatrix', self.draw_obj.bl_obj.matrix_world)
|
||||
self.shader.uniform_float('uSunDirAndFogStart', self.draw_obj.draw_mgr.sun_dir_and_fog_start)
|
||||
self.shader.uniform_float('uSunColorAndFogEnd', self.draw_obj.draw_mgr.sun_color_and_fog_end)
|
||||
self.shader.uniform_float('uAmbientLight', self.draw_obj.draw_mgr.ambient_light)
|
||||
self.shader.uniform_float('uFogColorAndAlphaTest', (*self.draw_obj.draw_mgr.fog_color, 1.0 / 255.0))
|
||||
self.shader.uniform_int('UnFogged_IsAffectedByLight_LightCount', (False, True, 0))
|
||||
|
||||
glEnable(GL_DEPTH_TEST)
|
||||
|
||||
self.c_batch.draw()
|
||||
|
||||
glDisable(GL_DEPTH_TEST)
|
||||
|
||||
gpu.shader.unbind()
|
||||
|
||||
glCheckError('draw fallback post')
|
||||
|
||||
def draw_wmo_batch(self):
|
||||
|
||||
glCheckError('draw')
|
||||
|
||||
#render_debug('Drawing batch for object \"{}\"'.format(self.draw_obj.bl_obj.name))
|
||||
|
||||
color_name = self.draw_material.bl_material.wow_m2_material.color
|
||||
transparency_name = self.draw_material.bl_material.wow_m2_material.transparency
|
||||
color = self.context.scene.wow_m2_colors[color_name].color if color_name else (1.0, 1.0, 1.0, 1.0)
|
||||
|
||||
if transparency_name:
|
||||
transparency_rec = self.context.scene.wow_m2_transparency.get(transparency_name)
|
||||
transparency = transparency_rec.value if transparency_rec else 1.0
|
||||
else:
|
||||
transparency = 1.0
|
||||
|
||||
combined_color = (*color[:3], color[3] * transparency)
|
||||
|
||||
u_alpha_test = 128.0 / 255.0 * combined_color[3] \
|
||||
if self.draw_material.blend_mode.index == EGxBLend.AlphaKey.index else 1.0 / 255.0 # Maybe move this to shader logic?
|
||||
|
||||
self._set_active_textures()
|
||||
|
||||
self.shader = self.determine_valid_shader()
|
||||
self.shader.bind()
|
||||
glCheckError('Pre-link program')
|
||||
self.c_batch.set_program(self.shader.program)
|
||||
glCheckError('Post-link program')
|
||||
|
||||
# draw
|
||||
if self.draw_material.depth_culling:
|
||||
glEnable(GL_DEPTH_TEST)
|
||||
|
||||
glDepthMask(GL_TRUE if self.draw_material.depth_write else GL_FALSE)
|
||||
|
||||
if self.draw_material.backface_culling:
|
||||
glEnable(GL_CULL_FACE)
|
||||
|
||||
if self.draw_material.blend_mode.blending_enabled:
|
||||
glEnable(GL_BLEND)
|
||||
|
||||
if self.is_skybox:
|
||||
glDepthRange(0.998, 1.0)
|
||||
|
||||
glBlendFunc(self.draw_material.blend_mode.src_color, self.draw_material.blend_mode.dest_color)
|
||||
# OpenGLUtils.glBlendFuncSeparate(self.draw_material.blend_mode.src_color,
|
||||
# self.draw_material.blend_mode.dest_color,
|
||||
# self.draw_material.blend_mode.src_alpha,
|
||||
# self.draw_material.blend_mode.dest_alpha)
|
||||
|
||||
self.shader.uniform_float('uViewProjectionMatrix', self.draw_obj.draw_mgr.region_3d.perspective_matrix)
|
||||
|
||||
self.shader.uniform_float('uPlacementMatrix', self.draw_obj.bl_obj.matrix_world)
|
||||
self.shader.uniform_float('uSunDirAndFogStart', self.draw_obj.draw_mgr.sun_dir_and_fog_start)
|
||||
self.shader.uniform_float('uSunColorAndFogEnd', self.draw_obj.draw_mgr.sun_color_and_fog_end)
|
||||
self.shader.uniform_float('uAmbientLight', self.draw_obj.draw_mgr.ambient_light)
|
||||
self.shader.uniform_float('uFogColorAndAlphaTest', (*self.draw_obj.draw_mgr.fog_color, u_alpha_test))
|
||||
self.shader.uniform_int('UnFogged_IsAffectedByLight_LightCount', (self.draw_material.is_unfogged,
|
||||
not self.draw_material.is_unlit, 0))
|
||||
|
||||
try:
|
||||
self.shader.uniform_int('uTexture', 0)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
self.shader.uniform_int('uTexture2', 1)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
self.shader.uniform_int('uTexture3', 2)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
self.shader.uniform_int('uTexture4', 3)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
self.shader.uniform_float('color_Transparency', combined_color)
|
||||
|
||||
self.c_batch.draw()
|
||||
|
||||
if self.is_skybox:
|
||||
glDepthRange(0, 0.996)
|
||||
|
||||
if self.draw_material.blend_mode.blending_enabled:
|
||||
glDisable(GL_BLEND)
|
||||
|
||||
if self.draw_material.backface_culling:
|
||||
glDisable(GL_CULL_FACE)
|
||||
|
||||
glDepthMask(GL_FALSE if self.draw_material.depth_write else GL_TRUE)
|
||||
|
||||
if self.draw_material.depth_culling:
|
||||
glDisable(GL_DEPTH_TEST)
|
||||
|
||||
gpu.shader.unbind()
|
||||
|
||||
glCheckError('draw end')
|
||||
|
||||
def free(self):
|
||||
|
||||
if self.tag_free:
|
||||
return
|
||||
|
||||
self.tag_free = True
|
||||
self.draw_obj.draw_mgr.draw_elements.remove_batch(self)
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
import bpy
|
||||
|
||||
from .shaders import EGxBlendRecord, WMOBlendingModeToEGxBlend
|
||||
|
||||
|
||||
class WMODrawingMaterial:
|
||||
__slots__ = (
|
||||
'draw_mgr',
|
||||
'bl_material_name',
|
||||
'blend_mode',
|
||||
'backface_culling',
|
||||
'is_unlit',
|
||||
'is_unfogged',
|
||||
'is_exterior_lit',
|
||||
'night_glow',
|
||||
'is_window',
|
||||
'clamp_s',
|
||||
'clamp_t',
|
||||
)
|
||||
|
||||
blend_mode: EGxBlendRecord
|
||||
backface_culling: bool
|
||||
is_unlit: bool
|
||||
is_unfogged: bool
|
||||
is_exterior_lit: bool
|
||||
night_glow: bool
|
||||
is_window: bool
|
||||
clamp_s: bool
|
||||
clamp_t: bool
|
||||
|
||||
def __init__(self, material: bpy.types.Material):
|
||||
self.bl_material_name = material.name
|
||||
|
||||
self.update_uniform_data()
|
||||
|
||||
@property
|
||||
def bl_material(self):
|
||||
try:
|
||||
return bpy.data.materials[self.bl_material_name]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def get_texture(self, tex_index: int):
|
||||
mat = self.bl_material
|
||||
|
||||
if mat:
|
||||
return getattr(mat.wow_wmo_material, 'diff_texture_{}'.format(tex_index + 1))
|
||||
|
||||
@property
|
||||
def texture_count(self):
|
||||
mat = self.bl_material
|
||||
counter = 0
|
||||
|
||||
if mat:
|
||||
for i in range(2):
|
||||
tex = getattr(mat.wow_wmo_material, 'diff_texture_{}'.format(i + 1))
|
||||
if tex:
|
||||
counter += 1
|
||||
|
||||
return counter
|
||||
|
||||
def update_uniform_data(self):
|
||||
|
||||
bl_material = self.bl_material
|
||||
|
||||
if not bl_material:
|
||||
return
|
||||
|
||||
self.blend_mode = WMOBlendingModeToEGxBlend[int(self.bl_material.wow_wmo_material.blending_mode)]
|
||||
self.backface_culling = '4' not in bl_material.wow_wmo_material.render_flags
|
||||
self.is_unlit = '1' in bl_material.wow_wmo_material.render_flags
|
||||
self.is_unfogged = '2' in bl_material.wow_wmo_material.render_flags
|
||||
self.is_exterior_lit = '8' in bl_material.wow_wmo_material.render_flags
|
||||
self.night_glow = '16' in bl_material.wow_wmo_material.render_flags
|
||||
self.is_window = '32' in bl_material.wow_wmo_material.render_flags
|
||||
self.clamp_s = '64' in bl_material.wow_wmo_material.render_flags
|
||||
self.clamp_t = '128' in bl_material.wow_wmo_material.render_flags
|
||||
|
||||
def get_bindcode(self, tex_index: int) -> int:
|
||||
|
||||
texture = self.get_texture(tex_index)
|
||||
|
||||
if texture:
|
||||
if not texture.bindcode:
|
||||
texture.gl_load()
|
||||
|
||||
return texture.bindcode
|
||||
|
||||
return 0
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
import traceback
|
||||
import bpy
|
||||
import numpy as np
|
||||
|
||||
from mathutils import Matrix
|
||||
from typing import List
|
||||
|
||||
from .drawing_batch import M2DrawingBatch
|
||||
from ..utils import render_debug
|
||||
from ...wbs_kernel.render import CM2DrawingMesh, CM2DrawingBatch
|
||||
from ..bgl_ext import glCheckError
|
||||
|
||||
|
||||
class M2DrawingObject:
|
||||
|
||||
batches: List[CM2DrawingBatch]
|
||||
|
||||
def __init__(self
|
||||
, bl_obj: bpy.types.Object
|
||||
, drawing_mgr: 'M2DrawingManager'
|
||||
, context: bpy.types.Context
|
||||
, is_skybox: bool = False):
|
||||
|
||||
self.context = context
|
||||
self.draw_mgr = drawing_mgr
|
||||
self.bl_obj_name = bl_obj.name
|
||||
self.is_skybox = is_skybox
|
||||
self.is_dirty = True
|
||||
self.is_batching_valid = False
|
||||
|
||||
self.mesh_ptr = bl_obj.data.as_pointer()
|
||||
self.c_mesh = CM2DrawingMesh(self.mesh_ptr)
|
||||
self.batches = []
|
||||
bl_obj.data.calc_loop_triangles()
|
||||
render_debug('Initialized drawing object \"{}\"'.format(self.bl_obj_name))
|
||||
|
||||
self.update_geometry()
|
||||
|
||||
def update_geometry(self, bl_obj: bpy.types.Object = None):
|
||||
if bl_obj:
|
||||
self.c_mesh.update_mesh_pointer(bl_obj.data.as_pointer())
|
||||
bl_obj.data.calc_loop_triangles()
|
||||
|
||||
self.is_batching_valid = self.c_mesh.update_geometry(not(self.context.screen.is_animation_playing or self.bl_obj.mode != 'OBJECT'))
|
||||
|
||||
self.is_dirty = True
|
||||
|
||||
def update_geometry_opengl(self, bl_obj: bpy.types.Object = None):
|
||||
|
||||
self.c_mesh.update_buffers()
|
||||
|
||||
if not self.is_batching_valid:
|
||||
|
||||
for batch in self.batches:
|
||||
batch.free()
|
||||
|
||||
self.batches = \
|
||||
[M2DrawingBatch(c_batch, self, self.context) for c_batch in self.c_mesh.get_drawing_batches()]
|
||||
|
||||
self.is_dirty = False
|
||||
|
||||
@property
|
||||
def bl_obj(self):
|
||||
|
||||
try:
|
||||
return bpy.data.objects[self.bl_obj_name]
|
||||
except KeyError:
|
||||
self.free()
|
||||
|
||||
def free(self):
|
||||
|
||||
for batch in self.batches:
|
||||
batch.free()
|
||||
|
||||
del self.draw_mgr.m2_objects[self.bl_obj_name]
|
||||
|
||||
render_debug('Freed drawing object \"{}\"'.format(self.bl_obj_name))
|
||||
|
||||
'''
|
||||
def update_bone_matrices(self):
|
||||
rig = self.bl_rig
|
||||
for i, pbone in enumerate(rig.pose.bones):
|
||||
self.bone_matrices[i] = [j[i] for i in range(4) for j in pbone.matrix_channel]
|
||||
|
||||
def create_batches_from_armature(self, rig: bpy.types.Object):
|
||||
|
||||
for obj in filter(lambda x: x.type == 'MESH', rig.children):
|
||||
|
||||
# Limit bone influences to 4. TODO: rework to be non-destructive!
|
||||
"""
|
||||
if obj.vertex_groups:
|
||||
active_obj = bpy.context.view_layer.objects.active
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
bpy.ops.object.vertex_group_limit_total()
|
||||
bpy.context.view_layer.objects.active = active_obj
|
||||
|
||||
"""
|
||||
|
||||
self.create_batch_from_object(obj)
|
||||
|
||||
def create_batch_from_object(self, obj: bpy.types.Object):
|
||||
self.batches[obj.name] = M2DrawingBatch(obj, self, self.context)
|
||||
|
||||
'''
|
||||
|
||||
|
||||
|
||||
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
import os
|
||||
import gpu
|
||||
|
||||
from enum import IntEnum
|
||||
from ctypes import c_uint, c_uint8
|
||||
from collections import namedtuple
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from ...utils.misc import singleton, Sequence
|
||||
from ..shaders import ShaderPermutationsManager
|
||||
from bgl import *
|
||||
|
||||
|
||||
class WMOPixelShader(IntEnum):
|
||||
NoShader = -1,
|
||||
MapObjDiffuse = 0,
|
||||
MapObjSpecular = 1,
|
||||
MapObjMetal = 2,
|
||||
MapObjEnv = 3,
|
||||
MapObjOpaque = 4,
|
||||
MapObjEnvMetal = 5,
|
||||
MapObjTwoLayerDiffuse = 6, # MapObjComposite
|
||||
MapObjTwoLayerEnvMetal = 7,
|
||||
MapObjTwoLayerTerrain = 8,
|
||||
MapObjDiffuseEmissive = 9,
|
||||
MapObjMaskedEnvMetal = 10,
|
||||
MapObjEnvMetalEmissive = 11,
|
||||
MapObjTwoLayerDiffuseOpaque = 12,
|
||||
MapObjTwoLayerDiffuseEmissive = 13,
|
||||
MapObjAdditiveMaskedEnvMetal = 14,
|
||||
MapObjTwoLayerDiffuseMod2x = 15,
|
||||
MapObjTwoLayerDiffuseMod2xNA = 16,
|
||||
MapObjTwoLayerDiffuseAlpha = 17,
|
||||
MapObjLod = 18,
|
||||
MapObjParallax = 19
|
||||
|
||||
|
||||
class WMOVertexShader(IntEnum):
|
||||
NoShader = -1,
|
||||
MapObjDiffuse_T1 = 0,
|
||||
MapObjDiffuse_T1_Refl = 1,
|
||||
MapObjDiffuse_T1_Env_T2 = 2,
|
||||
MapObjSpecular_T1 = 3,
|
||||
MapObjDiffuse_Comp = 4,
|
||||
MapObjDiffuse_Comp_Refl = 5,
|
||||
MapObjDiffuse_Comp_Terrain = 6,
|
||||
MapObjDiffuse_CompAlpha = 7,
|
||||
MapObjParallax = 8,
|
||||
|
||||
|
||||
EGxBlendRecord = namedtuple('EGxBlendRecord',
|
||||
['blending_enabled', 'src_color', 'dest_color', 'src_alpha', 'dest_alpha', 'index'])
|
||||
|
||||
|
||||
class EGxBLend(metaclass=Sequence):
|
||||
Opaque = EGxBlendRecord(False, GL_ONE, GL_ZERO, GL_ONE, GL_ZERO, 0)
|
||||
AlphaKey = EGxBlendRecord(False, GL_ONE, GL_ZERO, GL_ONE, GL_ZERO, 1)
|
||||
Alpha = EGxBlendRecord(True, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, 2)
|
||||
Add = EGxBlendRecord(True, GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE, 3)
|
||||
Mod = EGxBlendRecord(True, GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO, 4)
|
||||
Mod2x = EGxBlendRecord(True, GL_DST_COLOR, GL_SRC_COLOR, GL_DST_ALPHA, GL_SRC_ALPHA, 5)
|
||||
ModAdd = EGxBlendRecord(True, GL_DST_COLOR, GL_ONE, GL_DST_ALPHA, GL_ONE, 6)
|
||||
InvSrcAlphaAdd = EGxBlendRecord(True, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, 7)
|
||||
InvSrcAlphaOpaque = EGxBlendRecord(True, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, 8)
|
||||
SrcAlphaOpaque = EGxBlendRecord(True, GL_SRC_ALPHA, GL_ZERO, GL_SRC_ALPHA, GL_ZERO, 9)
|
||||
NoAlphaAdd = EGxBlendRecord(True, GL_ONE, GL_ONE, GL_ZERO, GL_ONE, 10)
|
||||
ConstantAlpha = EGxBlendRecord(True, GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA, GL_CONSTANT_ALPHA,
|
||||
GL_ONE_MINUS_CONSTANT_ALPHA, 11)
|
||||
Screen = EGxBlendRecord(True, GL_ONE_MINUS_DST_COLOR, GL_ONE, GL_ONE, GL_ZERO, 12)
|
||||
BlendAdd = EGxBlendRecord(True, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, 13)
|
||||
|
||||
|
||||
class WMOBlendingModeToEGxBlend(metaclass=Sequence):
|
||||
|
||||
Blend_Opaque = EGxBLend.Opaque
|
||||
Blend_AlphaKey = EGxBLend.AlphaKey
|
||||
Blend_Alpha = EGxBLend.Alpha
|
||||
Blend_NoAlphaAdd = EGxBLend.NoAlphaAdd
|
||||
Blend_Add = EGxBLend.Add
|
||||
Blend_Mod = EGxBLend.Mod
|
||||
Blend_Mod2x = EGxBLend.Mod2x
|
||||
Blend_BlendAdd = EGxBLend.BlendAdd
|
||||
|
||||
|
||||
WMOShaderTableRecord = namedtuple('WMOShaderTableRecord', ['pixel_shader', 'vertex_shader'])
|
||||
|
||||
|
||||
class WMOShaderTable(metaclass=Sequence):
|
||||
MapObjDiffuse = WMOShaderTableRecord(WMOPixelShader.MapObjDiffuse, WMOVertexShader.MapObjDiffuse_T1)
|
||||
|
||||
MapObjSpecular = WMOShaderTableRecord(WMOPixelShader.MapObjSpecular, WMOVertexShader.MapObjSpecular_T1)
|
||||
|
||||
MapObjMetal = WMOShaderTableRecord(WMOPixelShader.MapObjMetal, WMOVertexShader.MapObjSpecular_T1)
|
||||
|
||||
MapObjEnv = WMOShaderTableRecord(WMOPixelShader.MapObjEnv, WMOVertexShader.MapObjDiffuse_T1_Refl)
|
||||
|
||||
MapObjOpaque = WMOShaderTableRecord(WMOPixelShader.MapObjOpaque, WMOVertexShader.MapObjDiffuse_T1)
|
||||
|
||||
MapObjEnvMetal = WMOShaderTableRecord(WMOPixelShader.MapObjEnvMetal, WMOVertexShader.MapObjDiffuse_T1_Refl)
|
||||
|
||||
MapObjTwoLayerDiffuse = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerDiffuse,
|
||||
WMOVertexShader.MapObjDiffuse_Comp)
|
||||
|
||||
MapObjTwoLayerEnvMetal = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerEnvMetal,
|
||||
WMOVertexShader.MapObjDiffuse_T1)
|
||||
|
||||
TwoLayerTerrain = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerTerrain,
|
||||
WMOVertexShader.MapObjDiffuse_Comp_Terrain)
|
||||
|
||||
MapObjDiffuseEmissive = WMOShaderTableRecord(WMOPixelShader.MapObjDiffuseEmissive,
|
||||
WMOVertexShader.MapObjDiffuse_Comp)
|
||||
|
||||
waterWindow = WMOShaderTableRecord(WMOPixelShader.NoShader,
|
||||
WMOVertexShader.NoShader)
|
||||
|
||||
MapObjMaskedEnvMetal = WMOShaderTableRecord(WMOPixelShader.MapObjMaskedEnvMetal,
|
||||
WMOVertexShader.MapObjDiffuse_T1_Env_T2)
|
||||
|
||||
MapObjEnvMetalEmissive = WMOShaderTableRecord(WMOPixelShader.MapObjEnvMetalEmissive,
|
||||
WMOVertexShader.MapObjDiffuse_T1_Env_T2)
|
||||
|
||||
TwoLayerDiffuseOpaque = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerDiffuseOpaque,
|
||||
WMOVertexShader.MapObjDiffuse_Comp)
|
||||
|
||||
submarineWindow = WMOShaderTableRecord(WMOPixelShader.NoShader, WMOVertexShader.NoShader)
|
||||
|
||||
TwoLayerDiffuseEmissive = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerDiffuseEmissive,
|
||||
WMOVertexShader.MapObjDiffuse_Comp)
|
||||
|
||||
MapObjDiffuseTerrain = WMOShaderTableRecord(WMOPixelShader.MapObjDiffuse,
|
||||
WMOVertexShader.MapObjDiffuse_T1)
|
||||
|
||||
MapObjAdditiveMaskedEnvMetal = WMOShaderTableRecord(WMOPixelShader.MapObjAdditiveMaskedEnvMetal,
|
||||
WMOVertexShader.MapObjDiffuse_T1_Env_T2)
|
||||
|
||||
MapObjTwoLayerDiffuseMod2x = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerDiffuseMod2x,
|
||||
WMOVertexShader.MapObjDiffuse_CompAlpha)
|
||||
|
||||
MapObjTwoLayerDiffuseMod2xNA = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerDiffuseMod2xNA,
|
||||
WMOVertexShader.MapObjDiffuse_Comp)
|
||||
|
||||
MapObjTwoLayerDiffuseAlpha = WMOShaderTableRecord(WMOPixelShader.MapObjTwoLayerDiffuseAlpha,
|
||||
WMOVertexShader.MapObjDiffuse_CompAlpha)
|
||||
|
||||
MapObjLod = WMOShaderTableRecord(WMOPixelShader.MapObjLod,
|
||||
WMOVertexShader.MapObjDiffuse_T1)
|
||||
|
||||
MapObjParallax = WMOShaderTableRecord(WMOPixelShader.MapObjParallax,
|
||||
WMOVertexShader.MapObjParallax)
|
||||
|
||||
@singleton
|
||||
class WMOShaderPermutations(ShaderPermutationsManager):
|
||||
|
||||
shader_source_path = 'wmo_shader'
|
||||
|
||||
@staticmethod
|
||||
def get_shader_combo_index(vertex_shader_id: int, pixel_shader_id: int):
|
||||
|
||||
for record in WMOShaderTable:
|
||||
if record.value.vertex_shader == vertex_shader_id and record.value.pixel_shader == pixel_shader_id:
|
||||
return record.index
|
||||
|
||||
def get_shader_combo(self, id: int):
|
||||
# TODO: ugly
|
||||
|
||||
count = 0
|
||||
for i, record in enumerate(WMOShaderTable):
|
||||
|
||||
if i == count:
|
||||
return record
|
||||
|
||||
count += 1
|
||||
|
||||
Reference in New Issue
Block a user